This site · Technical spec
Implementation details
Built for readability in code and on screen. The kitchen sink is the sibling playground; this page is the boring-but-useful changelog dressed as prose.
Core stack
- Next.js 16 (App Router, React Server Components, route handlers, metadata API).
- React 19 + TypeScript 5.
- Tailwind CSS v4 with
@tailwindcss/typography,@tailwindcss/postcss, and repo-root@import 'tailwindcss' source('..')so utilities resolve when the dev server runs from odd working directories. - MDX (
@next/mdx,@mdx-js/react) for long-form pages alongside TSX. - Dev server pinned to webpack (
next dev --webpack/next build --webpack) for predictable MDX + tooling behavior.
Design system & theming
- Geist and Geist Mono via
next/font/google—tight tracking, monospace for meta and code. - Layered CSS:
design-tokens.css,theme-presets.css,semantic-utilities.css, wired into Tailwind’s@themebridge. - PaletteProvider: multiple curated palettes, separate picks for light and dark, persisted in
localStorage, with a tiny inline boot script before paint to reduce theme flash. - Header color mode + palette switchers; sticky header with backdrop blur; skip link and focus-visible rings throughout.
- ThemedPortrait swaps art by color mode—small delight, zero wizardry.
Content, APIs & caching
- Writing: Substack syndication via RSS (
rss-parser), decoded entities, ISRrevalidate = 300so the archive stays fresh without hammering the feed. - GitHub page: public repos from the GitHub REST API, filtered and enriched client-side metadata, hourly-style cache via fetch
next: { revalidate: 3600 }. - Footer widgets: route handlers for Strava (latest activity) and Oura (sleep summary)—live-ish “API as personality” without blocking the main layout.
- Structured data: JSON-LD for Person + WebSite in the root layout; Open Graph + Twitter cards; per-route
metadataand relativealternates.canonical.
Case study UX
- PageLayout with left sidebar nav and optional right “On this page” rail; mobile TOC patterns on long case studies.
- CaseStudyExpandableImage: click-to-fullscreen figures, viewport-width lightbox with vertical scroll for tall screenshots, Next/Image with
unoptimizedwhere re-encoding would soften crisp exports. - Full-screen magnifier (desktop): circular lens, 2×–16× zoom in whole-number steps, scroll-to-zoom over the image, click to toggle magnifier on/off, Escape exits the overlay. (The kind of feature you build when a single PRD screenshot deserves forensic attention.)
Interactive & motion
- Perpetual Beta: client-side force-directed graph (
canvas), concept taxonomy, fullscreen and layout modes—heavy on interaction state, light on dependencies. - Kitchen sink: Motion, carousels, comboboxes, layout experiments—living at /this-site/kitchen-sink.
- Lucide icons, clsx + tailwind-merge for class composition.
Perf, SEO & ops
- Vercel Analytics + Speed Insights in the root layout.
- Sitemap (
app/sitemap.ts) and robots metadata; middleware 301 from legacy/case-studiespaths;/about→/experienceredirect innext.config. - next/image remote patterns for Substack, GitHub Open Graph, avatars; SVG allowed with CSP sandbox where needed.
- Lighthouse npm scripts (
lh:mobile/lh:desktop) for regression checks when pages move.
Local tooling
- ESLint 9 + eslint-config-next, Prettier + Tailwind class sorting plugin.
outputFileTracingRootpinned so monorepo-ish parent folders don’t confuse serverless traces.- App and content live in one repo; environment secrets stay in Vercel (or local
.env) for Strava, Oura, and any server-only keys—nothing fancy, just boring hygiene.
