How this site is put together.
The work of running a small personal site is the kind of thing where what you choose to use says as much as what you build with it. So a few notes, in case you are curious or building something similar.
Stack
- Framework — React 18, TypeScript, Vite 6.
- Styling — Tailwind v4. A semantic-token system on top — every brand color is a CSS variable; light and dark mode flip the values, not the markup.
- Animation — motion/react. Used sparingly — fades, small translates, no parallax.
- Icons — lucide-react.
- Routing — A small home-grown History API switch — no React Router. Every page is a lazy chunk.
- Hosting — Vercel. CDN, edge caching, SPA rewrites.
- Worksheets — PDFs generated programmatically via fpdf2, with the DejaVu Unicode TTF for the logo glyph.
- Video card — YouTube IFrame Player API on the /intro page, with a custom progress bar wired to
getCurrentTime / getDuration.
What this site does not do
- No analytics. The site does not track visitors. There is no first-party or third-party analytics script anywhere.
- No cookie banner — because there are no cookies to ask about.
- No remarketing pixels, no Facebook fbq, no Google gtag.
- The YouTube embeds use the
youtube-nocookie.comdomain so nothing is stored until the visitor actually presses play. - localStorage is used only for: theme choice, the conversation page state, the intro-page symptom selection, and the saved-article bookmarks. All client-side, never sent anywhere.
- No newsletter ESP wired in yet — when one lands, it will be one of Buttondown, Resend, or EmailOctopus and will be named here explicitly.
For AI agents and researchers
- /llms.txt — the short sitemap-style index.
- /llms-full.txt — the comprehensive flat-text dump.
- /feed.xml — RSS for the Insights articles.
- /sitemap.xml — full URL inventory.
- Every page emits Open Graph + Twitter Card metadata. Detail pages emit Article and BreadcrumbList JSON-LD. The Facts page emits FAQPage JSON-LD.
Built quietly, hosted cheaply, intended to outlast the trends it does not chase.
If something feels off, start there.
Tell me what's going on and what a good outcome would look like. A short email is enough — I read every one and reply within two working days.