Build write-up · 3 min read

How I built this site

Twenty-seven pages of plain HTML, no framework and no build step, held to four written specs by twelve checks that measure the rendered page. It’s the closest thing to a production codebase I own.

Role
Everything: the design, the code, the checks that hold them together
Size
27 pages, 3 token files, 4 specs, 41 scripts
Status
Live. Every merge deploys; there is no staging in front of it
The homepage of this site at laptop width: the wordmark and six section links across the top, the portrait in a circle on the left, and on the right the eyebrow Hands-on Senior / Lead Product Designer over the title “I design complex workflows and prototype new ideas.”, a two-line dek beginning “Twenty years in enterprise software and new products,” a line saying “Open to senior and lead IC roles · Remote or Twin Cities hybrid,” a green See case studies button, an outlined See lab experiments button, and a Résumé (PDF) link. Under them, six capabilities in two rows of three, each with a small line icon in a pale disc, and a row of six client wordmarks along the bottom.

My approach

  1. 01Tokens

    • Three token files: color, type, and the page shell
    • Four specs that are the rule, not the record of one
    • A fourteen-step type scale and four fluid ramps between its steps
    Why a third of the markup is comments
  2. 02Pages

    • Hand-written HTML with the shell copied in, not included
    • A third of the markup is comments saying why
    • One generated file, and a check that rebuilds and diffs it
  3. 03Checks

    • Twelve checks; six of them render pages in a real browser
    • Contrast measured on the resting page and in every forced state
    • Every number the specs assert, recounted from the tree
    What the checks measure
  4. 04Ship

    • A merge is live in about a minute, with nothing in between
    • Guards that refuse rather than warn
    • AI wrote most of the scripts, to rules that came from failures I found
    What AI actually did

The problem

A portfolio can claim design systems, accessibility, and real code and still sit on a template with a contrast failure in the hero. Then it says the opposite. So this site had to be built to the standard it claims for the work.

That standard is three things I ask of any production codebase:

  • The rules are written down
  • The page is measured against them, not eyeballed
  • A change that breaks a rule is refused before a stranger sees it

Tokens first, and the specs are the rule

Three files hold every value the site may use: the colors, the type scale, and the spacing and radii of the page shell. A color that isn’t in the palette isn’t a color.

Four specs sit over those files: typography, color, spacing, and motion. When a spec and the stylesheet disagree, one of them is a bug, and all four have been found stale at least once.

About a third of the markup is comments saying why: what was tried, what it measured, and what sent it back. I think a rule with no reason attached is the first thing the next change deletes.

The design system itself, every value read live

What the checks measure

Twelve checks run on every merge. Six read the tree and finish in about a second.

The other six open the pages in Chrome and measure what rendered: every color a reader can see, every forced state, and every type size against the scale.

One prototype page draws its key states from JavaScript, only when a reader presses something. For a while, every check said the page passed while measuring a sixth of it.

So a registry now names every state a reader can reach, and each check presses its way into every one. A selector that matches nothing fails the run. Its first pass found a live hover at 1.29:1.

I watch the counts as closely as the verdicts. The state check once passed clean at 416 rules and at 617, and the gap was a third of the site going unmeasured.

What AI actually did

An AI working in a terminal wrote most of the scripts, to rules I set. Nearly every rule came from a failure I found first:

  • The pixel-reading contrast check exists because a caption shipped at 3.88:1 and the ordinary check could not see it
  • The state registry exists because a page passed on a sixth of itself
  • The token check exists because the specs drifted from the stylesheet three times before anyone read them against it

What that changed isn’t who decides. It’s how fast a bad idea can be shown to be bad. A rule I’d once have written down and hoped to remember is now a script that refuses.

The design is mine at every step: the scale, the palette, the order of the page, and every sentence. So is the judgment about what a check should hold the site to.

This way of working has a cost. The site is slower to change than a template, because a change that moves a number has to move the sentence that states it.

For a site whose subject is checking a claim everywhere it’s made, I think that’s the right price.