Sep, 16, 2026

The personal starter

If you’re a web developer or software developer in today’s world, you’d be familiar with the terms templates, kits, starters, boilerplates, generators, stacks etc. From my understanding as a developer, all of this in its simplest form aims at helping developers with code they refuse to write twice and will reuse. This concept has existed from Rails generators through HTML5 Boilerplate, Yeoman, create-react-app to the Remix Stacks, the Epic Stack, create-t3-app, the shadcn registry model and the list goes on. I’d in fact argue that your CSS libraries & frameworks, the likes of Bootstrap & Tailwind, sneak their way into this category because in a way, those CSS libraries & frameworks help you move fast with prewritten CSS styles.

While I’m also a software developer, I’d prefer to keep this topic in the lens of a web developer. This is because I see how easy it is to mix up the product regime (SaaS-like starters) with what I’d call, for the sake of clarity in this writing, the “studio regime”, which focuses more on websites. A third piece, and it’s the subject of this post’s stance, is “the personal starter”, usually with an audience of one.

I’m deliberately choosing to use the term “starter” among the others to categorize this, because I’d define a starter as an opinionated project folder with layers that could include the routes, controllers, utils and views you need etc.

Product vs studio

That definition is loose on purpose, because the layers change depending on who the starter is for. On the product side the layers you’d expect are auth, a database, email, payments, maybe analytics, and something like the Epic Stack or create-t3-app is a good picture of that. On the studio side none of that really shows up, instead it’s smooth scroll, page transitions, a WebGL layer that has to stay in sync with the page, a tune panel, a dev grid etc.

Both get called starters and both are opinionated, but I’d argue they aren’t deep in the same way, and a lot of the “this starter is bloated” or “this starter does nothing” takes I see come from holding one up against the other’s checklist.

The personal starter

The personal starter is a bit of a strange one because the author is also the only user. There’s no adoption to worry about, no landing page to sell it and no team to onboard, which sounds freeing until you realize the only thing keeping it honest is your next project. If I clone it for a new site and the first thing I do is delete half of it, then that half belonged to the last project and I just got attached to it.

What goes in

The way I’d decide what goes in is frequency. If something shows up in most of the sites I build it earns a place, and if it only showed up once, even if it was the best thing I made that year, it stays in that project. For the kind of sites I build that ends up being:

  • The page lifecycle (what runs when a page mounts and what gets cleaned up when it leaves)
  • The transition between pages
  • Scroll
  • The text reveals
  • Type and spacing tokens
  • The SEO head and the deploy setup

The paper shader on my own site doesn’t make the list, as much as I like it.

Shape and engines

There’s another split I’d make. Some of this code is shape, like the folders, the tokens, the layouts and the config, and I want every project to own its own copy and bend it however it needs. Other parts, like the transition engine or the page lifecycle, have an actual API, and copying those from project to project means every site ends up with its own slightly different version of the same bug.

For those I’d rather have small packages I can version and update, and let the starter just wire them up. In the Odyn Astro starter that wiring is one file, src/app.ts, and it mostly reads like a list of what’s plugged in:

import { createApp, safe } from "@odyn/lifecycle";
import { Conductor, wipeLeg } from "@odyn/conductor";
import { Reveal } from "@odyn/reveal";
import { createEngines, mediaHold } from "@odyn/engines";

Keeping projects in sync

This is also why I don’t try to keep projects in sync with the starter. It’s tempting, fix it once and every site gets the fix, but the moment a project starts it’s supposed to drift, that’s the whole point of it being mine to change. Most of the product starters say the same thing in their own way, the Epic Stack pretty much tells you the code is yours and there’s no update path.

What I do instead is stamp each project with the version of the starter it came from, so if I ever want to bring something across I can at least see what changed. It’s just a few lines in package.json:

"starter": {
"name": "odyn-astro-starter",
"initialised": false,
"ref": "v1.0.0",
"head": null,
"date": "2026-09-04"
}

Anything that proves itself in a project goes back into the starter by hand.

Why small

I’d also argue smaller lasts longer. A big starter feels great the day you clone it and then slowly turns into something you’re scared to touch, while a small one you can read in one sitting and actually keep current. Anthony Fu’s tiny starter-ts has outlived his much bigger Vitesse, and Kent C. Dodds’ Epic Stack somehow got more opinionated while getting smaller, which is the direction I want mine going in.

Odyn Astro starter

All of this is what I tried to put into the Odyn Astro starter. It’s static Astro with vanilla TypeScript, SCSS and GSAP, deployed on Cloudflare, no React and no islands, because that’s how I build sites.

The engines live in their own small packages, the rest is plain project code each new site owns, it runs from a fresh clone without needing an account or an API key (something I see people complain about on starter repos all the time), and there’s a written reason next to every decision so future me doesn’t have to guess why something is there.

It’s still early though. The real test for a personal starter is the second project that comes out of it, and whatever that project deletes without thinking twice is probably what I got wrong, so I’ll likely write about that when it happens.

Credits

Sincerely,