Design System.

Colour, type, grid, space, icons, motion. The rules this site is built out of, each one shown running rather than described.

8Hues
24Colour tokens
…Worst contrast
4Easing curves
01

Four rules everything else falls out of.

A system is only worth having if it decides things for you. These four do the deciding; every token further down is a consequence.

Derive, don’t pick

No token is chosen by eye. Each is generated from a rule, which is why there are twenty-four of them and only three numbers to remember.

One hue per room

Every section owns a hue and carries it from the tile into the page. Colour is how you know where you are, so it never gets used decoratively.

Motion is structure

Nothing moves for charm. Every transition either shows where a thing came from or where it is going. Four curves, used consistently.

Prove it, don’t claim it

Contrast ratios, chroma spreads and hue angles here are computed at runtime. If the system breaks, the page says so.

02

The whole palette comes out of one orange.

01
The wheel Every hue sRGB can reach, at one lightness. Saturation runs from nothing at the centre to each hue’s maximum at the rim.
02
Find the orange The brand mark’s #d4622a lands at 44°. That single point is the seed for everything else on this page.
03
Swing to its opposite Straight across sits 224°, and the greys were already at 258–266°. The cool half wasn’t invented; it was already there at low chroma.
04
Fan out the eight Three warm hues hold the brand’s side. Five cool ones develop out of the complement, spaced so no two read as the same colour in a grid.
05
Cap the chroma One ceiling across all eight, so no hue can shout louder than its neighbours. Where a hue can’t reach the cap, it sits inside it.
03

Three weights of each.

Lite is the tile. Ink is its label, its artwork, and the ground its page opens on. Mid carries rules, links and accents. Click any swatch to copy it.

Why the tiles sit at L 0.775

Two ways to read “bright.” Watch the bars arrive: one set lines up and the other can’t.

Worst case …, best …, a spread of … across eight different hues. That evenness is the rule working, not luck.

04

Two faces, no middle ground.

One face shouts and one explains. Nothing sits between them. The moment a third weight appears to bridge the two, the hierarchy stops working.

Impact / Anton

The house display face. Condensed, heavy, uppercase, tracked tight. Impact first so it’s the real thing where installed; Anton covers Linux, where it isn’t.

The two case studies are the deliberate exception: each carries its own product’s display face, because a case study that argues for a design system should be set in it. Coffer takes Plus Jakarta Sans 800, Box Buddy Baloo 2 800, and both tiles hand over to that face on hover, at the same moment they hand over to the product’s colour.

DM Sans

Everything you actually read. Optical-size axis, weights 300–600, 1.6 line height, capped at 52 characters so a paragraph never outruns a comfortable measure.

The scale

Display
clamp(48px, 12.5vw, 220px)
line-height .98
Section
clamp(32px, 5.6vw, 90px)
line-height 1.02
Subhead
clamp(18px, 2vw, 27px)
line-height 1.05
Body copy, set at a comfortable measure.
clamp(15px, 1.3vw, 19px)
line-height 1.6 · max 52ch
Note and caption text.
13px
line-height 1.6
05

A grid with a hole in it.

Four columns at 20/30/30/20, the middle two offset from each other by half a button, every seam tangent to an edge of the centre button. All eight tiles are different sizes, which is what stops it reading as a spreadsheet.

1 2 3 4 5 6 7 8

Space

--nav-tile-gap · 10px desktop / 5px mobile
tile padding · 23px desktop / 14px mobile
--b2 · half button, the offset the whole grid is built on
--button-size · 90px desktop / 64px mobile
page margin · 8vw, display type inset a further 2.4vw
06

Two numbers, three states.

The whole site changes shape at exactly two widths: 1024px and 640px. Everything else, meaning column count, where the section numeral sits, which rules are structural, how many cards fit in a row, is derived from those. Drag the handle to watch the grid re-form.

StateWidthColumnsNumeralRules drawnRows of three

Why 14, 8 and 4

Desktop keeps two columns for the margin numeral, which leaves twelve for the body, and twelve divides by 2, 3, 4 and 6, so every repeating row lands on a drawn rule instead of near one. Below that the numeral moves above the content and the body takes the full width: eight divides by 2 and 4, four only by 2. Three across is the one arity that never divides cleanly, so it gets a shared utility that narrows the row rather than being re-derived per page.

Solid is earned, per state

A rule is drawn solid only where content actually starts or stops on it; a rule content crosses stays dashed and says so. That verdict is re-made at each state. Boundary 2 is structural on desktop because the body begins there. Below desktop the body spans the full width, so the same line stops marking anything and demotes to a dashed reference. Drawing it solid on a phone put a hard line straight through body copy.

One exception, and it is a height. The Coffer case study opens on a full-screen hero, and on a short phone the copy alone fills the screen, so the product mockup landed just below the fold. That is a vertical problem, so it takes a vertical query: (max-width:640px) and (max-height:760px) tightens the type and shrinks the shot. It is the only height-based breakpoint on the site.

07

Solid at rest, outlined on touch.

One icon per tile, in that tile’s own deep tier. Five are the tile’s real vector reused rather than traced, including Mayo’s crest, coordinate for coordinate. Every one is a filled shape that hollows to a 2px stroke on hover: same silhouette, inverted weight. Hover them.

Coffer is the exception, and deliberately so. Its mark is a bitmap Angela owns, flooded with currentColor through its own alpha the way the tile does it, so it inverts by colour instead of by weight. Tracing it to win back the outline was not on the table; an earlier hand-traced version read as a different chest.

Each glyph keeps whatever viewBox its source came on: 100×100 for the drawn ones, 300×200 for the cloud, 45.4×28 for the crest. That is because reusing a real mark means taking its coordinate space with it rather than refitting it. vector-effect: non-scaling-stroke holds the outline at exactly 2px whatever the box, and fill and stroke are both currentColor, which is what lets a tile invert without a single extra rule.

08

Motion is architecture, not decoration.

Four rules decide whether motion on this site feels built or bolted on. None of them are about taste. Each one is a structural choice that a curve cannot rescue. Every demo below is live.

01 · One set of numbers, two states
scroll 0
The eight tiles hold exactly two arrangements, and both are the same formula at different values. Scrolling the home page drives it 0 → 1; opening the menu parks at the same two ends. Because navigating and opening the menu are literally the same numbers, they feel like one gesture at two speeds, something no amount of matched timing would fake.
Home scroll · every menu · nav.js
02 · Scroll sets a target, a loop eases toward it
move across →
raw
eased
Pointer and scroll events arrive in irregular bursts, so anything rendered straight off them inherits that stutter no matter how good the curve is. The fix is not a curve: input sets a target, and a frame loop moves the real value toward it at 0.14 per frame. The top dot is bound to input; the bottom one is damped.
The colour wheel · design-system.js
03 · Never rebuild animated DOM
per frame
rebuild
transform
measuring…
The first colour wheel redrew its markers with innerHTML every frame. That throws away compositing, forces layout on every node, and makes each marker pop instead of move. Building the nodes once and only ever transforming them was the entire fix. The easing never changed.
Wheel markers · grid rules · tile artwork
04 · Stagger is a ladder, not a group
together
laddered
Elements that arrive at once read as one block appearing. Given a delay per index they read as a sequence being built, and the eye follows the order instead of taking a snapshot. Grid rules ladder left to right, cells top to bottom, and the structural rules always land before the reference ones.
Every grid, cell and stagger on the site

One more, learned the hard way: direction belongs in a custom property, not a selector. Coffer's mockups alternate the side they enter from. Written as :nth-child(even) that rule counted the tab row as a child and outranked the arrived state on specificity, so two of four panels stopped mid-flight. Moving the direction into --dx / --rot fixed it, because custom properties carry no specificity at all.

The four curves

None are stock. Each exists because a stock easing visibly flattened the thing it was applied to. Each curve draws itself in its own shape; the dots run on the real values.

Snapcubic-bezier(.4, 0, 0, 1) The workhorse. Every reveal on the site. The second control point at 0,1 is what produces the long decelerating tail.
UIcubic-bezier(.4, 0, .2, 1) Hover states, tile colour changes, the menu. Symmetric enough to stay neutral when it fires dozens of times a minute.
Swoopcubic-bezier(.6, 0, 0, 1) The pinwheel opening and closing. Slower to leave, faster to arrive, so it reads as weight rather than speed.
Assemblycubic-bezier(1, .25, .85, 1) The home page scroll. x1 = 1 holds the tiles nearly still through the first stretch, so the grid arrives with a rush.

Reveals are one-shot. Once an element has arrived it never resets, even on the way back up. Replaying them makes a long page feel twitchy and makes re-reading unpleasant.

09

The constraint that set the palette.

Contrast wasn’t checked at the end. It picked the lightness the whole system sits at, which is why all eight clear AA without a single hand adjustment.

AA on all eight

Label on tile never drops below 4.6:1, computed live at the top of this page. No hue got a manual nudge to pass.

Motion opt-out

prefers-reduced-motion is honoured everywhere: the wheel stops, reveals resolve instantly, the marquee holds still.

Real focus order

The parked navigation is inert, not just invisible, so a keyboard never tabs into eight offscreen tiles it can’t see.

Colour is never alone

Every hue is paired with a label and a position in the grid. Nothing here is identified by colour on its own.

10

Where this came from.

The pinwheel grid, the tile-to-page transition and the idea that a brand site should behave like the thing it documents are all lifted from one place, and it would be dishonest not to say so.

Dropbox Brand Guidelines

The direct reference. The eight-tile pinwheel with a button as a hole in the grid, the scroll-driven assembly, and the label-in-its-own-deep-hue rule are theirs. Built by Dropbox Brand Studio with Daybreak Studio.

What I changed

Their palette is hand-picked; this one is generated. Eight hues derived from a single brand orange and its complement, held at one lightness so they weigh the same, which their set, measured, does not.

Foundations model

The section order, running principles, colour, type, grid, space, iconography, motion, accessibility, follows the structure common to Atlassian, Carbon, Polaris and Material.

Eight doorways.
One system.

Keep scrolling and the grid comes back. Or hit the tab, or press Escape.Keep swiping up and the grid comes back. Or tap the button.