Fluuen
A three-layer token system, generated from Figma into a shipped AI product — and an honest account of where the two drifted apart.
role
Product Designer · Design Systems
type
Design system · B2B SaaS product
year
2026
tools
Figma · Tokens Studio · Next.js
848
Color tokens
3
Token layers
121
Divergences found
6
Pipeline steps

This is a real, navigable product.
Try it live →A system first, then a product to test it
Fluuen is a no-code automation platform with AI agents, shipped as a navigable demo. But the product was never the deliverable — it was the test. I built the token system, then built something real on top to find out whether it held.
It mostly did. This is the account of the 121 places where it didn't.
Each artefact has one source of truth
When Figma and the code disagree, which one is wrong? I answered it per artefact. Tokens: Figma is the source. Screens: the code is. The shipped screens don't exist in Figma — that's a boundary, not a gap.
Component
status badge
Active · label
Semantic
icon.success
Primitive
green.500
Value
#3fb950
A component never learns its colour. It asks for a success label; three layers resolve that to a hex. Change the ramp, and everything that asked for success moves with it.
I wrote the generator instead of using Style Dictionary
Tokens Studio exports a verbose JSON tree — emoji-prefixed, Figma scopes, redundant segments. A 385-line script flattens it, resolves the alias chain, and writes clean CSS variables. Style Dictionary would have meant its learning curve plus the same custom transformers, for one output I could write directly.
The output is public and inspectable: the Storybook parses the generated CSS at build time, so its documentation can't drift from what ships.
StorybookWhat it cost: the naming is owned by the script, not copied from Figma — so the code reads bg-status-success, ugly but 1:1 with the source. No light mode, no second format, and I'm the only one who can debug it.

Build an agent yourself in the demo.
Open the builder →The pipeline kept CSS in sync with JSON — not with Figma
The gap hid for months because every check I had was a count. 897 in code against 848 in Figma looked like 49 missing. It was 85 stale names against 36 that never arrived, netting out. Counting answers how many. It doesn't answer: are these the same?
Mechanical
54 tokens
Pure renames — one clear destination.
Needs judgement
24 tokens
Renames needing a design call to resolve.
No destination
7 tokens
No destination — six hovers and a focus border.
A whole component — the Agent Builder inspector, 20 tokens — existed in Figma and not in code. Its neighbours shipped; it didn't. The drift wasn't decay. The system evolved and the code kept speaking last year's version of the same language.
Where they diverge, I classify rather than absorb
Select a state. The node's border is a token, not a colour — and this is the exact component where Figma and code drifted.
Live component · agent builder node
Send Slack message
a3
Action · Slack
Component
Control/Node/Structure/border-default
Semantic
border.default
Primitive
river-styx.400
Value
#1e1e26
Default: border.default → river-styx.400 → #1e1e26
node sublabel
#6b7280
components/builder/canvas-node.tsx:202
#868e9e
Control/Node/*
border-selected
brand.500
components/builder/canvas-node.tsx:53
brand.400
Control/Node/Structure/border-selected
shipped screens
code is truth
app/
not in Figma
What's done, what's partial by choice
Done: the token system and pipeline, the shipped screens, a Storybook that parses the production build so its docs can't drift. Partial by design: the demo runs on simulated data — a sandbox with no login, so anyone with the link is inside the product in seconds. Open debt: a sublabel contrast fix and the seven tokens with no home.
These aren't bugs — they're classified divergences. In a live product each has a one-line fix; as a portfolio piece, finding and naming them was the point.

See it running
Open the builder
The published file
Fluuen — a shipped AI automation product
Live demo →