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.js cycles auto / light / dark and persists to localStorage. hero.js drives the scroll animation: a position:fixed overlay measured with getBoundingClientRect, 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.