Vanta B2POS · Design system and handoff

Why choose one?

Why choose one?

Brand variation used to leak into the codebase and slow every release. Now it ships as tokens, generated once and consumed by both web and Flutter.

View
Best viewed on desktop
Back to search
Application No. 2387594
Actions
Application information
Type
Application No.
Client ID
Full name
Status
Amount
Created
Marketplace
2387594
1048372
Kuznetsov D. A.
Approved
108 740 ₽
18.09.2026 14:59
Data entry employee
Andrey Andreyevich Ivanov
Processing platform
Unified OFP platform
Store address
16 Tverskaya St., Moscow
Legal entity
TechnoLine LLC
Authorized by
Semyon Sergeyevich Sidorov
Signing method
SMS
Underwriting
ApprovedApplication approved for 108 740 ₽
Bank decisions
Red Bank
OFPAwaiting authorization
Term, mo.
8
Payment, ₽/mo.
14 797.20
Amount
108 740.00
Interest rate, %
23.12
Insurance
0
SMS notifications, ₽
0
Select
Decline
SMS signing
Specification
Blue Bank
SKPContract authorized
Term, mo.
12
Payment, ₽/mo.
10 067.87
Amount
108 740.00
Interest rate, %
19.90
Insurance
0
SMS notifications, ₽
0
Cancel authorization
Withdraw application
New application
Search applications
Reports
Training
Support
Cash collection
Andrey Ivanov
9:41
Issued (80)
Processing (10)
Declined (5)
₽216,740.00
Total loans issued in the last 7 days
Applications today (5)
No. 48291736
Aug 19, 202509:55
Cooling-off period
4:20
Customer name
Gorbachev D. E.
Customer ID
23456
Amount
₽324,580.00
No. 73920485
Aug 19, 202509:41
Issued
Customer name
Ivanov A. V.
Customer ID
23456
Amount
₽712,430.00
No. 55018237
Aug 19, 202509:12
Processing
Customer name
Petrov K. S.
Customer ID
23456
Amount
₽589,210.00
Home
Search
Form
Chat
Profile
Theme
Appearance

Role

Lead Product Designer, system owner

Team

7 designers I lead, working directly with web and Flutter engineering

Timeline

2025 – now

Surfaces

Web platform, Flutter app, partner widget

Scope

4 brands × light and dark, one semantic layer

8

themes from one semantic layer

2

platforms generated from the same source

0

raw colours referenced in product code

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.

Next case