- name
- generating-figma-design
- description
- Use when the user requests to design, create, build, generate, or make a new Figma component or screen — including phrases like "make a button", "design a settings page", "build a new card", "generate X". Produces a CSpec, compiles it to a scene graph, executes it in Figma via MCP, and verifies the output.
{{ACTIVE_RULES}}
# Generating Figma Design
## Overview
Unified `make` flow: CSpec → scene graph → compiler → Figma execute → screenshot → verify. Replaces the legacy `spec → design → review` cycle with a single compiler-driven action. All tokens resolve against the knowledge base; all Figma API rules are enforced by the compiler.
## When to Use
Invoke when the user:
- says `make`, `design`, `create`, `build`, `generate`, or asks for a "new component" / "new screen"
- has already run `setup` (knowledge base exists)
- has an MCP transport available (console or official)
Do NOT use if:
- the user is adjusting an existing design that is already in Figma — use `learning-from-corrections` instead
- the user is archiving or shipping — use `shipping-and-archiving`
- the knowledge base is missing — run `extracting-design-system` first
## Procedure
**Before starting, load:**
- `references/compiler-reference.md` (repo-root) — scene graph JSON format and rules
- `references/transport-adapter.md` (repo-root) — transport detection and tool mapping
## Prerequisites
- Knowledge base exists (registries populated) — if not: "Run `setup` first"
- MCP transport available (see `references/transport-adapter.md` (repo-root) Section A)
---
## Phase A — Context (target: 30s)
### A1. Detect transport
Read `references/transport-adapter.md` (repo-root) Section A. Determine console vs official transport.
```
Console: figma_get_status() -> setup.valid: true
Official: whoami() + test use_figma call
```
Report:
```
Transport: {console | official}
```
### A2. Load registry index
Load the **summary** of available DS components — names and types only, not full registry data:
- `registries/components.json` — extract component names, variant property names, and keys
- `registries/variables.json` — extract variable name paths (for token reference validation)
- `registries/text-styles.json` — extract style names (for `$text/` reference validation)
- `registries/icons.json` — extract icon names (if file exists)
- `registries/logos.json` — extract logo names (if file exists)
**Do NOT load guides, patterns, or figma-api-rules.md.** The compiler handles all Figma API rules.
### A2b. Check KB freshness (drift guard)
The compiler guarantees every `$token` resolves against the KB — but NOT that the
KB still matches the live Figma library. A token removed/renamed in Figma but
still present in a stale KB will **compile fine and then fail at execute time**.
This check is a runtime guard; it deliberately lives here (not in the compiler),
because a time-based check would break the compiler's determinism law.
Read `generatedAt` from each loaded registry and compare to today's date:
- **≤ 7 days** → fresh, no warning.
- **> 7 days** → surface: "⚠ KB last synced {N}d ago — the refresh cron may not be
running; tokens/components may have drifted from live Figma."
- **> 30 days, or `generatedAt` missing** → STRONGLY warn and recommend re-running
`setup` (or the KB cron) before generating: resolved tokens that were removed or
renamed in Figma will pass compile but fail on execute.
Carry the KB age into the C4 plan ("KB age: {N}d"). This does not block generation
— it informs the user before they commit to a `make`.
### A3. Load learnings
Load `knowledge-base/learnings.json` (skip if file doesn't exist).
Filter by context matching the user's description:
- Include all **global** learnings (`scope: "global"`)
- Include **contextual** learnings where `context.screenType` or `context.component` matches
### A4. Load recipe index
Load `knowledge-base/recipes/_index.json` (skip if file doesn't exist — no recipes yet).
---
## Phase B — Recipe Match
### B1. Extract archetype
From the user's description, identify:
- **Mode**: component or screen (ask if ambiguous)
- **Archetype**: screen type (settings, dashboard, form, detail, list...) or component type
- **Keywords**: key terms from the description (sidebar, form, table, cards, navigation...)
### B2. Score against recipe index
For each recipe in `_index.json`, compute a match score:
| Dimension | Weight | Method |
|-----------|--------|--------|
| Archetype match | 0.40 | Exact match on `meta.archetype` vs extracted archetype |
| Tag overlap | 0.25 | Jaccard similarity between recipe `tags` and extracted keywords |
| Structural match | 0.20 | Zone count, component types, parameter compatibility |
| Confidence | 0.15 | Recipe's current confidence score |
### B3. Apply match result
| Score | Action |
|-------|--------|
| **>= 0.85** | **Exact match.** Load recipe file, pre-fill CSpec from recipe parameters. Report: "Recipe match: {name} (score: {score}). Using as template." |
| **0.60 -- 0.84** | **Partial match.** Load recipe as scaffold. Report: "Partial recipe match: {name} (score: {score}). Using as starting point, will supplement missing zones." |
| **< 0.60** | **No match.** Proceed from scratch. Report: "No recipe match. Generating from scratch." |
---
## Phase C — CSpec (target: 30-60s)
### C0. Decompose into sections, then classify each (design intelligence)
Before writing any node, break the request into its major sections, then decide
HOW each section is built. This is where DS fidelity and composition are won.
**1. Decompose** the request into major sections, top to bottom:
- Screen → e.g. Header, Hero, Content panels, Footer.
- Modal / dialog → Title bar, Body / form sections, Action bar.
- Drawer / sidebar / panel → Navigation, Content area, Footer actions.
- Component → its part structure (container, leading, label, trailing, states).
**2. Classify each section into exactly one bucket** — this decides INSTANCE vs build:
- `exact` — a published DS component (or one of its variants) covers the whole
section → one INSTANCE node; set its `variant` + `properties`. **Preferred.**
- `compose` — no single component fits, but the section is built from DS pieces
(component INSTANCEs inside tokenized FRAMEs) → never raw shapes with hardcoded
values.
- `new` — no DS component covers it and it is not composable from existing ones
→ hand to C3 (`new_components`); the component is built first.
Default preference: `exact` > `compose` > `new`. A raw RECTANGLE/ELLIPSE whose
name matches a DS component is a red flag — the compiler warns (Rule 18); use an
INSTANCE instead.
Report the section map before C1:
SECTIONS:
{Section} → {exact: Component(variant) | compose | new: name}
### C1. Generate CSpec YAML
Choose the appropriate template:
- **Screen mode**: `skills/generating-figma-design/references/templates/screen-cspec.yaml`
- **Component mode**: `skills/generating-figma-design/references/templates/component-cspec.yaml`
Fill the CSpec based on:
- User description (intent, sections, components)
- Recipe template (if match found in Phase B)
- Registry data (available components, tokens, text styles)
**If a recipe was matched (>= 0.60):**
- Start from the recipe's `graph` structure
- Replace `{{ param }}` placeholders with values from the user's description
- Resolve `@lookup:ComponentName` references against the live registry
- Add/remove zones as needed for the specific request
**If no recipe match (from scratch):**
- Build the layout tree node by node using the CSpec template structure
- Reference DS components as INSTANCE nodes (by name — the compiler resolves keys)
- Use `$token` references for all spacing, colors, radius, typography — and pick
the **most specific token that carries intent**. When collections alias each
other (primitive ← semantic ← component), reference the most specific one:
prefer a semantic token (`$color/bg/...`) over a raw palette value, and a
component-level token over a semantic one when it exists. Never reference a
primitive when a semantic/component token expresses the same intent — a
primitive ignores theme/mode switches.
- Choose tokens by **intent, not by resolved value**. A token's value depends on
the active mode (light/dark); selecting by the value you see in the default
mode silently breaks the other modes.
- Use REPEAT nodes for lists/grids with repeated structure
### C2. Apply learnings
Integrate learnings from A3 into the CSpec:
- **Global learnings** (`scope: "global"`): auto-apply — replace default token values with learned preferences
- **Contextual learnings** (`scope: "contextual"`): suggest — note in comments, apply if context matches
Report applied learnings:
```
LEARNINGS APPLIED ({n}):
- {rule} (signals: {n}, scope: {scope})
- {rule} (signals: {n}, scope: {scope})
```
### C3. Detect new DS components (screen mode only)
Take the sections C0 classified as `new` (the patterns no existing DS component
covers and that are not composable from existing ones). Add each to the
`new_components` section of the CSpec. Sections classified `exact` become INSTANCE
nodes; sections classified `compose` become FRAMEs of INSTANCEs — neither reaches
this step.
**If new components are identified:**
```
{N} new DS component(s) needed:
1. {name} — {description}
These must be created before this screen. Starting with: {name}
```
-> Trigger a nested `make` flow for each new component. When all are done, resume the screen make.
### C4. Present plan to user
Show a **readable summary** of the CSpec (NOT raw YAML). Format as a plan tree:
```
PLAN: {name}
Mode: {screen | component}
Canvas: {1440px (web) | 390px (mobile) | 1024px (tablet)}
Recipe: {recipe name or "from scratch"}
Learnings: {n} applied
KB age: {N}d{ ⚠ stale — consider `setup` if > 30d}
STRUCTURE:
Root ({width}x{height}, {layout direction})
+-- {Zone 1} ({width}, {layout})
| +-- {Component} ({variant})
| +-- {Component} ({variant})
+-- {Zone 2} ({fillH}, {layout})
| +-- {Section 1}
| | +-- {Component} ({variant})
| +-- {Section 2}
| | +-- REPEAT x{n}: {Component}
DS COMPONENTS: {n} instances
TOKENS: {n} references
STATES: {list or "populated only"}
Generate this design?
```
### C5. User validates
Wait for explicit user confirmation. The user can:
- **Approve** -> proceed to Phase D
- **Adjust** -> modify the CSpec based on feedback, re-present plan
- **Cancel** -> abort
### C6. Save CSpec
Save the CSpec YAML to `specs/active/{name}.cspec.yaml`.
---
## Phase D — Compile + Execute
### D1. Convert CSpec to scene graph JSON
Transform the CSpec's `layout` tree into the scene graph JSON format defined in `references/compiler-reference.md` (repo-root):
- CSpec `layout` nodes map directly to scene graph `nodes`
- All `$token` references are preserved (the compiler resolves them)
- Component names in INSTANCE nodes are preserved (the compiler resolves keys)
- REPEAT and CONDITIONAL nodes pass through to the compiler
Add the root wrapper:
```json
{
"version": "3.0",
"metadata": {
"name": "{CSpec meta.name}",
"width": {CSpec meta.width},
"height": {CSpec meta.height},
"transport": "{detected transport}",
"fileKey": "{user's file key}"
},
"fonts": [ ... ],
"nodes": [ ... ]
}
```
**Font list:** Collect all unique font families and styles referenced by `$text/` tokens in the scene graph. Cross-reference against `registries/text-styles.json` to get actual font family + style values.
### D2. Write scene graph to temp file
```bash
# Write JSON to temp file
cat > /tmp/bridge-scene-{name}.json << 'EOF'
{ ... scene graph JSON ... }
EOF
```
### D3. Run the compiler
```bash
bridge-ds compile \
--input /tmp/bridge-scene-{name}.json \
--kb {kb-path} \
--transport {console|official}
```
The compiler outputs a JSON array of `{ id, code, description }` chunks to stdout.
### D4. Handle compiler errors
If the compiler returns errors to stderr:
1. Read the error messages and suggestions
2. Fix the scene graph JSON based on the suggestions (see `references/compiler-reference.md` (repo-root) Section 8 for common errors)
3. Re-write the temp file and re-run the compiler
4. **Maximum 3 attempts.** If still failing after 3, report errors to user and ask for guidance.
### D5. Execute chunks in Figma
For each output chunk from the compiler:
**Console transport:**
```
figma_execute({ code: "{chunk.code}" })
```
**Official transport:**
```
use_figma({
fileKey: "{fileKey}",
description: "{chunk.description}",
code: "{chunk.code}"
})
```
Execute chunks sequentially. If a chunk fails:
1. Read the error
2. Report to user
3. Attempt fix if the error is clear (e.g., font not loaded, component not found)
### D6. Take screenshot
Take a screenshot **AFTER the final chunk** (not after each chunk):
```
Console: figma_take_screenshot({ node_id: "{rootNodeId}", file_key: "{fileKey}" })
Official: get_screenshot({ nodeId: "{rootNodeId}", fileKey: "{fileKey}" })
```
### D7. Save snapshot
Save a snapshot of the design's node tree for future `fix` diffing.
Run a node tree extraction script via `figma_execute` (or `use_figma`), using the root node ID from D5.
Save to `specs/active/{name}-snapshot.json`:
```json
{
"meta": {
"spec": "{name}",
"generatedAt": "{ISO timestamp}",
"rootNodeId": "{rootId}",
"fileKey": "{fileKey}",
"recipe": "{recipe ID or null}",
"learningsApplied": ["{learning IDs}"]
},
"tree": { ... extracted node tree ... }
}
```
---
## Phase E — Present
Auf GitHub ansehen