How this site was built
The denouement
Every quest ends with a look back at the road. This is the story of how this site was built, told as its own lifecycle: the same six stages the site describes, applied to itself. The tools are on the colophon page. This page is about what happened.
The road, walked once more, from the first brief to the last watch.
- 232
- browser test runs on every push: 116 tests, on a desktop and a phone profile
- 4
- problems the checks caught before launch
- <10 s
- to build the whole site
- 460 KB
- total weight of the built site, fonts included
The road, stage by stage
Requirements
The Council
The brief was a résumé and one reference site. I wanted a personal site in the spirit of Keith Huster's that sells what I do for a client's development lifecycle: strategy, automation, release readiness and AI adoption. Ground rules came first. Everything comes from the résumé, no invented numbers, "seasoned" instead of a years count, and credentials live on the CV page.
- A résumé as the single source of truth
- Ground rules for the copy
Plan and design
Rivendell
The idea was simple: your lifecycle is a road, and quality walks all of it. Six stages became six waypoints, dressed in a fantasy-journey theme of parchment, ink and crimson seals. I fixed about seventeen color and font tokens and checked their contrast ratios before writing any CSS. Then the stack: static Astro, content in YAML validated by schemas, layout in components.
- Design tokens, light and dark
- Content schemas
- A page and component plan
Build
The Mines of Moria
The first version was a single hand-written HTML file, which made design changes quick. Once the design settled I rebuilt it as a project. Copy moved into 18 YAML files, markup into ten components, behavior into four small scripts, and the road map became SVG drawn from the content. Fonts are installed from npm and served from the same origin.
- 18 content files
- 10 components and 5 pages
- 4 small scripts
Test
The Bridge
Nothing crosses without evidence. A strict schema rejects bad content, an HTML validator checks the output, a link checker walks every anchor, and Playwright drives the built site in a real browser with axe watching for accessibility problems, in light and dark mode, on a desktop and a phone profile. The bridge held, and it also found four things I would rather nobody saw.
- A strict content schema
- HTML and link checks
- 116 browser tests on two profiles
Release
The Great River
A change reaches the world by one route. Commit, and a local hook validates it. Push, and the browser tests run. Open a pull request, and CI runs every check plus a secret scan. Merge to main, and the exact build that passed is deployed to Cloudflare. The only secrets are the two deploy credentials, and they live in GitHub's encrypted store, never in the repository.
- A five-job CI pipeline
- A deploy that only runs from main
- Secrets kept out of git
Maintain
The Watch
The road stays open through small habits. Dependabot proposes updates weekly and CI decides whether they land. Guard tests pin the wording decisions I made on purpose, so they don't drift. Changing a role or a number is a one-file edit that the schema checks. Next on the list: a form service so messages deliver without an email app, and an image pipeline if photos arrive.
- Weekly dependency updates
- Guard tests for wording
- A one-file edit for any change
What the checks caught
Text silently dropped from a YAML file
Two lines of copy contained unquoted commas inside one-line entries, so YAML split them and half the text vanished without an error. A comparison of the old and new pages spotted it. The schema is now strict, so any stray key fails the build and names the file.
Caught by a text comparison, then the strict schema.
Gold text that was too faint
The gold line on the dark AI panel measured 3.97:1 against the 4.5:1 that WCAG AA asks for. I had checked the panel color but not the slightly lighter tint under it. A lighter gold now carries text on dark panels, and the accessibility tests fail if any pairing slips.
Caught by axe accessibility checks in the browser tests.
Road map stops that were hard to click
Only the painted circle and the label responded to a click, so the space between them did nothing. The click test for each waypoint timed out. Every stop now has a full-size hit area.
Caught by the Playwright waypoint tests.
A compass rose with its top cut off
The compass behind the hero was clipped by the top edge of the section. No test noticed. I saw it the first time I looked at a real render, and moved it.
Caught by a screenshot review, by eye.
A skip link real Safari users couldn't reach
Chromium and Firefox include a plain link in the keyboard tab order by default; WebKit, the engine behind Safari, doesn't, unless a person has "Full Keyboard Access" turned on system-wide. The skip link exists specifically to be the first thing a keyboard user reaches, so on Safari it was quietly unreachable. It now carries an explicit tabindex.
Caught by the WebKit project, once it actually ran.
The end of the road, for now
The tools and the reasons for each are on the colophon page. Read the colophon.
Designed and built with Claude in a chat, over many rounds of direction and revision, then turned into this repository. The layout was inspired by keithhuster.com. Nothing here is a template.
Updated September 21, 2026
Want to talk about your SDLC?
Get in touch