A saree shop that now sells every week.
- Developer handoff
- Design system
- Figma library
- Brand identity
- Photography
- Storefront design
Problem
The shop sold, but its styles were typed by hand: 378 colours, 43 font sizes. Most values had no stated purpose, two text colours were hard to read, and keyboard focus could leave the filter.
Solution
I designed one token system with three layers, wrote down what each value is for, fixed contrast and focus, and gave Figma and the code the same names. Our developer built it into the shop. The token file is live. The written purposes and the contrast and focus fixes are built, not shipped.
- +395%Orders a month, by the founder’s count, before launch vs since
- 378 → 4Colours typed by hand
- 206 / 206Values with a written purpose: built, not shipped

The shop sold well, but how it worked lived in our heads.
The shopAnubhuti India sells silk sarees online. I designed the brand, shot the photographs and designed the shop with the founder, and our developer built it. Orders come through the website.
The riskThe catalogue now comes from a Google Sheet the founder edits, so the shop changes without us. Its styles only made sense if you remembered why.
Three of us, and one handoff.
Project managerBrought the idea, set the numbers we’d judge it by, and wrote the PRDs.
Me, product designerThe whole design, end to end: the brand, the photographs, every screen of the shop, and the design system behind it, in Figma and in the token names the code uses.
DeveloperBuilt the shop from my handoff: the screens, their specs and the tokens.
The shop looked fine.
The code didn’t.
20 October378 colours, 43 font sizes and 21 line heights were typed straight into the pages. Customers couldn’t see it. The next person would.
24 OctoberAfter the first fix, 36 of 155 values said what they were for. Timings were typed by hand 93 times, two text colours failed contrast, and focus could leave the filter.
36 of 155
Values said what they were for.
93 timings
Typed by hand.
2 colours too faint
The muted text and the copper numbers.
We fixed it in two passes, and customers saw no change.
Two rulesCustomers see no change, and checkout stays off until payments are verified.
OrderFix whatever reaches the most pages first. Write the reason for each value as it moves.
- The catalogue moves to a Google SheetThe founder publishes sarees without meLive
- Pass 1: one token file378 → 4 hand-typed coloursLive
- Figma libraryThe same names as the codeDone
- Audit36 of 155 values explainedDone
- Pass 2: purposes, timings, contrast, focus206 of 206 explainedBuilt, not shipped
- CheckoutBuilt, then switched offHeld back
What the system is made of
Every value lives in one file, tokens/tokens.json, with a name and a written reason.
Colour
Before378 colour values typed by hand, 35 of them different.
Now26 named colours, each with one job. Sindoor rust is the only action colour, and green belongs to WhatsApp. Every text pair is checked for contrast.
Type
Before43 font sizes and 21 line heights, picked page by page.
NowGilda Display for names and headings, Instrument Sans for everything you read or tap. 10 sizes, 14 roles, and headings that scale with the screen.
Spacing
BeforeGaps were chosen page by page.
Now21 steps from 2px to 120px, plus 10 named gaps for sections and layout that scale with the screen.
Corners and depth
CornersThree. Photos and layout stay square. Tags, fields and buttons get 2px. Hearts and the WhatsApp button are round.
DepthTwo shadows. One lifts menus, sheets and the quick view. A 1px ring marks the selected swatch. Nothing else floats.
Icons and motion
IconsThe shop’s own stroked icons, drawn on a 24px grid. The WhatsApp logo is the one exception.
Motion11 named timings, each with a job: 100ms for a press, 300ms for a sheet. Reduced motion switches decorative movement off.
A button asks for the action colour, not a hex code.
Three layers90 raw values, 77 meanings, 39 component values. Change the raw rust once and every button follows.
Two modesThe library also has a dark mode. Meanings swap, component names stay. The shop itself stays light.
Every component documents its states.
ComponentsButton, field, tag, product card, WhatsApp button, filter sheet and header. Each asks for meanings, never raw values.
DocsThe system library shows what each one is for, its states and the tokens behind them. The filter sheet keeps focus inside and closes on Escape.
How the system stays in one piece.
NamingNames say what a value is for, not what it looks like: color.action.primary, never “rust”. Figma uses the same names as the code, so nothing gets lost between the two.
DocumentationEvery value has a written reason and a note on where it’s used. Each component in the system library shows what it’s for, its states and the tokens behind it.
GovernanceA release check fails if a value has no purpose, a text pair fails contrast, or a timing is typed by hand. It passes locally and ships with pass 2, so for now it’s built, not shipped.
Who uses itI work in the Figma library and our developer works in the token file, with the same names on both sides. The founder edits the catalogue in a Google Sheet and never has to touch the system.
How changes get reviewedI design the change and write down its reason, our developer builds it into the token file, and it has to pass the release check before it ships.
We built checkout,
then kept it switched off.
BuiltBag, delivery and review all work, with validation.
Held backA saree costs thousands of rupees, and a payment that fails halfway loses a small label a customer. Until payments are verified, customers order through the founder.

Quantity, price and order summary.

Required fields and validation.

Order check. Payment remains disabled.
What changed, in numbers
- +395%Orders a month: from 3–4 before launch to about 17 sinceLive The founder’s count, not analytics. Orders through the website, not revenue; no ads.
- 378 → 4Colours typed by handLive The shop’s code, 20 vs 21 October, from git.
- 43 → 0Font sizes typed by handLive The same two commits.
- 206 / 206Values that say what they’re for, up from 36 of 155Built, not shipped Checked by check_system.py.
- 93 → 0Hand-typed animation timingsBuilt, not shipped My audit of the template CSS, 24 October.
- 2 → 0Text colours failing contrastBuilt, not shipped The same audit.
- 9 / modeKey text pairs that pass, light and darkBuilt, not shipped The same audit.
- 188Figma values checked against the codeDone Checked by hand.
Live numbers are true on anubhutiindia.com today. Pass 2 is built and checked, but not shipped yet. I don’t credit all of the order growth to this work.
What I’d do differently
Write the reason down the day I make the thing.
Explaining 206 values afterwards was the slow way. Next time each value gets its note the day it’s made, and the audit only has to check.
What’s next
Watch real people shop.
I haven’t measured how long it takes to find a saree. Next: sit with a few customers as they browse, then turn on payments and measure checkout.
Appendix
How the token file reaches the shop, the library and Figma.
Codetokens.json runs through a small Python compiler into CSS variables. The shop and the system library both read them.
Figma and checksFigma uses the same names; I checked all 188 of its values against the code. A release check fails if a value has no purpose, a text pair fails contrast, or a timing is typed by hand.


