← Work Ref IS-11

One shared truth for Storybook and Figma

Brand rules and structured content empower live sites and designer Figma files.

Figma kits often tell a design system's story a second time. Designers draw the components, engineers build them, and the two versions drift because nothing ties one to the other. Every correction gets made twice, by different people, or often doesn't and the two worlds drift. Double the work and half the benefit.

UNDRR's Mangrove Figma library is derived instead: a change made once lands everywhere. When I changed a core spacing value in code and republished, a designer's pilot file updated and kept every one of their edits. Nobody redrew anything or compared design and code by eye.

My solution for UNDRR works because three sources already agree on how truth is told. The content rules (structured content schemas) say what each component contains, the brand settings (design tokens) say how it looks in each of UNDRR's five brands, and the developers' live component catalogue (Storybook) says how it is laid out. A plugin built to this architecture reads all three and generates a native Figma library: 297 variants in 25 component families, real components rather than pictures of them.

That is triangulation: each source answers one question. So when Figma disagreed with one of them, I knew which, and every mismatch became a bug with an address instead of an argument about taste.

Why isn't this a solved problem?#

Storybook and Figma only look as if they do the same job. Both show a design system's components, so it seems they should stay in step on their own. They don't, for the same reason a Windows app doesn't simply run on a Mac: each platform lays things out and behaves in its own way, and Figma's Auto Layout is not CSS.

There is no standard way across. Every system has its own components, brands and edge cases, so any conversion depends on what you start from. Most teams settle for a degree of parity between the two, or accept that the front end is the real source of truth and update Figma by hand to keep up.

Hard, but not impossible. Separate what a component is from how it looks and how it is laid out, and most of the port becomes mechanical. That is also where AI helps. The work is reverse engineering: rebuilding something that already exists in another platform's terms, with the original there to check every result against.

Where did the truth come from?#

The hard part was as much the culture change as the technical build. Getting a broad range of stakeholders to agree on what a card, a hero or a landing page is made of took years of sustained leadership: I led the initiative across our content teams, developers and organizational leadership to shift perspectives. That meant getting teams to embrace abstraction: content schemas for structure, design tokens for appearance, and code for layout. By the time a Figma library came up, that discipline was already settled and empowering live syndication. (I've written about Mangrove as a content architecture that happens to ship a design system.)

The brand settings are a second, independent source. I led the effort to align the structure of the design tokens across UNDRR, PreventionWeb, MCR2030, DELTA Resilience and IRP into one unified set, which the plugin turns into 540 Figma variables. 471 of them (87.2%) are the same in every brand; the other 69 are where the brands differ: colour, corner radius, a softer surface here, hero spacing there.

Neither source needs to know about the other. A schema says nothing about colour, and a token says nothing about whether a card has an image. So you can hold one still and swap the other: below, the same Book Card schema under each brand's tokens.

Stage 1: two independent sources of truth Two boxes on the left: content schemas above, design tokens below, joined by a dotted line marked peers. Nothing else is drawn yet. Content schemas the content it holds Design tokens colour, type, spacing peers, independent
Two sources of truth, defined independently: schemas say what a component is made of; tokens say how it looks in each brand. Own work.

Hold the content, swap the brand

Switch brands on the Book Card. The content stays the same throughout: brand settings change how it looks, and Storybook decides how it is laid out.

The interactive brand switcher needs JavaScript. In short: 471 of 540 Figma variables (87.2%) are the same in all five brands; the rest change colour, corners and button sizing without changing what the card is made of.

What does Storybook add?#

Layout, and only layout. I led our front-end developers in building Mangrove out, and directed the work with engineering teams to integrate it across our live sites. Storybook is the working catalogue of that initiative: each pattern takes a schema's fields and the tokens' values and arranges them on a page. That arrangement is the one thing Storybook has the final word on.

The Book Card shows the split. Its four presets, including a version without an image, come from the schema, and its colour, type and spacing from the tokens. Where the boxes land is Storybook's call, and an automated geometry check measures against it.

Everything after this depends on that split. Each source owns one question, so each can be checked on that question alone.

Stage 2: Storybook adds layout The two source boxes on the left each send an arrow into a Storybook box in the centre, labelled adds layout. Content schemas the content it holds Design tokens colour, type, spacing Storybook adds the page layout
Storybook is where the two sources meet. It takes fields from the schema and values from the tokens, and adds the layout. Own work.

How is the Figma library built?#

The plugin asks each source the question it owns. Field lists and presets come from the schemas, values bind to Figma variables generated from the tokens, and geometry is checked against Storybook. Nothing in the library is authored in Figma: a designer switching the Book Card to its no-image preset is choosing one the schema already allows.

I directed AI coding agents to write most of the plugin, and the structure gave their work a right answer. The agents traced tokens through the code and generated the build instructions for each component, and every instruction could be checked against one of the three sources. Their output still had errors. The difference was that I could trace each one.

Stage 3: the plugin reads all three sources A Figma box on the right has three dashed lines reaching back to the content schemas for fields and presets, to the design tokens for variables, and to Storybook for geometry. Content schemas the content it holds Design tokens colour, type, spacing Storybook the page layout Figma 297 variants reads fields, presets reads variables reads geometry
The plugin asks each source the one question it owns, so Figma is located by three fixed points rather than copied from the nearest one. Own work.
Figma canvas showing Horizontal Book Card component presets (Default, NoImage, NoLink, ButtonOnly) alongside layer panels displaying Tag integration across MCR2030 and PreventionWeb brands
The schema's four Book Card presets as Figma variant properties, next to brand-specific Tag tokens. Own work.

What happened when the sources disagreed?#

Real output found the bugs; the sources told me where they lived. The automated tests all passed. The problems only showed up when I opened the generated components in Figma and inspected them.

Tokens against Figma: an invisible disabled control. The disabled ComboBox vanished in Figma. The converter had passed the opacity token 0.55 into a field expecting a percentage, so 55% became 0.55%. The token and Storybook agreed with each other, which put the fault on the converter. I fixed it, and the test harness that had missed it.

Storybook against Figma: text spacing that drifted. Small help text sat slightly differently in Figma than in the browser. Layout is Storybook's call, so I measured the line height in the browser and calibrated Figma to it.

The third mismatch was in a source. Real disaster risk data in the Table ran into fixed dividers in Figma and Storybook alike: both were faithful, but the schema had no length limit. I worked with colleagues to establish the limit and wrapping rules in the component guidance, and both now inherit them. Deriving a library from its sources can find gaps in the sources too.

Stage 4: two bugs on edges, one in a source The same diagram. The tokens-to-Figma line is highlighted and labelled 0.55 read as 0.55 percent. The Storybook-to-Figma line is highlighted and labelled line-height. The content schemas box itself is highlighted and labelled no length limit. Content schemas Design tokens Storybook Figma no length limit line-height 0.55 read as 0.55%
Two bugs sat on the lines between a source and Figma. The third sat in a source itself, and its fix flowed down to Storybook and Figma. Own work.

What did a token change prove?#

A change at the source carries through to designers' work. I changed a core UNDRR spacing token from 30px to 32px and republished the library. In a pilot file of 56 linked library instances, a resource page at desktop and mobile widths, the layout updated and every edited title, chosen preset and instance override survived.

Designers don't need the plugin to use the library. I led the adoption effort with our design team, ensuring this architecture empowered their craft rather than dictating it. The pilot was built entirely from the published library, with its own headings and local notes; the plugin is a build tool behind the scenes, and designers only ever touch the library.

Stage 5: a token change flows through to Figma The design tokens box is labelled 30px to 32px. Highlighted arrows run from it to Storybook and, along the lower arc, to Figma, which is labelled 56 instances, overrides kept. Content schemas Design tokens Storybook Figma 56 instances, edits kept 30px → 32px
The flow reverses: a spacing token changed at the source reached a designer's pilot file, and their edits survived. Own work.

What does it cost to keep?#

Less than redrawing by hand, but not free. The plugin and its tests come to about 77,000 lines of code, over 40% of it tests and audits, and someone has to keep that working as the product changes.

So I established a sustainable operating model. Brand settings sync automatically, because they are cheap to keep current. Full rebuilds of the library wait for major versions and new components. With rebuilds that infrequent, a paid tool such as story.to.design didn't make sense for us.

It only holds while Figma stays downstream. Copy, presets and visibility in a designer's own file belong to them. Edits to the shared library itself would turn Figma back into a second story. That needs a policy before the next rebuild, and there isn't one yet.

Why did this work?#

The technical build rested on years of culture change. If the schemas and tokens had been vague, the plugin would have had nothing to triangulate from, and the agents' output nothing to be checked against. Getting stakeholders across editorial, engineering and design to embrace these layers of abstraction took sustained leadership: the plugin simply harvested the alignment we had already built.

Managing my team meant holding the technical contracts; leading across teams meant building trust. Content authors needed confidence that schemas would protect their publishing workflows; developers needed patterns they could rely on in production; designers needed Figma components that respected their autonomy.

Each discipline gets the same story in its own tool. Designers get Figma and developers get Storybook, both drawing on the same content rules and brand settings. It's the same move I made in putting analytics into editorial workflows: meet each team in the tool it already works in.

Screenshot of the Mangrove Figma library showing the component catalogue organized by task (Actions, Forms and selection, Content and data, Navigation and disclosure) alongside component reference variants and design token text styles.
The Mangrove Figma library in use: component task catalogue, living button variants, and token-bound text styles derived from Storybook, the structured content schemas and the design tokens. Own work.

What one shared truth reaches

  1. 2,700 brand values

    5 brands × 540 Figma variables (471 shared, 69 by brand)

  2. 110 styles

    102 text, 8 effects

  3. 297 variants

    in 25 component families

  4. 56 linked instances

    in a designer's pilot file, every edit kept through a token change

Built with about 77,000 lines of code, 33,000 of them tests and audits.

Each step is derived, not drawn: the brand values, styles and component variants all come from the same sources, and a designer's page built from them kept its edits when one of those sources changed. Own work.

Was this useful?

👍 This was useful Found usefulFeedback count Thanks for the feedback! Curious how this was built?

Read next in sequence