Asteri AI

Role
Design Engineer
Timeframe
May to June 2026
Outcome
First design system shipped to production in six weeks
Stack
React, Next.js, TypeScript, Ant Design, CSS Modules, Design tokens, Figma, Codex

Asteri is a seed-stage AI startup, about ten people, building a work intelligence platform for Fortune 500 life sciences teams. They brought me in to improve the product experience. Six weeks later the company had its first design system in production and an engineering team continuing the rollout without me. The interesting part is the decision underneath that.

The finding

The brief said “improve the product experience.” The audit of the frontend said something more specific: systemic UI inconsistency. Colors, spacing, and radii varied screen to screen. Styling was restated inline, per file, by hand. Nothing shared a source of truth. None of it was scandalous on its own. Together it meant every new screen would drift a little further, and every fix would stay hand-made forever.

The tempting path

The obvious move was to start restyling screens. It shows progress fast, it is what a six-week engagement is expected to produce, and every inconsistent screen begged for it.

It is also a trap. Restyled screens without shared infrastructure drift right back. I would have spent six weeks producing before-and-afters, and the team would have inherited the same maintenance failure mode with nicer wallpaper.

Two paths from the audit finding: restyling screens directly was tempting but compounds drift; building token infrastructure first was chosen and shipped to production. Systemic UI inconsistency found by auditing the entire frontend Restyle screens directly the tempting path Fast, visible progress every fix re-styled by hand Drift comes back no shared source of truth; regressions compound Token infrastructure first the chosen path Primitives, then semantic tokens CSS variables + Ant Design theme mapping Pilot migration, appearance unchanged modernized implementation, zero visual diff Shipped to production engineering continues the rollout

Restyling was faster to show. Infrastructure was faster to compound.

The pivot

I proposed token infrastructure first: build the system, migrate gradually, leave rails the team can keep rolling on after I’m gone.

That is a hard sell at a seed-stage startup, where visible progress is oxygen. So I didn’t sell it in CSS terms. The pitch to leadership: the branding is strong, the implementation is inconsistent, and the inconsistency is expensive, because every UI change costs more than it should. Framed as maintenance cost and regression risk, infrastructure-first became the direction in one conversation.

Leadership added one constraint: a business-critical data table was off-limits. No redesign, no restyle, no rebuild. I planned the migration around it instead of fighting it. A system that only works when nothing is off-limits is not much of a system.

What got built

A two-layer token hierarchy: primitives (context-free color ramps, type scale, spacing) aliased into semantic tokens (surface, text, border, interaction states). The tokens generate CSS variables for CSS Modules and custom components, and map into the Ant Design theme layer so built-in components inherit them automatically. Change a value once, every surface updates.

Token architecture: primitives feed semantic tokens, which flow to CSS Modules and the Ant Design theme, so every product surface consumes one source of truth. Primitives color ramps · type scale · spacing · radius · motion Semantic tokens surface · text · border · interaction states Generated CSS variables consumed by CSS Modules and custom React components Ant Design theme mapping built-in components inherit tokens automatically Product UI one source of truth: change a value once, every surface updates
One source of truth; both styling systems consume the same tokens.

Before, a typical dashboard stat card restated every style decision inline:

<div style={{ background: '#f7f8fa', borderRadius: 8, padding: 16 }}>
  <span style={{ color: '#6b7280', fontSize: 13 }}>Active studies</span>
  <span style={{ color: '#111827', fontSize: 24, fontWeight: 600 }}>128</span>
</div>

After, the same card consumes semantic tokens:

.statCard {
  background: var(--surface-raised);
  border-radius: var(--radius-card);
  padding: var(--space-inset);
}
.statCard .label { color: var(--text-muted); font: var(--text-label); }
.statCard .value { color: var(--text-primary); font: var(--text-metric); }

Rendered output: identical. Which brings up the tradeoff.

The tradeoff

For the pilot I migrated the dashboard surfaces and kept their appearance intentionally unchanged. Same look, new plumbing. Zero visual diff was a feature: it made the migration reviewable, testable, and boring, which is exactly what you want from infrastructure.

It also cost me the flashy before-and-after. Six weeks of work you can show off, or six weeks of work that compounds. I picked the one that compounds.

Where it landed

The design system shipped to production inside the engagement, with documentation and an open migration path the engineering team adopted to continue the rollout. The engagement ended when the budget did, on good terms, with the door open post-funding.

The system kept working without me. That was the point.

Engagement arc: audit, business case, token architecture, pilot migration, then docs and handoff, six weeks end to end. Audit every frontend surface reviewed Business case debt translated to cost and risk Token architecture primitives to semantic layers Pilot migration same look, new plumbing Docs + handoff engineering continues rollout on rails six weeks, end to end
Deep dive: the audit numbers and the second architecture

The audit covered roughly 370 frontend files. What it found, counted:

Audit findings, count of style declarations by kind: about 1,024 pixel literals, 487 literal color values, 389 inline style objects, and only 202 references to centralized tokens. px literals ~1,024 literal color values ~487 inline style objects ~389 token references ~202

Roughly one style decision in ten flowed through a token. The rest were restated inline, per file, by hand.

The first token architecture I shipped had its own flaw: values duplicated across four places that each claimed to be the source of truth (a TypeScript theme object, two global stylesheets, and a primitives module). Duplication is a maintenance failure mode, the same disease in token clothing. I iterated to a leaner semantic architecture with fewer sources of truth, consumable by both React components and CSS Modules, mapped once into the Ant Design theme layer.

Final token coverage: color (brand, neutrals, semantic, interaction states), typography, spacing, layout, radius, elevation, motion, z-index, breakpoints, and icon sizing.

The pilot migration touched about seven dashboard files, QA’d against a mock server with a clean diff: only the expected files modified, no visual changes.