← All articles

We Killed Figma Twice. The Second Time It Stuck.

Nobody here opens Figma anymore. How two designers and a CTO replaced the design handoff with a pull request, and what the engineers said about it.

On 4 August, Kennedy, one of our two designers, posted in Slack:

“We’ve decided to take the plunge and make Sintra the source of truth”

Sintra was a repository our CTO, Seb R, had set up two months earlier, where the designers built prototypes in code instead of drawing them in Figma. He added that he did not see a future for Figma. The next day Simon, a frontend engineer, replied:

“One more source of truth… I think this is a mistake tbh”

I am also a frontend engineer here, and turning a design file into React is a large part of my job. For years I did it the slow way: open Figma, measure, guess the hover state, ship, wait for the list of fixes.

Two weeks ago I shipped a redesign of the Thoughts panel in Gama, the AI agent inside Vasco, and I never opened a design file. There was none. The design came from Seb R, who wrote it as Storybook stories in our monorepo, and I built it with a Claude Code skill that reads his handoff. QA was a short Slack thread.

A year ago the same feature would have cost a week of “can you move this 4px” and a list of visual fixes after the release. What follows is how we got from Simon’s message to that. It is not a clean story.

The Thoughts prototype rendered in Storybook, showing the agent’s steps expanded for a technical user
The Thoughts prototype in Storybook, handoff v2, on the “technical user” flow.
The same Thoughts panel running in production inside Gama
The same panel in production, in Gama.

A Design Is Done When Users Have It

Kennedy and Ariane were fast in Figma. That was never the problem. The problem was everything around the canvas. Finding the right component meant opening six files. A small change meant touching every screen that showed it.

And the Figma design system and the coded one drifted apart from day one: the same button with two names and two sets of styles, and nobody whose job it was to keep them aligned. Keeping them aligned is a full-time job. A team of two designers has nobody for it.

For engineers the pain was what the canvas did not show. Hover states, loading states and error states lived in the designers’ heads. Ariane calls them “tribal or invisible specs”.

So the developer guessed. Sometimes a colour in the mockup was wrong, and the developer copied it faithfully, because checking colours is not their job. Then a designer did a visual QA pass under time pressure, often after the release.

Seb R has one rule for this: a design is done when users have it. By that rule, a lot of our Figma work never finished. He is harsh about it. He is also right.

A Figma file zoomed out to 4%, with dozens of tiny screens and a long layers panel
The Figma file for the agentic capabilities of cycle 34, at 4% zoom. Dozens of screens, a layers panel full of “Skill canvas”, and nothing that says which state is which.

The Cliff

We first tried to keep Figma and let Claude fill the gap. I tried the Figma MCP server. It needed the Figma desktop app running on my machine, and the output was worse than pasting a screenshot into Claude.

The problem went deeper than the tooling. A Figma page is one big canvas with layers on layers. Code is made of components. People struggled to map one onto the other, and so did Claude. In a large file it lost track of what a unit even was.

So why did the designers stay? Kennedy is honest about it. Figma felt safe. They were experts in it, code was full of unknowns, and they feared losing their creativity. For a long time Claude was not faster than Kennedy at producing ideas, and until that changed, letting go was hard.

It changed, and it came with a push. One day in the spring Seb R sat next to Kennedy and told her to use Claude Code from now on. He describes it as pushing her off a cliff. She agrees with the description.

Note: no designer was harmed in the making of this article.

Here is what happened next, in her words:

“I decided to find out how far I could take it. We weren’t wired to the design system yet and the models were weaker, so it took a long time, a lot of asking, checking and asking again, but by the end I had something clickable that looked exactly as I had pictured it. In some ways it was better than anything I could have made in Figma: it had motion, interaction and animation all over it, things that would have taken me so much longer to build there. Seeing that, I knew this was a skill I had to invest in.”

Sintra, the Disposable Repo

In June, Seb R created Sintra: a separate repository, only for prototypes, with each branch deployed to its own preview on Cloudflare Pages. The README said that code in Sintra was disposable by default.

The Pena Palace in Sintra, Portugal: yellow and red towers above a hill of trees under a blue sky
Sintra, the town the repo is named after. Pena Palace, photo by Singa Hitam, CC BY 2.0.

Why a separate repo? Our monorepo has a lot of checks, and he wanted a place where designers could break things without fear, and without prototype code leaking into product code.

It worked. In three months Sintra got 35 prototypes, each with a CONTEXT.md and a HANDOFF.md, so the design decisions sat next to the code. Kennedy and Ariane stopped reaching for Lovable or Base44, because Sintra got closer to the design in their heads than any of those tools did.

That is where Kennedy’s Slack message came from, and Simon’s reply. Keep Simon in mind.

A Sintra prototype canvas showing a scheduled-task setup form next to the resulting Slack message, with annotations
A Sintra prototype on its canvas: the scheduled-task setup on the left, what the recipient gets in Slack on the right, with two annotations and a preview URL of its own.

It Looked Finished. That Was the Problem.

Sintra was not in our repo, so it did not use our components. It had its own copy of Zenith, our design system, and Claude had filled the gaps in that copy. Many gaps were filled wrong. Sintra used the Geist typeface. Vasco does not use Geist.

So a Sintra prototype looked finished, but it did not look like Vasco. I remember looking at one and asking the designer: is this done? It looks done. But I do not know if it is what we want.

Engineers did not know what to do with these prototypes. Copy the styles? Guess the real component? One developer copied exactly what Sintra showed, and our onboarding shipped with mismatched greens and inconsistent label weights. In other prototypes, Claude invented parts of the Gama UI, and people took them for planned features.

Ariane felt it most. In Figma she could audit every token, every size, every radius. In Sintra she could not. She lost hours trying to make one handoff match production.

In September, in Sintra’s last big pull request, she struck through one of its rules and left the note that became a team meme:

“The zenith in sintra is trash”

She stands by it, with context. Ask her.

The Sceptic Builds the Replacement

Simon saw the root cause. Sintra and the product were two codebases that copied from each other. The design system existed twice, and every handoff needed translation, by Claude or by a person.

The obvious fix was to publish our component library as a package. Simon said no. Build, publish, version, bump, for a small team that edits components every day, and the prototype still ends up on a different version than the app.

He looked at giving Claude both repos at once. That is coupling without admitting it. If the two repos depend on each other, they might as well be one.

Then, while listing what a prototyping app inside the monorepo would need (a list of features, versions per feature, a playground, a place for decisions), he realised he was reinventing Storybook. We already ran Storybook. We already published it to Chromatic on every branch.

So, three weeks after calling the plan a mistake, he rewrote the RFC: a prototype becomes a set of Storybook stories inside the monorepo. It imports the real components. Every push publishes to Chromatic, with a link per branch. New deploy pipeline: none.

Not everyone liked it. Seb R wrote that the RFC was killing good parts of Sintra. Someone opened a counter-RFC to keep Sintra, then cancelled it. We decided on 1 September.

We did not migrate the 35 prototypes, and we kept fewer than a third of the decision records. Simon now calls Sintra an incubator. He is being polite. It was also the prototype that proved the workflow, and he rebuilt the parts that deserved to survive.

What a Handoff Looks Like Now

A prototype is a folder under prototypes/ in the monorepo. Nothing in the app imports it, so nothing in it ships to users. Each prototype has three areas. Sandbox is the live work, where anything goes. Iterations are frozen versions, saved for review. Ready is what engineers build, and only a promotion can change it.

Take the Thoughts prototype I built from. Its Ready area holds four scenarios, each one a Storybook story: a user who only reads the answer, a technical user who opens every step to see how the agent got a number, a run where one step failed and the agent retried, and a Slack post that waits for approval.

Each scenario is a sequence of moments, and a link can open the prototype on any one of them. Hover states, loading states, the clamped long result with its “Show more” link: they are all there, one story at a time. For me, that was the list of states to build. No invisible specs.

Claude Code skills drive the flow. proto-start interrogates the designer before it draws anything. proto-handoff promotes an iteration to Ready, with a dated changelog. proto-implement reads Ready and asks the engineer whether to write a spec, make a plan, or build.

The handoff is no longer a prompt to paste. It is a snapshot: the flows, the components to build, and how the feature works. And because the prototype uses the real components, the colours, the spacing and the type cannot drift. What the engineer still owns is the data and the layout around it.

The handoff page of the Thoughts prototype in Storybook, listing the flows and components to build
The handoff page of the Thoughts prototype in Storybook: what v2 hands over, its four flows, and the components to build.

A Bowl of M&M’s

Our last retrospective summed it up in one line:

“No-Figma cycle: We went from prototype straight to handoff, with less QA and faster small changes.”

Kennedy says the ceiling went up. Motion, interactions, ten variations instead of two. They used to skip these because they cost too much. Seeing her design in production, exactly as she made it, was a dream for years. She also says the team now has to be deliberate with this much power.

Ariane is the one who keeps us honest. AI produces content that looks right and visuals that look right, and she catches herself not checking anymore. She put it like this:

“It is like a bowl of M&M’s where some might be poisoned. Do you double-check, or do you just go for it?”

Both learned a skill they did not expect: putting their taste into words. They now write Claude Code skills, so that everyone, designer or not, works to the same bar. Ariane has a proto-review skill in review right now. The person who wrote “The zenith in sintra is trash” now writes the rules that stop it from happening again.

Not Done Yet

Sintra had comments. Storybook does not. We miss them.

We are still learning when a handoff is ready. In October, one prototype had five handoff versions in 15 days, and none was ready. Sandbox, Iterations and Ready is our answer. We moved every prototype to it this week, and we lost some versions in the move.

In September, a prototype pull request broke main: nothing in it ships, but it still runs the repository’s lint and typecheck, and it failed both. A skill now merges prototype pull requests only when every check is green. They still fill the CI queue for everyone else.

And building is now so cheap that “good enough” is tempting. From the same retro:

“Being able to produce something isn’t the same as knowing whether it’s good”

Seb R describes design as a map with a fog of war. You explore the territory to find a better answer than your first one. So next cycle we spend more time before we build: define the problem first, then shape the solution. Simon says it shorter: build a better product, not more product.

The objection every engineer raises about all this is that the model is not deterministic. Seb R’s answer is that a team of 50 developers is not deterministic either. Someone forgets a test. Someone forgets an edge case. A good harness removes some of that randomness. It does not remove all of it, and we do not pretend it does.

It removed enough that when the Thoughts panel reached production, Seb R looked at it, asked for a few changes, published a v2 of the prototype, and I picked up the changes the same way I had picked up the first version. A designer’s panel went from prototype to production without the visual QA pass that used to follow a release, and the engineer in between never measured a pixel. Two months in, that is why we think this one will hold.


If building a designer’s panel without measuring a single pixel sounds like your kind of job, sometimes we hire.