Design system

The φ lattice

You cannot build a golden grid. φ is irrational and grids are rational. What you can build is the grid that converges on it — and then write down the axioms so a script can tell you when it breaks.

01

The quantum

Every length in the system is an integer multiple k of a single unit. Change the unit and the whole composition rescales with every ratio intact, because ratios are quotients of multipliers and the multipliers do not move. It is one equation with one free variable.

4px u — the quantum

Floor 4px, below which the reading body (4u) drops under 16px. Baseline B = 24px = 6u.

The rhythm tuner puts that variable on a slider: one knob rescales the page and emits the token block for whatever tuning you land on.

02

The ladder

Sizes climb by √φ, so that two steps make one φ. Each rung is a whole multiple of u, and the error against the irrational target is printed rather than hidden — it is the cost of living on a lattice.

Rungpxk · ustepvs √φskipvs φ
xs102.5u————
sm12.53.13u1.25−1.73%——
base164u1.28+0.63%1.6−1.11%
lg205u1.25−1.73%1.6−1.11%
xl266.5u1.3+2.20%1.625+0.43%
2xl328u1.2308−3.24%1.6−1.11%
3xl4210.5u1.3125+3.18%1.6154−0.16%
4xl5213u1.2381−2.67%1.625+0.43%
5xl6817u1.3077+2.80%1.619+0.06%

Every figure above is parsed from the compiled token file at build time. √φ = 1.272, φ = 1.618.

03

The pairs

A size and its leading are the pair a reader actually sees. Each one takes adjacent Fibonacci multiples of u — the best rational approximation of φ that exists at that size. Successive convergents overshoot and undershoot in turn, closing on φ without ever landing.

  • 2:3 4u on 6u 1.5 −7.29% vs φ The early convergent. The reading body.
  • 5:8 5u on 8u 1.6 −1.11% vs φ The lede pair, for a paragraph that opens a section.
  • 8:13 8u on 13u 1.625 +0.43% vs φ Snapped from 33px so the pair could be exact.
  • 13:21 13u on 21u 1.6154 −0.16% vs φ Snapped from 53px. Ladder yields to pair.

Specimen: the 5:8 lede pair, live

This paragraph is set in the lede pair: five units of size on eight units of leading, the setting for a paragraph that opens a section. The reading body under it is four on six. Nothing on this page is a screenshot of the system; it is the system, which is the only demonstration that cannot quietly go out of date.

04

The measure law

Twenty-one leadings of your own size. Because the unit the measure is counted in already scales with the size, one rule lands every column inside the 45–75 character band — with no per-size override anywhere in the system.

504px measure-body

21 × its own leading

672px measure-lg

21 × its own leading

05

Enforcement

Most systems document rules and never check them, so they drift one declaration at a time and nobody finds out. These six are axioms a script reads off the compiled output and the stylesheets that bind to it. A violation exits 1 and fails the build.

  1. A1 Every lead-* and space-* token is an integer multiple of u One lattice, or none.
  2. A2 Reading pairs are adjacent Fibonacci multiples: base 2:3, lg 5:8, 2xl 8:13, 4xl 13:21 The convergents of φ, oscillating toward it.
  3. A3 Adjacent sizes step by √φ (±3.5%); two-step ratios hit φ (±2.5%) Two steps of the ladder make one φ.
  4. A4 The measure is 21 leadings of the body’s own size One rule, no per-size overrides.
  5. A5 Every bound (font-size, line-height) pair uses one size with its own lead, on a line box ≡ 0 (mod u) Where systems actually fall off.
  6. A6 Nothing enters as a raw value: no px, rem or clamp sizes, leadings or spacing, in a stylesheet or inline A token, or it does not ship.

A5 is the one that matters in practice. A1 through A4 are properties of a token file, which is easy to keep clean. A5 is a property of every place a component binds a size to a leading — one hand-typed line-height: 1.5 beside a ladder size, and every rhythm below it inherits the error. So the linter reads the stylesheets, not just the tokens. A6 closes the last door: a raw 15px or an 18px padding typed anywhere, in a stylesheet or an inline style, fails the build before it can ship.

npm run check:rhythm ✓ RHYTHM: u=4px · body 16/24 · all axioms hold (A1 lattice, A2 Fibonacci pairs, A3 √φ/φ ladder, A4 measure=21B, A5 bound pairs, A6 no raw values)
06

What it got wrong

A design system with no recorded errors is one nobody has measured. Two are worth keeping.

The spacing ladder was mislabelled

space-1 through space-6 carried φ-exponent descriptions implying a geometric curve. Measured 2026-08-10: the labels overstated the actual curve by up to 24%. The low ladder is linear by design — utility spacing needs adjacent small steps, and forcing φ onto it produced gaps nobody could use. φ lives in the Fibonacci members and in the type ladder, not everywhere. Naming a linear ramp after φ did not make it φ; it made the label wrong.

Two sizes were off their pairs

2xl at 33px and 4xl at 53px were √φ-correct and Fibonacci-wrong. Snapping them to 32px and 52px cost about 2% of ladder accuracy and bought exact 8:13 and 13:21 pairs. When the ladder and the pairs disagree, the pairs win — the pair is what a reader sees.

enesru