01
The problem
Every design system case starts with mismatched buttons. This one did not.
B2POS runs across retail brands, and each deployment had been piling up its own colour overrides for years. The cost was not that screens looked different, it was that they looked different in the source code. Every feature was built once and then patched per brand, web and mobile drifted apart, and nobody could say what secondary text looked like in a brand’s dark mode without opening a file.
So the system had one job: make brand a value, not a fork.
02
The structure
Primitives
The raw ramps. Nothing in the product references them directly.
Semantic tokens
What the product actually speaks: surface, text primary, text secondary, separator. Every screen, component and state is built on this layer only.
The rule
A component does not know which brand it is in. It asks for text secondary and the theme answers. Eight exports, one component library.
03
Two platforms, one source
Web
One tokens file of CSS variables with three switching mechanisms: a data attribute, a theme class and a system preference fallback. Each variable carries its Figma path, so anyone can trace a value back to the design file.
Mobile
A Flutter theme extension next to the standard colour scheme, shipping the semantic layer plus only the primitives it uses. Not a translation of the web file: the same source, expressed the way Flutter engineers already think.
04
Generated with AI, reviewed by hand
The token libraries are generated rather than typed. What matters is the step after: every export is read line by line with the engineers who consume it, before it ships.
On the last pass that review caught three dark themes where secondary and tertiary text sat a step too bright: invisible on a good monitor, painful on a shop-floor device at the end of a shift.
05
Naming as handoff
Screens are named as the app’s own routes, layers in camelCase, and instances keep their component name. A designer and a Flutter developer point at the same thing when they say home/new-loan-application. It is the difference between a handoff meeting and a handoff link.
06
Where it is now
The system carries the B2POS platform, the Flutter app in closed test with 12,000 partner users, and the partner widget. A new brand is a token export, not a project. It works because the semantic layer came before the themes, not after.
