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,363 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-token-pipeline
|
|
3
|
+
description: Build a pipeline that syncs Figma design tokens to code. Use this skill when the user needs automated or on-demand synchronization of Figma Variables into CSS Custom Properties, Tailwind config, SCSS variables, or other token formats.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
@knowledge/figma-api-variables.md
|
|
7
|
+
@knowledge/design-tokens.md
|
|
8
|
+
@knowledge/design-tokens-variables.md
|
|
9
|
+
@knowledge/figma-api-webhooks.md
|
|
10
|
+
@knowledge/css-strategy.md
|
|
11
|
+
|
|
12
|
+
## Objective
|
|
13
|
+
|
|
14
|
+
Help the user build a token synchronization pipeline that reads Figma Variables (or extracts tokens from file data) and outputs production-ready CSS Custom Properties, Tailwind config, SCSS variables, or other formats. The skill covers the full pipeline: trigger mechanism (webhook, CLI, CI/CD), API access, variable resolution, alias chain following, mode classification, naming, multi-format rendering, and drift detection.
|
|
15
|
+
|
|
16
|
+
## Input
|
|
17
|
+
|
|
18
|
+
The user provides their token pipeline requirements as `$ARGUMENTS`. This may be:
|
|
19
|
+
|
|
20
|
+
- A description of the desired sync workflow (e.g., "sync Figma Variables to CSS and Tailwind on every library publish")
|
|
21
|
+
- A path to an existing token pipeline to enhance
|
|
22
|
+
- Specific requirements (output formats, mode handling, naming conventions)
|
|
23
|
+
- Questions about Variables API access or Enterprise requirements
|
|
24
|
+
|
|
25
|
+
If the input is a path, read the project files before proceeding. If the input is a description, proceed directly to Phase 1.
|
|
26
|
+
|
|
27
|
+
## Process
|
|
28
|
+
|
|
29
|
+
### Phase 1 — Assess
|
|
30
|
+
|
|
31
|
+
Determine the pipeline's scope, trigger mechanism, and constraints.
|
|
32
|
+
|
|
33
|
+
**Sync trigger:**
|
|
34
|
+
- **Webhook-driven**: automatic sync on Figma library publish events. Requires a server endpoint to receive `LIBRARY_PUBLISH` webhooks. Best for continuous sync.
|
|
35
|
+
- **CLI command**: manual `npm run sync-tokens` or similar. Best for controlled releases.
|
|
36
|
+
- **CI/CD job**: runs in GitHub Actions, GitLab CI, etc. Triggered on schedule or manual dispatch. Best for teams that want PR-based token review.
|
|
37
|
+
- **Combination**: webhook triggers a CI job, or CLI triggers a CI job
|
|
38
|
+
|
|
39
|
+
**Output formats (can select multiple):**
|
|
40
|
+
- **CSS Custom Properties** — `:root` block with mode-aware overrides. The primary format.
|
|
41
|
+
- **Tailwind config** — `theme.extend` referencing CSS variables via `var()`. For Tailwind projects.
|
|
42
|
+
- **SCSS variables** — `$variable` declarations referencing CSS Custom Properties. For SCSS projects.
|
|
43
|
+
- **JSON** — Flat or nested token structure. For tools like Style Dictionary, Tokens Studio, or custom consumers.
|
|
44
|
+
- **TypeScript** — Type-safe token constants. For programmatic token access.
|
|
45
|
+
|
|
46
|
+
**Variable scope:**
|
|
47
|
+
- All collections and variables (full sync)
|
|
48
|
+
- Filtered by collection name (e.g., only "Primitives" and "Semantic")
|
|
49
|
+
- Filtered by variable scope (e.g., only `ALL_SCOPES` or specific scopes like `FRAME_FILL`, `TEXT_CONTENT`)
|
|
50
|
+
|
|
51
|
+
**API access:**
|
|
52
|
+
- **Variables API** (Enterprise plan required): `GET /v1/files/:key/variables/local` with `file_variables:read` scope. Provides structured variable collections, modes, alias chains, scopes.
|
|
53
|
+
- **Fallback** (any plan): file traversal + threshold-based promotion. Reads node properties, detects repeated values, promotes to tokens. Less structured but works without Enterprise.
|
|
54
|
+
- Assess which access level the user has and plan accordingly. Both paths should produce equivalent CSS output.
|
|
55
|
+
|
|
56
|
+
**Mode strategy:**
|
|
57
|
+
- How many modes does each collection have?
|
|
58
|
+
- What do the modes represent?
|
|
59
|
+
- **Theme modes** (Light/Dark, Brand A/Brand B) → `@media (prefers-color-scheme)` + `[data-theme]` selectors
|
|
60
|
+
- **Breakpoint modes** (Mobile/Tablet/Desktop) → `@media (min-width)` with mobile-first ascending order
|
|
61
|
+
- **Density modes** (Compact/Default/Comfortable) → `[data-density]` attribute selector
|
|
62
|
+
- Which mode is the default (base `:root`)?
|
|
63
|
+
|
|
64
|
+
Report the assessment to the user before proceeding.
|
|
65
|
+
|
|
66
|
+
### Phase 2 — Recommend
|
|
67
|
+
|
|
68
|
+
Based on the assessment, recommend the pipeline architecture.
|
|
69
|
+
|
|
70
|
+
**Mode rendering strategy:**
|
|
71
|
+
|
|
72
|
+
For **theme modes**:
|
|
73
|
+
```css
|
|
74
|
+
/* Base (Light mode — default) */
|
|
75
|
+
:root { --color-primary: hsl(220, 90%, 56%); }
|
|
76
|
+
|
|
77
|
+
/* System preference */
|
|
78
|
+
@media (prefers-color-scheme: dark) {
|
|
79
|
+
:root { --color-primary: hsl(220, 90%, 65%); }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Class-based override (progressive enhancement) */
|
|
83
|
+
[data-theme="dark"] { --color-primary: hsl(220, 90%, 65%); }
|
|
84
|
+
```
|
|
85
|
+
- Render BOTH `@media (prefers-color-scheme)` AND `[data-theme]` for each non-default theme mode
|
|
86
|
+
- Only emit tokens whose values differ from the base mode in overrides
|
|
87
|
+
|
|
88
|
+
For **breakpoint modes**:
|
|
89
|
+
```css
|
|
90
|
+
/* Base (Mobile — smallest, default) */
|
|
91
|
+
:root { --spacing-section: 1.5rem; }
|
|
92
|
+
|
|
93
|
+
@media (min-width: 768px) {
|
|
94
|
+
:root { --spacing-section: 2rem; }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@media (min-width: 1024px) {
|
|
98
|
+
:root { --spacing-section: 3rem; }
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
- Mobile-first: smallest breakpoint is base, larger breakpoints add overrides
|
|
102
|
+
- Ascending `min-width` order
|
|
103
|
+
- Only emit changed tokens in each breakpoint
|
|
104
|
+
|
|
105
|
+
**Naming convention:**
|
|
106
|
+
- Preserve Figma variable path as the name basis: `color/primary/500` → `--color-primary-500`
|
|
107
|
+
- Slash-separated paths become hyphen-separated CSS property names
|
|
108
|
+
- Category prefixes maintained: `--color-*`, `--spacing-*`, `--font-*`, `--radius-*`, `--shadow-*`
|
|
109
|
+
- For file traversal fallback: use HSL classification for colors, base-unit detection for spacing (see `knowledge/design-tokens.md`)
|
|
110
|
+
|
|
111
|
+
**Alias chain resolution:**
|
|
112
|
+
- Variables can alias other variables (`VariableAlias` type)
|
|
113
|
+
- Chains can be multi-level: `semantic/primary` → `brand/blue-500` → `primitive/blue-500`
|
|
114
|
+
- Resolve to terminal value for each mode
|
|
115
|
+
- In CSS output, decide whether to preserve alias relationships as `var()` references or flatten to resolved values:
|
|
116
|
+
- **Preserve aliases** (recommended): `--color-primary: var(--color-blue-500);` — maintains semantic relationships, enables override
|
|
117
|
+
- **Flatten**: `--color-primary: hsl(220, 90%, 56%);` — simpler but loses relationship
|
|
118
|
+
|
|
119
|
+
**Drift detection:**
|
|
120
|
+
- Compare code tokens (parsed from existing CSS/JSON) against Figma source
|
|
121
|
+
- Report: added tokens (in Figma but not code), removed tokens (in code but not Figma), changed values
|
|
122
|
+
- Output as a structured diff report or GitHub PR comment
|
|
123
|
+
|
|
124
|
+
**Webhook setup** (if webhook trigger):
|
|
125
|
+
- Listen for `LIBRARY_PUBLISH` event type
|
|
126
|
+
- Verify passcode from webhook payload (`passcode` field must match configured secret)
|
|
127
|
+
- Debounce: if multiple publishes arrive within 30 seconds, process only the latest
|
|
128
|
+
- Retry handling: Figma retries failed webhook deliveries, so handlers must be idempotent
|
|
129
|
+
|
|
130
|
+
**Fallback strategy** (when Variables API unavailable):
|
|
131
|
+
- Traverse file nodes via REST API
|
|
132
|
+
- Collect repeated values across 5 domains (colors, spacing, typography, effects, breakpoints)
|
|
133
|
+
- Promote values used 2+ times to tokens (threshold-based promotion)
|
|
134
|
+
- Apply HSL color classification and spacing base-unit detection for naming
|
|
135
|
+
- Document the difference in output quality between Variables API and fallback paths
|
|
136
|
+
|
|
137
|
+
Present the recommendations and confirm before implementing.
|
|
138
|
+
|
|
139
|
+
### Phase 3 — Implement
|
|
140
|
+
|
|
141
|
+
Generate the token pipeline code.
|
|
142
|
+
|
|
143
|
+
**1. Sync script (main entry point):**
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// scripts/sync-tokens.ts (or src/tokens/sync.ts)
|
|
147
|
+
async function syncTokens(options: SyncOptions): Promise<SyncResult> {
|
|
148
|
+
// 1. Fetch variables from Figma (or fallback to file traversal)
|
|
149
|
+
// 2. Classify collection modes (theme vs breakpoint)
|
|
150
|
+
// 3. Resolve alias chains to terminal values
|
|
151
|
+
// 4. Assign semantic names (preserve Figma paths or apply HSL/scale naming)
|
|
152
|
+
// 5. Render to output formats (CSS, Tailwind, SCSS, JSON)
|
|
153
|
+
// 6. Run drift detection against existing token files
|
|
154
|
+
// 7. Write output files
|
|
155
|
+
// 8. Return sync report (added/changed/removed tokens)
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**2. Variable resolution module:**
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// src/tokens/resolver.ts
|
|
163
|
+
function resolveVariables(
|
|
164
|
+
variables: Variable[],
|
|
165
|
+
collections: VariableCollection[]
|
|
166
|
+
): ResolvedTokenMap {
|
|
167
|
+
// For each variable:
|
|
168
|
+
// - Classify the parent collection's modes
|
|
169
|
+
// - For each mode:
|
|
170
|
+
// - Follow alias chains to terminal value
|
|
171
|
+
// - Convert COLOR values to HSL
|
|
172
|
+
// - Convert FLOAT values to rem (divide by 16)
|
|
173
|
+
// - Determine which modes differ from the default
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- Follow alias chains: if value is `{ type: 'VARIABLE_ALIAS', id: '...' }`, look up the referenced variable and recurse
|
|
178
|
+
- Handle circular alias detection (guard against infinite loops)
|
|
179
|
+
- Classify modes using name heuristics from `knowledge/design-tokens-variables.md`
|
|
180
|
+
|
|
181
|
+
**3. Output renderers:**
|
|
182
|
+
|
|
183
|
+
**CSS renderer:**
|
|
184
|
+
```typescript
|
|
185
|
+
// src/tokens/renderers/css.ts
|
|
186
|
+
function renderCSS(tokens: ResolvedTokenMap): string {
|
|
187
|
+
// :root block with default mode values
|
|
188
|
+
// Theme mode overrides: @media (prefers-color-scheme) + [data-theme]
|
|
189
|
+
// Breakpoint mode overrides: @media (min-width) ascending
|
|
190
|
+
// Only tokens that differ from base mode in overrides
|
|
191
|
+
// HSL format for colors, rem for spacing/typography
|
|
192
|
+
// Comments with original Figma variable paths
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Tailwind renderer:**
|
|
197
|
+
```typescript
|
|
198
|
+
// src/tokens/renderers/tailwind.ts
|
|
199
|
+
function renderTailwind(tokens: ResolvedTokenMap): string {
|
|
200
|
+
// theme.extend configuration
|
|
201
|
+
// All values reference var() — never hardcoded
|
|
202
|
+
// Colors → theme.extend.colors
|
|
203
|
+
// Spacing → theme.extend.spacing
|
|
204
|
+
// Typography → theme.extend.fontFamily, fontSize
|
|
205
|
+
// Effects → theme.extend.borderRadius, boxShadow
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**SCSS renderer:**
|
|
210
|
+
```typescript
|
|
211
|
+
// src/tokens/renderers/scss.ts
|
|
212
|
+
function renderSCSS(tokens: ResolvedTokenMap): string {
|
|
213
|
+
// $variable declarations referencing var() CSS Custom Properties
|
|
214
|
+
// Organized by category with section comments
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**JSON renderer:**
|
|
219
|
+
```typescript
|
|
220
|
+
// src/tokens/renderers/json.ts
|
|
221
|
+
function renderJSON(tokens: ResolvedTokenMap): object {
|
|
222
|
+
// Nested structure preserving collection/group hierarchy
|
|
223
|
+
// Each token: { value, type, description, modes }
|
|
224
|
+
// Compatible with Style Dictionary or Tokens Studio input
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**4. Webhook handler (if webhook trigger):**
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// src/api/webhook.ts (or pages/api/figma-webhook.ts)
|
|
232
|
+
export async function handleWebhook(request: Request): Promise<Response> {
|
|
233
|
+
// 1. Verify passcode matches configured secret
|
|
234
|
+
// 2. Check event_type === 'LIBRARY_PUBLISH'
|
|
235
|
+
// 3. Debounce (skip if another sync started within 30 seconds)
|
|
236
|
+
// 4. Extract file_key from payload
|
|
237
|
+
// 5. Call syncTokens({ fileKey, ... })
|
|
238
|
+
// 6. Return 200 (Figma expects quick response)
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
- Passcode verification: compare `request.body.passcode` against environment variable
|
|
243
|
+
- Idempotent: safe to process the same event multiple times
|
|
244
|
+
- Quick response: return 200 immediately, process sync asynchronously if needed
|
|
245
|
+
|
|
246
|
+
**5. Drift detection module:**
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// src/tokens/drift.ts
|
|
250
|
+
function detectDrift(
|
|
251
|
+
currentTokens: ResolvedTokenMap,
|
|
252
|
+
existingFile: string
|
|
253
|
+
): DriftReport {
|
|
254
|
+
// Parse existing token file (CSS, JSON, or SCSS)
|
|
255
|
+
// Compare against current Figma tokens
|
|
256
|
+
// Categorize differences: added, removed, changed (with old + new values)
|
|
257
|
+
// Return structured report
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**6. CI/CD integration (if CI/CD trigger):**
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
# .github/workflows/sync-tokens.yml
|
|
265
|
+
name: Sync Design Tokens
|
|
266
|
+
on:
|
|
267
|
+
workflow_dispatch:
|
|
268
|
+
schedule:
|
|
269
|
+
- cron: '0 9 * * 1' # Weekly Monday 9am
|
|
270
|
+
|
|
271
|
+
jobs:
|
|
272
|
+
sync:
|
|
273
|
+
runs-on: ubuntu-latest
|
|
274
|
+
steps:
|
|
275
|
+
- uses: actions/checkout@v4
|
|
276
|
+
- uses: actions/setup-node@v4
|
|
277
|
+
- run: npm ci
|
|
278
|
+
- run: npm run sync-tokens
|
|
279
|
+
env:
|
|
280
|
+
FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
|
|
281
|
+
FIGMA_FILE_KEY: ${{ vars.FIGMA_FILE_KEY }}
|
|
282
|
+
- uses: peter-evans/create-pull-request@v6
|
|
283
|
+
with:
|
|
284
|
+
title: 'Update design tokens from Figma'
|
|
285
|
+
body: 'Automated token sync from Figma Variables'
|
|
286
|
+
branch: tokens/auto-sync
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Phase 4 — Validate
|
|
290
|
+
|
|
291
|
+
Verify the token pipeline produces correct output.
|
|
292
|
+
|
|
293
|
+
**Variable resolution:**
|
|
294
|
+
- [ ] Alias chains fully resolved to terminal values (no unresolved aliases)
|
|
295
|
+
- [ ] Circular alias detection prevents infinite loops
|
|
296
|
+
- [ ] All modes for each collection are processed
|
|
297
|
+
- [ ] Mode classification correct (theme vs breakpoint vs unknown)
|
|
298
|
+
- [ ] Default mode identified correctly (Light for themes, Mobile for breakpoints)
|
|
299
|
+
|
|
300
|
+
**CSS output:**
|
|
301
|
+
- [ ] Theme overrides use BOTH `@media (prefers-color-scheme)` AND `[data-theme]` selectors
|
|
302
|
+
- [ ] Breakpoint overrides use `@media (min-width)` in ascending mobile-first order
|
|
303
|
+
- [ ] Only tokens with differing values appear in mode overrides
|
|
304
|
+
- [ ] Colors in HSL format
|
|
305
|
+
- [ ] Spacing and font sizes in rem units (with px comments)
|
|
306
|
+
- [ ] Comments show original Figma variable paths
|
|
307
|
+
|
|
308
|
+
**Tailwind output:**
|
|
309
|
+
- [ ] All values reference `var()` — no hardcoded values
|
|
310
|
+
- [ ] Token categories map to correct Tailwind theme keys
|
|
311
|
+
- [ ] Config is a valid `theme.extend` snippet (not a full config replacement)
|
|
312
|
+
|
|
313
|
+
**Pipeline integrity:**
|
|
314
|
+
- [ ] Auth scope includes `file_variables:read` (for Variables API path)
|
|
315
|
+
- [ ] Fallback path works when Variables API returns 403 (non-Enterprise)
|
|
316
|
+
- [ ] Webhook passcode verification implemented (if webhook trigger)
|
|
317
|
+
- [ ] Drift detection correctly identifies added/removed/changed tokens
|
|
318
|
+
- [ ] Output files are deterministic (same input produces same output)
|
|
319
|
+
|
|
320
|
+
## Output
|
|
321
|
+
|
|
322
|
+
Generate the token pipeline files:
|
|
323
|
+
|
|
324
|
+
### Core Files
|
|
325
|
+
|
|
326
|
+
- **`scripts/sync-tokens.ts`** (or `src/tokens/sync.ts`) — Main sync entry point
|
|
327
|
+
- **`src/tokens/resolver.ts`** — Variable resolution with alias chain following
|
|
328
|
+
- **`src/tokens/classifier.ts`** — Mode classification (theme vs breakpoint)
|
|
329
|
+
- **`src/tokens/types.ts`** — Token types, resolved token map, sync options
|
|
330
|
+
|
|
331
|
+
### Renderer Files
|
|
332
|
+
|
|
333
|
+
- **`src/tokens/renderers/css.ts`** — CSS Custom Properties with mode overrides
|
|
334
|
+
- **`src/tokens/renderers/tailwind.ts`** — Tailwind theme.extend config
|
|
335
|
+
- **`src/tokens/renderers/scss.ts`** — SCSS variables (if requested)
|
|
336
|
+
- **`src/tokens/renderers/json.ts`** — JSON token structure (if requested)
|
|
337
|
+
|
|
338
|
+
### Trigger Files (based on selected trigger)
|
|
339
|
+
|
|
340
|
+
- **`src/api/webhook.ts`** — Webhook handler (if webhook trigger)
|
|
341
|
+
- **`.github/workflows/sync-tokens.yml`** — GitHub Actions workflow (if CI/CD trigger)
|
|
342
|
+
- **`scripts/sync-tokens.ts`** — CLI script with argument parsing (if CLI trigger)
|
|
343
|
+
|
|
344
|
+
### Supporting Files
|
|
345
|
+
|
|
346
|
+
- **`src/tokens/drift.ts`** — Drift detection module
|
|
347
|
+
- **Generated `tokens.css`** — Example output showing expected format
|
|
348
|
+
|
|
349
|
+
### Output Checklist
|
|
350
|
+
|
|
351
|
+
Before returning the pipeline code, verify:
|
|
352
|
+
|
|
353
|
+
- [ ] Correct auth scope for Variables API (`file_variables:read`)
|
|
354
|
+
- [ ] Alias chains fully resolved with circular reference protection
|
|
355
|
+
- [ ] Modes classified correctly (theme vs breakpoint)
|
|
356
|
+
- [ ] HSL format for colors, rem units for spacing
|
|
357
|
+
- [ ] Theme overrides render both `@media (prefers-color-scheme)` and `[data-theme]`
|
|
358
|
+
- [ ] Breakpoint overrides render mobile-first ascending `@media (min-width)`
|
|
359
|
+
- [ ] Tailwind config uses `var()` references (no hardcoded values)
|
|
360
|
+
- [ ] Webhook handler verifies passcode (if webhook trigger)
|
|
361
|
+
- [ ] Fallback path documented and functional for non-Enterprise users
|
|
362
|
+
- [ ] Drift detection identifies added/removed/changed tokens
|
|
363
|
+
- [ ] Pipeline output is deterministic (same input → same output)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ref-html
|
|
3
|
+
description: "Reference: Generate semantic HTML5 and layered CSS from Figma node data. Use this skill when the user has Figma design data and needs vanilla HTML + CSS output (no React, no JSX, no TypeScript). Ideal for static sites, email templates, prototypes, or framework-agnostic code."
|
|
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
|
+
@knowledge/design-tokens.md
|
|
13
|
+
|
|
14
|
+
## Objective
|
|
15
|
+
|
|
16
|
+
Generate semantic HTML5 markup and layered CSS from Figma node data. The output is framework-agnostic: a standalone `.html` file and a companion `.css` file using the three-layer CSS architecture (Tailwind utilities for layout, CSS Custom Properties for design tokens, and component-scoped classes for visual skin). No React, JSX, or TypeScript is involved.
|
|
17
|
+
|
|
18
|
+
## Input
|
|
19
|
+
|
|
20
|
+
The user provides Figma design data as `$ARGUMENTS`. This may be:
|
|
21
|
+
|
|
22
|
+
- Raw Figma REST API JSON (node tree with children, fills, strokes, effects, text properties)
|
|
23
|
+
- Extracted/summarized node properties
|
|
24
|
+
- A description of the Figma component or page (layer names, layout, colors, typography)
|
|
25
|
+
- A Figma file/node URL (use the REST API knowledge to fetch data if needed)
|
|
26
|
+
|
|
27
|
+
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.
|
|
28
|
+
|
|
29
|
+
## Process
|
|
30
|
+
|
|
31
|
+
Follow these steps in order. Each step references the relevant knowledge module for detailed mapping rules.
|
|
32
|
+
|
|
33
|
+
### Step 1: Analyze Node Tree Structure
|
|
34
|
+
|
|
35
|
+
Identify the component boundary and internal hierarchy:
|
|
36
|
+
|
|
37
|
+
- The root node is the top-level container.
|
|
38
|
+
- Map each child node to its role: structural container, text element, image, icon/vector, interactive element.
|
|
39
|
+
- Identify repeated patterns that could use consistent class naming.
|
|
40
|
+
- Note variants or states that may need CSS modifier classes.
|
|
41
|
+
|
|
42
|
+
### Step 2: Determine Semantic HTML5 Elements
|
|
43
|
+
|
|
44
|
+
Consult `knowledge/design-to-code-semantic.md`:
|
|
45
|
+
|
|
46
|
+
- Match layer names against semantic tag heuristics:
|
|
47
|
+
- **Structural landmarks**: `<header>`, `<nav>`, `<main>`, `<aside>`, `<section>`, `<article>`, `<footer>`
|
|
48
|
+
- **Headings**: `<h1>` through `<h6>` based on name and font size heuristics
|
|
49
|
+
- **Text**: `<p>`, `<span>`, `<blockquote>`, `<figcaption>`
|
|
50
|
+
- **Interactive**: `<button>`, `<a>`, `<input>`, `<form>`, `<select>`, `<label>`
|
|
51
|
+
- **Media**: `<img>`, `<picture>`, `<figure>`, `<svg>`
|
|
52
|
+
- **Lists**: `<ul>`, `<ol>`, `<li>` when repeated children are detected
|
|
53
|
+
- Enforce heading hierarchy: single `<h1>`, sequential levels, no headings inside buttons or links.
|
|
54
|
+
- Default to `<div>` only when no semantic match is found.
|
|
55
|
+
|
|
56
|
+
### Step 3: Extract Layout Properties
|
|
57
|
+
|
|
58
|
+
Consult `knowledge/design-to-code-layout.md`:
|
|
59
|
+
|
|
60
|
+
- For Auto Layout containers: map `layoutMode`, alignment, gap, padding, wrap, constraints.
|
|
61
|
+
- For each child: determine sizing mode on primary and counter axes.
|
|
62
|
+
- **CRITICAL**: FILL on primary axis requires BOTH `flex-grow: 1` AND `flex-basis: 0`.
|
|
63
|
+
- FILL on counter axis with max constraint uses `width: 100%`/`height: 100%`, not `align-self: stretch`.
|
|
64
|
+
- Handle absolute children with `position: relative` on parent and constraint-based offsets on child.
|
|
65
|
+
- For GROUP/legacy frames: absolute positioning with coordinate adjustments.
|
|
66
|
+
|
|
67
|
+
### Step 4: Extract Visual Properties
|
|
68
|
+
|
|
69
|
+
Consult `knowledge/design-to-code-visual.md`:
|
|
70
|
+
|
|
71
|
+
- **Fills**: solid colors -> `background-color`, gradients -> `background-image`, images -> handled in Step 6.
|
|
72
|
+
- **Strokes**: INSIDE alignment -> `box-shadow: inset 0 0 0 {width}px {color}` (NOT `border`). CENTER/OUTSIDE -> standard `border` or `outline`.
|
|
73
|
+
- **Effects**: drop shadows -> `box-shadow`, inner shadows -> `box-shadow: inset`, layer blur -> `filter: blur()`, background blur -> `backdrop-filter: blur()`.
|
|
74
|
+
- **Corner radius**: uniform -> `border-radius`, per-corner -> `border-radius: TL TR BR BL` with shorthand optimization.
|
|
75
|
+
- **Opacity**: node-level -> CSS `opacity`, fill-level -> embedded in color alpha. Never double-apply.
|
|
76
|
+
- **Gradients**: convert angle with `90 - figmaAngle` for CSS. Map gradient stops with position percentages.
|
|
77
|
+
- **Variable bindings**: resolve to `var(--token-name)` with pixel fallbacks for external library variables.
|
|
78
|
+
|
|
79
|
+
### Step 5: Extract Typography
|
|
80
|
+
|
|
81
|
+
Consult `knowledge/design-to-code-typography.md`:
|
|
82
|
+
|
|
83
|
+
- Map font family, weight, size, and style.
|
|
84
|
+
- **Line height**: ALWAYS use unitless ratio (`lineHeightPx / fontSize`). Never use px or % for line-height.
|
|
85
|
+
- Letter spacing: convert from Figma percentage to CSS `em` value.
|
|
86
|
+
- Text decoration, text transform, text alignment.
|
|
87
|
+
- Handle styled segments (mixed fonts/weights/colors within one text node) as nested `<span>` elements.
|
|
88
|
+
- Text auto-resize modes interact with layout sizing -- resolve the interaction.
|
|
89
|
+
|
|
90
|
+
### Step 6: Handle Assets
|
|
91
|
+
|
|
92
|
+
Consult `knowledge/design-to-code-assets.md`:
|
|
93
|
+
|
|
94
|
+
- **Vector containers** (nodes with only vector/boolean children and no Auto Layout): export as inline SVG or reference SVG file.
|
|
95
|
+
- **Images**: use `<img>` with descriptive `alt` text derived from layer name. Specify `srcset` at **2x minimum** for retina displays.
|
|
96
|
+
- **Decision tree**: If the vector is simple and needs color control -> inline SVG. If complex or decorative -> `<img src="asset.svg">`.
|
|
97
|
+
- Deduplicate identical images (same `imageHash`).
|
|
98
|
+
|
|
99
|
+
### Step 7: Extract Design Tokens
|
|
100
|
+
|
|
101
|
+
Consult `knowledge/design-tokens.md`:
|
|
102
|
+
|
|
103
|
+
- Collect repeated values (colors, spacing, font sizes, radii, shadows) across the node tree.
|
|
104
|
+
- Values used 2+ times are promoted to CSS Custom Properties.
|
|
105
|
+
- Apply semantic naming: HSL hue classification for colors, grid-based scale names for spacing.
|
|
106
|
+
- Figma Variable bindings take priority over auto-detected tokens.
|
|
107
|
+
- Token extraction priority: Variables API > styles > file traversal > Plugin API.
|
|
108
|
+
|
|
109
|
+
### Step 8: Generate Layered CSS
|
|
110
|
+
|
|
111
|
+
Consult `knowledge/css-strategy.md`:
|
|
112
|
+
|
|
113
|
+
Structure the CSS output with clear layer separation:
|
|
114
|
+
|
|
115
|
+
**Layer 1 -- Tailwind Utilities (layout bones):**
|
|
116
|
+
Applied as utility classes directly in the HTML `class` attribute:
|
|
117
|
+
- Flexbox: `flex`, `flex-row`, `flex-col`, `items-center`, `justify-between`
|
|
118
|
+
- Spacing: `gap-4`, `p-6`, `px-4`, `py-2`
|
|
119
|
+
- Sizing: `w-full`, `h-auto`, `max-w-lg`, `flex-1`
|
|
120
|
+
- Positioning: `relative`, `absolute`, `top-0`, `right-0`
|
|
121
|
+
- Responsive: `md:flex-row`, `lg:gap-8`
|
|
122
|
+
|
|
123
|
+
**Layer 2 -- CSS Custom Properties (design tokens):**
|
|
124
|
+
Defined in a `:root` block at the top of the CSS file:
|
|
125
|
+
```css
|
|
126
|
+
:root {
|
|
127
|
+
/* Colors */
|
|
128
|
+
--color-primary: #2563eb;
|
|
129
|
+
--color-surface: #ffffff;
|
|
130
|
+
--color-text-primary: #111827;
|
|
131
|
+
--color-border: #e5e7eb;
|
|
132
|
+
|
|
133
|
+
/* Typography */
|
|
134
|
+
--font-heading: 'Instrument Sans', sans-serif;
|
|
135
|
+
--font-body: 'Inter', sans-serif;
|
|
136
|
+
--font-size-xl: 1.5rem;
|
|
137
|
+
--font-size-base: 1rem;
|
|
138
|
+
|
|
139
|
+
/* Spacing */
|
|
140
|
+
--spacing-sm: 0.5rem;
|
|
141
|
+
--spacing-md: 1rem;
|
|
142
|
+
--spacing-lg: 1.5rem;
|
|
143
|
+
|
|
144
|
+
/* Effects */
|
|
145
|
+
--radius-md: 0.5rem;
|
|
146
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Layer 3 -- Component Classes (visual skin):**
|
|
151
|
+
BEM-named classes for component-specific visual styles:
|
|
152
|
+
```css
|
|
153
|
+
.card {
|
|
154
|
+
background-color: var(--color-surface);
|
|
155
|
+
box-shadow: inset 0 0 0 1px var(--color-border); /* INSIDE stroke */
|
|
156
|
+
border-radius: var(--radius-md);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.card__title {
|
|
160
|
+
color: var(--color-text-primary);
|
|
161
|
+
font-family: var(--font-heading);
|
|
162
|
+
font-size: var(--font-size-xl);
|
|
163
|
+
line-height: 1.3; /* unitless: lineHeightPx / fontSize */
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Step 9: Generate BEM Class Names
|
|
168
|
+
|
|
169
|
+
Consult `knowledge/design-to-code-semantic.md`:
|
|
170
|
+
|
|
171
|
+
- Block name from the root component (kebab-case from Figma layer name).
|
|
172
|
+
- Element names with double underscore: `block__element`.
|
|
173
|
+
- **NEVER nest deeper than one level**: `block__element` is valid, `block__element__sub` is NOT. Flatten to `block__sub` or use a modifier.
|
|
174
|
+
- Modifier with double dash: `block__element--modifier`.
|
|
175
|
+
- Deduplicate class names within the component tree.
|
|
176
|
+
|
|
177
|
+
### Step 10: Add ARIA and Accessibility
|
|
178
|
+
|
|
179
|
+
- `alt` attribute on every `<img>` (descriptive for content images, empty `alt=""` for decorative).
|
|
180
|
+
- `aria-label` on interactive elements without visible text labels.
|
|
181
|
+
- `role` attribute where semantic HTML alone is insufficient.
|
|
182
|
+
- `aria-hidden="true"` on decorative SVGs and icons.
|
|
183
|
+
- Keyboard-accessible interactive elements (buttons, links use native elements; custom controls get `tabindex` and key handlers).
|
|
184
|
+
|
|
185
|
+
### Step 11: Handle Responsive Breakpoints
|
|
186
|
+
|
|
187
|
+
If the Figma data includes multiple frames for breakpoints (detected via `#mobile`/`#tablet`/`#desktop` suffix or variant properties):
|
|
188
|
+
|
|
189
|
+
- Smallest frame provides base styles (no media query).
|
|
190
|
+
- Larger frames contribute override styles in `@media (min-width: ...)` blocks.
|
|
191
|
+
- Standard breakpoints: mobile (base), tablet (`768px`), desktop (`1024px`).
|
|
192
|
+
- Only emit properties that differ from the base.
|
|
193
|
+
- Reset layout properties (`align-self: auto`, `flex-grow: 0`, `flex-shrink: 1`, `flex-basis: auto`) that exist in base but not in larger breakpoints.
|
|
194
|
+
- Transform fixed pixel widths in responsive overrides to `width: 100%; max-width: Npx`.
|
|
195
|
+
|
|
196
|
+
## Output
|
|
197
|
+
|
|
198
|
+
Generate two files:
|
|
199
|
+
|
|
200
|
+
### 1. `component-name.html`
|
|
201
|
+
|
|
202
|
+
Semantic HTML5 with Tailwind utility classes for layout and BEM classes for visual skin:
|
|
203
|
+
|
|
204
|
+
```html
|
|
205
|
+
<section class="flex flex-col gap-4 p-6 card">
|
|
206
|
+
<h2 class="card__title">Card Heading</h2>
|
|
207
|
+
<p class="card__description">
|
|
208
|
+
Description text with <span class="card__highlight">highlighted</span> segments.
|
|
209
|
+
</p>
|
|
210
|
+
<figure class="card__media">
|
|
211
|
+
<img
|
|
212
|
+
src="hero.jpg"
|
|
213
|
+
srcset="hero.jpg 1x, hero@2x.jpg 2x"
|
|
214
|
+
alt="Product showcase"
|
|
215
|
+
class="w-full h-auto card__image"
|
|
216
|
+
>
|
|
217
|
+
</figure>
|
|
218
|
+
<button class="flex items-center justify-center card__action" type="button">
|
|
219
|
+
Get Started
|
|
220
|
+
</button>
|
|
221
|
+
</section>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 2. `component-name.css`
|
|
225
|
+
|
|
226
|
+
Layered CSS with clear section comments:
|
|
227
|
+
|
|
228
|
+
```css
|
|
229
|
+
/* ========================================
|
|
230
|
+
Design Tokens (Layer 2)
|
|
231
|
+
======================================== */
|
|
232
|
+
:root {
|
|
233
|
+
--color-primary: #2563eb;
|
|
234
|
+
--color-surface: #ffffff;
|
|
235
|
+
/* ... */
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* ========================================
|
|
239
|
+
Component Styles (Layer 3)
|
|
240
|
+
======================================== */
|
|
241
|
+
.card {
|
|
242
|
+
background-color: var(--color-surface);
|
|
243
|
+
border-radius: var(--radius-md);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.card__title {
|
|
247
|
+
color: var(--color-text-primary);
|
|
248
|
+
font-family: var(--font-heading);
|
|
249
|
+
font-size: var(--font-size-xl);
|
|
250
|
+
line-height: 1.3;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* ========================================
|
|
254
|
+
Responsive Overrides
|
|
255
|
+
======================================== */
|
|
256
|
+
@media (min-width: 768px) {
|
|
257
|
+
/* Only changed properties */
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@media (min-width: 1024px) {
|
|
261
|
+
/* Only changed properties */
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Key Differences from generate-react
|
|
266
|
+
|
|
267
|
+
This skill generates **vanilla HTML + CSS**:
|
|
268
|
+
- No JSX syntax (uses standard HTML attributes: `class` not `className`, `for` not `htmlFor`)
|
|
269
|
+
- No TypeScript interfaces or prop types
|
|
270
|
+
- No React imports, hooks, or component functions
|
|
271
|
+
- No CSS Modules import (classes are global BEM names, not hashed)
|
|
272
|
+
- Design tokens are defined inline in the CSS file's `:root` block
|
|
273
|
+
- Suitable for static sites, email templates, CMS integration, or any non-React context
|
|
274
|
+
|
|
275
|
+
### Critical Rules Checklist
|
|
276
|
+
|
|
277
|
+
Before returning the output, verify:
|
|
278
|
+
|
|
279
|
+
- [ ] INSIDE strokes use `box-shadow: inset`, not `border`
|
|
280
|
+
- [ ] Gradient angles use `90 - figmaAngle` conversion
|
|
281
|
+
- [ ] Line heights are unitless ratios (`lineHeightPx / fontSize`)
|
|
282
|
+
- [ ] Images reference 2x assets for retina (`srcset` or `@2x` naming)
|
|
283
|
+
- [ ] BEM nesting is flat: never `block__element__sub`
|
|
284
|
+
- [ ] FILL on primary axis has BOTH `flex-grow: 1` AND `flex-basis: 0`
|
|
285
|
+
- [ ] CSS has clear layer separation (tokens in `:root`, visual skin in BEM classes)
|
|
286
|
+
- [ ] No hardcoded color values in component classes -- use `var()` for tokens
|
|
287
|
+
- [ ] Semantic HTML5 tags used where layer names match heuristics
|
|
288
|
+
- [ ] ARIA attributes present on interactive and image elements
|
|
289
|
+
- [ ] Uses HTML attributes (`class`, `for`) not JSX attributes (`className`, `htmlFor`)
|
|
290
|
+
- [ ] Responsive overrides include layout property resets where needed
|