A design system,
treated as a product.
Rebuilding the foundation of a multi-platform workplace product ecosystem. From fragmented Material Design overrides into a tokenized, governed, and adopted system serving web, mobile, kiosks and meeting room displays.
Deskbird grew faster than the UI it was built on.
The product had been built quickly on top of Google Material Design, which made sense in the early days. As the team grew, a designer began adapting and overriding Material components without a clear system or governance model.
What started as “we’ll standardize later” became structural debt: duplicated patterns, drifting spacing, components that looked similar but behaved differently, and a frontend codebase increasingly hard to evolve.
When I joined, my first responsibility was to rebuild the foundation, not as a library of components but as the operational backbone of a fast-growing multi-platform product.
A 3-day audit across the web app, admin and mobile screens surfaced dozens of near-duplicate primitives. None of them were “wrong” in isolation. Together they made the product feel inconsistent and made every new screen a small negotiation.
The system was built as a product, with its own users and roadmap.
The mistake I’ve seen most often in design systems is over-engineering, building for the system instead of for the people using it. Deskbird needed a practical foundation, not the biggest component library possible.
Designers and frontend engineers. Their workflows defined every API and naming decision.
Backlog, releases, intake, and changelogs. Treated with the same rigor as any feature team.
Predictable shipping velocity, lower onboarding cost, consistent multi-platform UX.
Most of the answers were already inside the team.
Before designing a single component, I spent weeks watching how the team actually worked. The clearest signals came from screen-shares, not surveys.
- Figma screen-shares
- Asked designers to walk me through a real flow. Watched where they hesitated, copy-pasted, or rebuilt from scratch.
- Frontend syncs
- Bi-weekly with frontend leads. What hurts to maintain. What needs flexibility. What should be hard-locked.
- Inventory audit
- Catalogued every primitive in production. Mapped overrides back to a small set of intended patterns.
- Support tickets
- Read 6 months of customer-facing inconsistencies. The end-user felt the debt too.
Four constraints that shaped every decision.
Build what the product actually needs. Resist coverage as a vanity metric.
Components behave the same across platforms. Surprise is a bug.
Specs live where the work happens, inside Figma, next to the component.
Color, spacing, type, radius, elevation. No raw values in production.
Everything became a token. That changed how the team shipped.
When Figma rolled out variables, we restructured the foundation around a 3-tier token model: primitive → semantic → component. The output is a single JSON source that feeds Figma, web, iOS and Android, written once, propagated automatically.
~60 components, each defined by behavior rather than appearance.
Every component had a contract: states, density, accessibility, responsive behavior, and what it intentionally did not do. Below, a handful of the most-used primitives, recreated.
- Unselected
- ✓Selected
- Focus
- Disabled
We’ll send a recovery link to rui@deskbird.com. The current session will stay active until you sign back in.
We moved the docs into Figma. Adoption changed overnight.
Storybook served the engineering side, but designers rarely opened it and the content drifted from the live components. Once specs lived inside the component file, “is this allowed?” questions almost disappeared.
- 1 Box · 18 × 18 · radius.sm
- 2 Indicator · inset 2 · stroke 2
- 3 Label · text.body · space.2 gap
- 4 Focus ring · 3px · action.primary @ 35%
| Example | Role |
|---|---|
| Default | Unselected |
| Selected | Selected |
| Focus | Keyboard focus |
| Disabled | Disabled |
| Name | Type | Default |
|---|---|---|
| selected | boolean | false |
| disabled | boolean | false |
| indeterminate | boolean | false |
| label | string | — |
| onChange | function | — |
Drop in design-review questions after migrating docs into Figma
Average onboarding to ship a new screen, down from ~2 weeks
Specs, examples and properties living next to the component
The hardest decision wasn’t what to build. It was what to standardize.
I ran a bi-weekly sync with frontend leads. Not to review pixels, but to negotiate the line between hard-locked and intentionally flexible. The matrix below was the working contract.
A vendor library landed mid-roadmap. We treated it as a constraint, not a setback.
Frontend moved to PrimeNG. Rebuilding every component on top of it would have burned the team. Instead, we defined a three-layer model so adoption could continue without forcing technical taste into a corner.
Used as-is when the default behavior matches our spec. Faster delivery, lower surprise.
Restyled via tokens to match our system. Behavior inherited, surface owned.
Built from scratch when the contract or composition couldn’t be met otherwise.
The key: stopping the “rebuild everything” reflex and maintaining a clear contract for what lives in each layer. Every decision was reviewed and documented, so even when it had to move between layers, the transition was a known one.
One system. Seven surfaces. Same primitives.
Once tokens were in place, expansion stopped being a redesign. Adding a new surface meant mapping tokens to the host platform, not rebuilding the system.
Source of truth
Build pipeline
CSS · iOS · XML · Slack JSON
Intake, contribution, deprecation. The boring infrastructure that made it last.
A system without governance becomes folklore. Three lightweight processes kept the bar high without slowing teams down.
- · Linked from Figma + Storybook
- · Triage weekly · 30 minutes
- · Decision: adopt · defer · custom
- · Async RFC + Figma PR
- · Pairing slot if needed
- · Versioned release & changelog
- · Marked legacy in Figma + code
- · Migration guide per change
- · Sunset within 2 release cycles
What actually changed in the system.
I stopped tracking dashboards of percentages early on. The signals that mattered were structural: what teams stopped arguing about, what disappeared from PRs, what became the default path of least resistance.
Web app, admin, iOS, Android, kiosks, room displays and Slack/Teams all rendered to the same source of truth and the same core primitives.
Color, spacing, radius and typography stopped being inline constants. Replacing the theme or rebrand was a config change, ahead of a release.
Less drift, less rework. Anatomy, behavior and engineering details lived alongside the component, where the actual work was done.
Intake reviews and contribution sessions kept a repeatable rhythm, never blocking but never letting the system run off into entropy.
Cross-platform reviews stopped flagging the same spacing, color and component inconsistencies. Visual cohesion became business as usual.
Most product work became a reassembly of existing patterns. Cycle time shrank, quality bar went up.
What changed for the people using it.
Conversations moved away from spacing and color towards flow, hierarchy and customer value. The system absorbed the foundations, freeing the team’s attention.
Token-backed components meant a feature branch never landed in the WIP limbo. Behavior became a config concern instead of multi-team rewrites.
Kiosk and room displays launched in months instead of quarters. UX parity arrived naturally because the underlying primitives didn’t fork between surfaces, only composed differently.
A new product designer could ship their first production-quality screen in their first week, because the system was the path of least resistance, not the exception.
The lessons that stayed with me.
“A design system isn’t a library of components. It’s a collection of decisions the team has agreed to stop re-debating.”
- Start with intake and governance. Components come second. Without them, people stop trusting the system. Surface bias, choices have a cost.
- Treat constraints, vendor libraries, platform differences, as invitations to define what belongs in the system and what doesn't.
- Tokens earlier than feels necessary. The compounding return is enormous.
- Documentation only works at the artifact. Anywhere else and it shifts. Adoption is the only metric that matters. Coverage without adoption is theatre.