Site2026Design, build and copy

A site that has to argue for itself

A personal site with two jobs that usually fight: convince a design-literate visitor in ten seconds, and survive being read by an engineer.

  • Astro
  • Hand-authored CSS
  • GSAP
  • Cloudflare Pages

Context

Most personal sites answer one question and dodge the other. A polished shell says designer and has nothing underneath it. A list of jobs says engineer and reads like a CV. This one has to pass both readings at once, without a blog cadence, a content team or a design system to borrow.

The audience is narrow on purpose: someone hiring for platform or cloud security work, who will open the source, run the performance audit and read the copy properly. They are looking for reasons to close the tab.

Constraint

The constraints came before the design, and most of them are the reason it looks the way it does.

  • Free hosting, private repo. Static output on Cloudflare Pages. No server, no database, no runtime that can be slow at 3am.
  • Every effect pays for itself in bytes. That rules out the usual shortcuts: blurred orbs, backdrop-filter panels, blend-mode grain, a 9 MB background video.
  • No scroll hijacking. Native scrolling, real headings, keyboard first. If a visitor lands mid-page from a search result, the page still makes sense.
  • Motion is optional and never load-bearing. prefers-reduced-motion removes it, and nothing depends on an animation finishing to become readable.
  • No publishing pipeline. Content is Markdown in the repository. A push is a deploy.

Decision

Four decisions did most of the work.

Tokens instead of a framework. One stylesheet, with custom properties for type, space, motion and two themes. A utility framework earns its keep on a large application; here the interesting parts are a pinned stage, clip masks and a labelled cursor, and utilities make those harder to read rather than easier.

A pin, not a hijack. The “how I work” section uses position: sticky and a scroll listener whose only job is writing data-step. CSS owns every transition. Below 48rem, or on a short viewport, or with reduced motion, the pin switches off and the same content is a plain list. Turning the effect off costs nothing, because the effect was never load-bearing.

Motion that explains something. The pinned stage carries a real artefact — a terraform plan with its annotations — and each scroll step moves the emphasis down the list. The animation is the explanation, not a curtain in front of it. The same rule applies to the rest: line masks let a heading arrive the way type is set, and the labelled cursor only appears on a fine pointer.

Claims get checked. A link checker walks every built page, Lighthouse runs before a deploy, and the numbers on this page come from the same build the page is in.

Artefact

npm run buildproduction
✓ 36 page(s) built in 4.5s
✓ html files: 36
✓ internal refs checked: 686
✓ no broken internal links
✓ Base.css  36.5 kB raw · 10.0 kB gzip
✓ case.css   4.7 kB raw ·  1.3 kB gzip, case studies only
✓ accessibility 100 · best practices 100 · SEO 100
The whole quality gate: one static build, a link check and three Lighthouse categories. The header font is a self-hosted variable file, not a request to a font CDN.

Outcome

The site now argues its own case. It has a homepage that reads in one pass, a knowledge base of working notes rather than thought-leadership, and case studies for the projects that deserve more than a card. Nothing on it needs a database, a build server or a subscription.

The honest limits: the pinned stage hides its artefact below 64rem, where the column is too narrow to read a terminal; the labelled cursor is pointer-only by design; and this is the first case study, which makes it either admirably self-referential or slightly circular, depending on your patience.

The thing I would change next is the copy on the other project cards. A card can say what a thing is. It cannot say what it cost you.