Skip to content
Fedor Molot
All case studies

Mobupps·Design system — strategy, design and code·2026·17 min

Pepper UI: one source of truth for designers, developers and managers

The company's design system, built from the work it already ships: one set of tokens that writes the Figma library, the CSS, the React theme, the chart palette and the rules the AI tools follow — with 88 components, a brand anyone can download, and a test behind every rule. I designed it and built it in Figma and Claude Code.

Internal toolDesign systemsDesign tokensAccessibilityDesign engineeringBrand
LiveThe band from the top of the design system’s documentation site, on its own files — three blurred shapes drifting on the brand’s gradients, in CSS alone.
The problem
The brand blue answered to six different names across the company's files, and four names meant two different colours each. The decks, the website and the products each kept their own copy of the palette, the type scale and the rules — and the rules that mattered most existed only as corrections I had made in reviews. Developers do not open Figma, and managers should not have to.
What I did
I audited every surface by hand, then built one source: tokens that generate the Figma variables, the CSS, the Tailwind and React themes, the chart palette, the PowerPoint exporter's colours and the AI tools' rules. On top of it: 88 components with written contracts, a documentation site the build writes, a brand section for people who are not designers, and a test behind every rule.
What came of it
One name for every colour, and a build that fails when Figma, code and documentation disagree. The new company website installs the system as versioned packages. A product dashboard and the deck tool were moved onto it in working copies, the deck tool with zero pixels changed. Every contrast pair and every focus ring is measured, not assumed.

Six names for one blue

The Mobupps brand shows up in four places: the sales decks, the company website, the products its clients log in to, and a growing set of AI tools that make slides and pages on their own. All four were on brand at a glance. None of them agreed underneath.

I audited twelve surfaces by hand — the decks, the website, the products, the brand files and the AI skills — and recorded every colour, size and spacing value in each one, verbatim, with its name. Then I read the list twice.

Grouped by value, the brand blue #2B25D9 answered to six names: Persian Blue in the deck kit, color/blue/400 in the site's Figma file, --persian-blue and --blue in the deck tool, --color-blue-400 in the site's stylesheets, blue/400 in an AI skill — and once to no name at all.

Grouped by name, it was worse. --blue-bg was #E9E9FB in one file and #D4D3F7 in another file of the same app. --near-black was #141414 in one place and #171717 in the next. Nothing errors when that happens. The colour is just quietly wrong, and stays wrong until a designer happens to notice.

The rest followed the same pattern. Four different blacks were in use. The deck's headings were 66, 46 and 41 pixels; the site's were 65, 45 and 40 — two type scales one pixel apart, each correct in its own file. Charts were drawn three ways — two code libraries and Figma — with the palette copied by hand into each, and the PowerPoint export drew the third and fourth series in different colours from the browser.

Then I measured what actually reaches the screen: of every colour painted by the code, how many arrive through a named value rather than a hex code typed by hand. On the first day it was 41% — 2,349 of 5,730. The spread was the real finding. Wherever a designer had worked, between 57% and 68% of the colour was named. In a product front end built without a designer, it was 2 out of 1,830. In the AI skills it was zero.

The last gap was me. The rules that mattered most — no number floating without a container, padding equal on all four sides, a chart that shows its own baseline — existed as corrections I had made once, in a review. A system that lives in one person's head scales exactly as far as that person's calendar.

Built for the people who are not designers

A design system that lives in Figma serves one person: the designer. Developers do not open Figma. Managers should not have to. So the first design decision was not a colour — it was who arrives at the system, and what each of them is trying to do in the next five minutes.

Live

The top of the documentation’s Getting started page, on its own files. The four cards lead to pages that are not published here.

The documentation's front door for a newcomer. Three audiences arrive for different reasons, so there are three ways in, and each page ends with the first thing to actually do. The bar it is held to: a person who has never met the project can find which blue to use, whether a component is ready, where the logo is and which font to download — without asking anyone.
  • Designers work in one Figma library. Every variable carries the name the code uses, so a developer inspecting a frame reads var(--pui-…), not a number to retype. Every component is drawn in every size and every state it can be in, so nothing is left for a developer to guess.
  • Developers install packages: @pepperui/tokens for the values in CSS, SCSS, Tailwind or Python; @pepperui/css for the components as plain classes, no framework required; React components by name through the shadcn command line. A component is called the same thing in Figma, in the stylesheet, in React and in the documentation — and the tests fail if it is not.
  • Managers, sales, marketing and HR get a brand section written for them: the logos with their rules, the colours to copy, the fonts with a four-step install guide, the social templates, the swag. Every file downloads from the page, and nothing on it needs a Figma seat. For a client deck there is one route: the deck tool, not a blank slide.
  • The AI tools read the system the way a developer does — from a generated file — instead of carrying a pasted palette that drifts.
  • Anyone can ask for something through a short request form that does not assume they know what a token is. Every request gets one of four answers — it exists, it is queued, it is declined and why, or a question back — with a first answer promised within ten working days.

Principles come out of the work

I did not write the principles first. I took the corrections I had made over years of reviewing decks, dashboards and pages, grouped them, and extracted twelve. Each one names what it rules out, because a principle that forbids nothing is decoration. Three of them:

  • One thing per view. When it does not fit, cut content — never shrink the type or the padding. Rules out: two primary actions on one screen.
  • Consistent in the parts, varied in the composition. A component is identical everywhere, to the pixel — and two screens built from those components must not look alike. Rules out: slide two being slide one with new numbers.
  • Nothing from outside the system, and nothing patched on top of it. When an instance looks wrong, the fix is the component, never an override on the instance. Painting over an instance is the same mistake as typing a hex.

I borrowed in a fixed order: shadcn first, then GitLab's Pajamas, then Google's Material. From Pajamas came the structure — principles that forbid, the documentation as the brandbook, its contrast rules. From Material, type named by role rather than size, and touch-target minimums. From shadcn, the component language and the way components are distributed. What I refused was their uniformity. Material and Pajamas prize screens that all look alike; this system also has to produce client decks, and a deck of identical slides fails at its job. That is why the second principle exists.

One source, every side

The system has one source of truth: a set of token files, in the W3C design tokens format, in three tiers. Primitives are the raw values. Semantic tokens say what a value is for — the text on a card, the border of a field in error. Component tokens exist only where a component genuinely deviates, and the file says so in its header: if it grows, the semantic layer is wrong.

Three rules keep it honest:

  • Names are numbers, not adjectives. Persian Blue and Alizarin Crimson are retired. blue/400 tells you where it sits in its ramp; a poetic name tells you nothing, and a second one can always be invented.
  • Every value cites its source. Each token carries the file it was quoted from, so a value can be traced back to the surface that proved it.
  • Nothing is eyeballed. Two steps of the grey ramp did not exist anywhere in the company's files, so they were derived: the midpoint of their two real neighbours in OKLab, a colour space built for how people see. The same midpoint in plain RGB lands visibly too light. A script re-derives them in every test run and fails if they drift.
The three colours
The brand's three colours as a manager meets them on the documentation site: the hex code, the RGB, the token name and the job of each one. Red, yellow and blue, never one and never two — the rule is the brand's, and the system is built on it.

Three colours carry the brand, but a system needs more than three. Behind them sit eight more — each accent's own light tint, the three gradient stops the cover washes are drawn from, and the two status colours — and each one says the single job it has. A secondary colour never becomes the accent of a document; it supports the one that is.

The secondary colours
The eight colours behind the three, as the brand page shows them: the light tint of each accent, the three gradient stops, and the two status colours. The status red carries its own warning: it is not the brand red, and a document that uses the mark's red for a warning has spent the brand on bad news.

Underneath both sits the full system. Every colour is a ramp, and every step is a token with a number and, where it has one, a job: the accent's background at 100, the brand itself at 400, a table's header at 700. The grey ramp runs eleven steps, from the page's white to the black kept for print.

Four ramps of the colour system
The full colour system on the foundations page: the three accent ramps and the grey one, each step named by its number, with its value and, where it has one, its job. Two of the greys say derived — the two steps no file of the company's had, worked out in OKLab.

Space, corners and depth are scales too. Space runs from 2 to 128 pixels on a 4-pixel base, and corners double, from 4 pixels to a full pill. The rules I used to repeat in reviews are written beside them as sentences: a label is a pill and an action is a square; whatever sits inside a container is one radius step smaller than the container; padding is the same on all four sides.

Space and radius
Space and radius on the foundations page, each step a token drawn to its size. The radius table also says what each step is for — controls at 8, cards and dialogs at 16, chips and badges as a pill.

Depth is mostly tonal — a card on the page, a slot in a card — so shadows are few, and each one is named for the job it does.

The elevation levels
The elevation levels in use, on the Figma library's Elevation page — from a hairline under an input to the shadow under a dialog, each with its value and the components that take it.

Values change with modes, not with copies. The accent mode switches a surface between blue, red, yellow and all three. The canvas mode switches the type between the website at desktop, tablet and phone sizes and the 1920-pixel slide — which is how the deck's 66-pixel heading and the site's 65-pixel one became one role in two modes instead of two scales. Dark mode is not built yet, on purpose: Figma's plan allows four modes per collection, and the four accent modes the products need came first.

One build turns the source into everything a team uses:

  • CSS custom properties for the web, and SCSS for the website's PHP stack;
  • a Tailwind preset in both of its current formats, and a theme for shadcn;
  • the Figma variables, with their code names attached;
  • a Python module, so the PowerPoint exporter draws with the same colours as the browser;
  • the chart palette and the illustration library's values;
  • and DESIGN.md, the file AI agents read to learn the system.

A rule with a test behind it is a rule; a rule in a document is a hope. That sentence opens the system's verification script, and the test run makes 27 checks. Some are about values — no hard-coded colour above the first tier, no Figma collection over its four-mode limit. Some are about agreement — the chart theme equals the tokens, every icon a page draws exists in the library. The one that matters most is parity: a script reads the Figma library and the code and fails the run if a component, a variant or a name exists on one side and not the other.

One typeface, four jobs

The brand has one typeface, Poppins, in four weights, and the system gives each weight a job. Regular is for reading. Medium is for body-sized emphasis — buttons, labels, a card's title. SemiBold is a display weight for headings and big numbers, never for body text. Bold is kept for the few places the deck sets it — a table's row headers, cover and chapter titles. Light and Black, the weights the old brandbook named, are out.

Poppins at its four weights
The face, the four weights and what each is for — on the brand page, with the font files and their licence one click away. Fourteen type roles are built from these four weights, each sized for its canvas: the website at three widths, and the slide.

Icons work the same way: one set, Lucide, at four sizes — 16, 24, 32 and 48 pixels — each a token with the place it belongs. A glyph is swapped, never redrawn, and one the set lacks is a request to the system rather than a file of a page's own. The CSS package ships the same 276 glyphs as one sprite, so a developer writes the icon's name and the component paints it.

Forty of the icons
Forty of the set's 276 glyphs, from the icon page of the Figma library, each drawn at 24 pixels with its name — the same names the CSS package's sprite uses.

Components with a contract

The system holds 88 components. I did not pick them from a list of what design systems usually have. I took what the company's products and pages actually use, added shadcn's standard set so a developer never meets a gap, and added a whole family for the AI assistant's chat — messages, suggestions, attachments, the composer — because that is where the products are going.

The wall below is the documentation site's own front page, running on its own files. Every card on it is a component from the package, placed as it is — the page draws nothing of its own.

Live — try it

Every card here is a component from the package, placed as it is — the page draws none of its own. Type in a field, flip the switch, tick the box.

The wall from the documentation site's front page: buttons, fields, a data table, KPI tiles, the AI assistant's chat, a stepper, a command menu — every one a component from the CSS package, on the system's three colours. Type in the fields, flip the switch, tick the box.

Every component carries a contract, written once in Figma and carried into the code and the documentation: when to use it, when not to, what it is related to, and its anti-patterns. The button's says two primary buttons side by side, a primary button for cancel, ALL CAPS labels, and a fill changed on the instance. A contract is what lets a developer, a new designer or an AI agent make the decision I would have made — without asking me.

The block below is the CSS package's specimen — the page its screenshot tests are taken from — one component at a time. The two switches above it are the workshop's own: accent and canvas, setting the same two attributes the workshop sets.

Live — try it

Button. The section of the CSS package's specimen — the page its screenshot tests are taken from — with every size and state the component has. Switch the accent or the canvas the way the workshop does.

Twelve of the 88 components, from the package's own specimen, with every size and state each one has. Switch the accent and every part that takes one re-reads it from a single attribute; parts with a fixed role — the black primary button, a status colour — stay as they are, on purpose. Switch the canvas to Slide and every component built on type roles takes the deck's sizes.

Components also add up to patterns, and the newest is where the products are going: a chat with Echo AI, the company's AI assistant. It is nine components in one column — the card under its branded strip, the thread, the turns, the bubbles, the ranked proposal, the projection chips, the markers, the attachments and the composer — with one rule above them all: text a model wrote is marked where it appears.

The Echo AI chat
The top of the Echo AI chat, as the documentation renders it from the workshop: the branded strip, a date marker, the question in a quiet card with its time inside it, and Echo's answer under its own mark — a ranked proposal with a confidence pill and a budget on every row, and the actions that apply it. A pattern in Beta, on made-up data; no product runs it yet.

Components are released as Beta and earn Ready in production, not by a version number. Beta means usable, with an interface that may still change in a minor release; Ready means it changes only in a major one. A component gets there by being used in a product, which is a bar a release cannot clear on its own.

Accessibility, measured, not assumed

Accessibility claims are easy to write and hard to check, so the system measures instead of claiming.

  • Contrast, by role. Not every colour against every surface — that produces hundreds of meaningless failures. Each text role is checked on each surface it can actually sit on, nine roles by ten surfaces, and every one of the 90 cells has a verdict.
  • The focus ring, rebuilt. The ring the website used was a 15% tint, about 1.2:1 against the page — invisible to anyone who needed it. The new one is a 2-pixel line that clears the 3:1 floor on every surface a control can sit on, with the old tint kept behind it as a soft halo. Of the focus indicators the package paints, 330 of 333 now meet the strictest focus criterion in WCAG 2.2.
  • The keyboard. Tab order is document order across all 344 stops, and Shift+Tab is its exact reverse — no keyboard traps anywhere in the library.
The button's accessibility, measured
The bottom of the button's page: every ink-on-ground pair the button actually renders, with its measured ratio and the floor it is held to, then the focus ring on each surface. Nothing in these tables is typed by hand — they are a slice of the measurement files the build writes.

One exception is on record, and it is deliberate. The red subtitle reads 2.83 against a 3.0 floor on a card. It has been in front of real users across the site, the decks and the deck tool without a complaint, and retuning the brand red to pass one threshold would have broken the colour system everywhere else. So it is written down — named, dated, limited to that one pair in that one role — and reported by the tools rather than hidden. An accessibility tool that suppresses a real number is worse than none.

Charts from one palette

Charts were where drift had already become a visible bug, so the chart package was built early: one palette, four renderers — ECharts and Chart.js in the browser, the PowerPoint exporter, and the chart recipes in Figma. Every one of them reads the same values from the tokens.

The rules were settled on pictures, not in a document: the same chart drawn two ways, side by side, and the better one kept. Twelve came out of it. Eleven are about a chart's shape — a column stands on its baseline, a value axis draws a gridline at every labelled tick, a ranked list reads from the largest down. The twelfth is about colour, and it makes colour a rule rather than a choice: each accent mode has its own series order, so a chart never has to invent a colour. The block below holds six of the standard's own charts — one of each kind — running on their own files: pick an accent and watch the rule work on all six at once.

Live — try it

Six of the documentation's own charts — columns, line, horizontal bars, forecast, donut, stacked columns — drawn from the accent's chart tokens. Pick another accent: every series re-reads its colour from one attribute on the page.

Six kinds of chart from the standard's own page — columns, a line, horizontal bars, a forecast, a donut and stacked columns — each drawn in HTML from the accent's chart tokens. Switch the accent and every series on all six re-reads its colour from one attribute on the page, in that accent's own order.

Illustrations that are built, not drawn

The system also holds an illustration library: 37 isometric objects — a phone, a laptop, a server rack, a shield, a megaphone — and 30 scenes composed from them. Every scene exists in four palettes and facing two ways, drawn twice from one description: live in WebGL for the web, and as a still for slides and PDFs. The mobupps.com case study shows how a page places one; this is the library itself.

Every scene is put together from the objects, so the objects are the library's vocabulary. Its showcase page lists each one with the name to ask for it by.

The objects on the showcase page
Twenty-four of the objects on the library's showcase page, each with the name to ask for it by, an SVG, a PNG at 2× for slides, and a live version that turns under the pointer.
Live — try it

Loading the engine — until it is ready, the element shows the still, so a picture is never empty.

The design system's illustration element on the library's own scenes — the deck's three-layer slide, a data flow, an ad opening an app, a release, two phones. Switch the palette and the picture re-colours from the system's ramps; switch the direction and the camera moves to the other corner. Live drifts on its own and turns under the pointer; Still is the file a slide gets.

Nothing in the library is drawn by hand, but nothing reaches it without a designer's eye either. A complex new object is drafted with AI on a design canvas, rendered as a model, and marked up by me against the library's rules before any scene may use it. The markup is literal: red lines on the render, saying what moves where.

The sketch and the result
The sketch and the result. Left: my red lines over a draft of the deep-link picture, marking where the two cards should stand. Right: the result, approved and taken into the library — the cards at different depths, the second a step nearer.

An object goes through the same loop, from more sides. For the megaphone the example was mine: a blueprint of it in six views — side, opposite side, front, rear, top and bottom. The first model built to it did not follow it closely enough, so the rule became that a blueprint is matched view by view: every part measured off my panels, the model drawn in the same six views beside them at one scale, and corrected until each pair agreed.

The megaphone, checked against six views
The example and the check. In each pair, left: my blueprint; right: the model, drawn in the same view at the same length. A scene may turn an object any way, so every side has to hold.

Then the review, on the model itself, before any file was made from it.

My marks on the model
My two marks on the model: the tab on the housing comes off, and the handle goes plain white with a small red trigger.

And the result — the megaphone as the library ships it, drawn live by the same engine as every scene above.

Live — try it

Loading the engine — until it is ready, the element shows the still, so a picture is never empty.

The result: the megaphone in the library, live. Switch the palette and it re-colours from the system's ramps; switch the direction and it turns to face the other way. Still is the file a slide gets.

Some decisions are made on pictures and then held by the code. One object in the library, the pedestal, cast a soft shadow on the ground — the only shadow anywhere in it, and so an inconsistency on every page that used it. I looked at both versions, live and still, and removed it. The rule now is that no object casts a shadow: depth comes from the outline, the three lit faces and what stands in front of what.

The brand, for people who are not designers

The old brandbook was a PDF. A document that has to be re-exported to be corrected is a document that is wrong most of the time, so it is retired: the brand now lives in the same documentation, generated from the same source, in a section written for the people who use it most and who are not designers.

The logo page shows the five marks — the company and its four products — each on the ground it was drawn for, with every variant to download. Its rules are measured, not asserted. The clear space around a mark is a quarter of its height, a distance the artwork itself contains. The smallest size the wordmark may be used at was found by rendering it narrower and narrower and counting the letter counters still open; below 120 pixels on screen they start to close.

Clear space and the smallest size
The logo's two size rules on its brand page. Clear space is a quarter of the lockup's height on every side — the chevron in the disc measures almost exactly that. The minimum is measured: at 120 pixels wide all four counters are still open, and below it they start to fill in. In print the floor is 15 mm.

The mistakes are shown the same way: with the real file, put wrong.

What never to do to a mark
Two right ways and four wrong ones, each made from the real logo file rather than drawn as a mistake: straight onto a gradient, recoloured, stretched, crowded.

Most people meet the brand in a deck, so decks are built from the system too. The presentation page draws the deck's working set — nineteen layouts — in HTML from the same tokens and components as a product screen, at the slide's own sizes. A deck steps through the three colours, each slide taking the one after its neighbour, so no two neighbours match.

Six slides
Six of the nineteen layouts, coloured in the order a deck takes them — red, yellow, blue, red, yellow, blue: cards, an icon list and bullets beside a photograph, then the same three beside a chart. The same components on every slide and no two slides alike — the second principle, on the canvas it was written for.

The social templates are nineteen frames at the sizes the platforms ask for — covers, link posts, square posts, stories — each made from the design system's tokens and components and shown at its real pixel size, with the editable frame one click away.

Square posts
Six of the seven square posts in the social set — every colour and type size a token of the system, each the frame's own export. A marketer edits the words in the frame, not the design.

The swag follows the strictest version of the rules: one garment, one mark, nothing else. The mark is always placed from its file, never redrawn — a supplier is sent the file, and a redraw of it is refused.

A tee and a cap
Renders I made for the swag page: the full mark alone, on white and off-white cloth, at the centre of the chest and the front of the crown.
Three tote bags
A bag is a bigger canvas and carries more than a shirt, one idea per bag: the product ring with the four products, the mark with the company line, and the red disc alone.

Documentation the build writes

The documentation site has 110 pages, and none of them is edited by hand: a script generates every page from the repository — the tokens, the components and their contracts, the accessibility measurements, the roadmap, the changelog. A number on that site is the number in the build, or the build fails. Documentation that is typed separately from the thing it documents is wrong by the second release.

Beside it runs a workshop where every component is rendered from its specimen. In every test run each one is screenshotted and compared with a committed reference, and any changed pixel fails the run; an automated accessibility audit runs on each one too, and the few exceptions it allows each carry a written reason.

Built for the AI tools as well

Some of the company's slides and pages are now made by AI tools — Claude skills that build decks, dashboards and web pages. Before the system, each of them carried its own pasted table of colours, and the tables disagreed.

Now the build generates DESIGN.md, the file AI agents read to learn a design system, and lints it. The updated AI skills ask one skill about the system instead of carrying a palette: it holds no values of its own, it resolves any hex, old name or role to the right token, and a test fails the build if a value is ever pasted into it. The system is also published as a design system in Claude Design, so a new page or a new illustration starts from the same tokens and components as everything else — which is how the library's newest objects are drafted.

Proved where it matters, without surprising anyone

A design system is only as real as its first consumer. But a product team does not need a designer changing their code without warning, so I held to one rule: prove it in a working copy first, and hand the result to the owners.

The website runs on it. The new company website installs the tokens, the CSS and the illustrations as versioned packages, like any other dependency. Building it on the system sent more than forty requests back — a spacing step the scale lacked, a component a page needed. One of them: the site set every section 128 pixels apart and had typed that number by hand 39 times, because the spacing scale stopped at 80. The scale now runs to 128, and a named step carries the rule. The mobupps.com case study tells that side of the story.

A product dashboard: where it is going, and the first step. MAFO, the company's advertising platform, was built without a designer, on a stock UI kit. I was asked for concepts of a new look for MAFO and the company's other products, and I designed them on the system.

MAFO's dashboard today, and my concept for its new look, designed on the design system — afterMAFO's dashboard today, and my concept for its new look, designed on the design system — beforeBeforeAfter
Drag the handle. Before: MAFO's dashboard as it is today, on its stock UI kit — a working copy with made-up data. After: my concept for its new look, designed on the system — the headline numbers as tiles, the panels as cards, the charts on the system's palette. A concept, not a shipped screen; every name and number in it is made up.

A concept is not a product, so the move itself starts smaller and proves itself first. In a working copy of MAFO, I themed the whole app from the tokens through its own UI kit and rebuilt two screens — the dashboard and a table page — on the system's components. The old kit's components disappeared from those screens entirely, and the app's stylesheet shrank from 619 to 365 KB, partly because the old kit had been loaded twice. I ran the themed copy against the live data before handing it over.

The deck tool, with nothing changed. The best migration is the one nobody can see. In a copy of the deck tool, I replaced its hand-kept palette with the system's tokens, mapping every old name to its new one so no existing rule broke. Then I compared every slide of twenty decks, pixel for pixel: 141 of 141 identical, and 593 of 593 of the tool's own rule tests still green. The colours now come from the system; the slides do not know.

A deck slide before and after its colours moved onto the design system's tokens — afterA deck slide before and after its colours moved onto the design system's tokens — beforeBeforeAfter
A slide from the deck tool, before and after its palette moved onto the system's tokens — drag the handle. Nothing moves. That is the result: 141 slides compared at full resolution, none of them different by a single pixel.

How it is run

A design system without an owner is a style guide with a release date. So the running of it is written down as plainly as the components are.

  • Two approvers. The design lead and the tech lead. Some changes need one signature, some need both, and the rules say which.
  • Versions that mean something. Each package is released on its own, with a version that says what changed: a changed value is a minor release, a removed name is a major one, and a rename keeps the old name working as an alias until consumers move. Thirty-four releases have been cut across four packages.
  • One command checks every channel. A release is checked on the repository, the package registry, Claude Design and the documentation site, and the command reads the version back from each before it calls the release done.

What I would do differently

Look at the picture before trusting the gates. Once, every automated check on a component was green and its page was wrong in four ways at once — a logo drawn as a word, a bar wider than its container, a dropdown filling the screen. The checks tested what they were written to test; nobody had looked. That became a rule of the system: a component is checked rendered, and the check is the picture, not the stylesheet. I would have made it the rule on day one.

Count what is on screen from the start. My first audit counted names, not what reaches the screen. When I later measured usage, deleting a stylesheet nobody loaded raised the score by fifteen points without naming a single colour. I kept that out of the baseline — a number that improves when you look away is worthless — but measuring the right thing first would have found it sooner.

Measure whether people like using it, not only whether they use it. I skipped formal interviews: the system was already approved and the company was waiting for it, so the case for it was made. The cost is written down rather than argued away — the system measures how much of each surface runs on it, and nothing yet measures whether the people using it find it pleasant. That is the next instrument to build.

Scope, honestly

I designed the system and built it in Figma and Claude Code: the audit, the principles, the tokens and the build, the Figma library, the components and their contracts, the CSS, React, chart and illustration packages, the documentation and the workshop, the accessibility measurements, and the way the system is governed. The tech lead is the second approver. The product teams own adoption in their products, and the production apps were not changed by this project.

The company's logos predate the system; it documents them and sets their rules. The swag pictures are renders I made for the brand pages, not photographs of produced pieces.

Results

  • 6 → 1

    Names for the brand blue

    One hex code, six names across the deck kit, the site, its stylesheets, the deck tool and an AI skill — now color/blue/400 everywhere, from Figma to Python.

  • 386

    Tokens, written once

    They generate the Figma variables, CSS, SCSS, two Tailwind formats, the shadcn theme, a Python module for PowerPoint, and the DESIGN.md the AI agents read.

  • 27

    Checks in every test run

    From "no hard-coded value above the first tier" to "Figma, code and documentation name the same components". A rule with a test behind it.

  • 0 → 12 of 12

    Focus-ring pairs that pass

    The old ring was a 15% tint, about 1.2:1 against the page. Rebuilt as a 2 px line, it clears the 3:1 floor on every surface a control can sit on.

  • 141 of 141

    Deck slides unchanged after the move

    The deck tool's hand-kept palette swapped for the system's tokens and compared pixel for pixel — 593 of 593 of its own rule tests still green.