At a glance

  • Token-driven design system — 40 components, one source
  • Six prototype tools merged into one runnable app
  • AI drafts; a person releases at every gate

824commits · 5 weeks

Project Summary

Pulse takes a brand team from a strategic signal to a published social post — an AI marketing platform that never gives up human judgment. When I picked it up, the team was prototyping that one product in six different tools — pages that looked alike and shared nothing underneath — with about a week to fold them into a flow we could pitch.

Over five intensive weeks I went from owning the homepage to owning how the team ships: the merged mockup itself, then the token-driven design system and component library, the automation that keeps AI-generated UI on-system, and the handoff surfaces that let design, engineering, ML, and product finally work from one base.

01 · The melee

Same product, six tools — and not one shared line.

Prototypes that only looked like one product

When I picked up Pulse, everyone was iterating on the same product in a different tool: canvas frames, an AI page-builder, model-pasted HTML, screens composited from images. An early style pass kept the pages looking related, but nothing underneath matched. With a week left before the pitch we had to fold all of it into one flow, and that is where the lesson landed for me. Visual consistency is not system consistency.

Fig. 02Four prototypes, one face — and four sources that cannot be merged

02 · The bet

Boards can’t be pitched. Working code can.

Betting the pitch on code

A pitch needs a flow someone can click through and record, not a deck of stills, so the designer and I decided to prototype in code and let AI do most of the typing. To keep six parallel efforts roughly aligned, we seeded a thin style pass first. It gave us a shared look. It did not give us a system, and that difference shaped everything that followed.

the bet · two routes
Fig. 03The bet — the style pass made six efforts rhyme; it was a look, not a system

03 · The look

Branding at deadline speed: a studio, not a dashboard.

Neutral first, color with meaning

The identity had to be settled fast, and it had to survive AI reproduction, so I kept the rules few and wrote every one of them down. I also refused to pick the direction by taste alone. The accent candidates ran against the same dashboard side by side, and the winner had to prove itself on a full Home screen before we ratified the palette.

brand rules · written day one
surfaceneutral first — gray stage, soft cyan light
typeone face for everything · tabular numerals
hierarchysize · spacing · tone — never bold
coloronly with meaning · red = falling data
queuedscheduledgeneratingreadypublishedneeds attention

the generation ladder — each hue has one job; they light in order as you arrive

Fig. 04Few rules, firmly held — color appears only when it means something
Pulse accent study: two identical dashboards rendered side by side, one with the cyan candidate accent and one with green
Pulse home dashboard experiment with the winning cyan accent applied across signals, decision queue, and weekly report
Fig. 05The accent study — identical dashboards, candidate accents side by side; then the cyan experiment on a full Home
Pulse design-system foundations: the 'Neutral first, color with meaning' section with named swatches, status chips, and semantics rules
Fig. 06The rules, written down — the foundations page every hue answers to

04 · The wake-up

Owning Home meant reading everyone’s code.

The front door forces the map

My page was Home, the product’s entry point, so designing it meant understanding every tab, every module, and everyone’s files. Extraction kept failing: styles were welded to pages, interactions died in transit, and much of the generated code was unreadable. The wake-up call was a single prototype file 10,180 lines long. Nothing that size stays maintainable, for a person or, affordably, for a model.

one prototype file
Fig. 07The wake-up file against the shape that replaced it — scroll runs the split

If it’s all code anyway, hand it off clean

I started with my own file: split it, structured it, cleared the dead code. The realization underneath became the whole project. A prototype that looks right but is chaos in the code is still just a prototype — and since generating clean, structured code costs about the same as generating a mess, and it is all code either way, why not generate it in the shape engineering can actually receive, so the designer owns the real front-end result instead of throwing a picture over the wall?

So I asked the engineers a question nobody had raised yet: if design ships code, what shape would you actually accept? Their stack was React, so I rebuilt on their conventions and the handover went cleanly. To me that was the real milestone — AI quietly closing the old, contentious gap between what design draws and what engineering has to build.

own file first · then the bar
Fig. 08Engineer my own page, then ask engineering

05 · The rescue

One week, every prototype, one app.

Unify, engineer, migrate, merge

A week out, the call came to fold every prototype into one mockup and record the pitch video. I took them all: unify the surface, engineer file by file, migrate toward one stack, merge into a single runnable app. AI carried the bulk of the conversion and kept breaking things in transit, so I reviewed every page against its original and repaired every break by hand — a week of nights with a teammate.

the rescue · one pipeline
Fig. 09AI carried the bulk; the fidelity was hand work
308structural commits
1,905dead lines removed
Fig. 10The commit stream, paraphrased from the repo’s own log — no hashes, no names

Then the real data didn’t fit

For the pitch I wired in the ML team’s real data — and the shapes didn’t match what the screens had assumed. It was the code lesson again, from the other side: a mockup that looks finished but can’t hold real data is still just a picture. We had built the UI first and treated data as a detail to pour in later, when the honest order is the reverse — start from the data that exists, tag it, and design the chart around what it can actually give. Looking right was never the bar; being real enough for engineering to receive — real code and real data both — was. That is the gap the shared base was built to close.

06 · The base

The look became law: one base the whole team ships from.

One canonical base, checked by machines

The fix was a base everyone shares. The look was ratified into one canonical token sheet — six semantic ramps, a fixed type scale, an 8-based rhythm — beneath the 40 standalone components, and every screen composes from those contracts before inventing anything page-local. The standard became commits rather than advice: Prettier normalized the codebase, I purged 1,905 verified-dead lines, and a dependency-free check now enforces all of it in CI.

Pulse · token sheet
ready#49e0f5
positive#43ba51
scheduled#3987f3
risk#f19a08
in progress#6366f1
decline#ef4444
Aa64 · page display
Aa28 · section
Aa15 · body
spacing · 8-base
Fig. 11The canonical token sheet — six ramps, one scale, one rhythmclick / tap a chip to copy its hex
01AIPanel
02Button
03ButtonPrimary
04ButtonSecondary
05ButtonGhost
06ButtonDanger
07IconButton
08Card
09Grid
10MetricCard
11ActionCard
12MediaCard
13EmptyCard
14ErrorCard
15ConfirmBar
16Modal
17Icon
18PlatformBadge
19PostChip
20PlatformPreview
21ApprovalChain
22SegmentedTabs
23PageNavTabs
24ReportRangeTabs
25ActionRangeTabs
26AnalyticsSubtabs
27SignalSeverityTabs
28SignalRow
29SignalCard
30HorizontalBarChart
31VerticalBarChart
32ComboChart
33LineChart
34FunnelChart
35DataTable
36ScoreGauge
37StatList
38Sidebar
39StatusPill
40NodeGenerationMap
Fig. 12The full registry — 40 components, each its own folder over shared tokens
01verifyinventory ↔ preview ↔ board
02tokensdrift advisory
03generatedhand-edit guard
Fig. 13The CI guard checks — inventory, tokens, and hand-edits, reconciled on every merge
Build the link that doesn’t exist, then delete the copies.
The single-source doctrine, from the migration plan — every layer has one owner, and a check keeps them honest.

Stepping down from React, on purpose

I had proven I could ship the React path, and still made plain HTML and CSS the team’s prototype stack — an interim call, and one I stay honest about. Not everyone on the team can fully own engineering standards yet, and plain files meet everyone where they are: a designer and an engineer can both edit them, they export straight to Figma design boards, they preview from a double-click with no dev server to run, and they still convert cleanly into React or another framework later. A mockup a teammate can’t open might as well not exist. The floor mattered more than the ceiling — the discipline lives in the tokens and the checks, not the framework.

Preserve file:// support because designers may open this export directly.
Verbatim from the repo’s README — the floor, written into law.

07 · The skills

Rules the AI loads, so nobody has to repeat them.

Teaching the AI the system

A library only holds if every new prototype follows it, and re-typing the rules into a chat box every time is exactly how that falls apart. So I wrote the rules as skills the AI loads before it generates or edits: maintenance skills keep tokens, components, and previews in sync, and a design skill makes new work start on-system instead of getting repaired into it. Calendar began from that baseline, and the melee never came back.

where systems go to die
Fig. 14The repetition loop a skill deletes
skill · design-usage

Loaded before the AI generates or edits a prototype — the system, written as procedure.

  • compose from the component library before inventing page-local UI
  • tokens only — no raw hex, no off-scale spacing or type
  • every state ships: hover, focus, empty, loading, error
  • run the consistency check before any handoff

maintenance skills keep tokens, previews, and boards in sync

Fig. 15The rules, made loadable — on-system by construction, not by repair

The skill is a living document

When a review catches a drift, the fix lands in the skill’s markdown, not in someone’s memory. I keep editing those files the way engineers keep tests green: each decision we settle — a token, a component pattern, a rule about states — gets written where the AI reads it before it works. That is what makes the generation quality compound: every edit raises the floor of everything produced after it.

harness control · the loop that stays
Fig. 16Harness control — the feedback loop that stays
Late May
Six ways of building, one deadlineLate May · the same product in six tools, a pitch about a week out
Late May
The file that forced the questionLate May · the shared home prototype swells into one monolithic file
Early June
A finished design, waiting on a foundationEarly June · a teammate's finished page sits idle — no system to land on
Mid-June
The boards become one portable fileMid-June · the visual library rebuilt as a single self-contained page
Mid-June
HTML and CSS become the source of truthMid-June · the React copy demoted to a consumer of the canonical layer
Mid-June
The monolith becomes source, not blobMid-June · a build script splits it: 76 partials, 71 scripts, 22 sheets
Mid-June
Standards, written as commitsMid-June · Prettier, lint, lighter assets, a CI token gate
Late June
The demos converge into one productLate June · one static export, every page on the system's tokens
Late June
Wrapped for every consumerLate June · a teammate publishes the typed React package; CI syncs the CSS in
Early July
The payoff: 1,905 dead lines goneEarly July · drifted style copies collapse back to one source
Fig. 17Build timeline — five weeks from melee to system, late May to early July 2026

08 · The interface

Four roles, one base: previews, a package, a playground.

A surface for each side of the table

I grew a reading surface for each side of the table: a live component browser that renders every component and state from its standalone source, and a sliced, deliberately non-interactive Figma board built purely to be imported, so code UI flows back into design review. The handoff is not a snapshot either: when the system changes, a sync pass carries the decision back out to the designer surfaces.

Component browser rendered live · Pulse registry

Buttons

One control contract — four intents, each with its own busy and landed feedback.

click any button · submit → busy → landed
Fig. 18The component browser, rebuilt live — real components from the Pulse registry; the shipped browser holds all 40click through the registry — every state runs
Figma component board: PostChip state matrix and a labeled campaign anatomy map
Fig. 19The sliced Figma board — deliberately non-interactive, built to be imported into design review

From preview to infrastructure

The HTML library stayed the source of truth. Separately, and later, a teammate re-migrated it into a typed React package on the team’s private registry — a distinct build that copies the canonical CSS in so the package can’t drift from its origin, then a CI job publishes that package and deploys its playground. The playground goes past looks: you feed a component data and watch it hold. That was the thing the melee had been missing — not talent, but an interface between the people who had to work together.

React package · manifest
packageinternal, typed React set
distributionprivate registry
authoredtyped JSX wrappers
peerreact ≥ 18
stylessynced from the canonical CSS

versioned releases · CI rebuilds from the design system

Fig. 20The package’s plate — styles sync from the canonical CSS at build time
payload · jsonsample data
MetricCard · renders the payloadholds every state
Projected reach
420K+12%
Fig. 21The playground idea, live — feed a component data and watch it hold: empty, overflowing, brokenedit the JSON — the tile answers
Pulse React component library playground: AIPanel rendered from the package, with copyable usage code
Fig. 22The real playground — the published AIPanel rendered live, with per-component knobs and a JSON data editor
Four roles · one base

integration stopped being a rescue

Fig. 23The interface, read four ways

09 · The product

What the base carried: a studio with a person inside.

A calm studio, not a dashboard

On top of the system sits the application: a sidebar workspace that runs from Home and its docked assistant through Calendar, Signal, Analytics, Strategy, Campaigns, and the production Studio. Hierarchy comes from tone, spacing, and rhythm before borders, and every screenshot on this page renders from a plain file:// address.

Pulse app Home page: workspace sidebar for the demo brand, action-item KPI tiles, content queue, and signals feed
Fig. 24The unified Pulse app, Home — the page that forced the map, now on the system
Pulse Analytics weekly report with KPI tiles and key signals
Fig. 25Two more pages of the same static export — the scheduling Calendar and the weekly Analytics report, both from a file:// address
Pulse brand onboarding: an editorial hero reading 'Your brand, decoded. Your channels, run.' above brand-URL and brand-guide inputs
Fig. 26Onboarding — a new brand becomes working material: starter assets and a vault that feeds every generative step after it

A light brief, drafted by the AI, owned by the human

A post starts inside its campaign. New Post, then Create with AI, and from there it is a conversation rather than a form: the user gives a goal and a few assets, Pulse reads the brand vault and the campaign, and a structured Creative Brief comes back as editable fields inside the chat. Only approval hands off to generation.

Creative BriefDrafted by Pulse
Audience

Urban runners, 18–29, early-morning crews

Key message

City miles before the city wakes

Content direction

Short-form video · street-level POV

Tone

Confident, unhurried

Visual style

Natural light, muted brand palette

Est. spend · 320 credits
Fig. 27The Creative Brief — a person shapes the AI draftedit a field, then approve

Draft brief is ready — audience and tone come from your brand vault.

assistant · plain text, no bubble

Tighten the key message.

user · ink bubble, right-aligned

Creative BriefOpen brief

rich content · a card; inline controls stay flat

Fig. 28Chat contract — the assistant follows the product component contract

Two gates and a guardrail keep a person in charge

Approval runs through an ordered chain — reviewer, brand admin, org owner — with SLA timers and an escalation that never auto-approves. A plan gate signs off direction and spend before any credits burn; a content gate signs off the finished creative before it goes live.

01Reviewer
SLA 24h
02Brand admin
SLA 24h
03Org owner
Fig. 29Approval chain — SLA timers; escalation never auto-approves

AI can draft and schedule. A person releases to publish.

The guardrail is independent of the gates, so turning approvals off never lets an agent publish on its own.

Rebuilding a vibe-coded page, step by step

The clearest proof of all this is the Campaign page. It reached me as a teammate’s quick, vibe-coded prototype — one four-thousand-line HTML file, styles inlined, images pasted in as data, no system underneath. It looked like a product and behaved like a draft.

Over about two and a half weeks I rebuilt it on the base, a commit at a time: I pulled the status tabs and badges out as real components, reshaped the flow from a flat Campaign Library into a decision-first Overview — what needs your approval and what’s mid-production, with the assistant proposing directions from the week’s signals — added the plan-diff gate and the approval chain, and finally let it consume the design-system components directly. Same brief; a real product. A picture became something engineering could receive and a designer could keep owning — which is the whole point.

Before · the teammate’s vibe-code
The rough campaign prototype: a flat Campaign Library — a KPI strip, filter tabs, search, and a scroll of campaign cards, with the assistant collapsed to a chat pill
After · rebuilt on the base
The rebuilt campaign page: a decision-first Overview with an approvals card, a segmented production queue, and a Pulse-suggests rail of signal-driven campaign directions
Fig. 30Same brief, rebuilt — a browse-first Campaign Library became a decision-first Overview
the intake · then the base
Fig. 31The refinement, in the build — monolith to modular, on the design system

Most memorable moment

From shipping pages to building the system that ships them.

Pulse did not hand me a design-system brief. It handed me a melee: one product, six tools, a deadline, and the discovery that pages which look identical can share nothing at all. The real deliverable was never one more screen. It was the base underneath all of them.

So the work became structure. Tokens instead of taste, components instead of copies, and written rules an AI loads instead of instructions repeated into a chat box. Design reads previews, engineering reads a typed package, ML reads data states, product reads one runnable flow. The melee ended when everyone stopped squeezing into the same files and started shipping from the same base.

One rule survived every iteration untouched: AI can draft and schedule, but a person always releases to publish. Speed where it helps, a deliberate checkpoint where it matters. That balance, not the automation, was the design.

Goala goal and an optional note
Assetsuploaded or picked from the brand vault
Briefeditable fields, budget shown
Generateruns only after the brief is approved
Reviewcontent gate signs off the creative
Publisha person releases — always
Fig. 32Create-with-AI — where a person stays in the loop ai step human gate
Fig. 33The gate, recorded — brief → approve → generate → review → publish, a person at every red step