From design handoff to working implementation
How we redesigned our workflow to turn static design intent into working in-app flows.
Overview
We are a small startup team working on MVPs and POCs. Our product is built in Flutter, and our core product workflow is very lean: one designer - me - and one frontend developer, Ivan.
From the beginning, we followed the workflow that made the most sense and was widely accepted across the industry: I designed in Figma, and Ivan implemented in Flutter.
Figma was the obvious choice. It gave us speed, structure, collaboration, and a clear visual language. As the product grew, our Figma design system grew with it: more components, more variants, more states, more flows, and more documentation.
At first, this was exactly what we needed. But as the product evolved, the design system started carrying more weight.
The problem was not that Figma failed. The problem was that the system succeeded. It became large, useful, and central to our workflow - and that also meant it started becoming legacy.
Not legacy because it was old. The product is only a little over a year old. Legacy in the sense that any system becomes legacy once people depend on it and changing it creates maintenance cost.
Our Figma design system helped us move fast, but every design decision still had to be translated into Flutter. Every component, every state, every edge case, and every flow had to move from a static design artifact into a working product artifact.
That translation layer became the bottleneck.
When Claude Code was released, we saw an opportunity to rethink the process. Not just to move our design system from Figma to Widgetbook - that was only the first step - but to change the design deliverable itself.
Instead of handing off static Figma screens and waiting for implementation, I wanted to build working Flutter flows myself, test them in the simulator, handle more edge cases earlier, and send Ivan a pull request for review.
The goal: reduce translation time, shorten the feedback loop, and turn design and development into one shared workflow around working product artifacts.
The startup context
In a small startup working on MVPs and POCs, speed is not a luxury. It is part of survival. We needed to explore, validate, adjust, and ship quickly. We could not afford long design cycles for every possible state before anything reached development.
At the same time, moving fast did not mean we could ignore edge cases. In real products, edge cases are not small details. They are often where trust is built or broken.
A flow is not only its happy path. It also includes loading states, empty states, error states, validation errors, long text, missing data, small-screen behavior, permission issues, network failures, alternative user paths, AI-generated responses, partial results, retry states, and unclear or unexpected user input.
Designing all of these manually in Figma took a lot of time. For every important flow, covering edge cases meant creating more frames, more variants, more annotations, and more handoff documentation. As one designer, that became expensive. But skipping edge cases was not a good option either.
So the real question became: how can we move fast like a small startup without leaving important product states unresolved until late development?
The original workflow
Our original workflow was simple and direct. I designed screens, components, and flows in Figma. Ivan implemented them in Flutter. Then we reviewed the result together, fixed gaps, clarified edge cases, and adjusted the implementation.
Because we are only two people, communication was already close. We did not have the classic problem of disconnected departments, slow corporate handoffs, or endless alignment meetings.
The problem was not lack of communication. The problem was that the design artifact and the product artifact were still two different things.
I created the design intent in Figma. Ivan translated it into Flutter. Then I reviewed the implementation in the simulator or app. If something felt off, we discussed it, adjusted it, and reviewed it again.
That loop worked. But it was slower than it needed to be. Even in a small team, every design decision still had to pass through a translation layer. Spacing, states, interactions, responsive behavior, long content, validation messages, AI output states, and edge cases all had to be interpreted, implemented, reviewed, and sometimes corrected.
The bottleneck was not communication between me and Ivan. The bottleneck was the gap between the design artifact and the product artifact.
What "legacy" means here
In this case study, legacy does not mean old. Legacy means dependency. A system becomes legacy when the team depends on it and changing it becomes costly to maintain, synchronize, or evolve.
Our Figma design system became legacy in that sense. It was valuable. It was useful. It helped us scale. But because it existed separately from the Flutter implementation, it also created maintenance work.
Every component had two lives: one in Figma, one in Flutter. Every time something changed, we had to keep both aligned. The larger the system became, the more expensive that alignment became.
This became especially important during the current AI wave. AI introduced new product possibilities at a much faster pace: new flows, new behaviors, new input patterns, new output states, more dynamic content, and more uncertainty in how users interact with generated results.
Components that once felt stable suddenly needed to support new kinds of functionality. A simple input might need to support AI suggestions. A result screen might need to handle generated content, partial output, loading progress, errors, retries, and user feedback. A flow might need additional states that were not part of the original design system.
This meant the design system had to keep reinventing itself. And in a Figma-first workflow, every reinvention created maintenance cost: the component had to be updated visually, the implementation had to be updated in Flutter, and the two had to be reviewed and kept in sync.
So our Figma design system did not become legacy because it was old. It became legacy because it became important, widely used, and increasingly expensive to change in a fast-moving AI product environment.
That realization changed how we thought about the next step. The next version of our design system could not just be a larger Figma library. It had to be easier to change, test, and reuse directly in the product.
In the AI era, the cost of a design system is not only how well it documents what exists - but how quickly it can adapt to what becomes possible next.
The opportunity
Claude Code changed the tradeoff. Before AI-assisted coding became practical, moving design closer to production would have required much heavier frontend involvement from the start. That made the Figma-first workflow the most reasonable option.
But with Claude Code, I could start working directly with Flutter code without becoming the frontend owner. I could describe what I wanted to create, generate or adjust widgets, run the result, test it, and iterate quickly.
This created a new middle ground: I could build the first working version. Ivan could review and improve it. The product could move faster without removing engineering ownership.
This was the real opportunity. Not replacing development. Not skipping review. Not pretending AI-generated code is automatically production-ready. But changing the starting point of the collaboration.
Instead of saying "here is the design, please build it" - I could say "here is a working flow, running in the simulator. Let's review the PR and make it production-ready." That is a very different conversation.
The strategy
Step 1 - make the design system executable
The first step was moving the design system from a large Figma library into Widgetbook. Widgetbook allowed us to rebuild our design system as live Flutter widgets. This gave us a reusable set of components that could be tested, documented, reviewed, and eventually pulled into the app.
But this was not the final goal. A live component library is useful, but users do not experience components in isolation. Users experience flows.
So once the components started becoming live, the next question was: what if I could use them to build the flows myself?
Step 2 - turn design output into working flows
The bigger shift was moving from static design handoff to working implementation proposals. Using Claude Code, Widgetbook, Xcode, and the iOS simulator, I could start assembling real product flows from our live components.
Instead of designing a flow in Figma and waiting for Ivan to recreate it in Flutter, I could build the first working version myself. Test it in the simulator. Check the interaction. Adjust spacing and layout. Create edge cases. Fix obvious UX issues. Then submit a PR for Ivan to review.
This changed the designer's deliverable. The output was no longer only a Figma file. It became a working flow. A flow that could be tested, discussed, reviewed as code - a flow that could become a pull request.
The new workflow
Define the flow or component
I start by identifying the component, pattern, or full flow that needs to be created or improved. At this stage, I define not only what the interface should look like, but also what states it needs to support: what happens when data is loading? When there is no data? When the user makes an error? On a small screen? With long text? When AI output is partial or the system needs to explain uncertainty?
The goal is to think about the product as behavior, not only as layout.
Build or adjust it in Flutter using Claude Code
Instead of creating every state manually in Figma, I use Claude Code to generate or update the Flutter implementation. I can prompt the system to create a component, add variants, build a state, or assemble a flow:
- "Create a reusable card component with title, subtitle, icon, CTA, loading state, empty state, and long-text handling."
- "Add an error state and disabled state to this input component and expose them in Widgetbook."
- "Build the first version of this flow using our existing components and make sure it works on smaller iPhone screens."
- "Add a generated response state with partial loading, retry, and user feedback options."
This lets me move much faster from design intention to something I can actually test.
Test in Widgetbook
Widgetbook becomes the place where components and states can be reviewed independently from the full app. This is especially useful for testing edge cases. Instead of creating many static Figma frames, I can generate real states and inspect them as live Flutter widgets: default, loading, empty, error, disabled, long text, RTL, small screens, different themes, AI-generated content states, partial output, retry states, accessibility scenarios.
This made edge-case design cheaper. Not less important - cheaper to create, test, and refine. That changed the economics of edge-case design.
Build and test flows in the simulator
After the components are in place, I can assemble full flows and run them in the iOS simulator. This is where the process becomes much more powerful than static design. The simulator reveals things Figma cannot fully show: real screen constraints, keyboard behavior, safe areas, scrolling, touch targets, text rendering, navigation - the feeling of moving through the product.
This allows me to experience the flow much earlier. Not as a diagram. Not as a prototype that only imitates behavior. But as a working Flutter implementation. It also helps me catch UX issues before Ivan spends time polishing or integrating the feature.
Submit a PR for Ivan
Once the flow is working well enough, I submit a pull request. This PR is not treated as final production code. It is a working design proposal. It expresses the design intent in code and gives Ivan a much stronger starting point.
Instead of translating static screens from scratch, Ivan reviews the actual implementation: code quality, architecture, naming, reusability, performance, state management, Flutter best practices, consistency with the codebase, whether logic should live somewhere else, whether there is a cleaner technical approach.
This keeps engineering ownership in the right place. I can move fast and bring the flow closer to reality. Ivan makes sure it is technically correct, scalable, maintainable, and production-ready.
From handoff to pull request
The most important change was not the tool. It was the collaboration model.
Before, our process was sequential: I designed. Ivan implemented. I reviewed. We corrected.
Now, the process is more shared: I build the first working version. Ivan reviews and improves it. We discuss real behavior, real code, and real constraints.
The PR became our shared artifact. Not a Figma file on one side and implementation on the other. A working interface we could both discuss.
Instead of asking "can you build this screen?" the conversation became "here is the flow running in the simulator. What is the right way to make this production-ready?"
Before and after
What collaboration looked like
This process also created a new kind of collaboration between me and Ivan. Instead of only discussing static frames or waiting for implementation to see how something works, we could discuss live UI and real code much earlier.
Impact
The biggest impact was not only speed. It was reducing the distance between design intent and product reality.
Faster design-to-development cycles
I could move from idea to working UI much faster. Instead of waiting for every design to be translated from Figma into Flutter, I could create the first working version myself and bring it to review.
Less translation work
Ivan no longer had to start every UI task from static design files. He could start from a working implementation proposal and focus on making it better.
Better edge-case coverage
Because edge cases became easier to generate and test in Flutter, I could cover more of them earlier. This helped us avoid discovering important states too late in development.
Better support for AI-driven product changes
As AI introduced new feature possibilities and more dynamic product behavior, our design system needed to adapt faster. A live Flutter-based system made it easier to add new states, test new behaviors, and evolve components without maintaining everything twice.
More realistic design decisions
Seeing flows in the simulator made design decisions more grounded. Some things that look fine in Figma feel different on a real device. Testing earlier helped expose those moments faster.
Stronger collaboration
The PR and simulator became shared spaces for design and development. We were no longer working around separate artifacts. We were solving problems around the same working interface.
Better use of frontend time
Ivan's time became more focused on higher-value engineering work: architecture, maintainability, production quality, correct Flutter patterns, integration, performance, code review. Instead of spending that time manually recreating design intent from static screens.
What changed for me as the designer
Before this workflow, covering more product states usually meant creating more Figma work. If I wanted to fully cover a flow, I had to design more frames, more variants, more annotations, and more handoff material.
With the new workflow, edge cases became something I could explore interactively. I could generate a loading state, an error state, a long-text version, an empty state, or an AI-generated response state, then immediately run it in the simulator and decide whether it worked.
This shifted my effort from documenting possibilities to testing actual behavior. It made the design work feel closer to the product and more useful for development.
My deliverable changed from "here is how I think it should look" to "here is a working version of how it should behave." That is a big shift.
What changed for Ivan as the developer
For Ivan, the change was not that development became less important. The opposite. His review became more focused.
Instead of spending most of the time translating visual design into Flutter, he could review a working PR and focus on the things that require engineering judgment: whether the component structure was right, whether the code should be reorganized, whether the state management made sense, and whether there was a better technical pattern.
So the process did not remove the developer from the workflow. It moved him to a higher-leverage point in the workflow. He was no longer only building from design. He was improving, validating, and productionizing a working design proposal.
Key learning
The main learning was that the design system was not the whole story. Moving the design system into Widgetbook was important, but it was only the foundation. The bigger transformation was changing what design delivers.
A design system that only documents components helps teams stay consistent. But a design system that can be used to build working flows helps teams move faster.
In our case, the goal was not simply to replace Figma with Widgetbook. The goal was to reduce the translation layer between design and development. By moving from static handoffs to working PRs, we shortened the path between idea, implementation, review, and product reality.
This became even more important in an AI-driven product environment, where feature possibilities change quickly and components constantly need to support new behaviors. The design system needed to become easier to change. Not just easier to document.
Final reflection
This workflow is not a magic replacement for design or development. Claude Code does not remove the need for design judgment. Widgetbook does not remove the need for product thinking. AI-generated code does not remove the need for frontend review.
But together, they created a better workflow for our context: a small startup team. One designer. One frontend developer. A Flutter app. A growing Figma design system. AI-driven product changes. A need to move fast without ignoring edge cases.
For that context, the shift was powerful. We did not just move our design system from Figma to Widgetbook. We moved design from documentation toward implementation. And that changed how we worked together.
Design stopped ending in Figma, and development stopped starting from translation.
next case study From stacked lists to a career story