How this site is built
13 August 2026/2 min read
This is the first post, so it may as well be the colophon.
The stack
The site is React and Vite, compiled down to plain HTML before it ever reaches a browser. Every route gets rendered twice at build time: once into a client bundle, once through a server bundle that writes real markup to disk. What lands on Cloudflare is a folder of static files.
That matters more than it used to. A crawler that arrives at an empty
<div id="root"> and waits for JavaScript is a crawler that leaves. Language
models scraping for answers behave the same way, only less patiently. If the
sentence is not in the HTML, it does not exist.
The type
Two families, both self-hosted rather than pulled from a font CDN:
- Cabinet Grotesk for anything large. It has the tight, slightly squared counters that hold up when a headline is set at thirteen rems.
- Satoshi for reading.
Seven files, 172 kilobytes total, served from the same origin as everything else. No third party gets to watch you read.
The screenshots
The work index is nine real sites. The cover images are genuine screenshots, captured headless at 1440 by 900 on the day this went up, not mockups and not a device frame wrapped around a placeholder.
The page counts under each one come from that site's own sitemap.xml, read
the same morning. There is a rule in this codebase that says numbers have to be
countable, and the way you keep a rule like that is to make the lazy path the
honest one.
The writing
Posts are markdown files sitting in the repository. A small Vite plugin reads the frontmatter, runs the body through a markdown parser at build time, and hands back finished HTML. The parser never ships to the browser, so a long post costs a reader exactly as much as a short one.
Writing a new post means adding a file and building. That is the whole workflow, and the constraint is deliberate: anything faster tends to turn into something I post to instead of something I think in.