Stack
Plain HTML, CSS, and JavaScript. One file per page. No build step between writing and shipping.
Why not a framework
The previous version ran on Next.js. It worked fine — until I thought about what it was actually doing. A node_modules folder, a build pipeline, hydration overhead, and a framework update cycle, all for a site whose content fits in a handful of text files. A personal site is a document, not an application. The browser already knows how to render documents.
The one thing the new version had to keep was the hero animation: a full-bleed photo that shrinks and cross-fades into the portrait in the About section as you scroll. That’s the kind of thing people reach for GSAP or Framer Motion to do. It turns out a position:fixed overlay, getBoundingClientRect, and 80 lines of vanilla JS is all it takes.
How it’s built
- HTML
- Hand-authored. Semantic throughout —
article,section,nav,header,aside. No templating engine, no partials. Each page is a self-contained file you can read start to finish. - CSS
- Cascade layers (
@layer reset, tokens, base, components, pages) keep specificity flat and predictable. Design tokens use OKLCH so light and dark palettes scale perceptually. No preprocessor, no utility classes, no purge step. - JavaScript
- Two files.
theme.jscycles auto / light / dark and persists tolocalStorage.hero.jsdrives the scroll animation: aposition:fixedoverlay measured withgetBoundingClientRect, eased through a cubic curve, cross-fading on a CSS transition once the hero scrolls out. No library touches any of it. - Fonts
- Inter Variable and JetBrains Mono Variable, self-hosted as
.woff2. Preloaded in<head>so they never delay the first paint. - Hosting
- GitHub Pages. The working tree is the site. No build output, no CI pipeline, no deploy command — push and it’s live.