ADR-0142 The Figma library is generated from the repo
Amends: Playbook section 9
#Context
Section 9 says Figma follows code and names Tokens Studio as the sync. Tokens Studio moves variables. It cannot make a component, so a library synced that way still has its components drawn by hand, and a hand-drawn component drifts from the code the same way a hand-edited token does. Figma's REST API cannot create components either. A development plugin can: it runs inside the desktop app with the whole plugin API.
#Decision
tools/figma-sync builds the library. pnpm figma:build reads the token tiers, the surface layer, the roster and the component sources, and writes a plugin with that data inlined. Run in Figma, the plugin creates or updates every variable and every drawn component. A rerun updates in place, so instances in product files stay attached, and nothing a designer can bind to is deleted.
The collections are section 9's, with two it did not name.
| Collection | Modes | Holds |
|---|---|---|
| Primitives | none | every generated ramp and spatial scale, hidden from publishing |
| Theme | the four themes | the semantic colour roles, each an alias into Primitives, and the font roles |
| Density | comfortable, compact | the spatial roles, each an alias into Primitives |
| Surface | light, dark | the measured layer in wolf-rayet.css, which the components are built on |
| Component | none | every component tier, each an alias into the collections above, hidden from publishing (published with empty scopes since ADR-0143) |
Section 9 also names a mode-less Semantic collection aliasing Theme. It is not made. A role points at a different ramp step in each theme, because polarity flips across the matrix, so the roles need the four modes themselves and they live in Theme. The build checks that every alias resolves to the value the token file claims.
Variant properties carry the code's prop names. variant=critical, level=3 in Figma is variant="critical" level={3} in React; a button is appearance, spacing, isSelected and isDisabled. The one property with no prop behind it is interaction, for hover and pressed, which the browser supplies and a designer still has to draw.
A variant exists only where the contract allows it. The status indicator's pairs come from its component tier, which is generated from the contract; the button's appearances and their levels are read from Button.tsx.
#Rejected options
Keep Tokens Studio for the variables and draw the components by hand. It is what section 9 planned. It lost because the components are where drift shows, and it would leave the library's largest part outside the pipeline.
story.to.design, which makes Figma components from Storybook stories. It makes real variants. It lost because the rules that decide which variants exist would live in a third party's tool rather than in this repo.
#Not yet
- Section 9's files. ADR-0143 makes three of them and records why Proof is not one.
- Branching per change. Figma branching needs an Organization plan. On Professional a change is a commit and a rerun, and the cover names the commit it was built from.
- Code Connect, which also needs an Organization plan. Each component's description names its React export and its token file.
- Motion, shadows, grid and stacking. Figma has no variable type for them; they stay in code and each run reports the count.
#Consequences
No code changed and no scene moved. Two components are drawn, status-indicator and button; the other 31 component tiers are synced as variables and drawn in batches.