figma-code-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -0
- package/bin/install.js +328 -0
- package/knowledge/README.md +62 -0
- package/knowledge/css-strategy.md +973 -0
- package/knowledge/design-to-code-assets.md +855 -0
- package/knowledge/design-to-code-layout.md +929 -0
- package/knowledge/design-to-code-semantic.md +1085 -0
- package/knowledge/design-to-code-typography.md +1003 -0
- package/knowledge/design-to-code-visual.md +1145 -0
- package/knowledge/design-tokens-variables.md +1261 -0
- package/knowledge/design-tokens.md +960 -0
- package/knowledge/figma-api-devmode.md +894 -0
- package/knowledge/figma-api-plugin.md +920 -0
- package/knowledge/figma-api-rest.md +742 -0
- package/knowledge/figma-api-variables.md +848 -0
- package/knowledge/figma-api-webhooks.md +876 -0
- package/knowledge/payload-blocks.md +1184 -0
- package/knowledge/payload-figma-mapping.md +1210 -0
- package/knowledge/payload-visual-builder.md +1004 -0
- package/knowledge/plugin-architecture.md +1176 -0
- package/knowledge/plugin-best-practices.md +1206 -0
- package/knowledge/plugin-codegen.md +1313 -0
- package/package.json +31 -0
- package/skills/README.md +103 -0
- package/skills/audit-plugin/SKILL.md +244 -0
- package/skills/build-codegen-plugin/SKILL.md +279 -0
- package/skills/build-importer/SKILL.md +320 -0
- package/skills/build-plugin/SKILL.md +199 -0
- package/skills/build-token-pipeline/SKILL.md +363 -0
- package/skills/ref-html/SKILL.md +290 -0
- package/skills/ref-layout/SKILL.md +150 -0
- package/skills/ref-payload-block/SKILL.md +415 -0
- package/skills/ref-react/SKILL.md +222 -0
- package/skills/ref-tokens/SKILL.md +347 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ref-react
|
|
3
|
+
description: "Reference: Generate a production-grade React/TSX component from Figma node data. Use this skill when the user has Figma design data (JSON node tree, REST API response, or component description) and needs a typed React component with CSS Modules, proper semantics, and accessibility."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
@knowledge/design-to-code-layout.md
|
|
7
|
+
@knowledge/design-to-code-visual.md
|
|
8
|
+
@knowledge/design-to-code-typography.md
|
|
9
|
+
@knowledge/design-to-code-assets.md
|
|
10
|
+
@knowledge/design-to-code-semantic.md
|
|
11
|
+
@knowledge/css-strategy.md
|
|
12
|
+
|
|
13
|
+
## Objective
|
|
14
|
+
|
|
15
|
+
Generate a complete, production-grade React/TSX component from Figma node data. The output includes a typed function component (`.tsx`) and a companion CSS Modules file (`.module.css`) using the three-layer CSS architecture: Tailwind for layout bones, CSS Custom Properties for design tokens, and CSS Modules for visual skin.
|
|
16
|
+
|
|
17
|
+
## Input
|
|
18
|
+
|
|
19
|
+
The user provides Figma design data as `$ARGUMENTS`. This may be:
|
|
20
|
+
|
|
21
|
+
- Raw Figma REST API JSON (node tree with children, fills, strokes, effects, text properties)
|
|
22
|
+
- Extracted/summarized node properties
|
|
23
|
+
- A description of the Figma component (layer names, layout, colors, typography)
|
|
24
|
+
- A Figma file/node URL (use the REST API knowledge to fetch data if needed)
|
|
25
|
+
|
|
26
|
+
If the input is insufficient for full generation, ask the user for what is missing. At minimum you need: component structure (parent/child hierarchy), layout mode, and visual properties for each node.
|
|
27
|
+
|
|
28
|
+
## Process
|
|
29
|
+
|
|
30
|
+
Follow these steps in order. Each step references the relevant knowledge module for detailed mapping rules.
|
|
31
|
+
|
|
32
|
+
### Step 1: Analyze Node Tree Structure
|
|
33
|
+
|
|
34
|
+
Identify the component boundary and internal hierarchy:
|
|
35
|
+
|
|
36
|
+
- The root node is the component container.
|
|
37
|
+
- Map each child node to its role: structural container, text element, image, icon/vector, interactive element.
|
|
38
|
+
- Identify repeated patterns that suggest list/map rendering.
|
|
39
|
+
- Note any component instances or variants that imply prop-driven rendering.
|
|
40
|
+
|
|
41
|
+
### Step 2: Determine Semantic HTML Elements
|
|
42
|
+
|
|
43
|
+
Consult `knowledge/design-to-code-semantic.md`:
|
|
44
|
+
|
|
45
|
+
- Match layer names against semantic tag heuristics (header, nav, button, h1-h6, p, img, section, article, footer, etc.).
|
|
46
|
+
- Enforce heading hierarchy: single `<h1>`, sequential levels, no headings inside interactive elements.
|
|
47
|
+
- Detect interactive elements from names (button, link, input, form, checkbox, toggle, etc.).
|
|
48
|
+
- Map structural landmarks (header, nav, footer, main, aside, section).
|
|
49
|
+
- Default to `<div>` only when no semantic match is found.
|
|
50
|
+
|
|
51
|
+
### Step 3: Extract Layout Properties
|
|
52
|
+
|
|
53
|
+
Consult `knowledge/design-to-code-layout.md`:
|
|
54
|
+
|
|
55
|
+
- For Auto Layout containers: map `layoutMode`, alignment, gap, padding, wrap, constraints.
|
|
56
|
+
- For each child: determine sizing mode on primary and counter axes.
|
|
57
|
+
- **CRITICAL**: FILL on primary axis requires BOTH `flex-grow: 1` AND `flex-basis: 0`.
|
|
58
|
+
- FILL on counter axis with max constraint uses `width: 100%`/`height: 100%`, not `align-self: stretch`.
|
|
59
|
+
- Handle absolute children with `position: relative` on parent and constraint-based offsets on child.
|
|
60
|
+
- For GROUP/legacy frames: absolute positioning with coordinate adjustments.
|
|
61
|
+
|
|
62
|
+
### Step 4: Extract Visual Properties
|
|
63
|
+
|
|
64
|
+
Consult `knowledge/design-to-code-visual.md`:
|
|
65
|
+
|
|
66
|
+
- **Fills**: solid colors -> `background-color`, gradients -> `background-image`, images -> handled in Step 6.
|
|
67
|
+
- **Strokes**: INSIDE alignment -> `box-shadow: inset 0 0 0 {width}px {color}` (NOT `border`). CENTER/OUTSIDE -> standard `border` or `outline`.
|
|
68
|
+
- **Effects**: drop shadows -> `box-shadow`, inner shadows -> `box-shadow: inset`, layer blur -> `filter: blur()`, background blur -> `backdrop-filter: blur()`.
|
|
69
|
+
- **Corner radius**: uniform -> `border-radius`, per-corner -> `border-radius: TL TR BR BL` with shorthand optimization.
|
|
70
|
+
- **Opacity**: node-level -> CSS `opacity`, fill-level -> embedded in color alpha. Never double-apply.
|
|
71
|
+
- **Gradients**: convert angle with `90 - figmaAngle` for CSS. Map gradient stops with position percentages.
|
|
72
|
+
- **Variable bindings**: resolve to `var(--token-name)` with pixel fallbacks for external library variables.
|
|
73
|
+
|
|
74
|
+
### Step 5: Extract Typography
|
|
75
|
+
|
|
76
|
+
Consult `knowledge/design-to-code-typography.md`:
|
|
77
|
+
|
|
78
|
+
- Map font family, weight, size, and style.
|
|
79
|
+
- **Line height**: ALWAYS use unitless ratio (`lineHeightPx / fontSize`). Never use px or % for line-height.
|
|
80
|
+
- Letter spacing: convert from Figma percentage to CSS `em` value.
|
|
81
|
+
- Text decoration, text transform, text alignment.
|
|
82
|
+
- Handle styled segments (mixed fonts/weights/colors within one text node) as `<span>` elements.
|
|
83
|
+
- Text auto-resize modes interact with layout sizing -- resolve the interaction.
|
|
84
|
+
|
|
85
|
+
### Step 6: Handle Assets
|
|
86
|
+
|
|
87
|
+
Consult `knowledge/design-to-code-assets.md`:
|
|
88
|
+
|
|
89
|
+
- **Vector containers** (nodes with only vector/boolean children and no Auto Layout): export as inline SVG or `<img>` referencing an SVG file.
|
|
90
|
+
- **Images**: use `<img>` with `alt` text derived from layer name. Export at **2x minimum** for retina displays.
|
|
91
|
+
- **Decision tree**: If the vector is simple and needs color control -> inline SVG. If complex or decorative -> `<img src="asset.svg">`.
|
|
92
|
+
- Deduplicate identical images (same `imageHash`).
|
|
93
|
+
|
|
94
|
+
### Step 7: Generate CSS Using Three-Layer Architecture
|
|
95
|
+
|
|
96
|
+
Consult `knowledge/css-strategy.md`:
|
|
97
|
+
|
|
98
|
+
**Layer 1 -- Tailwind (layout bones):**
|
|
99
|
+
Apply Tailwind utility classes directly in JSX for:
|
|
100
|
+
- Flexbox: `flex`, `flex-row`, `flex-col`, `items-center`, `justify-between`
|
|
101
|
+
- Spacing: `gap-4`, `p-6`, `px-4`, `py-2`
|
|
102
|
+
- Sizing: `w-full`, `h-auto`, `max-w-lg`, `flex-1`
|
|
103
|
+
- Positioning: `relative`, `absolute`, `top-0`, `right-0`
|
|
104
|
+
- Responsive: `md:flex-row`, `lg:gap-8`
|
|
105
|
+
|
|
106
|
+
**Layer 2 -- CSS Custom Properties (design tokens):**
|
|
107
|
+
Define in the CSS Module file or a shared `tokens.css`:
|
|
108
|
+
```css
|
|
109
|
+
/* Token references consumed by Layer 3 */
|
|
110
|
+
color: var(--color-primary);
|
|
111
|
+
font-size: var(--font-size-lg);
|
|
112
|
+
border-radius: var(--radius-md);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Layer 3 -- CSS Modules (visual skin):**
|
|
116
|
+
Component-specific visual styles in `.module.css`:
|
|
117
|
+
```css
|
|
118
|
+
.card {
|
|
119
|
+
background-color: var(--color-surface);
|
|
120
|
+
box-shadow: inset 0 0 0 1px var(--color-border); /* INSIDE stroke */
|
|
121
|
+
border-radius: var(--radius-lg);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.card__title {
|
|
125
|
+
color: var(--color-text-primary);
|
|
126
|
+
font-family: var(--font-heading);
|
|
127
|
+
font-size: var(--font-size-xl);
|
|
128
|
+
line-height: 1.3; /* unitless ratio */
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Step 8: Generate BEM Class Names
|
|
133
|
+
|
|
134
|
+
Consult `knowledge/design-to-code-semantic.md`:
|
|
135
|
+
|
|
136
|
+
- Block name from the root component (kebab-case from layer name).
|
|
137
|
+
- Element names with double underscore: `block__element`.
|
|
138
|
+
- **NEVER nest deeper than one level**: `block__element` is valid, `block__element__sub` is NOT. Flatten to `block__sub` or use a modifier.
|
|
139
|
+
- Modifier with double dash: `block__element--modifier`.
|
|
140
|
+
- Deduplicate class names within the component tree.
|
|
141
|
+
|
|
142
|
+
### Step 9: Generate TypeScript Interfaces
|
|
143
|
+
|
|
144
|
+
Define prop interfaces for the component:
|
|
145
|
+
|
|
146
|
+
- Extract variant-driven props from Figma component properties (boolean, text, instance swap).
|
|
147
|
+
- Text content nodes become string props.
|
|
148
|
+
- Image nodes become `src`/`alt` prop pairs.
|
|
149
|
+
- Interactive elements get event handler props (`onClick`, `onSubmit`, etc.).
|
|
150
|
+
- Use descriptive names, not Figma layer names directly.
|
|
151
|
+
|
|
152
|
+
### Step 10: Assemble React Component
|
|
153
|
+
|
|
154
|
+
Combine all outputs into a complete `.tsx` file:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import React from 'react';
|
|
158
|
+
import styles from './ComponentName.module.css';
|
|
159
|
+
|
|
160
|
+
interface ComponentNameProps {
|
|
161
|
+
title: string;
|
|
162
|
+
description?: string;
|
|
163
|
+
onAction?: () => void;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function ComponentName({ title, description, onAction }: ComponentNameProps) {
|
|
167
|
+
return (
|
|
168
|
+
<section className={`flex flex-col gap-4 p-6 ${styles.card}`}>
|
|
169
|
+
<h2 className={`${styles.card__title}`}>
|
|
170
|
+
{title}
|
|
171
|
+
</h2>
|
|
172
|
+
{description && (
|
|
173
|
+
<p className={`${styles.card__description}`}>
|
|
174
|
+
{description}
|
|
175
|
+
</p>
|
|
176
|
+
)}
|
|
177
|
+
<button
|
|
178
|
+
className={`flex items-center justify-center ${styles.card__action}`}
|
|
179
|
+
onClick={onAction}
|
|
180
|
+
type="button"
|
|
181
|
+
>
|
|
182
|
+
Get Started
|
|
183
|
+
</button>
|
|
184
|
+
</section>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Output
|
|
190
|
+
|
|
191
|
+
Generate two files:
|
|
192
|
+
|
|
193
|
+
### 1. `ComponentName.tsx`
|
|
194
|
+
|
|
195
|
+
- Named export (not default export) with PascalCase component name.
|
|
196
|
+
- TypeScript interface for props.
|
|
197
|
+
- Semantic HTML elements with Tailwind layout classes + CSS Module visual classes.
|
|
198
|
+
- Proper ARIA attributes where needed (`aria-label`, `role`, `alt`).
|
|
199
|
+
- Inline SVGs for simple vectors, `<img>` for complex assets/images.
|
|
200
|
+
|
|
201
|
+
### 2. `ComponentName.module.css`
|
|
202
|
+
|
|
203
|
+
- BEM class names with flat hierarchy.
|
|
204
|
+
- Visual properties only (colors, backgrounds, borders/shadows, effects, typography skin).
|
|
205
|
+
- CSS Custom Property references for design tokens (`var(--token-name)`).
|
|
206
|
+
- Responsive overrides via media queries if multi-frame breakpoints detected.
|
|
207
|
+
- Comments showing Figma property origin for maintainability.
|
|
208
|
+
|
|
209
|
+
### Critical Rules Checklist
|
|
210
|
+
|
|
211
|
+
Before returning the component, verify:
|
|
212
|
+
|
|
213
|
+
- [ ] INSIDE strokes use `box-shadow: inset`, not `border`
|
|
214
|
+
- [ ] Gradient angles use `90 - figmaAngle` conversion
|
|
215
|
+
- [ ] Line heights are unitless ratios (`lineHeightPx / fontSize`)
|
|
216
|
+
- [ ] Images export at 2x minimum for retina
|
|
217
|
+
- [ ] BEM nesting is flat: never `block__element__sub`
|
|
218
|
+
- [ ] FILL on primary axis has BOTH `flex-grow: 1` AND `flex-basis: 0`
|
|
219
|
+
- [ ] Layout is in Tailwind classes; visual skin is in CSS Modules
|
|
220
|
+
- [ ] No hardcoded color values -- use CSS Custom Properties for anything that could be a token
|
|
221
|
+
- [ ] Semantic HTML tags used where layer names match heuristics
|
|
222
|
+
- [ ] ARIA attributes present on interactive and image elements
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ref-tokens
|
|
3
|
+
description: "Reference: Extract design tokens from Figma Variables, styles, or node data and generate CSS Custom Properties + Tailwind config. Use this skill when the user has Figma file data (Variables API response, style definitions, or node tree) and needs a structured token output with semantic naming, mode-aware rendering, and CSS/Tailwind integration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
@knowledge/design-tokens.md
|
|
7
|
+
@knowledge/design-tokens-variables.md
|
|
8
|
+
@knowledge/figma-api-variables.md
|
|
9
|
+
@knowledge/css-strategy.md
|
|
10
|
+
|
|
11
|
+
## Objective
|
|
12
|
+
|
|
13
|
+
Extract design tokens from Figma data and generate production-grade CSS Custom Properties (`:root` block with mode-aware overrides), optional SCSS variables, and a Tailwind `theme.extend` configuration snippet. The skill handles the full token pipeline: source identification, variable resolution, threshold-based promotion, semantic naming (HSL color classification, spacing scale detection), and multi-format rendering.
|
|
14
|
+
|
|
15
|
+
## Input
|
|
16
|
+
|
|
17
|
+
The user provides Figma token source data as `$ARGUMENTS`. This may be:
|
|
18
|
+
|
|
19
|
+
- **Variables API response** -- JSON from `GET /v1/files/:key/variables/local` containing variables and collections with `valuesByMode`
|
|
20
|
+
- **Plugin API variable data** -- Extracted variable collections from `figma.variables.getLocalVariableCollectionsAsync()`
|
|
21
|
+
- **Node tree with bound variables** -- Figma REST API node data containing `boundVariables` on fills, strokes, layout properties, and text
|
|
22
|
+
- **Style definitions** -- Published styles from the file (colors, text styles, effects)
|
|
23
|
+
- **Raw node tree** -- Full node subtree for heuristic-based token extraction (file traversal fallback)
|
|
24
|
+
- **Plain language description** -- Description of the design system's colors, spacing, typography, etc.
|
|
25
|
+
|
|
26
|
+
If the input is insufficient, ask the user for clarification. At minimum you need either: (a) variable collections with values, or (b) a node tree with enough nodes to detect repeated values for promotion.
|
|
27
|
+
|
|
28
|
+
## Process
|
|
29
|
+
|
|
30
|
+
Follow these steps in order. Consult the referenced knowledge modules for all mapping rules, naming conventions, and edge cases.
|
|
31
|
+
|
|
32
|
+
### Step 1: Identify Token Source and Access Path
|
|
33
|
+
|
|
34
|
+
Determine which token extraction path to use based on the input data. Consult `knowledge/figma-api-variables.md` for access requirements and `knowledge/design-tokens-variables.md` for the source priority chain.
|
|
35
|
+
|
|
36
|
+
**Priority order:**
|
|
37
|
+
|
|
38
|
+
1. **Variables API** (best) -- Structured, multi-mode, scoped. Requires Enterprise org full member access with `file_variables:read` scope. If the user provides Variables API JSON, use this path.
|
|
39
|
+
2. **Published styles** -- Good for non-Enterprise plans. Limited to published content.
|
|
40
|
+
3. **File tree traversal** -- Fallback for any plan. Heuristic-based extraction from node properties. Uses threshold promotion.
|
|
41
|
+
4. **Plugin API** -- When running inside a Figma plugin context. Access via `figma.variables.getLocalVariableCollectionsAsync()`.
|
|
42
|
+
|
|
43
|
+
**If the user does not have Enterprise access**, inform them that the Variables API path is unavailable and proceed with file traversal + threshold promotion. Do NOT block on missing Variables access -- always provide a working fallback path.
|
|
44
|
+
|
|
45
|
+
### Step 2: Extract Raw Token Values
|
|
46
|
+
|
|
47
|
+
Based on the identified source path:
|
|
48
|
+
|
|
49
|
+
**Variables API path:**
|
|
50
|
+
- Parse variable collections and their modes
|
|
51
|
+
- For each variable: read `resolvedType` (COLOR, FLOAT, STRING), `valuesByMode`, `scopes`
|
|
52
|
+
- Classify each collection's modes using mode name detection (see Step 3)
|
|
53
|
+
- Distinguish local vs remote variables using the `remote` boolean field
|
|
54
|
+
- Follow alias chains: if a variable's value is a `VariableAlias`, resolve to the terminal value for each mode
|
|
55
|
+
|
|
56
|
+
**File traversal path:**
|
|
57
|
+
- Traverse the node tree recursively
|
|
58
|
+
- Collect values from five domains, tracking usage count per unique value:
|
|
59
|
+
- **Colors**: solid fills (`fill.color`), strokes (`stroke.color`), shadow effect colors
|
|
60
|
+
- **Spacing**: `itemSpacing` (gap), `paddingTop/Right/Bottom/Left`, margins
|
|
61
|
+
- **Typography**: font families, font sizes, font weights, line heights
|
|
62
|
+
- **Effects**: box shadows (drop shadow, inner shadow), border radii
|
|
63
|
+
- **Breakpoints**: frame dimensions that suggest responsive breakpoints
|
|
64
|
+
- Normalize values before comparison (lowercase hex, whitespace-normalize rgba)
|
|
65
|
+
- Collect any `boundVariables` references found on nodes (these get priority in Step 6)
|
|
66
|
+
|
|
67
|
+
### Step 3: Detect Modes (Variables Path Only)
|
|
68
|
+
|
|
69
|
+
Consult `knowledge/design-tokens-variables.md` Section 4 for mode detection rules.
|
|
70
|
+
|
|
71
|
+
Classify each collection's modes as one of:
|
|
72
|
+
- **Theme modes** -- Mode names like "Light", "Dark", "Brand A", "Brand B"
|
|
73
|
+
- **Breakpoint modes** -- Mode names like "Mobile", "Tablet", "Desktop", "sm", "md", "lg"
|
|
74
|
+
- **Unknown** -- Cannot classify; treat as theme modes by default
|
|
75
|
+
|
|
76
|
+
**Default mode selection:**
|
|
77
|
+
- Theme modes: "Light" is default (base `:root`)
|
|
78
|
+
- Breakpoint modes: smallest breakpoint (typically "Mobile") is default (mobile-first)
|
|
79
|
+
- Unknown: first mode in the collection is default
|
|
80
|
+
|
|
81
|
+
### Step 4: Promote Values to Tokens
|
|
82
|
+
|
|
83
|
+
Consult `knowledge/design-tokens.md` Section 1 (Stage 2: PROMOTE).
|
|
84
|
+
|
|
85
|
+
**Threshold-based promotion (file traversal path):**
|
|
86
|
+
- Values used 2 or more times are promoted to CSS Custom Properties
|
|
87
|
+
- Single-use values remain inline in component CSS (not tokenized)
|
|
88
|
+
- The threshold of 2 is the default; adjust if the user specifies differently
|
|
89
|
+
|
|
90
|
+
**Variables path:**
|
|
91
|
+
- All Figma Variables are automatically promoted (they are explicit designer-curated tokens)
|
|
92
|
+
- No threshold needed -- variables are tokens by definition
|
|
93
|
+
|
|
94
|
+
**Priority when both exist:**
|
|
95
|
+
- Bound variable references on a property always take priority
|
|
96
|
+
- Auto-detected tokens fill gaps where no variable binding exists
|
|
97
|
+
- If a variable and an auto-detected token produce the same CSS value, the variable wins
|
|
98
|
+
|
|
99
|
+
### Step 5: Assign Semantic Names
|
|
100
|
+
|
|
101
|
+
Consult `knowledge/design-tokens.md` Sections 3-6 for naming rules per category.
|
|
102
|
+
|
|
103
|
+
**Token naming convention:** `--{category}-{name}-{variant}`
|
|
104
|
+
|
|
105
|
+
**Colors (HSL-based classification):**
|
|
106
|
+
1. Convert to HSL (Hue 0-360, Saturation 0-100, Lightness 0-100)
|
|
107
|
+
2. Classify:
|
|
108
|
+
- Saturation < 10% --> `neutral` with lightness scale (100-900)
|
|
109
|
+
- Hue 0-20 or 340-360 --> `error`
|
|
110
|
+
- Hue 30-60 --> `warning`
|
|
111
|
+
- Hue 90-150 --> `success`
|
|
112
|
+
- Most-used saturated color --> `primary`
|
|
113
|
+
- Second most-used saturated --> `secondary`
|
|
114
|
+
- Remaining --> `accent`, `accent-2`, etc.
|
|
115
|
+
3. Neutral lightness scale: `step = Math.round((1 - lightness / 100) * 8 + 1) * 100` clamped to [100, 900]
|
|
116
|
+
4. Output format: HSL values for easy manipulation: `--color-primary: hsl(220, 90%, 56%)`
|
|
117
|
+
|
|
118
|
+
**If Variables API is the source**, use the variable's own path as the name base (e.g., `color/primary/500` --> `--color-primary-500`). HSL classification is only needed for file traversal path where names must be inferred.
|
|
119
|
+
|
|
120
|
+
**Spacing (4px base unit detection):**
|
|
121
|
+
1. Detect the base unit from collected spacing values (typically 4px or 8px)
|
|
122
|
+
2. Express each spacing value as a multiple of the base: `value / baseUnit`
|
|
123
|
+
3. Name pattern: `--spacing-{multiplier}` (e.g., `--spacing-1` = 4px, `--spacing-4` = 16px)
|
|
124
|
+
4. If a clear base unit cannot be detected, use pixel-based naming: `--spacing-4` = 4px, `--spacing-16` = 16px
|
|
125
|
+
|
|
126
|
+
**Typography:**
|
|
127
|
+
- Font families: `--font-primary`, `--font-secondary`, `--font-mono`
|
|
128
|
+
- Font sizes: `--text-xs`, `--text-sm`, `--text-base`, `--text-lg`, `--text-xl`, `--text-2xl`, etc. (match to nearest standard scale)
|
|
129
|
+
- Font weights: `--font-regular` (400), `--font-medium` (500), `--font-semibold` (600), `--font-bold` (700)
|
|
130
|
+
|
|
131
|
+
**Effects:**
|
|
132
|
+
- Shadows: `--shadow-sm`, `--shadow-md`, `--shadow-lg` (by blur radius / spread scale)
|
|
133
|
+
- Border radii: `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-full`
|
|
134
|
+
|
|
135
|
+
**Name deduplication:**
|
|
136
|
+
- If two tokens would get the same name, append a numeric suffix: `--color-accent`, `--color-accent-2`
|
|
137
|
+
- For Variables API tokens, the variable path provides unique names naturally
|
|
138
|
+
|
|
139
|
+
### Step 6: Render CSS Custom Properties
|
|
140
|
+
|
|
141
|
+
Consult `knowledge/design-tokens-variables.md` Sections 5-7 for mode-aware rendering and `knowledge/css-strategy.md` for where tokens fit in the three-layer architecture.
|
|
142
|
+
|
|
143
|
+
**Base `:root` block (default mode values):**
|
|
144
|
+
|
|
145
|
+
```css
|
|
146
|
+
/* ========================================
|
|
147
|
+
Design Tokens (Layer 2)
|
|
148
|
+
======================================== */
|
|
149
|
+
|
|
150
|
+
:root {
|
|
151
|
+
/* Colors */
|
|
152
|
+
--color-primary: hsl(220, 90%, 56%);
|
|
153
|
+
--color-secondary: hsl(258, 88%, 66%);
|
|
154
|
+
--color-neutral-100: hsl(0, 0%, 96%);
|
|
155
|
+
--color-neutral-900: hsl(0, 0%, 9%);
|
|
156
|
+
--color-error: hsl(0, 84%, 60%);
|
|
157
|
+
--color-success: hsl(142, 71%, 45%);
|
|
158
|
+
|
|
159
|
+
/* Spacing (4px base) */
|
|
160
|
+
--spacing-1: 0.25rem; /* 4px */
|
|
161
|
+
--spacing-2: 0.5rem; /* 8px */
|
|
162
|
+
--spacing-4: 1rem; /* 16px */
|
|
163
|
+
--spacing-6: 1.5rem; /* 24px */
|
|
164
|
+
--spacing-8: 2rem; /* 32px */
|
|
165
|
+
|
|
166
|
+
/* Typography */
|
|
167
|
+
--font-primary: 'Inter', sans-serif;
|
|
168
|
+
--font-heading: 'Instrument Sans', sans-serif;
|
|
169
|
+
--text-sm: 0.875rem; /* 14px */
|
|
170
|
+
--text-base: 1rem; /* 16px */
|
|
171
|
+
--text-lg: 1.125rem; /* 18px */
|
|
172
|
+
--text-xl: 1.5rem; /* 24px */
|
|
173
|
+
|
|
174
|
+
/* Effects */
|
|
175
|
+
--radius-sm: 0.25rem; /* 4px */
|
|
176
|
+
--radius-md: 0.5rem; /* 8px */
|
|
177
|
+
--radius-lg: 1rem; /* 16px */
|
|
178
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
179
|
+
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Theme mode overrides:**
|
|
184
|
+
|
|
185
|
+
```css
|
|
186
|
+
/* Dark theme */
|
|
187
|
+
@media (prefers-color-scheme: dark) {
|
|
188
|
+
:root {
|
|
189
|
+
--color-primary: hsl(220, 90%, 65%);
|
|
190
|
+
--color-neutral-100: hsl(0, 0%, 15%);
|
|
191
|
+
--color-neutral-900: hsl(0, 0%, 95%);
|
|
192
|
+
/* Only tokens that change in dark mode */
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Class-based theme (alternative/additional) */
|
|
197
|
+
[data-theme="dark"] {
|
|
198
|
+
--color-primary: hsl(220, 90%, 65%);
|
|
199
|
+
--color-neutral-100: hsl(0, 0%, 15%);
|
|
200
|
+
--color-neutral-900: hsl(0, 0%, 95%);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Breakpoint mode overrides (mobile-first):**
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
@media (min-width: 768px) {
|
|
208
|
+
:root {
|
|
209
|
+
--spacing-4: 1.25rem; /* 20px at tablet */
|
|
210
|
+
--text-xl: 1.75rem; /* 28px at tablet */
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@media (min-width: 1024px) {
|
|
215
|
+
:root {
|
|
216
|
+
--spacing-4: 1.5rem; /* 24px at desktop */
|
|
217
|
+
--text-xl: 2rem; /* 32px at desktop */
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Rendering rules:**
|
|
223
|
+
- Only emit overrides for tokens whose values differ from the base mode
|
|
224
|
+
- Theme collections render as `@media (prefers-color-scheme)` AND `[data-theme]` selector (both, for progressive enhancement)
|
|
225
|
+
- Breakpoint collections render as `@media (min-width)` with mobile-first ordering
|
|
226
|
+
- Use rem units for spacing and font sizes (divide pixel value by 16)
|
|
227
|
+
- Use HSL for colors (enables easy lightness/saturation manipulation)
|
|
228
|
+
- Add comments showing the original pixel values for developer reference
|
|
229
|
+
|
|
230
|
+
### Step 7: Render Tailwind Config Extension
|
|
231
|
+
|
|
232
|
+
Generate a `tailwind.config.ts` extension snippet that maps tokens to Tailwind utilities:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import type { Config } from 'tailwindcss'
|
|
236
|
+
|
|
237
|
+
export default {
|
|
238
|
+
theme: {
|
|
239
|
+
extend: {
|
|
240
|
+
colors: {
|
|
241
|
+
primary: 'var(--color-primary)',
|
|
242
|
+
secondary: 'var(--color-secondary)',
|
|
243
|
+
neutral: {
|
|
244
|
+
100: 'var(--color-neutral-100)',
|
|
245
|
+
900: 'var(--color-neutral-900)',
|
|
246
|
+
},
|
|
247
|
+
error: 'var(--color-error)',
|
|
248
|
+
success: 'var(--color-success)',
|
|
249
|
+
},
|
|
250
|
+
fontFamily: {
|
|
251
|
+
primary: 'var(--font-primary)',
|
|
252
|
+
heading: 'var(--font-heading)',
|
|
253
|
+
},
|
|
254
|
+
fontSize: {
|
|
255
|
+
sm: 'var(--text-sm)',
|
|
256
|
+
base: 'var(--text-base)',
|
|
257
|
+
lg: 'var(--text-lg)',
|
|
258
|
+
xl: 'var(--text-xl)',
|
|
259
|
+
},
|
|
260
|
+
spacing: {
|
|
261
|
+
1: 'var(--spacing-1)',
|
|
262
|
+
2: 'var(--spacing-2)',
|
|
263
|
+
4: 'var(--spacing-4)',
|
|
264
|
+
6: 'var(--spacing-6)',
|
|
265
|
+
8: 'var(--spacing-8)',
|
|
266
|
+
},
|
|
267
|
+
borderRadius: {
|
|
268
|
+
sm: 'var(--radius-sm)',
|
|
269
|
+
md: 'var(--radius-md)',
|
|
270
|
+
lg: 'var(--radius-lg)',
|
|
271
|
+
},
|
|
272
|
+
boxShadow: {
|
|
273
|
+
sm: 'var(--shadow-sm)',
|
|
274
|
+
md: 'var(--shadow-md)',
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
} satisfies Config
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Tailwind mapping rules:**
|
|
282
|
+
- All Tailwind values reference CSS Custom Properties via `var()` -- never hardcode values
|
|
283
|
+
- This ensures Tailwind utilities automatically adapt to theme/breakpoint mode changes
|
|
284
|
+
- Color tokens map to `theme.extend.colors` (enables `bg-primary`, `text-secondary`, etc.)
|
|
285
|
+
- Spacing tokens map to `theme.extend.spacing` (enables `gap-4`, `p-6`, etc.)
|
|
286
|
+
- Typography tokens split across `fontFamily`, `fontSize`
|
|
287
|
+
- Effect tokens map to `borderRadius`, `boxShadow`
|
|
288
|
+
|
|
289
|
+
### Step 8: Render SCSS Variables (If Requested)
|
|
290
|
+
|
|
291
|
+
Only generate SCSS output if the user explicitly requests it:
|
|
292
|
+
|
|
293
|
+
```scss
|
|
294
|
+
// _variables.scss — Generated from Figma design tokens
|
|
295
|
+
|
|
296
|
+
// Colors
|
|
297
|
+
$color-primary: var(--color-primary);
|
|
298
|
+
$color-secondary: var(--color-secondary);
|
|
299
|
+
|
|
300
|
+
// Spacing
|
|
301
|
+
$spacing-1: var(--spacing-1);
|
|
302
|
+
$spacing-4: var(--spacing-4);
|
|
303
|
+
|
|
304
|
+
// Typography
|
|
305
|
+
$font-primary: var(--font-primary);
|
|
306
|
+
$text-base: var(--text-base);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
SCSS variables reference CSS Custom Properties (not raw values) to maintain single source of truth.
|
|
310
|
+
|
|
311
|
+
## Output
|
|
312
|
+
|
|
313
|
+
Generate two files (three if SCSS requested):
|
|
314
|
+
|
|
315
|
+
### 1. `tokens.css`
|
|
316
|
+
|
|
317
|
+
- `:root` block with all promoted tokens organized by category (colors, spacing, typography, effects)
|
|
318
|
+
- Mode-aware overrides via `@media (prefers-color-scheme)`, `[data-theme]` selectors, or `@media (min-width)` for breakpoints
|
|
319
|
+
- Comments showing original Figma variable paths or pixel values
|
|
320
|
+
- HSL format for colors, rem units for spacing/typography
|
|
321
|
+
|
|
322
|
+
### 2. `tailwind.config.ts` (extension snippet)
|
|
323
|
+
|
|
324
|
+
- `theme.extend` configuration referencing CSS Custom Properties
|
|
325
|
+
- All values use `var()` references to tokens defined in `tokens.css`
|
|
326
|
+
- Ready to merge into existing Tailwind configuration
|
|
327
|
+
|
|
328
|
+
### 3. `_variables.scss` (only if requested)
|
|
329
|
+
|
|
330
|
+
- SCSS variable declarations referencing CSS Custom Properties
|
|
331
|
+
|
|
332
|
+
### Output Checklist
|
|
333
|
+
|
|
334
|
+
Before returning token output, verify:
|
|
335
|
+
|
|
336
|
+
- [ ] Colors use HSL format (`hsl(h, s%, l%)`)
|
|
337
|
+
- [ ] Spacing values use rem units with pixel comments
|
|
338
|
+
- [ ] Spacing is based on consistent base unit (default 4px)
|
|
339
|
+
- [ ] Token names follow `--{category}-{name}-{variant}` convention
|
|
340
|
+
- [ ] Variables API tokens preserve original variable path in names
|
|
341
|
+
- [ ] File traversal tokens use HSL classification for color naming
|
|
342
|
+
- [ ] Mode overrides only contain tokens that differ from the base
|
|
343
|
+
- [ ] Theme modes render both `@media (prefers-color-scheme)` and `[data-theme]`
|
|
344
|
+
- [ ] Breakpoint modes render mobile-first `@media (min-width)` in ascending order
|
|
345
|
+
- [ ] Tailwind config references `var()` for all values (no hardcoded values)
|
|
346
|
+
- [ ] Fallback path is documented when Variables API is not available
|
|
347
|
+
- [ ] Single-use values (below threshold) are NOT promoted to tokens
|