🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.🚧 Under construction — I'm migrating this site from Framer to Next.js and publishing it early for testing, so a lot of the content is still in flux.
Open menu
Switch to Darkhello@product.inc

Vibe-code

Every token, component and screen in this site, derived from source and drawn as one graph you can point at

Vibe-codeStatic analysisNode + SVGDesign systems
Usage Graph — cover

A design system is a set of rules about what a screen is allowed to use, and those rules are only real if something can check them. Mine could not be checked. The contract names a closed vocabulary of semantic tokens, every surface in the repository is supposed to spend only those, and nothing anywhere could answer the two questions that actually come up: is this token load-bearing or has it never been used, and what moves if I change it. Grep is no help it cannot tell a class from the same string in a comment, and it cannot see the classes that are the real problem, the plausible-looking ones that quietly emit no CSS at all.

So I wrote the thing that answers it. It reads the contract, expands it into every utility class it can legally generate, walks every file in the repository, and derives the graph that was already implicit in both: tokens into primitives into components into screens. That takes about four tenths of a second and nothing is written down, which means there is no snapshot to go stale. The part worth showing is what happens once it is data. You can print any slice of it, and you can also draw all of it at once — which turns out to be the only view that makes the shape of a design system visible.

Engagement
Tool built for my own design system
Role
Wrote all of it
Scope
Static analysis, CLI, live visualization
Runs
On every request, from source

Role

Solo build — designed and vibe-coded end to end. A Node script with no dependencies for the derivation and the CLI, and an interactive SVG visualization in the site itself. The derivation and the drawing landed on the same day.

Files scanned

0

Every .ts and .tsx in the site and in the design system's own source.

Components mapped

0

Sorted into five layers, from base primitives out to app routes.

Dependencies drawn

0

Every import and every token use — derived, not declared anywhere.

Tokens spent nowhere

0

Defined in the contract and used by nothing. Not findable before this.

01The problem

Rules that nothing could check

The design system in this repository is a contract: a fixed list of semantic tokens, and a rule that UI code spends those and nothing else. Contracts like that are easy to write and hard to hold, because the failure mode is silent. A raw hex in a component looks fine in review. So does a leftover default-palette class — and that one is worse, because in this setup the default Tailwind palette is not installed, so the class emits no CSS whatsoever and the element simply renders with no color while the diff reads as perfectly ordinary.

The other half of the problem is direction. Before any broad change — renaming a token, editing a brand file, retiring a component — the question is what else moves, and the honest answer was always a guess dressed up as a grep. Not knowing made every sweep more cautious and slower than it needed to be, and it meant the tokens nobody used stayed in the contract indefinitely, because nothing could prove they were safe to remove.

The contract is closed, which is the property that makes all of this tractable: a finite vocabulary expands into a finite set of legal classes, so usage extraction is exact matching rather than pattern-guessing.
Why it can be derived at all
02Derivation

Everything derived, nothing stored

The script starts from the contract and expands each namespace into every Tailwind utility that namespace can generate — every color prefix, every spacing prefix, every radius corner. Collisions in that table are a build error rather than a warning, which is what lets the rest of the tool match blindly and trust the result. Then it walks the source: class strings, custom-property references, imports. Files become nodes, imports become compose edges, matched utilities become token edges, and the layer a node belongs to falls out of where it lives.

None of it is written to disk. There is no generated manifest to regenerate, no cache to invalidate, and no committed snapshot that can quietly drift from the code it claims to describe — the graph is re-derived from source every time anything asks for it, including the page you are reading, which derived its own figures when it was built.

03The drawing

Five columns, and every edge at once

Tokens, base primitives, systems, surfaces, screens — the pipeline, drawn left to right.

A dependency graph is usually shown one query at a time, which asks you to hold the shape in your head. This shows the whole thing. Every node is a bar whose length is its weight — for a token, how often it is spent; for a component, how much styling it carries — so each column ranks itself without a single number on screen. All five thousand or so edges are drawn once underneath at five percent opacity, where they stop being lines and become weather.

Tokenscontract · 143Baseprimitives · ui-lib · 152Systemsproduct · kits · 93Surfacessite · docs · 157Screensapp routes · 59colortextfontfont-weightspacingradiusshadowcontainerease
Fig. 01The whole system in one canvas: 143 tokens on the left, then the primitives, the systems, the surfaces and the routes they end up on. Everything here was derived from this repository when this page was built.

Interaction is the two questions the CLI answers, drawn instead of printed. Hovering is the shallow one — direct neighbours, downstream in one colour and upstream in another. Clicking is the deep one: the transitive closure in both directions, which for a base primitive is most of the picture and for a leaf screen is almost none of it. The asymmetry is the useful part, and the version at the end of this study is the one to try it on.

04What it found

The tokens nobody spends

The first thing it produced was a ledger: every token in the contract, ranked by how many places actually use it. The head is unsurprising and reassuring — a border color, a muted text color, a small type size, each carrying several hundred sites. The tail was the point. A handful of tokens turned out to have never been used anywhere: a whole namespace reserved for a native kit that no web surface has ever spent, and a nested radius nothing reached for. None of that was findable before.

text/xs632
color/border-default592
color/text-muted519
color/text-default451
text/sm369
color/text-faint347
color/surface-raised341
color/primary328
font-weight/semibold289
radius/full260
font-weight/bold226
font-weight/medium213
radius/md180
color/surface176

143 tokens in the contract. 138 are used somewhere; 5 are used nowhere at all.

Fig. 02The token ledger, live: the most-spent tokens in the contract, and the count of tokens that are defined in it and spent nowhere.

The check command runs the same extraction with the opposite intent. Anything off the contract is a finding, split into two tiers: dead defaults and raw colors exit non-zero, because both are bugs rather than opinions, while arbitrary values are collected into a review list instead, because sometimes a magic number really is the right answer and the tool is not in a position to know which.

05Impact

What moves if I change this

The version of the question that comes up most is about brand files. Every brand in the system defines some namespaces and inherits the rest, so editing one is a targeted change with an untargeted reach, and the tool can resolve exactly which surfaces sit inside it and which token namespaces it actually redefines. Selecting a node does the same thing visually: the picture dims to just that node's reach, and the amount of canvas left lit is the answer.

Tokenscontract · 143Baseprimitives · ui-lib · 152Systemsproduct · kits · 93Surfacessite · docs · 157Screensapp routes · 59colortextfontfont-weightspacingradiusshadowcontainerease
Fig. 03The same canvas, drawn with the primary color selected. Everything still lit either uses that token or renders something that does — the blast radius of a one-line change to a brand file.
06The catch

It is reading the page it is drawn on

The figures above were derived from this repository at build time, and the site itself is one of the layers in them — the components that render this study are nodes in the graph the study is about, and the tokens spent laying out this paragraph are bars in the first column. That is not a trick; it is just what happens when the tool reads the source rather than a description of it. It is also the closest thing to a proof that the picture is current.

The reason it is in this section rather than a tools folder is that it changed how the design system gets worked on. Sweeps start with a query instead of a search, a token rename is a bounded change rather than a nervous one, and the two classes of styling bug that used to be invisible now have a command that names them. The derivation and the drawing both landed the same day, which is the part that still surprises me most.

07The tool

Have a go

The figures above are stills. This is the studio tool itself — search it, click through it, and read the panel.

What shipped

  • Derives the whole graph — tokens, components, screens, and the edges between them — from the token contract and the source, with nothing hand-maintained.

  • Answers the questions a sweep starts with: who uses this token, what composes this component, what is the blast radius of editing a brand file.

  • Exits non-zero on classes that are off the contract — dead defaults and raw colors — and keeps a separate review list for arbitrary values.

  • Draws every node and every edge in one five-column canvas; pointing at any bar lights its dependencies, clicking one holds its full transitive reach.

  • Found five tokens in the contract that the codebase has never once used.

Selected decisions

  1. 01

    Made extraction exact rather than heuristic by expanding the closed contract into a utility table first, so a match is a match and a collision is a build error.

  2. 02

    Kept the graph derived and unstored: the freshness contract is that there is nothing to keep fresh.

  3. 03

    Encoded weight as bar length in both directions — a token by how often it is spent, a component by how much styling it carries — so the canvas ranks itself.

  4. 04

    Drew all five thousand edges at once, faintly, and let selection do the filtering, rather than showing a graph you have to assemble in your head one query at a time.

  5. 05

    Shipped the same derivation to a CLI and a web canvas from one module, so the printed answer and the drawn one cannot disagree.