Skip to main content
SR

AI Engineering Lab

I define tokens, components and rules once. Your team uses them in React, Angular, Vue, Swift or Kotlin, and your agents read them instead of guessing: less repeated code, fewer tokens spent and fewer fixes in review.

This page is the proof: one source of truth, rendered for people and published for agents. AI speeds up the implementation; the architecture, accessibility and final review stay with me.

See the system

Everything on this page comes from the same tokens and specs. No AI API, no database.

For your team

  • One component, five stacks: React, Angular, Vue, Swift and Kotlin
  • Change a token once and every app follows
  • Specs with usage and accessibility rules built in

For your agents

  • Spec, tokens and code from a public JSON registry
  • Rules to follow instead of styles to guess
  • A check that catches hardcoded values before review
01One source of truth

One system, every stack.

Tokens and specs are written once. Style Dictionary turns tokens/lab.tokens.json into CSS variables, SwiftUI and Jetpack Compose, and every stack below gets the same Card from the same templates. Change the primary colour and all five follow.

Change primary color

#E23A0D

Same token as the playground's Accent.

Contrast check

All 10 contrast pairs from the specs pass with this primary.

From the playground

Variantelevated

Radius8px

Pick Card in the playground to change the variant.

One change, every output

  • tokens.cssReact · Angular · Vue

    --ds-color-primary: #e23a0d;
  • Tokens.swiftSwift

    public static let colorPrimary = Color(red: 0.886, green: 0.227, blue: 0.051, opacity: 1)
  • Tokens.ktKotlin

    val colorPrimary = Color(0xffe23a0d)

Primary is #E23A0D in React, Angular, Vue, Swift and Kotlin.

Live preview · webcard · elevated · 8px · #E23A0D

Tokens, not hex codes

The image is a placeholder.

The live preview renders this example with the same card.css and button.css.
import type { CSSProperties } from "react"import { Button } from "./Button"import { Card, cardParts } from "./Card" // The card in the lab: an image, a title and a primary Button as its action. const media: CSSProperties = {  width: "100%",  aspectRatio: "16 / 9",  objectFit: "cover",  borderRadius: "calc(var(--ds-radius-card) / 2)",} export function CardExample() {  return (    <Card variant="elevated" size="md">      <img src="/cover.jpg" alt="" style={media} />      <h3 className={cardParts.title}>Tokens, not hex codes</h3>      <Button variant="primary">Read the docs</Button>    </Card>  )} 

Spec

specs/card.spec.json · What the component is, how to use it and which tokens it reads. The code above takes its variants, sizes and defaults from it.

{  "$schema": "./schema/component-spec.schema.json",  "name": "Card",  "description": "A surface that groups related content, such as a title, a short text and one action.",  "source": "components/lab/demo-components.tsx (styles: RECIPES.card in lib/lab/playground.ts)",  "element": "article",  "extends": "HTMLAttributes<HTMLElement>",  "whenToUse": [    "Group related content with at most one main action: a project, an article, a setting summary.",    "Show several items of the same kind side by side, each in its own Card."  ],  "whenNotToUse": [    "As a clickable surface: Card has no button role or keyboard handling. Put a link or a Button inside it instead.",    "For page layout or whole sections: use plain layout elements."  ],  "props": [    {      "name": "variant",      "type": "enum",      "values": [        "elevated",        "outlined",        "filled"      ],      "default": "elevated",      "required": false,      "description": "Surface style: shadow, hairline border or a tint of color.primary."    },    {      "name": "size",      "type": "enum",      "values": [        "sm",        "md",        "lg"      ],      "default": "md",      "required": false,      "description": "Padding and maximum width, from RECIPES.card.sizes."    },    {      "name": "disabled",      "type": "boolean",      "default": false,      "required": false,      "description": "Sets aria-disabled, dims the card to 50% and blocks pointer events."    },    {      "name": "children",      "type": "node",      "default": null,      "required": false,      "description": "The content, styled with cardParts (eyebrow, title, body, action)."    },    {      "name": "className",      "type": "string",      "default": null,      "required": false,      "description": "Extra classes, merged after the recipe with cn()."    }  ],  "variants": [    "elevated",    "outlined",    "filled"  ],  "sizes": [    "sm",    "md",    "lg"  ],  "states": [    {      "name": "default",      "description": "elevated: color.surface with a soft shadow. outlined: transparent with a color.border hairline. filled: color.surface tinted 10% with color.primary."    },    {      "name": "hover",      "description": "elevated: deeper shadow. outlined: the border turns color.primary. filled: the tint grows to 16%. data-force=\"hover\" pins this state for docs and visual tests."    },    {      "name": "disabled",      "description": "aria-disabled=\"true\", 50% opacity and no pointer events."    }  ],  "tokens": [    {      "path": "color.surface",      "usage": "elevated background, and the base of the filled tint."    },    {      "path": "color.text",      "usage": "Text colour, including cardParts.action."    },    {      "path": "color.muted",      "usage": "cardParts.body and cardParts.eyebrow text."    },    {      "path": "color.primary",      "usage": "cardParts.action underline and focus ring, outlined hover border, filled tint. Never text."    },    {      "path": "color.border",      "usage": "outlined border."    },    {      "path": "radius.card",      "usage": "Corner radius; the action's focus ring uses half of it."    },    {      "path": "space.sm",      "usage": "Padding at size sm (the web recipe's p-4 has the same value)."    },    {      "path": "space.md",      "usage": "Padding at size md (p-5, same value)."    },    {      "path": "space.lg",      "usage": "Padding at size lg (p-6, same value)."    },    {      "path": "fontSize.title",      "usage": "cardParts.title text (text-base, same value)."    },    {      "path": "fontSize.body",      "usage": "cardParts.body and cardParts.action text (text-sm, same value)."    }  ],  "accessibility": {    "role": "article, from the native <article> element. The Card itself is not interactive.",    "keyboard": [      "The Card is not focusable; Tab reaches the links or buttons inside it.",      "When disabled, also take inner actions out of the tab order (tabIndex={-1}): aria-disabled and pointer-events do not do that."    ],    "focus": "The action (cardParts.action) shows a 2px color.primary ring on focus-visible. Inner Buttons keep their own ring.",    "contrast": "Title and body text at least 4.5:1 against the card background in every variant (WCAG 2.2 AA, 1.4.3).",    "contrastChecks": [      {        "label": "title and action text",        "foreground": "color.text",        "background": "color.surface",        "min": 4.5      },      {        "label": "body and eyebrow text",        "foreground": "color.muted",        "background": "color.surface",        "min": 4.5      },      {        "label": "action focus ring",        "foreground": "color.primary",        "background": "color.surface",        "min": 3      }    ],    "labels": "Start the content with a heading (cardParts.title) so the article can be found by heading navigation."  },  "composition": [    "Content goes inside as children, styled with cardParts: eyebrow, title, body and action.",    "cardParts.action styles a link. A Button can be the action instead, as in the 'One system, every stack' Card, which composes an image, a title and a primary Button."  ],  "example": {    "language": "tsx",    "code": "<Card variant=\"elevated\" size=\"md\">\n  <p className={cardParts.eyebrow}>Design system</p>\n  <h3 className={cardParts.title}>Tokens, not hex codes</h3>\n  <p className={cardParts.body}>Components read semantic tokens.</p>\n  <a href=\"/system\" className={cardParts.action}>Read the docs</a>\n</Card>"  }}

Shared or platform-local

Decided per token, not left to the sync. Colours, radii, spacing, type and the visible control heights are the same everywhere. The minimum touch target is not: the web, Apple and Google each set their own.

TokensScopeValue
color.{surface, text, muted, primary, onPrimary, border, controlBorder}SharedSame on every platform
radius.{card, button, input}SharedSame on every platform
space.{sm, md, lg}SharedSame on every platform
fontSize.{title, body}SharedSame on every platform
control.{sm, md, lg}SharedSame on every platform
control.minTargetPlatform-local
  • Web 24px
  • iOS 44pt
  • Android 48dp

Set in tokens/lab.tokens.json, under $extensions.

tokens/lab.tokens.jsonSource of truth

The source file, with your primary and radius edits applied. Every stack above is built from it.

{  "color": {    "surface": {      "$type": "color",      "$value": "#1B1C21",      "$description": "Card background",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "text": {      "$type": "color",      "$value": "#F2F2F4",      "$description": "Primary text on surface",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "muted": {      "$type": "color",      "$value": "#A0A0AB",      "$description": "Secondary text: card body, hints, placeholders",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "primary": {      "$type": "color",      "$value": "#E23A0D",      "$description": "Brand accent: buttons, links, focus",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "onPrimary": {      "$type": "color",      "$value": "#000000",      "$description": "Text on primary, picked for contrast",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "border": {      "$type": "color",      "$value": "#2E3037",      "$description": "Decorative hairlines and outlined cards",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "controlBorder": {      "$type": "color",      "$value": "#6B6E78",      "$description": "Boundary of form fields, at least 3:1 against surface",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    }  },  "radius": {    "card": {      "$type": "dimension",      "$value": "0.5rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "button": {      "$type": "dimension",      "$value": "0.5rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "input": {      "$type": "dimension",      "$value": "0.5rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    }  },  "space": {    "sm": {      "$type": "dimension",      "$value": "1rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "md": {      "$type": "dimension",      "$value": "1.25rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "lg": {      "$type": "dimension",      "$value": "1.5rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    }  },  "fontSize": {    "title": {      "$type": "fontSize",      "$value": "1rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "body": {      "$type": "fontSize",      "$value": "0.875rem",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    }  },  "control": {    "sm": {      "$type": "dimension",      "$value": "2rem",      "$description": "Small control height",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "md": {      "$type": "dimension",      "$value": "2.5rem",      "$description": "Medium control height",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "lg": {      "$type": "dimension",      "$value": "3rem",      "$description": "Large control height",      "$extensions": {        "dev.santirequelme": {          "scope": "shared"        }      }    },    "minTarget": {      "$type": "dimension",      "$value": "1.5rem",      "$description": "Minimum touch target: 24px web (WCAG 2.5.8), 44pt iOS, 48dp Android",      "$extensions": {        "dev.santirequelme": {          "scope": "platform",          "ios": "2.75rem",          "android": "3rem"        }      }    }  }}
02For people

Change the design, read the code.

A designer or developer tunes the component and gets code that matches. Every control updates the live component and the code at the same time; the preview renders the exact React component shown in the panel.

Controls

Component

Variant

Size

Theme

State

8px

Accent

#E23A0D
Live previewbutton · primary · md · default
Text on accent: 4.84:1 AA--ui-radius: 8px--ui-accent:#E23A0D
Framework
This is the code the preview is running.
import { forwardRef, type ButtonHTMLAttributes } from "react"import { cn } from "@/lib/utils" const base = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--ui-radius)] font-medium transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ui-canvas)] disabled:cursor-not-allowed disabled:opacity-50" const sizes = {  sm: "h-8 px-3 text-[13px]",  md: "h-10 px-4 text-sm",  lg: "h-12 px-5 text-base",} as const const variants = {  primary: "bg-[var(--ui-accent)] text-[var(--ui-on-accent)] enabled:hover:bg-[var(--ui-accent-hover)] data-[force=hover]:bg-[var(--ui-accent-hover)]",  secondary: "border border-[var(--ui-border)] bg-[var(--ui-surface)] text-[var(--ui-fg)] enabled:hover:border-[var(--ui-accent)] data-[force=hover]:border-[var(--ui-accent)]",  ghost: "bg-transparent text-[var(--ui-fg)] enabled:hover:bg-[color-mix(in_srgb,var(--ui-accent)_12%,transparent)] data-[force=hover]:bg-[color-mix(in_srgb,var(--ui-accent)_12%,transparent)]",} as const export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {  variant?: keyof typeof variants  size?: keyof typeof sizes} export const Button = forwardRef<HTMLButtonElement, ButtonProps>(  ({ variant = "primary", size = "md", type = "button", className, ...props }, ref) => (    <button      ref={ref}      type={type}      className={cn(base, sizes[size], variants[variant], className)}      {...props}    />  ),)Button.displayName = "Button"
03For agents

Built for agents, not just people.

The same system is published as a public registry, so an agent reads the right spec, tokens and code instead of guessing from screenshots or writing the component again.

What it saves, measured on this page

What an agent reads to build the Card and Button for Angular: the registry's answer, not the source files.
26 KBinstead of 54 KB
The Angular Card component. Its CSS (106 lines) is written once and shared by React, Angular and Vue.
32 lines
Caught by validate_usage in the answer written without the system, before anyone reviews it.
7 issues
Source files compared

AGENTS.md, tokens/lab.tokens.json, specs/card.spec.json, specs/button.spec.json, lib/lab/stacks.ts, lib/lab/component-css.ts, lib/lab/templates/shared.ts, lib/lab/templates/card.ts, lib/lab/templates/button.ts

Measured on this demo when the page is built. Not a benchmark of a real project.

What the system checks about itself

Runs before every build

Validating usage is not enough: a wrong token used correctly is still wrong in five languages. So the build also checks the values: every contrast pair the specs ask for, the touch target on each platform, and that each token is declared shared or platform-local. If one fails, the deploy stops.

Contrast
93/93
Touch targets
6/6
Token scope
2/2
See every check (101)
  • Button: primary labelcolor.onPrimary on color.primary: 4.84:1, needs 4.5:1
  • Button: secondary and ghost labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Button: focus ringcolor.primary on color.surface: 3.92:1, needs 3:1
  • Card: title and action textcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Card: body and eyebrow textcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Card: action focus ringcolor.primary on color.surface: 3.92:1, needs 3:1
  • Input: typed text and labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Input: placeholder and hintcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Input: field boundarycolor.controlBorder on color.surface: 3.34:1, needs 3:1
  • Input: focus bordercolor.primary on color.surface: 3.92:1, needs 3:1
  • Button: no text in color.primaryPrimary is only used for fills, borders, underlines and focus rings
  • Card: no text in color.primaryPrimary is only used for fills, borders, underlines and focus rings
  • Input: no text in color.primaryPrimary is only used for fills, borders, underlines and focus rings
  • Touch target on webcontrol.minTarget is 24px; WCAG 2.2, 2.5.8 Target Size (Minimum) asks for 24px
  • Touch target on iOScontrol.minTarget is 44pt; Apple Human Interface Guidelines asks for 44pt
  • Touch target on Androidcontrol.minTarget is 48dp; Material Design asks for 48dp
  • Web control heightssm 32px, md 40px, lg 48px, at least 24px
  • iOS tap area in codeButton and Input pad their tap area to Tokens.controlMinTarget
  • Android tap area in codeButton and Input pad their tap area to Tokens.controlMinTarget
  • Every token is shared or platform-local18 shared, 1 platform-local (control.minTarget)
  • Platform-local tokens have iOS and Android valuesEach one has a web, iOS and Android value
  • Playground light, Signal: Button: primary labelcolor.onPrimary on color.primary: 4.84:1, needs 4.5:1
  • Playground light, Signal: Button: secondary and ghost labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Signal: Button: focus ringcolor.primary on color.surface: 4.33:1, needs 3:1
  • Playground light, Signal: Card: title and action textcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Signal: Card: body and eyebrow textcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Signal: Card: action focus ringcolor.primary on color.surface: 4.33:1, needs 3:1
  • Playground light, Signal: Input: typed text and labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Signal: Input: placeholder and hintcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Signal: Input: field boundarycolor.controlBorder on color.surface: 3.69:1, needs 3:1
  • Playground light, Signal: Input: focus bordercolor.primary on color.surface: 4.33:1, needs 3:1
  • Playground light, Violet: Button: primary labelcolor.onPrimary on color.primary: 4.79:1, needs 4.5:1
  • Playground light, Violet: Button: secondary and ghost labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Violet: Button: focus ringcolor.primary on color.surface: 4.38:1, needs 3:1
  • Playground light, Violet: Card: title and action textcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Violet: Card: body and eyebrow textcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Violet: Card: action focus ringcolor.primary on color.surface: 4.38:1, needs 3:1
  • Playground light, Violet: Input: typed text and labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Violet: Input: placeholder and hintcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Violet: Input: field boundarycolor.controlBorder on color.surface: 3.69:1, needs 3:1
  • Playground light, Violet: Input: focus bordercolor.primary on color.surface: 4.38:1, needs 3:1
  • Playground light, Blue: Button: primary labelcolor.onPrimary on color.primary: 5.33:1, needs 4.5:1
  • Playground light, Blue: Button: secondary and ghost labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Blue: Button: focus ringcolor.primary on color.surface: 3.93:1, needs 3:1
  • Playground light, Blue: Card: title and action textcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Blue: Card: body and eyebrow textcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Blue: Card: action focus ringcolor.primary on color.surface: 3.93:1, needs 3:1
  • Playground light, Blue: Input: typed text and labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Blue: Input: placeholder and hintcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Blue: Input: field boundarycolor.controlBorder on color.surface: 3.69:1, needs 3:1
  • Playground light, Blue: Input: focus bordercolor.primary on color.surface: 3.93:1, needs 3:1
  • Playground light, Green: Button: primary labelcolor.onPrimary on color.primary: 6.44:1, needs 4.5:1
  • Playground light, Green: Button: secondary and ghost labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Green: Button: focus ringcolor.primary on color.surface: 3.25:1, needs 3:1
  • Playground light, Green: Card: title and action textcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Green: Card: body and eyebrow textcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Green: Card: action focus ringcolor.primary on color.surface: 3.25:1, needs 3:1
  • Playground light, Green: Input: typed text and labelcolor.text on color.surface: 18.58:1, needs 4.5:1
  • Playground light, Green: Input: placeholder and hintcolor.muted on color.surface: 5.88:1, needs 4.5:1
  • Playground light, Green: Input: field boundarycolor.controlBorder on color.surface: 3.69:1, needs 3:1
  • Playground light, Green: Input: focus bordercolor.primary on color.surface: 3.25:1, needs 3:1
  • Playground dark, Signal: Button: primary labelcolor.onPrimary on color.primary: 4.84:1, needs 4.5:1
  • Playground dark, Signal: Button: secondary and ghost labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Signal: Button: focus ringcolor.primary on color.surface: 3.92:1, needs 3:1
  • Playground dark, Signal: Card: title and action textcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Signal: Card: body and eyebrow textcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Signal: Card: action focus ringcolor.primary on color.surface: 3.92:1, needs 3:1
  • Playground dark, Signal: Input: typed text and labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Signal: Input: placeholder and hintcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Signal: Input: field boundarycolor.controlBorder on color.surface: 3.34:1, needs 3:1
  • Playground dark, Signal: Input: focus bordercolor.primary on color.surface: 3.92:1, needs 3:1
  • Playground dark, Violet: Button: primary labelcolor.onPrimary on color.primary: 4.79:1, needs 4.5:1
  • Playground dark, Violet: Button: secondary and ghost labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Violet: Button: focus ringcolor.primary on color.surface: 3.88:1, needs 3:1
  • Playground dark, Violet: Card: title and action textcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Violet: Card: body and eyebrow textcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Violet: Card: action focus ringcolor.primary on color.surface: 3.88:1, needs 3:1
  • Playground dark, Violet: Input: typed text and labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Violet: Input: placeholder and hintcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Violet: Input: field boundarycolor.controlBorder on color.surface: 3.34:1, needs 3:1
  • Playground dark, Violet: Input: focus bordercolor.primary on color.surface: 3.88:1, needs 3:1
  • Playground dark, Blue: Button: primary labelcolor.onPrimary on color.primary: 5.33:1, needs 4.5:1
  • Playground dark, Blue: Button: secondary and ghost labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Blue: Button: focus ringcolor.primary on color.surface: 4.32:1, needs 3:1
  • Playground dark, Blue: Card: title and action textcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Blue: Card: body and eyebrow textcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Blue: Card: action focus ringcolor.primary on color.surface: 4.32:1, needs 3:1
  • Playground dark, Blue: Input: typed text and labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Blue: Input: placeholder and hintcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Blue: Input: field boundarycolor.controlBorder on color.surface: 3.34:1, needs 3:1
  • Playground dark, Blue: Input: focus bordercolor.primary on color.surface: 4.32:1, needs 3:1
  • Playground dark, Green: Button: primary labelcolor.onPrimary on color.primary: 6.44:1, needs 4.5:1
  • Playground dark, Green: Button: secondary and ghost labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Green: Button: focus ringcolor.primary on color.surface: 5.22:1, needs 3:1
  • Playground dark, Green: Card: title and action textcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Green: Card: body and eyebrow textcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Green: Card: action focus ringcolor.primary on color.surface: 5.22:1, needs 3:1
  • Playground dark, Green: Input: typed text and labelcolor.text on color.surface: 15.21:1, needs 4.5:1
  • Playground dark, Green: Input: placeholder and hintcolor.muted on color.surface: 6.56:1, needs 4.5:1
  • Playground dark, Green: Input: field boundarycolor.controlBorder on color.surface: 3.34:1, needs 3:1
  • Playground dark, Green: Input: focus bordercolor.primary on color.surface: 5.22:1, needs 3:1

Run it locally with pnpm tokens:audit. Agents get the same results in /r/tokens.json.

Public registry

Live

Static, read-only JSON, generated at build time from the same tokens, specs and templates. CORS is open, so any tool can fetch it.

  • GET/r/index.json

    Every component, its variants and sizes, and the supported stacks.

    Open/r/index.json
  • GET/r/tokens.json

    The full token set, with values and their CSS, Swift and Kotlin names.

    Open/r/tokens.json
  • GET/r/rules.json

    The agent rules: AGENTS.md plus each spec's accessibility rules.

    Open/r/rules.json
  • GET/r/card.json?stack=angular

    One component: spec, tokens and code. Stacks: react, angular, vue, swift, kotlin.

The MCP below is a conceptual demo of what I would set up for your team: no MCP server runs on this site. The public registry above is the part that works today.

MCP demo

Illustrative
Example configExample

How a developer would connect an MCP server in Claude Code (.mcp.json) or Cursor (.cursor/mcp.json). The address is a placeholder: there is no server behind it.

{  "mcpServers": {    "design-system": {      "type": "http",      "url": "https://design-system.example/mcp"    }  }}
Guided conversationStep 1/7

The requests are a script; the responses are real, computed in your browser from the same core that serves /r.

Developer

Using the design system MCP, build a settings card with an image and a save button for my Angular app.

Before and after

The same request, answered without and with the design system.

Without the design system

Illustrative · written by hand

A typical generic answer: hardcoded colours and sizes, a div as a button (no role, no keyboard), and a placeholder instead of a label.

<!-- settings-card.component.html --><div class="card" style="background: #1e1e1e; border-radius: 12px; padding: 20px">  <img src="cover.jpg" />  <h3 style="color: #ffffff; font-size: 18px">Notification settings</h3>  <input placeholder="Email" style="border: 1px solid #333333" />  <div class="btn bg-blue-600" style="color: #ffffff; padding: 10px 16px" (click)="save()">    Save  </div></div>

validate_usage on its props

Buttoninvalid

  • errorclassName · Palette colour class bg-blue-600 bypasses the tokens.
  • errorstyle.color · Hardcoded colour #ffffff.
  • errorstyle.padding · Hardcoded size 10px.
  • errorstyle.padding · Hardcoded size 16px.

Inputinvalid

  • errorstyle.border · Hardcoded colour #333333.
  • errorstyle.border · Hardcoded size 1px.
  • errorlabel · label is required and rendered as a visible <label for>. Do not use the placeholder as the label. The hint is announced through aria-describedby.

With the design system

Generated from the registry

Card and Button from the registry, styled only with tokens, with a real <button> and the spec's focus styles.

import { Component } from "@angular/core"import { ButtonComponent } from "./button.component"import { CardComponent } from "./card.component" // The card in the lab: an image, a title and a primary Button as its action.@Component({  selector: "app-card-example",  standalone: true,  imports: [CardComponent, ButtonComponent],  template: `    <ds-card variant="elevated" size="md">      <img class="media" src="/cover.jpg" alt="" />      <h3 class="ds-card__title">Notification settings</h3>      <button dsButton variant="primary">Save changes</button>    </ds-card>  `,  styles: `    .media {      width: 100%;      aspect-ratio: 16 / 9;      object-fit: cover;      border-radius: calc(var(--ds-radius-card) / 2);    }  `,})export class CardExampleComponent {} 

validate_usage on its props

Buttonvalid

04How I work

From design to production, with someone accountable.

The workflow behind the system: what AI speeds up, what I decide, and how a vague first pass becomes a reviewed component.

Four steps, one person accountable.

How a component moves from a design to production. Pick a step to see what AI speeds up and what I decide.

Objective

Turn the Figma component into an explicit spec that both people and agents can implement without guessing.

Example input

specs/button.md

component: Buttonvariants: primary | secondary | ghostsizes: sm 32 · md 40 · lg 48tokens: --ui-accent --ui-on-accent --ui-radiusstates: default · hover · focus-visible · disabled · loadinga11y: native <button>, visible focus ring, aria-busy while loadingapi: extends ButtonHTMLAttributes, forwardRef, no boolean flags

What AI helps with

  • Reading variables and variants from Figma through Figma MCP
  • Drafting the spec and listing edge cases I might miss
  • Recalling past decisions and conventions stored in Engram

What I review or decide

  • The component API and naming
  • Which states exist, and what is out of scope
  • How design values map to existing tokens

Risks and how I handle them

  • The spec copies pixel values from FigmaMap every value to a token before implementation
  • States are forgotten (loading, disabled, focus)A fixed state checklist in every spec

Output

A reviewed spec with acceptance criteria.

Same button, two levels of intent.

A first pass from an underspecified prompt, next to the version after review. The first pass is not bad because AI wrote it, but because the request was vague. With the spec from step 1, the first draft lands much closer to the refined one.

Highlighted lines in the refined version: Accessibility

import { forwardRef, type ButtonHTMLAttributes } from "react"import { cn } from "@/lib/utils"import { Spinner } from "./spinner"import { buttonRecipe, type ButtonSize, type ButtonVariant } from "./button.recipe" export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {  variant?: ButtonVariant  size?: ButtonSize  loading?: boolean} export const Button = forwardRef<HTMLButtonElement, ButtonProps>(  (    { variant = "primary", size = "md", loading = false, disabled, type = "button", className, children, ...props },    ref,  ) => (    <button      ref={ref}      type={type}      disabled={disabled || loading}      aria-busy={loading || undefined}      className={cn(buttonRecipe({ variant, size }), className)}      {...props}    >      {loading && <Spinner aria-hidden="true" />}      <span className={cn(loading && "opacity-70")}>{children}</span>    </button>  ),)Button.displayName = "Button"

Inspect a difference

Accessibility

Why

A native <button> brings keyboard support, focus and the right role for free. type="button" avoids accidental form submits, aria-busy announces loading, and the label stays in place so screen readers still read it.

Trade-off

None worth avoiding here, since a styled <div> needs role, tabIndex and key handlers to get only part of this.

Where each tool fits.

Tools I use in this workflow. They are not connected to this page, they are a map of how I work.

Tools

  • Figma
  • Figma variables

Activities

  • User flows and component design
  • Variables for colour, spacing and radius

Deliverables

  • Figma frames
  • Token set
05Engineering principles

What I optimise for.

  • P01

    Reusable, maintainable components

    One recipe drives every variant and size; the playground prints the same source it renders.

    See the playground
  • P02

    Accessible interfaces

    Native elements, visible focus, labelled inputs and announced states, the first thing I check in review.

    See the accessibility diff
  • P03

    Consistent design systems

    Components read semantic tokens, so theme, radius and accent change through configuration, not edits.

    Change the tokens
  • P04

    Type safety and predictable state

    Unions over boolean flags; a single config object is the only state the playground has.

    See the API diff
  • P05

    Performance and responsive behaviour

    This page ships no highlighting library and calls no API; the code view is a small local tokenizer.

    See the process
  • P06

    Human review of AI-generated code

    AI drafts, I review: keyboard, screen reader, API ergonomics and visual QA before anything ships.

    See step 3
  • P07

    Fast iteration, no unnecessary complexity

    Small diffs, no new dependencies unless they pay for themselves, abstractions only when there is a second use.

    See the workflow

Want this for your team?

If your team rewrites the same components in every app, or your agents keep inventing styles, I can set up the tokens, specs, components and registry for your product.