0%

process log

Heyyyy! I'm building a design system for humans and AI.

A multibrand fintech token system. Most systems are built to be read by someone who already knows how they work. Hand them to an AI and it picks wrong, confidently, every time. Token names like bg-white-0 mean nothing out of context.

So every token name should encode the decision. Every description should answer what this is for, what it isn't, and what it sits next to.

This is the live log - every decision, every wrong turn, every thing I changed my mind about.

ai-design-system-thumbnail

System state

Built to be read correctly by both designers and AI tools.

225
primitives
128
Semantic States
54
surface tokens
4+
Multibrand Support
12 May 2026Phase 00Audit

Auditing existing design systems

Before building anything, measure what exists

Auditing existing design systems

Audited a handful of free and paid design systems - Untitled UI, Kern UI, Align UI, Hero UI - running their primitive palettes through a programmatic OKLCH analysis. The goal wasn't to criticise any one system. It was to find the failure modes that look fine in Figma but break down in real component usage and in dark mode.

  • 25.7-point lightness spread at step 500 across hues - Blue at L=55.5, Yellow at L=81.2. Same step, completely different visual weight.
  • 24.8° hue drift on the neutral scale - shifts from cool-cyan at light steps to blue-violet at dark steps.
  • Light-end compression on yellow, teal, green - steps 50-200 nearly indistinguishable in practice.
  • Dark mode surfaces lose hue differentiation - all hues converge at steps 800-950 making color-coded cards look identical.
  • Used Tailwind v4 primitives as the starting point. Custom OKLCH-calibrated scales deferred to v2.1.
14 May 2026Phase 01New

Primitive color layer

225 raw values. Zero semantic meaning.

  • 9 chromatic hues x 11 steps + 3 alpha tokens each = 126 vars
  • 9 gray families x 11 steps = 99 vars - neutral, slate, gray, zinc, stone, taupe, mauve, mist, olive
  • OKLCH reference string on every variable. Source: Tailwind v4.
  • Merged chromatic + gray families into one collection 01 · Color Primitives - both are raw values, same usage rule (never bind from components directly), no reason to split.
18 May 2026Phase 02New

Alias layers - brand and gray swap

Mode-based swapping with no component re-binding required

Alias layers - brand and gray swap
  • 02 · Active Gray - 11 tokens, 4 modes. Each mode aliases into a gray family in Color Primitives.
  • 03 · Theme - 14 tokens, 4 modes. Each mode aliases into a chromatic hue in Color Primitives.
  • Chose mode-based over collection-based swapping. A Brand - Purple + Brand - Active wrapper was built first and discarded - required explaining two-collection indirection to every designer. Mode switch is one action.
  • 4-mode cap on Professional plan is an accepted constraint at current scale.
19 May 2026Phase 03Rebuilt

First semantic attempt - torn down

Three structural problems found mid-build

First semantic attempt - torn down
  • Brand tokens existed in three places simultaneously - Component Tokens, Brand - Purple, Brand - Active. Nothing referenced Brand - Active.
  • background/primary/faint - "primary" adds nothing. No secondary exists. Pure noise in every name.
  • "Component Tokens" as a collection name - surface tokens apply to page layouts too, not just components.
  • content/* covered both text and icon fills - Figma requires TEXT_FILL vs ALL_FILLS scopes separately. One token can't correctly serve both.
  • Rebuilt from scratch. Patching in place would leave naming inconsistencies that AI tools would misroute forever.
20 May 2026Phase 04Decision

Naming convention

Group / Role / Appearance / State - names that encode the decision

Naming convention
  • Four-axis convention: Group (background · text · border · icon) / Role (surface · brand · negative · success · warning...) / Appearance (bold · subtle · muted · faint · inverse) / State (hover · pressed · selected · disabled · focus)
  • Chose surface as role for neutral tokens. Considered: "primary" (redundant - no secondary), "neutral" (collides with neutral state in State collection), no qualifier (ambiguous). Surface is descriptive and unique.
25 May 2026Phase 05New

Semantic - Surface

54 tokens covering every component color need

Semantic - Surface
  • background/surface/* - faint · subtle · muted · bold · inverse (5 tokens)
  • background/brand/* - bold · subtle · muted · inverse (4 tokens)
  • text/surface/* · text/brand/* · text/link/* - 9 tokens
  • border/surface/* · border/brand/* - 9 tokens
  • icon/surface/* · icon/brand/* - 9 tokens
  • All interaction states - hover · pressed · selected · disabled · focus for surface and brand (18 tokens)
  • Every token carries structured description: USE / NOT / PAIR / EXAMPLE / alias
  • Merged surface + interaction tokens into one collection - a designer building a button needs both simultaneously. Separation was a build artifact, not an architectural decision.
26 May 2026Phase 06Breaking change

Content/* -> Text/* + Icon/*

Splitting a v1.4 assumption that was always wrong

Content/* -> Text/* + Icon/*
  • v1.4 content/* covered both text and icon fills with a single token per role
  • text/* - TEXT_FILL scope. icon/* - ALL_FILLS scope. 20 content tokens -> 30 tokens.
  • Exceptions: text/surface/muted (placeholder - text only), text/link/* (text only)
  • Clean break, not a deprecation path. Mixed v1/v2 conventions are harder to explain to AI tools than a clear cut with a migration map.
18 May 2026Phase 07New

Semantic - State

128 tokens - 8 states x 4 groups x 4 appearances

Semantic - State
  • 8 states x 4 groups (background / text / border / icon) x 4 appearances (bold · subtle · muted · faint) = 128 tokens
  • State tokens point directly to Color Primitives - unaffected by Theme or Active Gray mode changes
  • Named negative not error - error implies a technical failure. In fintech the red state covers overdrawn balances, declined payments, destructive confirmations. Negative is semantically broader.
30 May 2026Phase 08New

Base group - tokens that never move

Guaranteed white, black, transparent - regardless of mode or gray family

Base group - tokens that never move
  • 9 base tokens. Both modes resolve to the same absolute value - never inverts.
  • Use cases: bank card renders, payment receipts, partner logo containers, document previews - real-world white surfaces that must not invert in dark mode.
  • background/surface/faint is near-white and inverts. background/base/white is #ffffff always. Different jobs, different tokens.
05 Jun 2026Phase 09Audit

System audit

Programmatic check across 428 variables

System audit
  • 0 broken alias references across all collections
  • 256 state aliases correctly pointing to Color Primitives
  • 36 brand tokens -> Theme · 52 neutral tokens -> Active Gray - all correct
  • 225 Color Primitive vars have empty scopes - appear in all pickers. Config issue, deferred.
  • 7 Radius sharp mode values missing. Deferred.
  • space/0 missing value. Deferred.
  • Config issues don't affect token resolution or alias chains. Fixed before first component build.
Architecture

Collection map

What binds where and why

01 · Color Primitives
225 · Value
All raw values. 9 chromatic + 9 gray families. Never bind from components directly.
02 · Active Gray
11 · 4 modes
Gray swap lever. Switch mode on frame to change gray family.
03 · Theme
14 · 4 modes
Brand swap lever. Switch mode on frame to change brand color.
04 · Semantic - Surface
54 · Light/Dark
Primary component binding. background / text / border / icon - surface + brand + all interaction states.
05 · Semantic - State
128 · Light/Dark
Status and feedback. 8 states x 4 groups x 4 appearances.
Never bind from componentsSwap levers onlyComponent binding targets
Abdulqahar UsmanFnStack DS v2 · 2026 · Figma Variables API