Colophon
How this site is built - just an accurate record of the stack in case it's useful to anyone building something similar.
Last updated
Framework & hosting
- Framework
- Astro 6.3 - static, no adapter. Pages are pre-rendered at build time and served as static files. No server-side rendering, no edge Worker running per request. This keeps cold starts at zero and the performance budget honest.
- Hosting
- Cloudflare Workers
(Static Assets binding) - the
@astrojs/cloudflareadapter is absent because there are no dynamic routes yet. Static files are served directly from Cloudflare's edge without a Worker script in the hot path. - Deploy
- Wrangler -
wrangler deploypushes thedist/build to Cloudflare. No Pages, and CI (GitHub Actions) runs type-check, lint, tests, a build, and Lighthouse on every push; the deploy itself stays a manual step.
Styling
- CSS engine
- Tailwind CSS v4 CSS-first config - the design tokens live in a
@theme {}block inglobal.css, not a JS config file. Tailwind's utilities reference the same custom properties that raw CSS and React islands use. One source of truth. - Colour space
- oklch - perceptually
uniform, P3 gamut support, better interpolation than sRGB hex. The dark background is
oklch(16.36% 0.0067 178.64); the teal accent isoklch(69.71% 0.108 186.44). - Type scale
-
Fluid
clamp()scales computed on a 1.25 ratio (major third), running from 320px to 1240px viewports. Type and spacing scale continuously - no breakpoint jumps. Inspired by Utopia. - Scoped styles
-
Each
.astrocomponent carries its own<style>block - Astro scopes these at build time. Global utilities (tokens, base resets, the skip link) live inglobal.cssonly. Nothing leaks.
Typography
- Display / headings
- Fraunces - a "wonky" optical-size serif with soft, considered letterforms. Variable font (weight + optical size axes). Used for headings, the home positioning line, and OG card titles.
- Body
- Inter - high-readability sans, variable font. 18px / line-height 1.6 on desktop; 16px on mobile. Measure held at 65ch.
- Mono
- JetBrains Mono - code blocks, inline code, and the "currently building" card. Part of the visual identity, not just a fallback.
- Loading
-
Astro 6's built-in Fonts API - self-hosted, subset,
font-display: swap, preloaded above the fold. No external font requests at runtime. Zero layout shift from font loading.
Content
- Format
-
MDX - essays and case studies are
.mdxfiles insrc/content/, version-controlled in git. No CMS. No database. Editing means editing a file and committing it. - Code blocks
- Expressive Code - line numbers, language labels, hover-copy button, and a custom syntax palette derived from the site's tokens. Not a stock rainbow theme.
- Reading time
- Calculated at build via a remark plugin - adjusted for code blocks and figures, not raw word count ÷ 200. Small integrity signal.
Performance & SEO
- Lighthouse
- 100/100/100/100 on home, /writing, an essay, and /work. Performance is part of the argument - a slow site undermines the credibility it's trying to build. Targets are enforced at each phase gate, not audited at launch.
- OG images
- astro-og-canvas - per-entry cards generated at build via Skia (canvaskit-wasm). Fraunces title on a dark background with the teal left border. Static files, no runtime Worker.
- View transitions
-
Native cross-document CSS View Transitions - the
@view-transition { navigation: auto; }rule inglobal.cssopts the site in. The motion is CSS; the only JavaScript is a ~25-line inline hint that tags each navigation forward, back, or morph so the page slides the right way. Graceful degradation in browsers that don't support it. - AEO / LLM-legibility
-
Semantic HTML5 landmarks, JSON-LD (
Person,BlogPosting,CreativeWork,BreadcrumbList),/llms.txt+/llms-full.txt, and raw-markdown endpoints at/writing/[slug].md. Astro's static output puts content in the markup - the biggest single AEO win, no JS hydration required to extract text. - Analytics
- Cloudflare Web Analytics - privacy-respecting, no cookie banner, no Google. The site doesn't track visitors to sell them things.
A few deliberate choices
- Dark is default.
prefers-color-schemeis respected, with a persisted manual toggle. Light mode is first-class - the same tokens, just swapped at a semantic layer. - The Now page is never stale. The "last updated" timestamp on the about page is pulled from git history at build time, targeting the about file specifically. Edit the file, commit, the timestamp updates automatically. Calls the bluff of every dead "Now" page online.
- prefers-reduced-motion everywhere. Not a checkbox - all animations and transitions respect it, including the cross-document view transitions and the home type reveal.
- No front-end framework. The main site ships zero React - no islands, no hydration.
The interactive bits - search, the theme toggle, footnote popovers - are a few KB of vanilla
JS. The React work lives in a separate
/labapp, kept out of the main bundle. - Icons are inline SVG. Lucide via
astro-icon- inlined at build, sized by token, no runtime JS.