Design system · Mobile app · Built from scratch
Users tripped
over the cracks.
Developers hit
the iceberg.
Screens ran on hand-typed values. I rebuilt them as one system that development builds from, and handoff got faster.
At the surface
Users got mixed signals.
A button changed color from screen to screen, and spacing kept shifting. Underneath, every screen had its own reds, greens and spacing, all typed by hand.
The cost
Below the surface,
the real price was paid.
Developers lost time.
Every screen meant asking: which blue, which size, which button?
The code got heavier.
Overrides stacked on overrides. Every fix added another patch.
Every screen felt like a different app.
Layouts changed, CTAs moved, and users had nothing familiar to hold on to.
The way up · 1 of 4
Sort the chaos.
I mapped every element type and gave each one fixed logic: a role, clear states, one radius.
Many button styles→3 roles
Above the water
Nothing yet. The work starts below.
The way up · 2 of 4
Many values, one name.
Each group became one token, named the same in Figma and in code.
Above the water
One blue, on every screen.
The way up · 3 of 4
Tokens became components.
Self-contained, reusable parts. Every question developers asked got one answer.
Above the water
One button, one shape.
Paid back
Same iceberg. Now it holds.
It took time to build. Once it was in place, the next full redesign shipped faster.
Above the water
One product. Users never saw the work, only the calm.
Faster development
Fewer bugs
A consistent experience
Chapter 2 · Behind the system
A system only works if the team uses it.
Three moves that took it from my file to everyone’s daily work.
Every question got one answer.
Many open questions → one answer
From back-and-forth to one pass.
Many round trips → one pass
One name, two worlds.
Presented → Defended → Adopted
Chapter 3 · Six tracks
Six tracks, one system.
Color, type, buttons, spacing, responsiveness and accessibility. Each one answered a question developers kept asking.
Developers asked
“A bit darker.” Which hex is that?
A new green on every screen
Right and wrong now come from two feedback tokens. Every screen shows the same green and the same red.
AnswerOption.css
Developers asked
“Make it pop.” Is pop 18 or 20px?
Nothing to read first
Three roles from the type scale: heading, body and label. The order reads itself.
QuestionScreen.css
Developers asked
Which one is primary? The bluest?
Five buttons, no hierarchy
One Button component with clear hierarchies. One primary action per screen, always in the same place.
Developers asked
“Add more space.” How much is more?
Gaps set by eye
The list owns one gap token. Every answer sits 12px apart, on the same edge.
AnswerList.css
Developers asked
“Make it responsive.” To what?
Fixed width, cut off
The panel fills its container, with padding from a token. It fits any phone.
Feedback.css
Developers asked
Looks great. Can anyone read it?
Soft, and unreadable
Buttons use tested color pairs. Text and surface pass together at 5.2 : 1, on every screen.
ContinueButton.css
Chapter 4 · What I learned
Looking back.
One lesson, and two notes for next time.
The lesson
Boring is the feature.
Users never noticed the system. They moved through the app without stopping to think. That’s how I knew it worked.
What I’d do earlier
Review tokens from day one.
I’d set the token-review checkpoint before the first screen, not after inconsistencies had already piled up.
What I’d measure next
Whether it stays boring.
How many new screens ship with zero hand-typed values, and how many questions developers still ask per feature.
Buyers couldn’t picture it. So I designed the whole picture.
View case study