Oleksandr Chykhaiev AI-driven UX/UI Designer
All work

Case study · Design system, 2026

StayDirect Design System

Rebuilding a design system next to the product: tokens, 50 components with docs, and the checks that keep them honest.

Role
UX/UI designer, author of v1 and v2
Scope
Tokens, type, 50 components, documentation, audits
Tools
Figma variables, Figma Plugin API, Claude
Status
v2 is a concept; not yet adopted by the product team

Problem

v1 had the right parts but loose rules, so screens drifted away from the library.

My role

Author of v1 and v2: tokens, 50 documented components and scripted quality audits.

Outcome

A published Figma library: 154 variables, 50 components, 18 screens built only from it. v2 is a concept, not adopted by the team yet.

51primitive values
103semantic tokens
50components
410variants
104icons, one style
One value traced through the system: ember-500 primitive to the fill-action token to the Button, with other primitives, semantic tokens and components

01

Context & my role

This is the design system behind the StayDirect case, where the product, my role and the NDA are explained. I built v1 while working on the product. For the portfolio I rebuilt it as v2 before re-creating any screen, and grew it together with the screens.

This case is only about the system: how I audited v1, the rules I added in v2, and the scripted checks that keep it honest.

02

Problem

v1 had the right structure, with primitive and semantic tokens and documented components, but loose rules. A system with loose rules looks consistent in the library and drifts in the product.

Audit of v1: no scopes, 2.5:1 placeholder contrast, 0 of 100 spacing values bound, 140 variants in one Button, and the v2 fix for each

For a product that asks guests to pay outside Airbnb, visual inconsistency is not cosmetic: it lowers trust at the moment of payment.

03

Process

  1. Audit v1

    Listed what to keep (two token layers, component docs) and what to fix (above).

  2. Direction

    Picked four references for the new style (dark hero cards, light large numbers, pill tabs, airy bento layouts) and turned them into one style tile.

  3. Foundations

    4 variable collections: primitives (33 colours, 18 numbers) hidden from pickers, and semantic tokens (66 colours, 37 numbers) named by role, scoped, with CSS names. Geist for all type, 16 text styles. Radius and spacing scales as tokens; gaps and paddings are separate sets.

  4. Component recipe

    Variant properties only for what changes the look; booleans and instance swaps for content; hover, focus and pressed from overlay tokens; a documentation page with usage, properties, the full variant matrix and the tokens it uses.

  5. Grow with the flows

    The library was not finished before the screens. Each flow added what it needed and documented it before its screens were rebuilt on it (v2.0 → v2.5).

  6. Audit again

    A scripted quality pass on the whole library (v2.6, below).

Foundations: 51 primitives to 103 semantic tokens to 50 components, one value traced end to end, type, radius and spacing scales

04

Key decisions

1 Ember is the only action colour, with dark text

White text on ember fails contrast at 2.84:1; near-black passes at 6.92:1. Blue is used only for highlights
Decided
Every primary button, link, focus ring and selected tab uses ember #FF6B2C, and labels on ember are near-black.
Why
White text on ember is 2.84:1 and fails WCAG AA; near-black is 6.92:1. One clickable colour is also one rule users learn once.
Rejected
White-on-orange buttons (the common default) and a second brand colour for actions.

2 Blue only highlights

Decided
Blue marks what to notice (key numbers, badges, the glow on dark hero cards) and is never clickable.
Why
In v1, five accents competed for attention. Splitting “act” and “notice” into two colours made screens easier to scan.

3 Components can only see semantic tokens

Decided
Primitives are hidden from pickers; components use scoped semantic tokens with CSS names.
Why
A scope stops mistakes at the moment of picking, and the CSS name gives developers the same word the designer used.
Rejected
One flat token list: simpler on day one, impossible to change later.

4 Separate Button and Icon Button

Button variant matrix: 5 types by 5 states at size M, with its properties and rules
Decided
Two components with the same three properties (type, size, state) instead of one 140-variant set.
Why
Fewer properties per set make the right variant easy to find; both stay in sync through shared tokens.
See the generated documentation page
Button documentation page: usage, properties and variants

5 Build the library next to the screens

Releases v2.0 to v2.6: each flow added its components; 50 components, 410 variants, 104 icons, 17 documented component pages
Decided
Each flow adds its components, documented, before its screens are rebuilt on them.
Why
Components designed in a vacuum miss real content and real states. Components pulled from real screens get used.
Rejected
Finishing the full library before starting the flows.

05

Quality checks

I ran scripted audits on every component through the Figma Plugin API, with an AI assistant writing and running the scripts. Each check answers one question: does this component really use the system, or does it only look like it does?

Audit results: colours 96%, spacing 98%, text 100%, radius 60% to 93%, and the four bugs the checks caught with their fixes
  • Collapsed auto-layout. Some components collapsed to 10px when resized. They looked fine on the docs page and broke in screens. Fixed with hug sizing and a re-check of every variant.
  • Icon colours after the icon swap. Replacing the icon library left old colours inside Button and Icon Button. Fixed by binding icon colours to icon tokens per type and state.
  • Docs out of sync. The token board still showed 10 old names and missed 5 new tokens. Labels are now rebuilt from the real variables.
  • 224 raw radii. Pills and chips used a raw 999 radius. Now bound to corner-full.

06

Outcome & learnings

What exists now: a published Figma library with 50 documented components, 154 variables (51 primitives, 103 scoped semantic tokens with CSS names), and 18 re-created screens built only from it. The product team has not adopted v2 yet, so I don’t claim delivery-speed or consistency metrics from production.

Rules matter more than parts

v1 had most of the parts. What it lacked were rules that stop mistakes: scopes, one action colour, contrast by default.

A system grows best next to real screens

Each flow added components; each component made the next flow faster.

Audit the system like a product

A library can look perfect on its docs page and still be full of hard-coded values. Scripted checks found bugs I would never see by eye.

What I would do from day one

Set scopes when creating each variable, keep gaps and paddings as separate sets, and run the audit after every release.

Next case Diamonds VPN A live 3D website, designed by me and built with AI-assisted code.