← Back to the screen

Design system portfolio

Aperture — tailwind-css — the record

The four direction lines behind this page, the generator command that produced its tokens, and the pairs it was measured against.

A developer tool's marketing site: the hero, the argument, the pricing. Aperture records a service's calls, queries and jobs in production and replays one of them against the code on a laptop.

Direction

Archetype — editorial spread. Six blocks, five column rhythms. The argument hangs its numeral in one margin and its evidence in the other, and movement 3 swaps the two sides.

Data stance — prose-first. Every figure sits inside a sentence or a margin line naming what it counts.

Density — comfortable, on Tailwind's single --spacing: 0.25rem base. One block breaks it: the recording list runs at 14px on 1.45 leading, against 64px between movements and 96px at the two ends.

The one bold thing — every colour is a measured step. No default indigo, no gray-400 body text, no gray-300 control border, and the pricing figures are set tabular.

Generator

tailwind_theme.py --theme colors
tailwind_theme.py --theme scales

Both write tokens.css. That file is generator output; nothing here edits it.

Measured first

tailwind_theme.py --pitfalls     # exits 1; all six defaults fail, none appear here
tailwind_theme.py --ramps        # first step reaching 4.5:1 on white, per hue

--ramps puts the accent at teal 700 rather than 500. Only six of the 26 hues reach 4.5:1 on white at step 500, and teal is not one of them.

Palette

Three families, from tokens.css only: slate (neutral), teal (accent), red (the over-volume state). The page declares the semantic layer once and flips it per theme, so the markup names roles rather than steps.

PairWhereRatio (contrast.py)
white on teal-800primary button, light7.55:1
slate-600 on whiteevery muted line, light7.56:1
teal-700 on whitelinks, numerals, focus ring5.44:1
slate-100 on slate-900the tight band, both themes16.28:1
teal-300 on slate-950accent, dark13.71:1
slate-950 on teal-300primary button, dark13.71:1
slate-400 on slate-950muted line, dark7.68:1
red-600 on whiteover-volume state4.92:1

Two border tokens, not one. slate-200 (1.23:1) separates rows and never bounds a control. slate-500 (4.77:1 light, 4.23:1 dark) is the boundary of anything SC 1.4.11 covers. Muted text sits a step darker than WCAG asks, at slate-600, because APCA reads 4.77:1 as a 24px colour.

The second state

The pricing block carries a real volume control. Past a plan's included replays that plan states the overage in words and money rather than going quiet; the page loads at 40,000 a month so the page shows the state before anyone touches the control. The workspace line carries a 37-character customer name, the string that breaks a two-column definition list: the label track is measured at 8rem rather than left to auto, so the name wraps in the track that is left instead of starving the label to nothing.

Deviations

No build step, so this page declares the semantic tokens on :root rather than in @theme inline and writes out the utilities they would generate. Names and values match what that block emits. The favicon and the two theme-color metas carry the sRGB of their own tokens, because neither attribute can hold a var().