Phase 1: Visual Design Foundation
Step 1.1: Audit and Inventory
Goal: Understand what you're designing for before you build anything
Why this matters: Think of this like taking inventory before organizing a kitchen. You need to know what pots, pans, and ingredients you have before deciding how to arrange your cabinets. Similarly, you need to understand your design landscape before building a system.
What to Document:
1. Platforms (Where will your designs live?)
Examples:
✓ Web (desktop browser)
✓ Web (mobile browser)
✓ iOS native app
✓ Android native app
✓ Desktop application (Mac/Windows)
✓ Email templates
✓ Marketing landing pagesWhy it matters: Each platform has different constraints:
- •Web: Must work in different browsers, responsive sizing
- •iOS: Follows Apple's Human Interface Guidelines, specific touch targets
- •Android: Follows Material Design principles, different screen densities
- •Email: Very limited CSS support, must work in Outlook
Quick tip:
Open your product on different devices and screenshot what looks different. These differences will inform your system.
2. Product Surfaces (Different areas of your product)
Examples:
✓ Marketing website (public-facing)
✓ Main application (logged-in users)
✓ Admin dashboard (internal tools)
✓ Mobile app
✓ Documentation site
✓ Email notificationsWhy it matters: Different surfaces often need different visual weights:
- •Marketing sites are usually more colorful and bold
- •Applications are more subdued and functional
- •Admin tools prioritize information density
Quick tip:
Make a simple list. Walk through your product and write down every distinct "area" or "section" that feels different.
3. Brand Requirements (Visual identity consistency)
Single Brand Example:
Company: Acme Corp
Products: All use same blue, same logo, same fonts
Need: 1 cohesive design systemQuick tip:
Document your existing brand guidelines (logo colors, fonts, etc.) before starting. This will inform your color and typography decisions.
4. Catalog Existing Patterns (What do you already have?)
How to do this as a beginner:
a) Take screenshots of every unique element:
- •Every button style you see
- •Every form input
- •Every card or container
- •Every color used
- •Every font size
b) Group similar items:
Buttons I found:
- Blue button with white text (appears 47 times)
- White button with blue text (appears 23 times)
- Red button with white text (appears 8 times)
- Green button with white text (appears 12 times)
- Link that looks like button (appears 34 times)c) Count inconsistencies:
Button corner roundness:
- Completely square corners (0px radius) - 15 instances
- Slightly rounded (4px) - 32 instances
- Medium rounded (8px) - 41 instances
- Very rounded (12px) - 8 instances
Problem: We have 4 different button roundness levels!
Solution: Design system will standardize to 1 or 2 optionsQuick tip:
Use a tool like Figma's "Inspect" feature or a browser inspector to see exact values. Write them all down - even if they seem chaotic.
5. Accessibility Requirements (Who needs to use your product?)
What is WCAG?
Web Content Accessibility Guidelines - basically rules to make sure everyone can use your product, including people with:
- •Vision impairments (low vision, color blindness, blindness)
- •Hearing impairments
- •Motor impairments (difficulty using a mouse)
- •Cognitive impairments
Levels Explained:
- •Level A: Bare minimum (you must do this)
- •Level AA: Standard for most businesses (recommended)
- •Level AAA: Highest standard (nice to have)
Common Requirements You'll Deal With:
1. Color Contrast:
Bad: Light gray text (#999) on white background
Good: Dark gray text (#333) on white background
Rule: Text must have 4.5:1 contrast ratio
Tool: Use WebAIM Contrast Checker2. Touch Target Size:
Bad: Button is 20px x 20px (too small)
Good: Button is 44px x 44px minimum
Why: People with motor impairments or thick fingers need larger targets3. Keyboard Navigation:
Must be able to:
- Tab through all interactive elements
- See which element is focused (visible outline)
- Activate buttons with Enter/Space
- Close modals with EscapeQuick tip:
Try using your product with only your keyboard (no mouse). Any time you get stuck, that's an accessibility problem to document.
Step 1.2: Visual Design Primitives
Goal: Build your basic building blocks - the "atoms" of your design
Think of it like cooking: Before you can make a cake, you need basic ingredients (flour, sugar, eggs). Before you can make a design system, you need basic visual ingredients (colors, fonts, spacing).
COLOR - Your Visual Palette
What you're building: A set of approved colors that everything in your system will use.
1. Base Palette (Brand Colors)
These are THE colors that represent your brand:
Real Example - Stripe:
Primary: #635BFF (purple - their signature color)
Used for: Main buttons, links, brand moments
Real Example - Notion:
Primary: #000000 (black)
Secondary: #EB5757 (red)
Used for: Headers, important actionsHow to choose (for beginners):
- •Start with your logo colors
- •Pick 1-2 primary colors that represent your brand
- •Pick 1-2 accent colors for variety
- •Keep it simple: 3-5 brand colors maximum
Quick tip:
Go to your company's brand guidelines or ask marketing for official brand colors. They'll usually give you hex codes like #3B82F6.
2. Semantic Colors (Colors with Meaning)
These colors communicate specific meanings to users:
Success (Green family):
#10B981 - "Your payment went through!"
#DEF7EC - Light green background for success messages
Warning (Yellow/Orange family):
#F59E0B - "Please review this before continuing"
#FEF3C7 - Light yellow background for warnings
Error (Red family):
#EF4444 - "Something went wrong"
#FEE2E2 - Light red background for errors
Info (Blue family):
#3B82F6 - "Here's some helpful information"
#DBEAFE - Light blue background for info messagesWhy these specific colors:
- •Green = success (universal - think traffic lights)
- •Red = danger/error (universal)
- •Yellow = caution (universal)
- •Blue = informational (neutral, trustworthy)
Quick tip:
Don't reinvent the wheel. Users expect red for errors and green for success. Fight this expectation only with good reason.
3. Neutral Scale (Grays/Backgrounds)
This is your most-used color set. You need a range from white to black:
Real example scale (Tailwind-style):
White → Light Gray → Medium Gray → Dark Gray → Black
#FFFFFF (backgrounds)
#F9FAFB (subtle backgrounds)
#F3F4F6 (borders, dividers)
#E5E7EB (disabled buttons)
#D1D5DB (borders)
#9CA3AF (placeholder text)
#6B7280 (secondary text)
#4B5563 (body text)
#374151 (headings)
#1F2937 (important text)
#111827 (maximum contrast)
#000000 (pure black - rarely used)Why so many grays? Each gray has a job:
- •Lightest grays: backgrounds, subtle divisions
- •Medium grays: borders, inactive elements
- •Dark grays: body text, secondary information
- •Darkest grays: headings, primary information
Quick tip:
Use a tool like UI Colors or Tailwind's color generator. Enter your base gray and it generates the whole scale.
TYPOGRAPHY - Your Text Styles
What you're building: Rules for all text in your product.
1. Font Families
Real Example - GitHub:
Primary: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica
(This uses the system font - different on Mac vs Windows)
Real Example - Notion:
Primary: "Inter" (custom font they host)
Real Example - Code Editor:
Monospace: "SF Mono", "Monaco", "Courier" (for code)How to choose:
- •System Fonts (Free, fast, familiar)
- Mac: SF Pro, Helvetica
- Windows: Segoe UI
- Cross-platform: -apple-system, system-ui
- •Google Fonts (Free, easy)
- Inter (modern, clean)
- Roboto (neutral)
- Open Sans (friendly)
- •Custom Fonts (Brand-specific, costs money)
- Requires licensing
- Must host font files
- Slower to load
Quick tip:
When in doubt, use Inter from Google Fonts. It's free, looks professional, and works everywhere.
2. Type Scale (Font Sizes)
You need a range of sizes from small fine print to large headings:
Real Example Scale:
Name Size Use Case Example
xs 12px Fine print, captions "© 2025 Company"
sm 14px Small labels Form labels
base 16px Body text (DEFAULT) Paragraphs
lg 18px Large body, intro text Article lead
xl 20px Small headings Card titles
2xl 24px Section headings <h3>
3xl 30px Page subheadings <h2>
4xl 36px Page headings <h1>
5xl 48px Display text Landing page hero
6xl 60px Large display Marketing headlinesThe Golden Rule:
- •Your base size should be 16px (readable on all devices)
- •Each step up should be noticeably bigger (1.25x or 1.5x ratio)
- •Never go smaller than 12px (accessibility issue)
Quick tip:
Use a type scale calculator like Type-Scale.com. Pick "Major Third" ratio (1.25) for conservative, "Perfect Fourth" (1.33) for more dramatic.
SPACING - How Things Breathe
What you're building: A system for all gaps, margins, and padding in your product.
The Magic Number: Base Unit
Pick one number as your foundation. Everything else multiplies from it.
Most Common: 8px
Why? Divides evenly, works with most screen sizes
Scale from 8px:
4px (half) Tight spacing between related items
8px (1x) Small gaps, compact layouts
12px (1.5x) In-between size
16px (2x) Default spacing (most common)
24px (3x) Medium spacing between sections
32px (4x) Large gaps, breathing room
48px (6x) Section separators
64px (8x) Major sections
96px (12x) Between page sections
128px (16x) Hero section paddingQuick tip:
When in doubt, use 16px (2x your base). It's the Goldilocks spacing - not too tight, not too loose.
Step 1.3: Figma File Organization Best Practices
Goal: Set up your Figma files for easy token export and component management
Why this matters: A well-organized Figma file structure makes token creation, component building, and export 10x easier. Set this up correctly now to save hours later.
Recommended File Structure
📁 Design System (Main File)
├── 📄 Page: 🎨 Foundation
│ ├── Frame: Color Primitives (all raw colors)
│ ├── Frame: Color Semantic (purpose-based colors)
│ ├── Frame: Typography Scale (all text styles)
│ ├── Frame: Spacing Scale (spacing documentation)
│ └── Frame: Elevation/Shadows (shadow tokens)
│
├── 📄 Page: 🧱 Components
│ ├── Frame: Atoms (buttons, inputs, icons)
│ ├── Frame: Molecules (search bars, cards)
│ └── Frame: Organisms (navigation, headers)
│
├── 📄 Page: 📐 Layouts
│ ├── Frame: Grid System
│ ├── Frame: Breakpoints
│ └── Frame: Page Templates
│
└── 📄 Page: 📖 Documentation
├── Frame: Guidelines
├── Frame: Do's and Don'ts
└── Frame: Component Usage ExamplesVariables Panel Organization
When creating Variables in Figma, organize them into Collections:
Collection: Primitives
├── primitive/color/blue/50
├── primitive/color/blue/500
├── primitive/color/blue/900
├── primitive/spacing/xs (4px)
├── primitive/spacing/sm (8px)
└── ...
Collection: Semantic
├── semantic/background/primary (→ primitive/color/gray/50)
├── semantic/text/primary (→ primitive/color/gray/900)
├── semantic/text/danger (→ primitive/color/red/600)
└── ...
Collection: Component
├── component/button/background/primary (→ semantic/action/primary)
├── component/button/text/primary (→ semantic/text/inverse)
└── ...Naming Conventions for Variables
Use forward slashes (/) for hierarchy:
✓ GOOD:
primitive/color/blue/500
semantic/text/primary
component/button/background/hover
✗ BAD:
blue-500 (no hierarchy)
textPrimary (camelCase instead of slash hierarchy)
btn-bg-hover (unclear abbreviations)Component Organization Tips
- •One component per frame: Keep each component in its own frame for easy navigation
- •Show all variants: Display all size/state variations in one place
- •Use Auto Layout: Makes components responsive and easier to maintain
- •Link to variables: Don't hardcode values—always reference variables
- •Document usage: Add descriptions to component properties
Pre-Export Checklist
Before exporting tokens or sharing with developers, verify:
- □All variables are properly named with hierarchy (slash notation)
- □Variables are organized into logical Collections
- □Semantic tokens reference primitive tokens (not hardcoded values)
- □Component tokens reference semantic tokens
- □Components use variables for all properties (colors, spacing, sizing)
- □Dark mode variables are set up (if needed)
- □No duplicate or conflicting variable names
Pro tip for teams:
Create a "Design System Starter Template" with this structure already set up. Share it with your team so everyone starts with the same organization. This ensures consistency across projects.
Phase 2: Design Tokens & Variables
Design tokens are the foundation of a scalable design system. They transform your visual primitives into reusable, platform-agnostic values that can be shared across design and code.
What are Design Tokens?
Think of them like variables in code. Instead of writing the color blue (#3B82F6) everywhere, you create a token called "primary-blue" and reference that. If you need to change the shade of blue later, you change it once, and it updates everywhere.
Without tokens:
button-color: #3B82F6
link-color: #3B82F6
badge-color: #3B82F6
(Change requires updating 500+ instances)
With tokens:
token: primary-blue = #3B82F6
button-color: primary-blue
link-color: primary-blue
badge-color: primary-blue
(Change token once, updates everywhere)Figma Variables vs Figma Tokens Plugin
There are two main approaches to managing design tokens in Figma. Understanding the difference is important:
Figma Variables (Native, Recommended)
Figma's built-in Variables system is now the standard way to manage design tokens. Introduced in 2023, it's native to Figma and requires no plugins.
- ✓Native feature - No plugin required, built into Figma
- ✓Type support: Colors, numbers, strings, booleans
- ✓Collections & Modes: Organize tokens and support themes (light/dark)
- ✓Native export: DTCG JSON format (File → Variables → Export)
- ✓Future-proof: Officially supported by Figma
Quick tip:
Access the Variables panel in Figma: View → Variables (or Option + Shift + K on Mac / Ctrl + Shift + K on Windows). This is where you'll create and manage all your design tokens.
Figma Tokens Plugin (Community, Legacy)
Before Figma Variables existed, the community-built "Figma Tokens" plugin was the standard approach. It's still widely used, especially in legacy projects.
- •Plugin required - Must install from Figma Community
- •More token types: Includes typography, spacing, sizing, borders, shadows
- •Git sync: Can sync directly to GitHub/GitLab
- •JSON format: Custom format, requires Style Dictionary transformation
- •Legacy support: Many existing design systems still use this
Which should you use?
New projects: Use Figma Variables. It's native, simpler, and officially supported.
Existing projects: If you're already using Figma Tokens plugin and it's working well, migration isn't urgent. Both approaches work, but plan to eventually migrate to Variables.
Token Hierarchy: The Three-Layer System
Layer 1: PRIMITIVES (Raw values)
├── What: Actual colors (#3B82F6), actual numbers (16px)
├── Who edits: Design system managers only
├── How often: Rarely (maybe once a year for rebrand)
└── Example: primitive/color/blue/500 = #3B82F6
↓ Referenced by ↓
Layer 2: SEMANTIC (Purpose-based)
├── What: References to primitives with meaningful names
├── Who edits: Design system managers
├── How often: Occasionally (quarterly adjustments)
└── Example: semantic/text/primary = primitive/color/gray/900
↓ Referenced by ↓
Layer 3: COMPONENT (Component-specific)
├── What: References to semantic tokens for specific components
├── Who edits: Component designers
├── How often: Frequently (when building/updating components)
└── Example: component/button/text/default = semantic/text/inversePhase 3: Component Architecture
With your tokens in place, it's time to build components that leverage them. Proper component architecture ensures consistency and makes maintenance effortless.
Component Hierarchy (Atomic Design)
Atoms (Basic building blocks)
├── Button
├── Input
├── Icon
├── Label
├── Badge
└── Avatar
Molecules (Simple combinations)
├── Input with Label
├── Button Group
├── Search Field
└── Select Dropdown
Organisms (Complex patterns)
├── Navigation Bar
├── Form Section
├── Card with Actions
└── Data TableComponent Properties Strategy
Use Figma's Component Properties to create flexible, reusable components:
- •Variants: Size (sm, md, lg), State (default, hover, active, disabled)
- •Boolean: Icon, Label, Badge visibility toggles
- •Text: Label content, Placeholder text
- •Instance Swap: Icon selection, nested components
Quick tip:
Every component property should reference variables. Button background → component/button/background/default. This ensures your components automatically adapt when tokens change.
Phase 4: Export Strategy
Figma now supports native export of design tokens using the DTCG (Design Tokens Community Group) format, making it easy to share your design system with code.
Native Figma Export (DTCG Format)
Export your variables:
- •File → Variables → Export variables
- •Choose DTCG JSON format
- •Exports all collections and modes
DTCG JSON Structure
{
"primitive": {
"color": {
"blue": {
"50": {
"$type": "color",
"$value": "#eff6ff"
},
"500": {
"$type": "color",
"$value": "#3b82f6"
}
}
}
},
"semantic": {
"background": {
"primary": {
"$type": "color",
"$value": "{primitive.color.gray.50}"
}
}
}
}Token Validation & Quality Checks
After exporting tokens, validate them to catch errors before they reach your codebase.
Manual Validation Checklist
- □JSON validity: Ensure exported JSON parses without errors
- □Token references: All
{references}point to existing tokens - □Color format: Colors are in hex (#RRGGBB) or valid CSS format
- □Naming consistency: All tokens follow your naming convention
- □No duplicates: No duplicate token names across collections
- □Type correctness: $type matches value format (color, dimension, etc.)
Common Export Errors
❌ Error 1: Broken Reference
{
"$value": "{primitive.color.blue.500}"
}
// But primitive.color.blue.500 doesn't exist
✓ Fix: Create the missing token or update the reference
❌ Error 2: Circular Reference
semantic.text.primary → semantic.text.body → semantic.text.primary
✓ Fix: Break the circle by referencing primitives
❌ Error 3: Wrong Type
{
"$type": "dimension",
"$value": "#3B82F6" // This is a color, not a dimension!
}
✓ Fix: Correct the $type to "color"Testing Token Integration
After validation, test tokens in your codebase:
- 1.Import test: Try importing tokens into your build system
- 2.CSS generation: Convert to CSS variables and verify output
- 3.Visual test: Apply tokens to a test page and compare to Figma
- 4.Dark mode check: If using modes, verify theme switching works
- 5.Contrast audit: Run accessibility contrast checks on colors
Quick tip:
Create a simple HTML page that displays all your tokens (color swatches, text samples, spacing examples). This visual reference makes it easy to spot errors and verify tokens match your Figma designs.
Phase 5: LLM Integration via MCP
The Model Context Protocol (MCP) enables AI assistants to access and work with your design system directly. There are two complementary approaches you'll use together.
Understanding the Two Types of MCP Servers
It's crucial to understand that you'll likely use BOTH types of MCP servers in your workflow:
Key Distinction:
- 1.Figma's Official MCP Server - Pulls design data FROM Figma (files, variables, components, frames)
- 2.Custom Design System MCP Server - Exposes YOUR design system TO LLMs (guidelines, tokens, patterns, rules)
- •Approach 1: Figma's Official MCP Server (HTTP/SSE transport, connects directly to your Figma files, works with VS Code, Cursor, Windsurf, and Claude Code CLI)
- •Approach 2: Custom Design System MCP Server (stdio transport, exposes your design system's rules and patterns, works with Claude Desktop and other stdio-compatible clients)
Approach 1: Figma's Official MCP Server
Figma's official MCP server connects LLMs directly to your Figma files to pull design data, generate code from frames, and access variables and components.
What This Gives You:
- ✓Generate code from selected Figma frames
- ✓Pull in variables, components, and layout data
- ✓Access Figma file structure and design properties
- ✓No authentication required (uses Figma's built-in auth)
Two Connection Methods
Remote Server (Hosted by Figma):
URL: https://mcp.figma.com/mcp
Benefits: Always up-to-date, no local installation needed
Transport: Streamable HTTP with SSE
Supported: VS Code, Cursor, Windsurf, Claude Code CLIDesktop Server (Local Figma App):
URL: http://127.0.0.1:3845/mcp
Benefits: Works offline, faster responses
Requirement: Figma Desktop app must be running
Transport: Streamable HTTP with SSE
Supported: VS Code, Cursor, Windsurf, Claude Code CLIInstallation & Configuration
Claude Code CLI (Easiest):
claude mcp add --transport http figma https://mcp.figma.com/mcpVS Code (settings.json):
{
"mcp.servers": {
"figma-remote": {
"type": "streamableHttp",
"url": "https://mcp.figma.com/mcp"
}
}
}Cursor (settings):
{
"mcpServers": {
"figma": {
"url": "https://mcp.figma.com/mcp"
}
}
}Quick tip:
For detailed setup instructions and authentication, see the official documentation at developers.figma.com/docs/figma-mcp-server/
Note on Claude Desktop:
The official Figma MCP server uses HTTP/SSE transport and currently does not support Claude Desktop, which requires stdio transport. For design system exposure in Claude Desktop, see Approach 2 below.
Approach 2: Custom Design System MCP Server
While Figma's MCP server pulls FROM Figma, you also need to expose your design system's rules, patterns, and guidelines TO the LLM. This is where a custom MCP server comes in.
What This Gives You:
- ✓Expose your design system context (brand, principles, guidelines)
- ✓Provide design tokens in LLM-friendly format
- ✓Share component templates and boilerplates
- ✓Include accessibility guidelines and checklists
- ✓Tools for generating components, tokens, and auditing code
Creating Your Custom MCP Server
This project includes a code generator that creates a custom MCP server for your design system. The generated server uses stdio transport and works with Claude Desktop.
// Generated server structure:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// Exposes resources like:
// - design-system://context (overview, brand, principles)
// - design-system://tokens (all design tokens)
// - design-system://component-template (React boilerplate)
// - design-system://accessibility (WCAG guidelines)
// Provides tools like:
// - generate_component (create new components)
// - generate_design_tokens (export to CSS/Tailwind/TypeScript)
// - audit_accessibility (check WCAG compliance)
// - add_component_variant (extend existing components)Installation for Claude Desktop
After generating your MCP server, edit your Claude Desktop config file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json{
"mcpServers": {
"my-design-system": {
"command": "node",
"args": [
"/absolute/path/to/your-mcp-server/dist/index.js"
],
"env": {}
}
}
}Quick tip:
Use the Design System Builder tool in this project to generate your custom MCP server. It will create package.json, TypeScript source, Claude Desktop config, and a README with full instructions.
Using Both Approaches Together (Recommended)
The most powerful workflow uses BOTH MCP servers:
- 1.Figma's MCP Server → Pulls design data (variables, components, frames)
- 2.Your Custom MCP Server → Provides design system rules and patterns
- 3.LLM combines both → Generates code that follows your system AND matches Figma designs
Example workflow:
1. "Pull the button component from Figma file xyz"
→ Figma MCP server fetches the design
2. "Generate React code following HypnoLabs design system patterns"
→ Custom MCP server provides templates and guidelines
3. LLM combines both → Generates code matching Figma design + your patternsPhase 6: CSS Global System
Transform your Figma tokens into CSS variables for use in your codebase. This creates a single source of truth between design and code.
Converting Tokens to CSS Variables
:root {
/* Primitive Colors */
--color-blue-50: #eff6ff;
--color-blue-500: #3b82f6;
--color-blue-900: #1e3a8a;
/* Semantic Colors */
--background-primary: var(--color-gray-50);
--text-primary: var(--color-gray-900);
/* Component Tokens */
--button-bg-primary: var(--color-blue-500);
--button-text-primary: var(--color-white);
/* Spacing Scale */
--spacing-xs: 0.25rem; /* 4px */
--spacing-sm: 0.5rem; /* 8px */
--spacing-md: 1rem; /* 16px */
}
/* Dark Mode */
[data-theme="dark"] {
--background-primary: var(--color-gray-900);
--text-primary: var(--color-gray-50);
}Phase 7: Prompt Engineering for LLM Structuring
Effective prompts help LLMs understand and work with your design system correctly.
System Prompt Template
You are a design system expert helping to structure and implement a design system.
DESIGN SYSTEM CONTEXT:
- Name: [System Name]
- Version: [Version]
- Platforms: [Web, iOS, Android]
TOKEN HIERARCHY:
1. Primitive tokens: Raw values (colors, sizes)
2. Semantic tokens: Purpose-based aliases
3. Component tokens: Component-specific values
RULES:
1. Always use tokens, never hardcode values
2. Reference semantic tokens, not primitive ones
3. Maintain 4.5:1 contrast for normal text
4. Touch targets must be at least 44x44pxPhase 8: Advanced Workflows
Automate synchronization between Figma and your codebase for seamless updates.
Version Control for Design Tokens
Design tokens should be version controlled alongside your code to maintain consistency and enable rollbacks.
Recommended Directory Structure
your-project/
├── design-tokens/
│ ├── figma-export/ # Raw export from Figma
│ │ └── tokens.json # DTCG JSON from Figma Variables
│ ├── processed/ # Transformed tokens
│ │ ├── tokens.css # CSS custom properties
│ │ ├── tokens.scss # Sass variables
│ │ ├── tokens.ts # TypeScript constants
│ │ └── tailwind.config.js # Tailwind theme extension
│ └── README.md # Documentation on token usage
├── src/
└── package.jsonGit Workflow for Token Updates
# Step 1: Export from Figma
# File → Variables → Export variables → Save as design-tokens/figma-export/tokens.json
# Step 2: Transform tokens
npm run tokens:transform
# Step 3: Review changes
git diff design-tokens/
# Step 4: Commit with descriptive message
git add design-tokens/
git commit -m "design-tokens: update primary blue shade (500 → 600)
- Adjusted primary blue from #3b82f6 to #2563eb
- Improves contrast ratio from 4.2:1 to 5.1:1 (WCAG AA compliant)
- Affects: buttons, links, focus states"
# Step 5: Create pull request for review
git push origin feature/update-primary-color
gh pr create --title "Update primary color for better accessibility"Token Versioning Strategy
Use semantic versioning for design token releases:
- •MAJOR (1.0.0): Breaking changes (renamed tokens, removed tokens)
- •MINOR (0.1.0): New tokens added (backwards compatible)
- •PATCH (0.0.1): Token value adjustments (no API changes)
// package.json
{
"name": "@your-company/design-tokens",
"version": "2.1.3",
"description": "Design tokens for Your Company design system",
"main": "processed/tokens.js",
"exports": {
"./css": "./processed/tokens.css",
"./scss": "./processed/tokens.scss",
"./tailwind": "./processed/tailwind.config.js"
}
}Changelog Best Practices
Maintain a CHANGELOG.md to track token changes:
# Changelog
## [2.1.3] - 2025-11-26
### Changed
- `primitive.color.blue.500`: #3b82f6 → #2563eb (improved contrast)
- `semantic.text.link`: Now uses blue.600 instead of blue.500
### Impact
- Affects all link colors and primary buttons
- WCAG AA compliant (5.1:1 contrast on white)
## [2.1.2] - 2025-11-20
### Added
- `semantic.border.focus`: New token for focus outlines
- `component.input.border.focus`: Uses semantic.border.focus
### Fixed
- `semantic.background.danger`: Fixed incorrect reference to red.100Pro tip:
Set up a GitHub Action or CI pipeline that automatically validates token JSON structure, checks for broken references, and runs contrast audits on token changes. This catches errors before they reach production.
Continuous Sync Workflow
{
"scripts": {
"tokens:export": "# Manual: Export from Figma to design-tokens/figma-export/tokens.json",
"tokens:transform": "node scripts/transform-tokens.js",
"tokens:validate": "node scripts/validate-tokens.js",
"tokens:sync": "npm run tokens:validate && npm run tokens:transform",
"sync:components": "figma-code-connect sync",
"sync:all": "npm run tokens:sync && npm run sync:components"
}
}Automated Figma Sync (Advanced)
For teams with frequent token updates, automate the export process:
// scripts/sync-figma-tokens.js
import { figmaAPI } from './figma-api.js';
async function syncTokens() {
// 1. Fetch variables from Figma API
const variables = await figmaAPI.getVariables(fileId);
// 2. Transform to DTCG format
const tokens = transformToD TCG(variables);
// 3. Write to file
await fs.writeFile('design-tokens/figma-export/tokens.json',
JSON.stringify(tokens, null, 2));
// 4. Run transformation
await exec('npm run tokens:transform');
console.log('Tokens synced successfully!');
}
syncTokens();# .github/workflows/sync-tokens.yml
name: Sync Design Tokens
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9am
workflow_dispatch: # Manual trigger
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Sync tokens from Figma
run: npm run sync:figma
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
- name: Create PR if changes detected
run: |
if [[ `git status --porcelain` ]]; then
gh pr create --title "chore: sync design tokens from Figma" \
--body "Automated token sync"
fiPhase 8.5: Code to Figma Workflow
While Figma-first workflows are ideal, sometimes you need to go the opposite direction: extracting design patterns from existing code and documenting them in Figma. This reverse workflow is valuable for teams migrating to design systems or documenting legacy codebases.
When to Use Code → Figma
- →Existing production codebase lacks design documentation
- →Engineering-led project needs design system retroactively
- →Migrating from another design tool to Figma
- →Component library exists but design specs are scattered
Scenario 1: Mature Design System → Figma
If you already have a structured design token system (CSS variables, Sass variables, Style Dictionary, etc.), you can export these tokens and push them to Figma as Variables.
Principles: Token Export Pipeline
The general flow is: Code Tokens → DTCG JSON → Figma API → Figma Variables
- 1.Extract: Convert your existing tokens to DTCG (Design Tokens Community Group) format
- 2.Transform: Map token types to Figma Variable types (color, number, string)
- 3.Upload: Use Figma REST API to create/update Variables
- 4.Validate: Verify tokens appear correctly in Figma
Traditional Approach: Style Dictionary + Figma API
Style Dictionary can transform your tokens and export them to Figma-compatible JSON:
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
figma: {
transformGroup: 'js',
buildPath: 'build/figma/',
files: [{
destination: 'tokens.json',
format: 'json/nested',
filter: (token) => {
// Only export color and dimension tokens
return ['color', 'dimension', 'fontFamily'].includes(token.type);
}
}]
}
}
};
// Then transform to DTCG format for Figma
npm run tokens:build
node scripts/upload-to-figma.jsExample upload script using Figma REST API:
// scripts/upload-to-figma.js
const fs = require('fs');
const fetch = require('node-fetch');
const FIGMA_TOKEN = process.env.FIGMA_TOKEN;
const FILE_KEY = process.env.FIGMA_FILE_KEY;
async function uploadTokensToFigma() {
const tokens = JSON.parse(fs.readFileSync('build/figma/tokens.json', 'utf8'));
// Transform tokens to Figma Variables format
const variables = Object.entries(tokens.color).map(([name, value]) => ({
name: `color/${name}`,
resolvedType: 'COLOR',
valuesByMode: {
[modeId]: rgbaToFigmaColor(value)
}
}));
// POST to Figma API
const response = await fetch(
`https://api.figma.com/v1/files/${FILE_KEY}/variables`,
{
method: 'POST',
headers: {
'X-Figma-Token': FIGMA_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({ variables })
}
);
console.log('Tokens uploaded:', await response.json());
}
uploadTokensToFigma();Pro Tip: Token Studio for Figma
The Token Studio plugin provides a GUI for importing JSON tokens directly into Figma without writing API scripts. It supports DTCG format, token aliasing, and bidirectional sync.
LLM-Assisted Approach: Token Audit & Validation
Use LLMs to analyze your token structure before uploading to Figma:
PROMPT: Token Structure Audit
I have the following design token structure exported from my codebase:
[Paste tokens.json here]
Please analyze:
1. Are token names semantic and consistent?
2. Do I have proper primitive → semantic → component hierarchy?
3. Are there any missing token types I should add before importing to Figma?
4. Are color values using accessible contrast ratios?
5. Suggest improvements for Figma Variable organization (collections, modes)
Format your response as:
- Issues Found: [list]
- Recommendations: [list]
- Suggested Figma Collections: [list]Scenario 2: Code-First Projects → New Figma System
When you have an existing codebase without an explicit design system, you need to extract implicit design patterns first, then document them in Figma.
Principles: Pattern Extraction
- 1.Inventory: Scan codebase for colors, spacing, typography, shadows
- 2.Normalize: Group similar values (e.g., #333, #323232 → gray-900)
- 3.Name: Create semantic names based on usage patterns
- 4.Structure: Build token hierarchy from extracted patterns
- 5.Import: Create Figma Variables from structured tokens
Traditional Approach: Manual Analysis + Scripts
Write scripts to scan your codebase for design values:
// scripts/extract-colors.js
const fs = require('fs');
const glob = require('glob');
// Regex patterns for common color formats
const colorPatterns = [
/#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, // Hex
/rgba?\([^)]+\)/g, // RGB/RGBA
/hsl\([^)]+\)/g, // HSL
];
const colorInventory = new Map();
// Scan all CSS/JS/JSX files
glob.sync('src/**/*.{css,scss,js,jsx,tsx}').forEach(file => {
const content = fs.readFileSync(file, 'utf8');
colorPatterns.forEach(pattern => {
const matches = content.match(pattern) || [];
matches.forEach(color => {
const normalized = normalizeColor(color);
colorInventory.set(
normalized,
(colorInventory.get(normalized) || 0) + 1
);
});
});
});
// Sort by frequency
const sortedColors = [...colorInventory.entries()]
.sort((a, b) => b[1] - a[1])
.map(([color, count]) => ({ color, count }));
fs.writeFileSync(
'design-audit/colors.json',
JSON.stringify(sortedColors, null, 2)
);
console.log(`Found ${sortedColors.length} unique colors`);LLM-Assisted Approach: Codebase Analysis
LLMs excel at analyzing unstructured code and identifying patterns:
PROMPT: Design Pattern Extraction
I need to extract an implicit design system from an existing React codebase.
Here are the CSS files and component files:
[Attach or paste key style files]
Please analyze and:
1. **Color Inventory:**
- List all unique colors used
- Group similar colors (e.g., shades of blue)
- Suggest semantic naming (primary, secondary, accent, etc.)
- Recommend which to keep vs. consolidate
2. **Spacing Patterns:**
- Identify all margin/padding values used
- Suggest a consistent spacing scale (4px, 8px, 16px, etc.)
- Map existing values to suggested scale
3. **Typography:**
- List font families, sizes, weights, line heights
- Suggest a type scale and hierarchy
4. **Shadows & Effects:**
- Extract box-shadow values
- Suggest elevation scale (sm, md, lg, xl)
5. **Output Format:**
- Provide DTCG JSON format suitable for importing to Figma
- Include collections structure for Figma Variables
Example output format:
```json
{
"color": {
"primitive": {
"blue": {
"500": { "value": "#3b82f6", "type": "color" }
}
},
"semantic": {
"primary": { "value": "{color.primitive.blue.500}", "type": "color" }
}
}
}
```Quick Tip: Use MCP for Deep Analysis
Create a custom MCP server that gives LLMs direct access to your codebase for more thorough analysis:
// Custom MCP tool: analyze-design-patterns
{
name: "analyze_design_patterns",
description: "Scan codebase for implicit design tokens",
inputSchema: {
type: "object",
properties: {
directory: { type: "string" },
fileTypes: { type: "array", items: { type: "string" } }
}
}
}The LLM can then call this tool to analyze your entire codebase programmatically.
Scenario 3: Component Library → Figma Components
Documenting existing React/Vue/Svelte components in Figma creates a single source of truth for both designers and developers. This is especially valuable for component libraries and design systems.
Principles: Component Documentation Strategy
- •Props → Variants: Map component props to Figma component properties
- •States → Variants: Hover, active, disabled states as Figma variants
- •Composition: Nested components should match code hierarchy
- •Documentation: Add descriptions matching JSDoc/TSDoc comments
Traditional Approach: Manual Recreation with Guidelines
Create documentation to guide designers in recreating components accurately:
# Button Component Documentation
## React Implementation
```tsx
<Button
variant="primary" | "secondary" | "ghost"
size="sm" | "md" | "lg"
disabled={boolean}
leftIcon={ReactNode}
rightIcon={ReactNode}
>
Button Text
</Button>
```
## Figma Recreation Guidelines
1. **Create Component Set:**
- Name: "Button"
- Variants: variant, size, state
2. **Variant Properties:**
- variant: primary, secondary, ghost
- size: sm (32px), md (40px), lg (48px)
- state: default, hover, active, disabled
3. **Tokens to Use:**
- Background: {button.background.[variant]}
- Text: {button.text.[variant]}
- Border: {button.border.[variant]}
- Padding horizontal: {button.padding.x.[size]}
- Padding vertical: {button.padding.y.[size]}
4. **States:**
- Hover: Reduce opacity to 90%
- Active: Darken background by 10%
- Disabled: 50% opacity, cursor not-allowedLLM-Assisted Approach: Component Spec Generation
PROMPT: Generate Figma Component Spec
I have the following React component:
[Paste component code]
Please generate a detailed Figma component specification including:
1. **Component Properties:**
- Map React props to Figma component properties
- Define variant sets (what should be variants vs. separate components)
- Specify property types (variant, boolean, instance swap, text)
2. **Visual Specifications:**
- Dimensions for each size variant
- Spacing (padding, gap)
- Typography settings
- Color tokens to use
- Border radius, shadows, etc.
3. **Interactive States:**
- Default, hover, active, focus, disabled states
- Specify visual changes for each state
4. **Component Hierarchy:**
- Break down nested component structure
- Define Auto Layout settings (direction, spacing, alignment)
5. **Design Tokens Reference:**
- List which design tokens should be used
- Create token mapping table
Format as a structured Figma component creation guide.Note: html-to-figma Plugin
The html-to-figma plugin can import rendered HTML/CSS directly into Figma. While not perfect, it's a good starting point for complex components. You'll still need to clean up the result and apply proper tokens.
Scenario 4: Bidirectional Sync Workflows
The ultimate goal: keep code and Figma in sync automatically, regardless of where changes originate.
Principles: Establishing Source of Truth
Key Distinction: Source of Truth
You must establish a clear source of truth for each token type:
- →Figma as Source: Design tokens, colors, spacing, typography (design decisions)
- →Code as Source: Computed values, responsive breakpoints, theme modes (engineering decisions)
- →Bidirectional: Component documentation, specs (collaborative decisions)
Traditional Approach: Git-Based Workflows
# Bidirectional Sync Architecture
┌─────────────────────────────────────────────────────────────┐
│ Git Repository │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ design-tokens/ │ │ figma-sync/ │ │
│ │ - primitive/ │◄────sync────►│ - last-sync/ │ │
│ │ - semantic/ │ │ - conflicts/ │ │
│ │ - component/ │ └──────────────────┘ │
│ └─────────────────┘ │
└──────────▲──────────────────────────────────▼──────────────┘
│ │
[Figma Export] [Figma Import]
│ │
┌──────┴──────────────────────────────────┴──────┐
│ Figma File │
│ Design Variables → Code Tokens (Export) │
│ Code Tokens → Design Variables (Import) │
└───────────────────────────────────────────────┘
**Workflow:**
1. Changes in Figma trigger webhook → export tokens → PR
2. Changes in code → transform tokens → upload to Figma → notify team
3. Conflicts → manual review → resolve → syncExample GitHub Action for bidirectional sync:
# .github/workflows/design-tokens-sync.yml
name: Design Tokens Bidirectional Sync
on:
push:
paths:
- 'design-tokens/**'
repository_dispatch:
types: [figma-webhook]
jobs:
sync-to-figma:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Transform tokens
run: npm run tokens:build
- name: Upload to Figma
run: node scripts/upload-to-figma.js
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
- name: Post Slack notification
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-d '{"text":"Design tokens synced to Figma ✅"}'
sync-from-figma:
if: github.event_name == 'repository_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Export from Figma
run: node scripts/export-from-figma.js
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
- name: Check for conflicts
id: conflict-check
run: node scripts/check-conflicts.js
- name: Create PR or Auto-merge
run: |
if [ "${{ steps.conflict-check.outputs.has-conflicts }}" == "true" ]; then
gh pr create --title "🔀 Figma sync (conflicts)" \
--body "Conflicts detected - manual review required"
else
git commit -am "chore: sync from Figma"
git push
fiLLM-Assisted Approach: Conflict Resolution
PROMPT: Design Token Conflict Resolution
I have conflicting changes to the same design token:
**Figma Version (designer changed):**
```json
{
"color/primary": {
"value": "#2563eb",
"type": "color",
"description": "Updated to meet WCAG AA contrast"
}
}
```
**Code Version (engineer changed):**
```json
{
"color/primary": {
"value": "#3b82f6",
"type": "color",
"description": "Matches brand guidelines v2.1"
}
}
```
**Context:**
- Last sync was 3 days ago
- Figma change: contrast accessibility fix
- Code change: brand update
Please:
1. Analyze the conflict reason
2. Recommend which version to keep (or if we need a new value)
3. Suggest communication to team
4. Provide updated token with combined context
Consider:
- Accessibility requirements (WCAG AA)
- Brand consistency
- Breaking changes to existing components
- User impactPro Tip: Conflict Prevention
Prevent conflicts by establishing clear ownership rules:
- ✓Primitive tokens: Figma owns (colors, base spacing)
- ✓Semantic tokens: Joint ownership (sync bidirectionally)
- ✓Component tokens: Code owns (computed values)
- ✓Add CODEOWNERS file to design-tokens/ directory
Practical Implementation Guide
Figma REST API Essentials
Key endpoints for Code → Figma workflows:
// 1. Create Variables (bulk)
POST https://api.figma.com/v1/files/{file_key}/variables/batch
{
"variableCollections": [{
"name": "Primitives",
"modes": [{ "name": "Light" }, { "name": "Dark" }]
}],
"variables": [{
"name": "color/blue/500",
"resolvedType": "COLOR",
"variableCollectionId": "{collection_id}",
"valuesByMode": {
"{mode_id}": { r: 0.231, g: 0.51, b: 0.965, a: 1 }
}
}]
}
// 2. Update Existing Variables
PUT https://api.figma.com/v1/files/{file_key}/variables/{variable_id}
{
"valuesByMode": {
"{mode_id}": { r: 0.145, g: 0.227, b: 0.925, a: 1 }
}
}
// 3. Get All Variables (for sync comparison)
GET https://api.figma.com/v1/files/{file_key}/variables/localExample: Complete Token Upload Script
// upload-tokens-to-figma.ts
import fs from 'fs';
interface Token {
value: string;
type: 'color' | 'dimension' | 'fontFamily';
description?: string;
}
interface TokenCollection {
[category: string]: {
[token: string]: Token;
};
}
async function uploadTokensToFigma(
tokens: TokenCollection,
fileKey: string,
accessToken: string
) {
const baseUrl = 'https://api.figma.com/v1';
// Step 1: Get or create Variable Collection
const collectionsRes = await fetch(
`${baseUrl}/files/${fileKey}/variables/local`,
{ headers: { 'X-Figma-Token': accessToken } }
);
const { meta } = await collectionsRes.json();
let collectionId = meta.variableCollections.find(
(c: any) => c.name === 'Design Tokens'
)?.id;
if (!collectionId) {
// Create collection
const createRes = await fetch(
`${baseUrl}/files/${fileKey}/variables/batch`,
{
method: 'POST',
headers: {
'X-Figma-Token': accessToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({
variableCollections: [{
name: 'Design Tokens',
modes: [{ name: 'Light' }]
}]
})
}
);
const created = await createRes.json();
collectionId = created.variableCollections[0].id;
}
// Step 2: Transform tokens to Figma format
const variables = [];
const modeId = meta.variableCollections
.find((c: any) => c.id === collectionId)
.modes[0].modeId;
for (const [category, categoryTokens] of Object.entries(tokens)) {
for (const [name, token] of Object.entries(categoryTokens)) {
variables.push({
name: `${category}/${name}`,
resolvedType: mapTypeToFigma(token.type),
variableCollectionId: collectionId,
valuesByMode: {
[modeId]: transformValue(token.value, token.type)
},
description: token.description || ''
});
}
}
// Step 3: Upload in batches (Figma has rate limits)
const BATCH_SIZE = 50;
for (let i = 0; i < variables.length; i += BATCH_SIZE) {
const batch = variables.slice(i, i + BATCH_SIZE);
await fetch(`${baseUrl}/files/${fileKey}/variables/batch`, {
method: 'POST',
headers: {
'X-Figma-Token': accessToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({ variables: batch })
});
console.log(`Uploaded batch ${i / BATCH_SIZE + 1}`);
// Rate limit: wait 1 second between batches
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log('✅ All tokens uploaded to Figma');
}
function mapTypeToFigma(type: string): string {
const mapping: Record<string, string> = {
'color': 'COLOR',
'dimension': 'FLOAT',
'fontFamily': 'STRING'
};
return mapping[type] || 'STRING';
}
function transformValue(value: string, type: string): any {
if (type === 'color') {
// Convert hex to RGBA object
const hex = value.replace('#', '');
const r = parseInt(hex.substr(0, 2), 16) / 255;
const g = parseInt(hex.substr(2, 2), 16) / 255;
const b = parseInt(hex.substr(4, 2), 16) / 255;
return { r, g, b, a: 1 };
}
if (type === 'dimension') {
// Convert rem/px to number
return parseFloat(value);
}
return value;
}
// Usage
const tokens = JSON.parse(
fs.readFileSync('design-tokens/tokens.json', 'utf8')
);
uploadTokensToFigma(
tokens,
process.env.FIGMA_FILE_KEY!,
process.env.FIGMA_TOKEN!
);MCP Server Concepts for Code → Figma
Create custom MCP tools to expose code analysis to LLMs:
// Example MCP server tools for design system analysis
{
"tools": [
{
"name": "extract_design_tokens",
"description": "Scan codebase for implicit design tokens",
"inputSchema": {
"type": "object",
"properties": {
"directory": {
"type": "string",
"description": "Root directory to scan"
},
"tokenTypes": {
"type": "array",
"items": { "enum": ["color", "spacing", "typography", "shadow"] }
}
}
}
},
{
"name": "analyze_component_props",
"description": "Extract component API from TypeScript definitions",
"inputSchema": {
"type": "object",
"properties": {
"componentPath": {
"type": "string",
"description": "Path to component file"
}
}
}
},
{
"name": "upload_tokens_to_figma",
"description": "Upload extracted tokens to Figma Variables",
"inputSchema": {
"type": "object",
"properties": {
"tokens": {
"type": "object",
"description": "DTCG formatted tokens"
},
"figmaFileKey": { "type": "string" }
}
}
}
]
}With these MCP tools available, an LLM can orchestrate the entire Code → Figma workflow:
PROMPT: Code to Figma Workflow
Please analyze my React component library and create a Figma design system:
1. Use extract_design_tokens to scan ./src/components for colors, spacing, typography
2. Analyze the extracted tokens and normalize similar values
3. Create a proper token hierarchy (primitive → semantic → component)
4. Use analyze_component_props on key components (Button, Input, Card)
5. Generate Figma component specs for each component
6. Use upload_tokens_to_figma to push the structured tokens to Figma file: {file_key}
Provide a summary report of:
- How many tokens were extracted and consolidated
- Which components were analyzed
- Recommendations for design system improvementsPro Tip: Incremental Migration
Don't try to migrate everything at once. Start with:
- 1.Colors (easiest to extract and most impactful)
- 2.Spacing and typography (clear patterns)
- 3.Core components (Button, Input, Card)
- 4.Complex components and compositions
Each phase can be deployed independently, making the migration less risky.
Recommended Tools Summary
| Tool | Purpose | Best For |
|---|---|---|
| Style Dictionary | Transform tokens between formats | Existing design systems with structured tokens |
| Token Studio | Bidirectional sync, GUI for tokens | Teams wanting no-code token management |
| html-to-figma | Import rendered HTML to Figma | Quick component documentation, starting point |
| Figma REST API | Programmatic Figma access | Custom automation, CI/CD integration |
| LLM + MCP | Intelligent analysis, pattern extraction | Legacy codebases without explicit design systems |
Why This Matters
Historically, design systems flowed one direction: Figma → Code. But modern workflows are more nuanced. Sometimes code leads (especially in engineering-heavy orgs), sometimes design leads, and often both evolve simultaneously. Supporting bidirectional workflows ensures your design system stays synchronized regardless of where changes originate.
Phase 9: Best Practices & Tips
Token Naming Best Practices
DO:
- ✓Use clear, descriptive names: semantic/text/primary
- ✓Follow consistent hierarchy: category/subcategory/name/variant
- ✓Use purpose-based semantic names: semantic/background/danger
DON'T:
- ✗Use presentational names: text/dark-gray
- ✗Skip semantic layer: primitive → component directly
- ✗Use abbreviations that aren't universal: btn/bg/prim
Phase 10: Troubleshooting & Common Issues
Issue 1: Token References Breaking
Problem: Variables reference each other incorrectly or show "Unresolved" in Figma
Error in Figma:
semantic/text/primary → {primitive.color.gray.900}
❌ Shows "Unresolved" badge
Common causes:
1. Typo in reference path
2. Referenced token doesn't exist
3. Referenced token is in different collection
4. Circular reference loopSolutions:
- •Check path syntax: Use absolute references like {primitive.color.blue.500}
- •Verify token exists: Search in Variables panel to confirm the token is created
- •Check collection scope: Ensure both tokens are in same or accessible collections
- •Avoid circular refs: Don't create A → B → A loops
- •Document dependencies: Keep a visual map of token hierarchy
Issue 2: Figma Export Contains Invalid JSON
Problem: Exported JSON file won't parse or has errors
Common issues:
❌ Missing closing braces
❌ Trailing commas
❌ Invalid escape characters in token names
❌ Special characters in valuesSolutions:
- •Validate JSON: Use jsonlint.com or `jq` command to check validity
- •Check token names: Avoid special characters like quotes, backslashes
- •Re-export: Sometimes Figma export can be corrupted - try again
- •Use validation script: Add JSON schema validation to your pipeline
Issue 3: Colors Look Different in Code vs Figma
Problem: Colors appear different when applied in browser/code
Possible causes:
1. Color space mismatch (sRGB vs Display P3)
2. Gamma correction differences
3. Browser color profile settings
4. Monitor calibration differences
5. Dark mode/light mode contextSolutions:
- •Use sRGB in Figma: Document Settings → Color profile → sRGB
- •Export as hex: Avoid RGB() format which can have rounding issues
- •Test in target browser: Always verify colors in actual environment
- •Use color picker: Sample actual rendered color to confirm match
Issue 4: MCP Server Not Connecting
Problem: MCP server won't connect or times out
Error messages:
"Failed to connect to MCP server"
"Connection timeout"
"Server not responding"Solutions for Official Figma MCP:
- •Check internet: Remote server requires connection
- •Verify URL: Ensure `https://mcp.figma.com/mcp` is correct
- •For desktop server: Confirm Figma Desktop app is running
- •Check firewall: Ensure port 3845 is not blocked (desktop server)
Solutions for Custom MCP Server:
- •Check paths: Verify absolute path to dist/index.js is correct
- •Build server: Run `npm run build` to compile TypeScript
- •Check permissions: Ensure file is executable (chmod +x)
- •Test manually: Run `node /path/to/dist/index.js` to see errors
- •Restart Claude Desktop: Reload config after changes
Issue 5: Inconsistent LLM Outputs
Problem: LLM generates code that doesn't follow design system rules
Example bad output:
// LLM hardcodes colors instead of using tokens
const Button = () => (
<button style={{ background: '#3B82F6' }}> // ❌ Hardcoded
Click me
</button>
)
// Should be:
const Button = () => (
<button className="bg-primary"> // ✓ Uses token
Click me
</button>
)Solutions:
- •Use MCP server: Provide design system context via custom MCP server
- •Explicit prompts: Always specify "use design tokens" or "follow HypnoLabs patterns"
- •Provide examples: Show correct token usage in your prompt
- •Add validation: Ask LLM to check its own output against token list
- •Iterative refinement: Review and correct, then ask LLM to learn from corrections
Issue 6: Token Count Explosion
Problem: Design system has too many tokens, becomes unmanageable
Signs of token bloat:
• 500+ tokens in your system
• Multiple similar tokens (blue-light, blue-lighter, blue-lightest, etc.)
• Tokens used only once
• Overlapping semantic tokensSolutions:
- •Audit usage: Track which tokens are actually used in components
- •Consolidate similar: Merge tokens that differ by tiny amounts
- •Remove unused: Delete tokens that aren't referenced anywhere
- •Stick to scales: Use systematic scales instead of one-off values
- •Regular cleanup: Quarterly token audits to prevent accumulation
Prevention is better than cure:
Set up a token approval process. Before adding new tokens, check if existing ones can be reused. Require justification for why a new token is needed. This prevents token bloat before it starts.
Phase 11: Starting with shadcn/ui and Making It Your Own
shadcn/ui provides production-ready components you can customize to match your design system.
What is shadcn/ui?
A collection of beautifully designed, accessible React components built with Radix UI and Tailwind CSS. Unlike traditional libraries, you copy the source code into your project—you own it completely.
Customization Strategy
Don't: Replace shadcn components entirely
Do: Keep shadcn components, remap their CSS variables to your tokens
:root {
/* Map your tokens to shadcn variables */
--primary: 217 91% 60%; /* Your brand blue in HSL */
--background: 210 20% 98%; /* Your background */
--radius: 0.75rem; /* Your border radius */
}
.dark {
--primary: 217 91% 60%;
--background: 222 47% 11%;
}Quick tip:
Start with shadcn/ui for standard components (buttons, inputs, dialogs) and build custom components for unique brand moments. This gives you speed AND customization.
Phase 12: Testing & Quality Assurance
Testing your design system ensures consistency, accessibility, and reliability across your product.
Visual Regression Testing
Catch unintended visual changes when tokens or components are updated.
// Example with Chromatic or Percy
import { render } from '@testing-library/react';
import { Button } from '@/components/ui/button';
describe('Button Visual Tests', () => {
it('matches snapshot', () => {
const { container } = render(
<>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="primary" disabled>Disabled</Button>
</>
);
expect(container).toMatchSnapshot();
});
});Accessibility Testing
Ensure your design system meets WCAG standards.
Automated Accessibility Checks
// Using jest-axe and Testing Library
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { Button } from '@/components/ui/button';
expect.extend(toHaveNoViolations);
describe('Button Accessibility', () => {
it('should not have accessibility violations', async () => {
const { container } = render(
<Button>Click me</Button>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has proper ARIA attributes', () => {
const { getByRole } = render(<Button>Submit</Button>);
const button = getByRole('button', { name: 'Submit' });
expect(button).toBeInTheDocument();
});
});Color Contrast Testing
// Check contrast ratios for all color combinations
import { getContrastRatio } from '@/lib/color-utils';
describe('Token Contrast Tests', () => {
it('primary text on white meets WCAG AA', () => {
const ratio = getContrastRatio('#1F2937', '#FFFFFF');
expect(ratio).toBeGreaterThanOrEqual(4.5); // WCAG AA
});
it('primary button has sufficient contrast', () => {
const bgColor = '#3B82F6'; // semantic.action.primary
const textColor = '#FFFFFF'; // semantic.text.inverse
const ratio = getContrastRatio(bgColor, textColor);
expect(ratio).toBeGreaterThanOrEqual(4.5);
});
});Component API Testing
Test that components accept correct props and behave as expected.
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from '@/components/ui/button';
describe('Button Component', () => {
it('renders with correct variant classes', () => {
render(<Button variant="primary">Text</Button>);
const button = screen.getByRole('button');
expect(button).toHaveClass('bg-primary');
});
it('calls onClick handler when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
fireEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Disabled</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});Design Token Validation
Validate token structure and relationships programmatically.
// Token validation script
import tokens from './design-tokens/figma-export/tokens.json';
describe('Design Token Tests', () => {
it('all token references are valid', () => {
const validateReferences = (obj, path = '') => {
for (const [key, value] of Object.entries(obj)) {
const currentPath = path ? `${path}.${key}` : key;
if (value.$value && typeof value.$value === 'string') {
// Check if it's a reference
if (value.$value.startsWith('{') && value.$value.endsWith('}')) {
const refPath = value.$value.slice(1, -1);
const referenced = getNestedToken(tokens, refPath);
expect(referenced).toBeDefined(
`Token ${currentPath} references non-existent ${refPath}`
);
}
} else if (typeof value === 'object') {
validateReferences(value, currentPath);
}
}
};
validateReferences(tokens);
});
it('no circular references exist', () => {
const checkCircular = (tokenPath, visited = new Set()) => {
if (visited.has(tokenPath)) {
throw new Error(`Circular reference detected: ${[...visited, tokenPath].join(' → ')}`);
}
visited.add(tokenPath);
const token = getNestedToken(tokens, tokenPath);
if (token.$value?.startsWith('{')) {
const refPath = token.$value.slice(1, -1);
checkCircular(refPath, new Set(visited));
}
};
// Test all tokens
Object.keys(tokens).forEach(collection => {
checkCircular(collection);
});
});
it('all colors are valid hex codes', () => {
const hexRegex = /^#[0-9A-Fa-f]{6}$/;
// ... check all color tokens match hex format
});
});Manual Testing Checklist
Some things still require human testing:
- □Keyboard navigation: Tab through all interactive elements
- □Screen reader testing: Test with NVDA, JAWS, or VoiceOver
- □Mobile responsiveness: Test on actual devices, not just browser tools
- □Dark mode: Switch themes and verify all components look correct
- □Browser compatibility: Test in Chrome, Firefox, Safari, Edge
- □Zoom levels: Test at 100%, 150%, 200% zoom
- □Print styles: If applicable, test print layouts
Performance Testing
Ensure your design system doesn't impact performance.
// Example performance tests
import { measurePerformance } from './test-utils';
describe('Design System Performance', () => {
it('CSS bundle size is under 50KB (gzipped)', async () => {
const bundleSize = await getBundleSize('./dist/tokens.css');
expect(bundleSize.gzipped).toBeLessThan(50 * 1024);
});
it('component library loads in under 200ms', async () => {
const loadTime = await measurePerformance(() => {
require('@/components/ui/button');
require('@/components/ui/input');
require('@/components/ui/card');
});
expect(loadTime).toBeLessThan(200);
});
});CI/CD Integration
Run tests automatically on every commit.
# .github/workflows/design-system-tests.yml
name: Design System Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run token validation
run: npm run test:tokens
- name: Run component tests
run: npm run test:components
- name: Run accessibility tests
run: npm run test:a11y
- name: Visual regression tests
run: npm run test:visual
env:
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_TOKEN }}
- name: Check bundle size
run: npm run test:sizePro tip:
Create a "Design System Health Dashboard" that shows test results, token coverage, accessibility scores, and bundle sizes. This gives stakeholders visibility into system quality and helps catch regressions early.
Quick Reference Checklist
Starting a New Design System
- □Complete visual design audit
- □Create primitive color, spacing, typography scales
- □Set up variable collections in Figma
- □Create semantic token layer
- □Build core components (atoms)
- □Connect variables to components
- □Export tokens to DTCG JSON
- □Set up MCP server for LLM integration
- □Generate CSS variables from tokens
- □Document usage guidelines
- □Test with LLM generation workflows
Congratulations!
You now have a comprehensive understanding of building design systems that integrate seamlessly with LLM workflows. Start small, iterate often, and let automation handle the synchronization between design and code.