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.

Box Buddy is the deliberate exception: it carries its own product’s display face, Baloo 2 800, because a case study that argues for a design system should be set in it, and its tile hands over to that face on hover at the same moment it hands over to the colour. Mass Virtual takes the slot next to it and does not, because its own voice is condensed uppercase, which is what Anton already is. Nothing to hand over.

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.

Two numbers, and they are widths. Every breakpoint on this site is a width. There was once a single height-based one, on a case study whose full-screen hero pushed its product shot below the fold on a short phone, but that page has since been retired and the exception went with it. The rule it proved still holds: reach for a height query only when the problem is genuinely vertical, which is rarer than it looks.

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.

Mass Virtual is the exception, and for the opposite reason to the rest. There is no vector mark to reuse: the only copy of that logo here is burnt into a photograph, and tracing a wordmark off a JPEG ships a slightly wrong version of somebody else’s brand. So its cell is drawn, a headset rather than a logo, which is the subject of the work instead of the client’s identity.

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. A retired case study's mockups alternated the side they entered 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

A library I keep a live file.

Everything above documents the site you are standing in. This one is the other half of the practice: a working Figma library, open and messy at the edges, that I use to keep up with the tool. When Figma ships variables modes or a new way to handle properties, this is where I go and rebuild something in it.

It started as the design system for a reading app called Pagepaw. I shelved the product after some research turned up two competitors doing it better, which was the right call and a cheap one to make at that stage. The library outlived it. It is the piece that was always going to be useful again.

101Variables, two modes
43Components
172Variants
8Documented pages
Generated, not drawn

The tokens were written in code first and the app was built from them. The library was then generated out of that same code, so it can’t quietly disagree with what shipped. A library maintained by hand starts lying the first week somebody fixes something without opening Figma.

Modes, not duplicate frames

Light and dark are two modes of one variable collection rather than two sets of screens. Flip the mode on any frame in the file and it holds, which is the only version of dark mode that survives contact with a second designer.

Start on Decisions

Page five is eight calls where my first answer was wrong, each set against what replaced it. More honest about how the work went than the finished screens are, and the page I would open first if I were you.

The file’s own cover, which doubles as its index. Use the page menu top left to move through foundations, components, screens, wireframes, decisions, the prototype and the art.

11

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.

Angela Clemons designed and built this system, and the site running on it. Available now for contract or full-time, remote, US and international. angela.b.clemons@gmail.com

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.