design-system-generator
Design System Generator
Transform product artifacts into design systems that feel so natural users think "of course, how else would it be?"
Philosophy
Great design systems don't impose arbitrary aesthetics. They reveal what was always latent in the product's purpose. The goal is not to decorate but to crystallize the product's soul into visual and interaction patterns.
Before generating specifications, understand three things:
- Who feels what? The target audience's emotional state before, during, and after using the product
- What's the core tension? Every product resolves a tension. The design system should embody that resolution
- What must feel inevitable? The final system should feel like the only possible answer
Token Architecture
This skill uses a three-layer token system inspired by shadcn/ui and the W3C Design Tokens specification. Every visual decision flows through three levels of abstraction:
PRIMITIVE (what exists) → color.blue.500, spacing.4, font.size.md
↓
SEMANTIC (what it means) → --primary, --muted-foreground, --border
↓
COMPONENT (where it goes) → button.primary.background, input.border.default
The background/foreground convention: Every semantic role comes as a pair. The base name (e.g., --primary) is the background/fill. The -foreground suffix (e.g., --primary-foreground) is the text/icon color on that surface. Always pair them: bg-primary text-primary-foreground.
Color format: Use OKLCH (Oklch Lightness Chroma Hue) as the primary color space. OKLCH provides perceptually uniform steps — equal numeric changes produce visually equal brightness changes, which is critical for accessible color scales. Provide hex fallbacks for documentation readability.
See references/token-architecture.md for the complete token system specification.
Input Requirements
Gather from the user:
- Product description or PRD
- Target audience profile (demographics, psychographics, context of use)
- User flow or key screens/wireframes
- Brand constraints if any (existing logos, colors, fonts)
- Competitive context (optional but helpful)
If missing critical inputs, ask. Don't hallucinate audience or product details.
Output Structure
Generate a design system document with these sections:
1. Emotional Foundation (Mandatory First Step)
Before any visual decisions, establish:
AUDIENCE EMOTIONAL MAPPING
--------------------------
Before product: [emotional state - frustration, confusion, desire, etc.]
During product: [transformation happening]
After product: [desired emotional outcome]
CORE TENSION: [what problem/desire the product resolves]
DESIGN PROMISE: [one sentence: what the design must communicate]
Example:
AUDIENCE: Busy professionals tracking personal goals
Before: Overwhelmed, scattered, guilty about unfulfilled intentions
During: Clarity emerging, small wins accumulating
After: Empowered, in control, proud of progress
CORE TENSION: Ambition vs. time scarcity
DESIGN PROMISE: Progress should feel effortless and inevitable
2. Primitive Tokens
Define the raw palette — all available values before any semantic meaning.
Neutral Base
Select a neutral base that matches the brand personality. Each base creates a distinct feel:
| Base | Undertone | Feels Like |
|---|---|---|
| Neutral | Pure gray | Clean, stark, digital-native |
| Stone | Warm gray | Grounded, earthy, natural |
| Zinc | Cool gray | Industrial, precise, technical |
| Gray | Blue-gray | Corporate, reliable, familiar |
| Slate | Blue-tinted | Professional, established, calm |
NEUTRAL BASE: [selected base]
Light mode scale:
50: [oklch value] / [hex] -- Backgrounds, subtle fills
100: [oklch value] / [hex] -- Alternate backgrounds
200: [oklch value] / [hex] -- Borders, dividers
300: [oklch value] / [hex] -- Disabled text, placeholders
400: [oklch value] / [hex] -- Muted text
500: [oklch value] / [hex] -- Secondary text
600: [oklch value] / [hex] -- Body text (light bg)
700: [oklch value] / [hex] -- Headings
800: [oklch value] / [hex] -- High emphasis
900: [oklch value] / [hex] -- Maximum emphasis
950: [oklch value] / [hex] -- Near-black
Dark mode scale:
[reversed scale with adjusted lightness/chroma]
Brand Colors
BRAND COLOR PRIMITIVES
----------------------
Primary scale (50-950):
[full scale with oklch + hex, derived from the emotional foundation]
Secondary scale (50-950):
[if needed — only when the brand demands a true second hue]
Accent scale (50-950):
[for delight, celebration, highlights]
Destructive scale (50-950):
[reds for error/danger states]
Typography Primitives
Select fonts that embody the emotional foundation. Reference references/typography-psychology.md.
FONT FAMILIES
-------------
Display: [Font name] - [why it fits the emotional promise]
Body: [Font name] - [why it fits]
Mono: [Font name] (if needed)
SIZE SCALE (base 16px):
xs: 12px / 0.75rem
sm: 14px / 0.875rem
base: 16px / 1rem
lg: 18px / 1.125rem
xl: 20px / 1.25rem
2xl: 24px / 1.5rem
3xl: 30px / 1.875rem
4xl: 36px / 2.25rem
5xl: 48px / 3rem
WEIGHT SCALE:
regular: 400 -- Body text
medium: 500 -- Labels, emphasis
semibold: 600 -- Headlines, buttons
bold: 700 -- Hero text
LINE HEIGHT:
tight: 1.25 -- Headlines, display
normal: 1.5 -- Body text
relaxed: 1.75 -- Long-form reading
LETTER SPACING:
tight: -0.025em -- Display, large text
normal: 0 -- Body
wide: 0.025em -- Labels, caps, small text
Spacing & Radius Primitives
SPACING SCALE (base 4px):
0: 0
1: 4px / 0.25rem
2: 8px / 0.5rem
3: 12px / 0.75rem
4: 16px / 1rem
5: 20px / 1.25rem
6: 24px / 1.5rem
8: 32px / 2rem
10: 40px / 2.5rem
12: 48px / 3rem
16: 64px / 4rem
20: 80px / 5rem
24: 96px / 6rem
RADIUS SCALE:
none: 0
sm: 0.25rem / 4px
md: 0.375rem / 6px
lg: 0.5rem / 8px
xl: 0.75rem / 12px
2xl: 1rem / 16px
full: 9999px
3. Semantic Tokens
Map primitives to UI roles. This is the design system's API — the contract between design decisions and implementation. Every value references a primitive, never a raw value.
The Complete Semantic Token Map
SEMANTIC TOKENS (light / dark)
==============================
--- Core Surfaces ---
--background: [page background]
--foreground: [default text on page background]
--card: [card/elevated surface]
--card-foreground: [text on card]
--popover: [dropdown/tooltip/overlay surface]
--popover-foreground: [text on popover]
--- Interactive ---
--primary: [main brand action — buttons, links]
--primary-foreground: [text/icon on primary]
--secondary: [secondary actions, subtle buttons]
--secondary-foreground: [text on secondary]
--accent: [hover highlights, subtle emphasis]
--accent-foreground: [text on accent]
--destructive: [danger/error actions]
--destructive-foreground:[text on destructive]
--muted: [disabled backgrounds, subtle fills]
--muted-foreground: [placeholder text, disabled text, captions]
--- Structural ---
--border: [default border color]
--input: [input field border color]
--ring: [focus ring color]
--- Global Shape ---
--radius: [global border radius — brand personality]
--- Data Visualization ---
--chart-1: [primary chart color]
--chart-2: [secondary chart color]
--chart-3: [tertiary chart color]
--chart-4: [quaternary chart color]
--chart-5: [quinary chart color]
--- Sidebar (complex apps) ---
--sidebar: [sidebar background]
--sidebar-foreground: [sidebar text]
--sidebar-primary: [sidebar active/selected item]
--sidebar-primary-foreground: [text on sidebar active item]
--sidebar-accent: [sidebar hover state]
--sidebar-accent-foreground: [text on sidebar hover]
--sidebar-border: [sidebar border/divider]
--sidebar-ring: [sidebar focus ring]
Radius as brand personality: The --radius token is a single value that defines the entire brand feel:
| Radius | Personality |
|---|---|
| 0 | Sharp, serious, enterprise |
| 0.25rem | Professional, restrained |
| 0.375rem | Balanced, modern default |
| 0.5rem | Friendly, approachable |
| 0.75rem | Soft, consumer-friendly |
| 1rem+ | Playful, app-like |
Mapping Example
Show explicitly how primitives map to semantic tokens:
MAPPING: Primitives → Semantic
===============================
Given: primary = blue, neutral base = slate
Light Mode:
--background: slate.50 oklch(0.984 0.003 247) / #f8fafc
--foreground: slate.950 oklch(0.129 0.042 264) / #020617
--primary: blue.600 oklch(0.546 0.245 262) / #2563eb
--primary-foreground: white oklch(1 0 0) / #ffffff
--muted: slate.100 oklch(0.968 0.007 247) / #f1f5f9
--muted-foreground: slate.500 oklch(0.554 0.046 257) / #64748b
--border: slate.200 oklch(0.929 0.013 255) / #e2e8f0
--input: slate.200 oklch(0.929 0.013 255) / #e2e8f0
--ring: blue.600 oklch(0.546 0.245 262) / #2563eb
--radius: 0.625rem
Dark Mode:
--background: slate.950 oklch(0.129 0.042 264) / #020617
--foreground: slate.50 oklch(0.984 0.003 247) / #f8fafc
--primary: blue.500 oklch(0.623 0.214 259) / #3b82f6
--primary-foreground: slate.950 oklch(0.129 0.042 264) / #020617
--muted: slate.800 oklch(0.279 0.041 260) / #1e293b
--muted-foreground: slate.400 oklch(0.704 0.04 256) / #94a3b8
--border: slate.800 oklch(0.279 0.041 260) / #1e293b
--input: slate.800 oklch(0.279 0.041 260) / #1e293b
--ring: blue.500 oklch(0.623 0.214 259) / #3b82f6
--radius: 0.625rem
4. Component Tokens
Map semantic tokens to specific components. This layer is optional for simple systems but valuable for complex or multi-brand products.
COMPONENT TOKENS
================
button.primary.background: var(--primary)
button.primary.foreground: var(--primary-foreground)
button.primary.hover: [primary with adjusted lightness]
button.secondary.background: var(--secondary)
button.secondary.foreground: var(--secondary-foreground)
button.destructive.background: var(--destructive)
button.destructive.foreground: var(--destructive-foreground)
button.ghost.background: transparent
button.ghost.foreground: var(--foreground)
button.ghost.hover: var(--accent)
input.background: var(--background)
input.border: var(--input)
input.border.focus: var(--ring)
input.placeholder: var(--muted-foreground)
card.background: var(--card)
card.foreground: var(--card-foreground)
card.border: var(--border)
badge.default.background: var(--primary)
badge.default.foreground: var(--primary-foreground)
badge.secondary.background: var(--secondary)
badge.secondary.foreground: var(--secondary-foreground)
badge.destructive.background: var(--destructive)
badge.destructive.foreground: var(--destructive-foreground)
badge.outline.background: transparent
badge.outline.border: var(--border)
5. Component Patterns
Reference references/component-patterns.md for full patterns. Key specs here:
Buttons
BUTTON HIERARCHY
----------------
1. PRIMARY (one per view max)
Tokens: bg-primary text-primary-foreground
Hover: primary with +5% lightness
Use: The ONE action you want users to take
2. SECONDARY
Tokens: bg-secondary text-secondary-foreground
Hover: secondary with +5% lightness
Use: Alternative valid paths
3. DESTRUCTIVE
Tokens: bg-destructive text-destructive-foreground
Use: Delete, remove, cancel subscription
4. OUTLINE
Tokens: border-input bg-background text-foreground
Hover: bg-accent text-accent-foreground
Use: Lower-priority actions
5. GHOST
Tokens: bg-transparent text-foreground
Hover: bg-accent text-accent-foreground
Use: Toolbar actions, inline actions
6. LINK
Tokens: text-primary underline
Use: Inline text actions
BUTTON SIZES:
sm: h-8 px-3 text-xs rounded-[calc(var(--radius)-2px)]
md: h-9 px-4 text-sm rounded-[var(--radius)]
lg: h-10 px-6 text-sm rounded-[var(--radius)]
xl: h-11 px-8 text-base rounded-[var(--radius)]
icon: h-9 w-9 rounded-[var(--radius)]
Form Elements
INPUT FIELDS
------------
Height: h-9 (36px) to h-10 (40px)
Padding: px-3 py-1
Border: 1px solid var(--input)
Focus: ring-2 ring-[var(--ring)] ring-offset-2
Radius: rounded-[var(--radius)]
Background: var(--background)
Text: var(--foreground)
Placeholder: var(--muted-foreground)
Label: text-sm font-medium text-foreground
Helper: text-xs text-muted-foreground
Error: text-xs text-destructive
VALIDATION:
- Inline on blur, not keystroke
- Error: border-destructive + error message below
- Success: subtle checkmark (optional)
Cards
CARD SPECIFICATION
------------------
Background: var(--card)
Border: 1px solid var(--border)
Radius: rounded-[var(--radius)]
Shadow: sm (light mode), none (dark mode)
Padding: p-6
Card Header: pb-2
Card Title: text-lg font-semibold text-card-foreground
Card Description: text-sm text-muted-foreground
Card Content: pt-0
Card Footer: pt-4 flex items-center
6. Motion & Interaction
MOTION PRINCIPLES
-----------------
Purpose: Guide attention, provide feedback, create delight
Never: Delay users, distract from content, add without purpose
TIMING TOKENS:
instant: 0ms -- State changes, toggles
fast: 100-150ms -- Micro-interactions, hovers, focus rings
normal: 200-300ms -- Transitions, reveals, collapses
slow: 400-500ms -- Page transitions, celebrations
EASING:
ease-out: entering elements (decelerate in)
ease-in: exiting elements (accelerate out)
ease-in-out: moving elements, layout shifts
spring: playful interactions (if brand supports it)
INTERACTION FEEDBACK:
Button press: scale(0.98) + slight darken, fast timing
Hover: background token shift (e.g., accent), fast timing
Focus: ring-2 ring-[var(--ring)] ring-offset-2, instant
Success: brief pulse or checkmark, normal timing
Error: subtle shake (2px, 3 cycles), fast timing
Loading: skeleton shimmer or spinner, never frozen UI
Accordion: height transition, normal timing, ease-out
7. Accessibility Baseline
CONTRAST REQUIREMENTS (WCAG 2.1 AA):
Normal text (<18px): 4.5:1 minimum
Large text (18px+ bold): 3:1 minimum
UI components: 3:1 minimum
Focus indicators: 3:1 against adjacent colors
INTERACTIVE TARGETS:
Minimum: 44x44px touch targets (WCAG 2.5.8)
Spacing: 8px minimum between targets
FOCUS STATES:
Visible focus ring on ALL interactive elements
Style: ring-2 ring-[var(--ring)] ring-offset-2 ring-offset-[var(--background)]
Never remove focus outline without replacement
Keyboard navigation must work for all interactive patterns
COLOR INDEPENDENCE:
Never use color alone to convey meaning
Pair color with: icons, text labels, patterns, or position
MOTION SAFETY:
Respect prefers-reduced-motion
Provide reduced/no-animation fallbacks for all transitions
Process
- Extract the emotional foundation from product docs
- Select a neutral base that matches brand undertone
- Define primitive scales (colors in OKLCH, type, spacing, radius)
- Map primitives to semantic tokens using background/foreground pairs
- Select typography that embodies the brand voice
- Build color system around emotional moments
- Specify component tokens referencing semantic layer
- Add motion that feels natural, not decorative
- Verify every token pair meets WCAG contrast requirements
- Document dark mode values for every semantic token
Dark Mode Rules
Dark mode is not an afterthought — it's a parallel track built into the token system from step 1.
- Every semantic token MUST have both light and dark values
- Dark mode reduces saturation and shifts lightness, never inverts
- Surface hierarchy uses multiple levels (background → card → popover), not just "black"
- Primary colors shift lighter in dark mode for visibility
- Foreground colors flip (dark text → light text) maintaining contrast ratios
- Semantic colors (success, error, warning) preserve hue but adjust lightness
- Borders become more subtle (lower contrast against dark surfaces)
- Shadows are usually removed or replaced with subtle border differentiation
References
references/token-architecture.md- Three-layer token system, complete semantic token map, neutral presetsreferences/typography-psychology.md- Font personality mappings and pairing rulesreferences/color-emotion.md- Color psychology, OKLCH values, audience palettesreferences/component-patterns.md- Common UI patterns with token consumption maps
Anti-Patterns
- Token soup: Too many options create decision paralysis. ~20 semantic tokens cover an entire component library. Constrain choices.
- Aesthetic without purpose: Every decision should trace back to user emotion and the design promise
- Skipping the semantic layer: Never reference primitives directly in components. Always go through semantic tokens.
- Mismatched pairs: Using
bg-primary text-primaryinstead ofbg-primary text-primary-foreground. The foreground must always be the readable counterpart. - Hex-only thinking: Use OKLCH for perceptually uniform color manipulation. Hex is for documentation readability.
- Dark mode as inversion: Flipping black/white is not dark mode. It requires deliberate surface hierarchy and adjusted chroma.
- Ignoring context: A fitness app and a banking app need different energy even if targeting similar demographics
- Trend-chasing: Glassmorphism and gradients aren't personality. What's the actual emotional intent?
- Radius inconsistency: Use one global
--radiusvalue. All components derive from it, creating visual coherence.