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:
- No built-in blog. Tags, archive, RSS all have to be hand-rolled on top of
createContentLoader. - Markdown is the router, so a pure app page has to be a
xxx.mdwrapping a<ClientOnly>component. - The dealbreaker: no viewport-level lazy loading.
defineAsyncComponentloads 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.

Comments
…