Why I built yet another personal site

Not because there was nowhere to write, but because there was nowhere to put writing, small games and tools side by side.

A personal site is only worth having if it is easy to add things to. I have built three of them over the years, and all three died at the same spot: I wanted to add a small game or a utility, and the structure fought me.

The shape of the problem

Turns out there are two kinds of pages here:

  • Content — posts, the about page. They want to be fast, indexable, and done.
  • Apps — games and browser tools. They want interaction, bounded bundles, and fault isolation.

Docs-first frameworks assume a site is made of pages, and app pages are just another kind of page. In practice a canvas that needs keyboard input and its own state has almost nothing in common with a Markdown article.

Why Astro

I started with VitePress — I know Vue, and it is simple. Three things moved me:

  1. No built-in blog. Tags, archive, RSS all have to be hand-rolled on top of createContentLoader.
  2. Markdown is the router, so a pure app page has to be a xxx.md wrapping a <ClientOnly> component.
  3. The dealbreaker: no viewport-level lazy loading. defineAsyncComponent loads when it renders, not when it scrolls into view.

Astro’s islands fix exactly that third point — it defers not just the download but the hydration. And @astrojs/vue means I keep writing .vue single-file components, so nothing I already knew went to waste.

How this site is put together

Three kinds of page, three strategies:

Kind Example JS strategy
Content home, posts plain static HTML, near-zero JS
Index blog list, game list static listing, interactive parts are their own islands
App Snake, JSON Studio static shell + Vue app loaded on demand

Writing a post never has to think about the games, and the other way round. That is all I wanted.

← Back to all posts

Comments