Claude to Figma: keeping AI-generated UI bound to your design system
On one build I found 127 places bound to a raw colour instead of a named role. Every single one had passed visual review. They all surfaced the moment someone asked for dark mode. That number is the whole argument. Not because 127 is large, but because none of them looked wrong. A value that was typed in and a value that came from the system are visually identical. The difference only exists in what happens next. The failure isn't that the agent breaks the rules It's that it extends them. Give an agent a design system and ask it to build. When it reaches something the system covers, it uses the system — genuinely, reliably. When it reaches something the system doesn't cover, it does not stop and ask. It invents. And what it invents is a name that sounds exactly like one of yours, sitting right next to the real ones, reading as though someone chose it on purpose. That's why this is so hard to catch by eye. A fabricated token isn't a glaring error. It's a plausible one. Six months later nobody can tell you whether it was a deliberate exception or a hallucination, and by then five components depend on it. Readable is not the same as closed Making a library available to an agent gets you components it will reuse. It does not get you a closed set. A closed set means: these values exist, everything else does not, and anything outside them fails loudly rather than passing quietly. The distinction sounds pedantic and it decides everything. A readable system produces output that mostly matches. A closed system produces output you can audit. Which is the real test I'd apply to any AI design setup: not how much of your system it covers, but what happens to the things it doesn't cover. If those slip through silently, coverage is irrelevant — you've just made the drift harder to spot. Layers, and not reaching past them Tokens have layers for a reason. Base values underneath — the raw material. Named roles on top — what a value is for. And the product interface binds to the role, never reaching past it to grab the raw value directly. It's a boring rule. It's also the one that decides whether a theme change is a switch or a rebuild. The reason it gets broken constantly is that reaching past a layer always works in the moment. The screen looks right. The rule only earns its keep later, when a value needs to mean something different in a different context and there's nothing in the file that knows the difference between "this blue" and "the colour a primary action uses". The same discipline applies to how many names exist. Every role you add is a decision someone else has to understand. A system that grows a new name every time a screen needs something slightly different has stopped being a system and become a very structured way of typing values in. Pull tokens from the interface, don't invent them first Writing a full token set before any interface exists produces two predictable problems: a pile of values nobody ever uses, and gaps at exactly the places where the real decisions turned out to be. I get much better results extracting the system from interface that already exists and has been reviewed — every value in it earned its place by being needed. What that produces is smaller, and everything in it is load-bearing. The order matters more than the format. A set derived from real screens knows what it's for. A set written in advance is a guess with good syntax. Dark mode as an audit, not a feature This is the cheapest check in the entire process and almost nobody uses it as one. Flipping to dark stops asking the file what a value looks like and starts asking what it means. A value bound to a role knows how to behave in the other mode. A value typed in only ever knew how to look right in one context, and it fails immediately and visibly. Ten seconds, and it finds what a careful visual review across dozens of screens will not. That's how the 127 surfaced: not through diligence, but through a mode switch. If you only take one thing from this: after any large AI-assisted change, flip the theme before you look at anything else. Self-checks only work against something that can fail Asking a model to review its own work against a principle written in prose gets you agreement. It will confirm that yes, it used the design system, and it will believe that. Asking it to check output against a file of permitted values gets you a list of differences. One of those is a review. The other is a mood. So the check has to be mechanical: here is the set of legal values, here is what's in the output, show me what appears in one and not the other. Anything that can't produce a difference isn't a check. What this doesn't solve A closed set stops invention. It doesn't tell you whether the set is any good — constrain an agent to a badly designed system and you'll get consistent, coherent, thoroughly wrong output, delivered fast. And there's a cost people don't mention: closing the set means someone has to maintain it. Every genuinely new requirement now needs a decision rather than an improvisation. That's the point, and it's also work, and on a small project it can be more work than the drift would have cost. The whole thing, recorded on one real project I recorded the full path end to end — brief, structure and flows, generated screens, locked token system, Figma with real components and variables, clickable prototype, developer handoff — on a single project, breakages included: Claude AI UI/UX: Complete Workflow from Brief to Figma — the same path on one real project, brief through to a Figma handoff. If you've run the dark-mode check on an AI-assisted build, I'm curious what your number was. Mine was 127 and I did not see it coming.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to