Years in the making
None of this drift happened overnight, it was years of accumulated tech debt finally coming due. Components had scattered across the codebase with nobody tracking where they lived or whether a "new" one quietly duplicated an old one. Semantic tokens and primitive values got used interchangeably depending on who wrote the code and when, so the same visual intent could resolve to three different hex values in three different files. Government-specific themes, built for state partnerships like New Mexico's, got applied willy-nilly wherever a deadline demanded it, with no system for when a theme override was appropriate versus when it should have been a real token. The result: no consistent look and feel across our four different platforms, React web, LiveView web, iOS, and Android, each drifting further from the others with every release.
The spark
It started with a small, honest question: "Why does our data_table look different from table in Storybook? They should be the same." Pulling that thread revealed they were never the same component. They were three separate tables, data_table, table, and a newer table_new, each hand-built at a different time with different styling. Nothing in the code kept them in sync.
That one question exposed a bigger truth: on the LiveView side of our product, components had quietly drifted apart and nobody could see it, because each component lived alone on its own page or buried inside a single product screen. There was no place to line them up side by side.
Two systems, two speeds
Wonderschool builds UI on two stacks that share the same visual design tokens (colors, spacing, type) but maintain their components very differently.
~82 stories, ~98% coverage. One consolidated library, public Storybook, Chromatic visual-regression, Figma links, and accessibility checks. It avoided drift by consolidating early.
~12 stories. Two parallel component sets: an auto-loading legacy set and an intentional one you must import by hand. Pages silently fall back to the old components, drift was the default behavior, not a one-off mistake.
What we built
We turned the LiveView Storybook into a diagnostic tool, not just a component showroom, two new pages, now in an open pull request.
1. Component Audit: a census of the system
At a glance: what components exist, where each lives in the code, whether it has a story yet, and where the same UI has been built more than once. It surfaced the duplicate tables, three copies of the form component, a set of duplicate "Endor" components, and the legacy usage counts above. Every stat box is clickable, a number like "16 invisible" drills straight into the list it represents.
2. Drift Gallery: the visual proof
It renders each deprecated component directly beside its blessed replacement, old button vs. new button, old input vs. new input, old table vs. new table, so the divergence is something you see, not just read. Where a component genuinely can't be shown in isolation (it needs a logged-in user, a live query, or app context) we listed it honestly with the reason rather than faking it.
The deprecated CoreComponents.modal and slim_modal aren't shown live here: they read undeclared internal state and only render correctly inside a real app page. That fragility is itself a reason they're deprecated.
3. Token documentation: making the invisible layer legible
Underneath every component sits a three-layer token system, primitive values, semantic tokens, and component tokens, that most of the team had never actually seen laid out. I built a documentation page that traces one color, blue, through all three layers side by side, then lists the full primitive palette and every semantic token (background, text, border, icon, button state) with its hex value and where it's used. Both the React and LiveView Storybooks read from this same source, so the page closes the loop the whole audit was about: one shared vocabulary, visible to everyone, not just the two people who happened to write it.
Where this goes next
The audit turns a vague sense of "our components are inconsistent" into a concrete, prioritized worklist: build stories for the 16 invisible components, consolidate the duplicate tables, forms, and Endor parallels onto a single blessed version, and retire the legacy set in order of effort, small contained orphans first, the 309-file icon campaign last.
The React Storybook is the model for where LiveView should land: public deployment, visual-regression, Figma links, accessibility checks. Because both stacks already share the same tokens, consolidating each side moves us toward genuine cross-stack consistency.
Why it matters
Drift becomes visible, and therefore preventable, you can't fix what you can't see. It creates a shared map designers, PMs, and engineers can agree on. It turns "our UI feels inconsistent" into a ranked list with real usage numbers behind it. And it compounds: every story added and every duplicate retired makes the next inconsistency easier to spot. What began as one puzzling table is now a durable, shareable tool for keeping the entire LiveView design system honest.