$npx -y skills add dylantarre/design-system-skills --skill figmaSyncs design tokens between code and Figma using Variables API or Tokens Studio plugin. Use when establishing Figma-to-code workflows, exporting Figma tokens, or setting up design-development handoff.
| 1 | # Figma Token Integration |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Sync design tokens between code and Figma using Figma Variables, the Tokens Studio plugin, or Style Dictionary. Establish a single source of truth workflow for design-to-code handoff. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Setting up Figma Variables from code tokens |
| 10 | - Exporting Figma styles to code tokens |
| 11 | - Establishing a design token workflow |
| 12 | - Syncing colors, typography, and spacing with Figma |
| 13 | |
| 14 | ## Quick Reference: Figma Token Types |
| 15 | |
| 16 | | Figma Type | Maps To | Example | |
| 17 | |------------|---------|---------| |
| 18 | | Color Variable | `--color-*` | `--color-primary-500` | |
| 19 | | Number Variable | `--spacing-*`, `--radius-*` | `--spacing-md` | |
| 20 | | String Variable | Font family, mode names | `--font-sans` | |
| 21 | | Boolean Variable | Feature flags | Theme mode toggles | |
| 22 | |
| 23 | ## The Process |
| 24 | |
| 25 | 1. **Choose workflow direction**: |
| 26 | - Code → Figma (tokens are source of truth in code) |
| 27 | - Figma → Code (designers own tokens in Figma) |
| 28 | - Bidirectional (sync both ways) |
| 29 | 2. **Select tooling**: Native Variables, Tokens Studio, or custom |
| 30 | 3. **Define token structure**: Categories, naming, modes |
| 31 | 4. **Set up sync mechanism**: Plugin, API, or manual |
| 32 | 5. **Document workflow**: Who updates what, when to sync |
| 33 | |
| 34 | ## Workflow Options |
| 35 | |
| 36 | | Approach | Best For | Tools | |
| 37 | |----------|----------|-------| |
| 38 | | Figma Variables (native) | Simple setups, color/number tokens | Figma UI, REST API | |
| 39 | | Tokens Studio | Complex tokens, multi-file | Tokens Studio plugin + GitHub | |
| 40 | | Style Dictionary | Enterprise, CI/CD integration | Style Dictionary + Figma API | |
| 41 | | Manual sync | Small teams, infrequent changes | Copy/paste with conventions | |
| 42 | |
| 43 | --- |
| 44 | |
| 45 | ## Figma Variables (Native) |
| 46 | |
| 47 | ### Creating Variables from Code Tokens |
| 48 | |
| 49 | **Token structure for Figma:** |
| 50 | ```json |
| 51 | { |
| 52 | "color": { |
| 53 | "primary": { |
| 54 | "50": { "value": "#eff6ff", "type": "color" }, |
| 55 | "100": { "value": "#dbeafe", "type": "color" }, |
| 56 | "500": { "value": "#3b82f6", "type": "color" }, |
| 57 | "900": { "value": "#1e3a8a", "type": "color" } |
| 58 | }, |
| 59 | "gray": { |
| 60 | "50": { "value": "#f9fafb", "type": "color" }, |
| 61 | "900": { "value": "#111827", "type": "color" } |
| 62 | } |
| 63 | }, |
| 64 | "spacing": { |
| 65 | "xs": { "value": 4, "type": "number" }, |
| 66 | "sm": { "value": 8, "type": "number" }, |
| 67 | "md": { "value": 16, "type": "number" }, |
| 68 | "lg": { "value": 24, "type": "number" } |
| 69 | }, |
| 70 | "radius": { |
| 71 | "sm": { "value": 4, "type": "number" }, |
| 72 | "md": { "value": 8, "type": "number" }, |
| 73 | "lg": { "value": 16, "type": "number" }, |
| 74 | "full": { "value": 9999, "type": "number" } |
| 75 | } |
| 76 | } |
| 77 | ``` |
| 78 | |
| 79 | ### Figma REST API Example |
| 80 | |
| 81 | **Create variables via API:** |
| 82 | ```typescript |
| 83 | import Anthropic from '@anthropic-ai/sdk'; // Example using Figma API |
| 84 | |
| 85 | interface FigmaVariable { |
| 86 | name: string; |
| 87 | resolvedType: 'COLOR' | 'FLOAT' | 'STRING' | 'BOOLEAN'; |
| 88 | valuesByMode: Record<string, any>; |
| 89 | } |
| 90 | |
| 91 | async function createFigmaVariables( |
| 92 | fileKey: string, |
| 93 | collectionName: string, |
| 94 | tokens: Record<string, any> |
| 95 | ): Promise<void> { |
| 96 | const accessToken = process.env.FIGMA_ACCESS_TOKEN; |
| 97 | |
| 98 | // Step 1: Create variable collection |
| 99 | const collectionResponse = await fetch( |
| 100 | `https://api.figma.com/v1/files/${fileKey}/variables`, |
| 101 | { |
| 102 | method: 'POST', |
| 103 | headers: { |
| 104 | 'X-Figma-Token': accessToken, |
| 105 | 'Content-Type': 'application/json', |
| 106 | }, |
| 107 | body: JSON.stringify({ |
| 108 | variableCollections: [ |
| 109 | { |
| 110 | action: 'CREATE', |
| 111 | name: collectionName, |
| 112 | initialModeId: 'light', |
| 113 | }, |
| 114 | ], |
| 115 | }), |
| 116 | } |
| 117 | ); |
| 118 | |
| 119 | const { variableCollections } = await collectionResponse.json(); |
| 120 | const collectionId = variableCollections[0].id; |
| 121 | |
| 122 | // Step 2: Create variables |
| 123 | const variables: FigmaVariable[] = []; |
| 124 | |
| 125 | for (const [category, values] of Object.entries(tokens)) { |
| 126 | for (const [name, token] of Object.entries(values as Record<string, any>)) { |
| 127 | variables.push({ |
| 128 | name: `${category}/${name}`, |
| 129 | resolvedType: token.type === 'color' ? 'COLOR' : 'FLOAT', |
| 130 | valuesByMode: { |
| 131 | light: parseValue(token.value, token.type), |
| 132 | }, |
| 133 | }); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | await fetch(`https://api.figma.com/v1/files/${fileKey}/variables`, { |
| 138 | method: 'POST', |
| 139 | headers: { |
| 140 | 'X-Figma-Token': accessToken, |
| 141 | 'Content-Type': 'application/json', |
| 142 | }, |
| 143 | body: JSON.stringify({ |
| 144 | variables: variables.map((v) => ({ |
| 145 | action: 'CREATE', |
| 146 | variableCollectionId: collectionId, |
| 147 | ...v, |
| 148 | })), |
| 149 | }), |
| 150 | }); |
| 151 | } |
| 152 | |
| 153 | function parseValue(value: string | number, type: string): any { |
| 154 | if (type === 'color') { |
| 155 | // Convert hex to Figma RGBA |
| 156 | const hex = value as string; |
| 157 | const r = parseInt(hex.slice(1, 3), 16) / 255; |
| 158 | const g = parseInt(hex.slice(3, 5), 16) / 255; |
| 159 | const b = parseInt(hex.slice(5, 7), 16) / 255; |
| 160 | return { r, g, b, a: 1 }; |
| 161 | } |