Molochou
← All notes

Design tokens live in the browser already

Rebuilding an existing product in Figma starts the same way every time. Open dev tools, read a hex value, type it into a colour style, go back, read the next one. An hour of transcription before any design work begins.

The strange part is that the values are already right there. A rendered page is a complete, accurate, up to date token set. Not what a style guide claims the system is: what the product actually ships. Getting it out is a scraping problem, and scraping problems are solved.

So I solved it, and immediately found that extraction was the easy half.

The output is noise

Read the computed styles of a real page and you get hundreds of values. Four hundred greys, most of them within one or two steps of each other. Border colours that are the text colour at eight percent. Spacings of 13, 14 and 15 pixels sitting next to each other, all of them accidents.

That is not a design system. It is a photograph of one, including every place where the system already lost.

Handing that to a designer is worse than handing them nothing, because now they have four hundred things to sort instead of a blank file and a decision.

The grouping is the product

The useful work is the part after extraction: clustering near-identical values, dropping the ones that appear once, and proposing a set small enough that a person can hold it.

That means the tool has to be opinionated. It has to decide that these six greys are one grey, and be willing to be wrong sometimes. A tool that refuses to decide gives you the raw list, and the raw list is what you already had.

I spent far more time on the clustering than on reading the page, which is the opposite of what I expected on day one and the thing worth saying out loud.

Where the reading has to happen

One constraint shaped the architecture. A Figma plugin cannot fetch and render an arbitrary page: it runs in a sandbox with no browser to point at anything.

So the reading happens where the page already is, in the browser, as an extension, and the result is handed to the plugin. That sounds like an implementation detail and it decides a feature: because the extension runs in a session you are already signed into, it works on pages behind a login. A server-side renderer never would.

The best constraint is the one that hands you a capability while it takes an option away.