Dynery · Design System · 2026

Refactoring a live
design system
with AI.

How I used AI to refactor, clean up and fix Dynery's design system — three eras of decisions, one iOS payments app — and then re-cut it so the whole team can run it without me.

Lead Product Designer · sole designer May – Aug 2026 iOS-first React Native · 80%+ iOS
Active is chromatic · disabled is neutral and dimmed
01 / The stake

In a payments app, our active buttons looked disabled.

2023 · MVP system

Built by the previous designer.

2024 · The 2024 system

Mine — some MVP components inherited, most built to that year's decisions.

2026 · The refresh

This case.

no primary-container role existed

The app pre-authorizes money when you join a table. A control that reads as dead is a trust problem, not a polish problem.

“the whole light-tint side was unfinished — full of TBD”

02 / Two moving targets

Our taste moved. So did iOS.

#1 legacy · boxy
Confirm
radius 6 · teal
#2 Apple iOS 26/27 kit
Confirm
near-capsule · liquid glass

iOS 26 → 27: directly referenced instances changed style even after Swap Library

#3 own · radius 16
Confirm
our component · our token

All-Open-Sans had started to feel cold as the brand matured. At the same moment Apple's Liquid Glass reset what “native” looks like. Both pressures hit one file.

I could not read a file this size by hand.

A great many buttons
A few weeks, on and off
Not blocking — but only I could fix it
03 / The brief

I briefed AI the way I'd brief a design lead.

written and run inside Claude Code
§2 — Locked
Brand primary is locked: #00696B. Its hue never changes.
Warm colors are semantic-status-only.
Serif appears ONLY on Display / H1 / H2.
§3 — Root cause
our light tints were so low in saturation they were perceptually identical to our disabled greys
§9 — Acceptance
Audit the old system verbatim first.
Label every pairing with its contrast ratio.
No warm color outside status.
State any assumptions made.

The judgment stayed mine; the generation was delegated. The brief audits the old system verbatim first, so before/after is provable.

04 / The system

One hue-stable ramp. One neutral ramp. One real “active light” role.

Teal · 50 → 900 · hue-stable
Neutral ramp

Names what our greys already were: iOS system grays.

Status-only warm
error
#FF3B30
warning
#FF8D28
pending
#FFC957
success
#34C759

Warm lives here, and nowhere else.

Retired
Old → new
Lighter/Subtle teal (TBD)
primaryContainer #CCEBE6
— (did not exist)
onPrimaryContainer #00494A
Text/Disabled #D1D1D6
labelDisabled #3C3C432E
Status “Disabled” #C4C4C4
fillDisabled #E5E5EA @ 0.35
Spacers 28 & 40 “TBD”
space/7, space/10

Every pairing labelled with its contrast ratio in the brief — because the brief demanded it.

05 / One real iteration

The serif I specified is not the serif we shipped.

Fraunces on every Display / H1 / H2
Restaurant Name
$24.00
numbers and prices: always sans

The brief's rule: one serif, applied across the whole heading tier.

Specimen shown in the page's type

Newsreader, dual heading scale — serif enters the product through one component: the Home Banner
Restaurant Name
$24.00
numbers and prices: always sans

Specimen shown in the page's type

Newsreader sits closer to the brand's tone and is the face the planned UI iteration standardizes on.

06 / Code as truth

The tokens became a typed theme, so the decisions can't be forgotten.

// tokens.ts · one source of truth, light + dark
export const teal = {
  100: '#CCEBE6',   // primaryContainer · new role
  700: '#00696B',   // brand primary (locked)
  900: '#00494A',   // onPrimaryContainer
};

theme.colors.primary          = teal[700];
theme.colors.primaryContainer = teal[100];
theme.colors.fillDisabled     = 'rgba(229,229,234,0.35)';

// Button.tsx
<Button variant="soft">Save for later</Button>
// disabled: neutral grey @ 0.35 — never a teal tint
teal[700] = '#00696B' // brand primary (locked)
theme.colors.primary
<Button variant="soft">
light + dark no styling library components consume Theme, never raw hex

React Native shaped the design back: static font weights, unitless points, no backdrop-filter. Handing off RN tokens is now part of how I deliver — I'm not responsible for the code, but the front end I built helped engineering land it.

The new tokens existed. The 26,747-node product file did not know yet.

Part two

From refresh to repair.

A refreshed token set is a promise. The live file — three button generations, hundreds of Apple-kit instances — is where the promise gets tested.

07 Own the component
08 The audit
09 The turn
10 The defect
07 / Own the component

Own the component. Borrow only the aesthetic.

Confirm reservation
Material
Corner token

Liquid Glass is a material, not a component identity. Radius is one token — capsule ↔ 16 in one switch.

retire the boxy legacy stop instancing Apple's kit glass for the navigation layer only

“Adopt the liquid-glass aesthetic — drop the liquid-glass dependency.”

consolidation landed · ~700 instances decoupled · (creator's account)

08 / The audit

AI read all 26,747 nodes and handed me a scope of work.

v1.0 · the model's first pass
26,747
nodes
36
screens
248
variables
698
sub-44pt tap targets
10+
button heights
32%
token adoption
10%
on the worst screen (PU1.3)
8–13×
duplicated screens

Done by hand this was about a month of my time. It read as a real cleanup project — itemized. Then I re-verified before assigning a single hour of it.

The first thing I checked did not survive.

09 / The turn

Same screen. Opposite conclusion.

32 / 315 = 10.2%
All hardcoded — ranked #1 to fix.

Colour, spacing, radius and type counted as one number.

32 / 47 = 68.1%
Above average — removed from the list.

Colour separated from spacing. The same 32 bound nodes, a truthful denominator.

56% ACTIVE

56% active · 44% parked or hidden
the model counted the dead space

698 → 174nodes (18 sizes; 108 are one component)
10+ → 4heights (28/44/48/50)
8 copies → 0active (all parked)
Errata · v1.0 said → v1.1 found
factual
the #1a1a1a “hardcoded” hex
a bound DS variable
factual
token names teal-500 / teal-700
swapped
self-contradicting
the recommended fix #3C3C43 @ 60%
3.44:1, fails AA
self-contradicting
the “legacy grey” #727272
4.81:1, the only grey that passes
counting
PU1.3 at 10%
68% on color

5 of the 16 errata rows.

“AI scales whatever counting rule you give it — including the wrong one.”

“good archiving inflated the defect count — the rule must subtract dead space first”

10 / The defect

The real defect was in the system — and it needed a decision, not a find-and-replace.

token · text/secondary
2.67 : 1
AA large text needs 3 : 1 · body needs 4.5 : 1
Decided
A · Follow Apple

Restrict the token to non-critical supporting text; document the exception.

B · Meet AA

A solid ≤ #767676; #727272 = 4.81:1. The road not taken.

the “done” green #1F5E48 was bound to a named variable — an intentional choice, so a decision, not a replacement
4 itemsscope
1–1.5person-days
2design decisions
and an explicit “do not fix” list

I set the counting rule — active canvas only, color separate from spacing — and wrote it into the monthly regression, so the baseline cannot mislead itself again.

The system was mine to run. The question was whether anyone else could.

Part three

From a system for me to a system for the team.

Everything so far made the system correct. None of it made it usable by someone who is not a designer.

11 The question
12 The Light version
13 Next
14 What shipped
11 / The question

“What are you actually saying to the AI?”

— our head of brand partnership & investor relations, at a daily standup, after seeing my comments on a PostHog readout

the angle and the data visualization struck him — the charts were AI-generated too

The advantage was never the model. It was design judgment written into the instructions. Keeping that as a personal edge would be stubborn.

12 / The Light version

I re-cut the system for readers who can't open Figma — people and agents.

The full system
components · variants · variables · breakpoints · spacing · effects
strip what they never need
keep the core
say which icon and which method
write it so an agent can run it
The Light version
tokens spelled out
core components
which icon · which method
intake with defaults
anti-patterns from real bugs
text an agent can call
“Every value is spelled out here — no Figma access required.”
A reservation screen configured by our COO with the Light version: two guests, Tuesday 20 January 2026, a 6:00 PM slot selected, and a greyed-out 9:00 PM slot.
even the disabled slot follows the rule: neutral and dimmed Configured by our COO with the Light version · no designer involved

built by the COO on the same system

the other six people in the company use it brand partnership makes its own investor-meeting and conference demos far less product-team involvement

(creator's account)

What an external stakeholder needs is rarely a developer-ready screen. It's a framework that renders fast enough to communicate and demo with.

13 / Next

The next version is for people who are not designers at all.

Planned

Brand color + a quick-guide rail on every document

Planned

Which chart explains which concept

Planned

A light visual style guide so a non-designer can build an on-tone demo from their own idea

The system's next users are the people furthest from design.

14 / What shipped

The status board.

Refreshed token system — 248 variables in the migrated library

Supported

Typed React Native theme, light + dark

Supported

Engineering adopted the tokens; RN tokens now part of my handoff

Creator's account

Button consolidation, ~700 instances decoupled, migrated in batches ordered by the corrected metric

Creator's account

Secondary-text decision (follow Apple, restricted use, documented exception)

Creator's account

Light version in use by the other six people; the COO's screen is the proof

Supported (screen)Creator's account (rollout)

Home Banner — the serif's first bounded product use

Ready

Light version, next iteration

Planned
62.4%
color-token adoption on the active canvas (474 bound vs 286 raw) — “a baseline with a monthly re-run, not a result”.

No user-facing metric is claimed. The outcome is a system that is correct, owned, cheaper to audit, delivered as tokens, and now run by people other than me.

15 / Close

“Through AI, a designer can make everyone stronger.”

The audit was only right because I set what counted.

The Light version only worked because a designer proposed it — not a distillation of one.

Dave Cai · Lead Product Designer · 2026

made in Seattle with ❤️