No. 01
AI-Optimized Design System
We didn't set out to build a design system. We were trying to stop an AI from generating the wrong shade of blue.
- AI Agents
- Figma Tokens
- Tailwind
- Storybook
- Role
- Frontend Engineer
- Team
- Platform + Design
- Timeframe
- 2024
Confidently Wrong
It started with a button. We ran a Figma design through our MCP setup, asked the agent to implement it, and got back clean, confident code. The button was blue. Just not the right blue.
Our brand blue lives at av-blue-500 — a custom token in our Tailwind config. In Figma, it was simply labeled blue. When the LLM saw that coming through the MCP context, it mapped it to Tailwind's stock blue-500. Same name, different hex. The output looked plausible enough to slip past a quick review.
How tokens got lost in translation
Figma variable
color/BlueLLM assumes
Tailwind blue-500Generated code
bg-blue-500bg-av-blue-500Same name, different hex — no error thrown, wrong color rendered.
And it wasn't just blue. Any Figma variable name that overlapped with Tailwind's built-in vocabulary was a potential mismatch. We'd catch it in review, ask for corrections, re-run. The frustrating part wasn't that the AI got it wrong — it had no way to know it was wrong.
The Fix That Wasn't
The fastest thing we could do was write a .md file. Token naming convention, Figma-to-Tailwind translation, a line telling the agent 'when Figma says blue, use av-blue-500.' Dropped it into agent context for every UI task. It worked.
Both Sides Were Ready
The real problem was structural. Figma had variables — just blue, green, brand-primary — declared with no architecture. No primitive layer, no semantic mappings, no consistent naming convention to anchor anything to.
When we brought this to the design and product team, they weren't surprised. They'd wanted to fix Figma's token structure for a while too — the old setup had variables but no reusable component mappings, and designers were working around it constantly. The AI problem gave everyone a concrete reason to finally do it.
- 01
Primitives
Raw values — every color in the palette named by scale. av-blue-50 through av-blue-950, matching the frontend token names exactly.
- 02
Semantic layer
Intent-based tokens — action-primary, surface-default, text-muted. What designers reference in components.
- 03
Maps
Explicit bindings from Figma semantic tokens to frontend Tailwind tokens. What the LLM actually resolves when it reads a design.
The Call We Almost Got Wrong
Once tokens were cleaner on both sides, there was an obvious next question: should the frontend match it completely? Build a full custom design system — primitives, semantic layer, component styles — using CSS custom properties and typed objects instead of Tailwind utilities?
We looked at it seriously. It's the clean-room ideal. But Tailwind already provides a semantic utility layer, we'd been on it since day one, and migrating the entire app would cost weeks for gains that were mostly theoretical. The av- prefix was already working. We kept it.
Teaching the Machine
With tokens aligned, we wrote the real version of that earlier .md file — docs/design-system.md. Token translation tables, component APIs, exact prop shapes, common pitfalls. Everything an LLM needs to generate correct UI without guessing.
One detail that matters: this doc isn't loaded into every agent context. AGENTS.md references it conditionally — the agent pulls it in only when the task involves UI. For everything else, the doc stays out of context entirely. Rough estimate, we're spending 30-40% less tokens on corrections and re-runs compared to before.
Component by Component
Fixing tokens solved the color problem. But there's a second failure mode: an LLM reaching for a custom one-off implementation when a shared component already exists. We started documenting the component library, most-used first.
- AVButton: Props, variants, loading states, accessibility requirements.
- Icons16 / Icons24: Import paths, stroke-vs-fill distinction, sizing conventions.
- AVShimmer: When to use it, the parent-dimensions gotcha.
- AVTooltip: Hover vs click mode, portal flag for overflow parents.
- AVTablePaginated: Full table API including collapsible rows and progressive loading.
For the core ones — buttons, icons, shimmer, tooltip, metric cards — Storybook previews went up too. Locally hosted, so design can verify a component without running the full app.
Still in progress. Every component that gets documented is one less thing the LLM has to invent.
Where It Stands
- UI delivery (was 2–3 wk)
- <1 wk
- Less LLM context on corrections
- ~35%
- Components documented
- 10+
There are still edge cases. An agent will occasionally reach for a raw Tailwind class when an av- token is the right call. But the floor is higher now, and the drift is much smaller.
The bigger shift is that design and engineering are finally working from the same source of truth. That wasn't the original goal — it was a side effect of trying to fix an AI hallucination problem.