name: dx-figma-extract description: Extract design context, tokens, and screenshots from a Figma URL. Saves figma-extract.md and reference screenshots. Use after requirements phase when a Figma URL is in the story. Trigger on "extract figma", "figma design", "get figma". Do NOT use for general Figma browsing, viewing designs without a story, or when no spec directory exists. when_to_use: "Use after requirements when a Figma URL is available. Trigger on 'extract figma', 'figma design', 'get figma', 'read figma', or when a Figma URL is in the story and design context is needed." argument-hint: "[ADO Work Item ID] [Figma URL] — both optional, any order. Uses most recent story if ID omitted." compatibility: "Requires Figma desktop app with Dev Mode MCP enabled (port 3845). File must be open in Figma." metadata: version: 2.28.0 mcp-server: figma category: design-to-code allowed-tools: ["read", "edit", "search", "write", "agent", "figma/", "playwright/"]
You extract everything needed from a Figma design link — reference code, design tokens, screenshots — so that Figma is never consulted again in downstream steps.
Use ultrathink for node selection logic — matching Figma frame names to story context requires careful reasoning.
1. Parse Arguments & Locate Spec Directory
Parse $ARGUMENTS into two optional parts: an ADO work item ID and a Figma URL. They can appear in any order, or only one, or neither.
Detection rules:
- Figma URL: any token containing
figma.com/— set$FIGMA_URL_ARG - ADO ID: any token that is purely numeric — set
$ADO_ID_ARG - Remaining tokens: ignore (may be noise from slash-command parsing)
Locate spec directory using only the ADO ID (never the Figma URL):
SPEC_DIR=$(bash .ai/lib/dx-common.sh find-spec-dir $ADO_ID_ARG)
If no ADO ID was provided, find-spec-dir returns the most recent spec directory. If the script exits with error, ask the user for the work item ID.
2. Check Existing Output
- Check if
figma-extract.mdexists in the spec directory - If it exists and
raw-story.mdhasn't changed → printfigma-extract.md already up to date — skippingand STOP - If stale → continue (regenerate)
3. Find Figma URL
Priority order:
$FIGMA_URL_ARG(from arguments) — if provided, use it as the Figma URL$SPEC_DIR/raw-story.md— search for URLs matchingfigma.com/design/<fileKey>/<fileName>?node-id=<nodeId>$SPEC_DIR/dor-report.md(Design section) — fallback if raw-story.md has no Figma URL
If no Figma URL found anywhere: Print No Figma URL found in story or arguments — skipping and STOP.
URL Parsing:
- Extract
nodeIdfromnode-id=parameter, convert hyphens to colons (1-2→1:2) - Extract
fileKeyfrom the path segment after/design/(recorded in figma-extract.md for reference) - If URL format is
figma.com/design/:fileKey/branch/:branchKey/:fileName→ usebranchKeyas fileKey
User-provided URL override:
If $FIGMA_URL_ARG was provided AND raw-story.md also contains a Figma URL, record both in figma-extract.md and flag the override:
⚠️ Using user-provided Figma URL (differs from story URL)
Story URL: <url from raw-story.md>
User URL: <url from user>
If raw-story.md has no Figma URL, record the source as "User-provided URL (no story URL)".
4. Gather Story Context
Read these files for component identification (used in node selection and relevance check):
$SPEC_DIR/explain.md— distilled requirements with component names$SPEC_DIR/research.md— codebase findings with component directories
Extract and remember:
- Component names (e.g., "Header", "ProductCard", "hero")
- Variation names (e.g., "brand", "default", "pdp")
- UI element names (e.g., "dropdown", "stepper", "card", "teaser")
- Key terms from the story title and requirements
5. Node Selection
Call get_metadata to understand the node structure:
mcp__plugin_dx-core_figma__get_metadata
nodeId: <nodeId>
clientLanguages: "html,css,javascript"
Analyze the XML response:
Case A — Node is a COMPONENT, INSTANCE, or FRAME (single viewport, not a PAGE):
Use this node directly. Set viewports: [{ name: "default", nodeId: <nodeId> }]. Proceed to Step 6.
Case B — Node is a PAGE or top-level FRAME with many children:
- Parse child frame names from the XML
- First, check for viewport variants (Case C below) among the children
- If no viewport variants found, match against component names from explain.md/research.md:
- Case-insensitive substring match
- Strip common prefixes (e.g., "Desktop/", "Mobile/", "Component/")
- Score by relevance to story context
- High-confidence single match → auto-select, print:
Auto-selected Figma node: "<name>" (ID: <nodeId>) - Multiple candidates → ask the user:
Figma link points to a page with multiple components: 1. <name1> (ID: <id1>) 2. <name2> (ID: <id2>) 3. <name3> (ID: <id3>) Which component(s) should I extract? (numbers, comma-separated) - No match → ask the user with the full list of top-level children
- After selecting a node, check if IT contains viewport variants (Case C). A selected component frame may itself contain Desktop/Mobile children.
Case C — Viewport variants detected:
A node (the linked node itself, or a selected child) contains multiple viewport variants as children. Detect using these heuristics:
- Name-based: Child frame names containing (case-insensitive):
desktop,mobile,tablet,responsive,phone,web, or common width values (1440,1280,1024,768,375,390,414) - Size-based: Two or more sibling frames where one is wide (>900px) and another is narrow (<500px) — check frame width from the XML
widthattribute - Pattern-based: Names like
Component / Desktop,Hero - Mobile,Desktop View,Mobile View,@desktop,@mobile
When viewport variants are detected:
- Print:
Multi-viewport design detected: <list of variant names with dimensions> - Set
viewportslist, e.g.:[{ name: "desktop", nodeId: "123:456", width: 1440 }, { name: "mobile", nodeId: "123:789", width: 375 }] - Sort viewports by width descending (desktop first)
- Proceed to Step 6 which will extract each viewport separately
When NOT viewport variants: Sibling frames that represent different components (e.g., "Header" and "Footer") are NOT viewport variants — they differ in content, not just width. Use name heuristics first; fall back to size comparison only for ambiguous cases.
6. Extract Design Data
For each viewport in the viewports list (or once if single viewport), make three MCP calls. When multiple viewports exist, loop through each and tag all output with the viewport name.
6a. Design Context
mcp__plugin_dx-core_figma__get_design_context
nodeId: <viewport.nodeId>
clientLanguages: "html,css,javascript"
Save: reference code, annotations, design system hints. Tag with viewport name if multi-viewport.
Important: The response contains image/SVG asset URLs served locally by the Figma desktop MCP (e.g., http://localhost:3845/assets/<hash>.png). The PostToolUse hook automatically downloads these to $SPEC_DIR/prototype/assets/. After the hook runs, check $SPEC_DIR/prototype/.figma-asset-manifest.json for the downloaded file paths.
6b. Screenshot
Before calling get_screenshot, write the target path so the PostToolUse hook saves the image there:
Single viewport:
mkdir -p $SPEC_DIR/prototype
echo "$SPEC_DIR/prototype/figma-reference.png" > .ai/.figma-screenshot-target
Multi-viewport:
mkdir -p $SPEC_DIR/prototype
echo "$SPEC_DIR/prototype/figma-reference-<viewport.name>.png" > .ai/.figma-screenshot-target
Example: figma-reference-desktop.png, figma-reference-mobile.png
Then call:
mcp__plugin_dx-core_figma__get_screenshot
nodeId: <viewport.nodeId>
The hook automatically saves the PNG to the target path and reports the location via additionalContext.
Also create a convenience symlink/copy for backward compatibility: copy the desktop (widest) screenshot to figma-reference.png so downstream skills that expect the default filename still work.
6c. Variable Definitions
Only call once (tokens are shared across viewports):
mcp__plugin_dx-core_figma__get_variable_defs
nodeId: <viewport.nodeId> # use the first/desktop viewport
Save: design token definitions (colors, spacing, typography variables).
7. Screenshot Layer Analysis (Design Quality)
This step is mandatory. Consult references/design-quality.md for the full pattern catalog, three-phase analysis process, and output format.
Designers sometimes paste website screenshots as context and overlay new elements on top. This step detects those patterns, classifies each node, and produces a cleaned reference code.
Summary
Phase 1 — Structural detection: Scan the
get_metadataXML andget_design_contextreference code against the pattern catalog inreferences/design-quality.md. Classify each top-level child asdesigned|hybrid|screenshot-context|decoration.Phase 2 — Visual confirmation: Read the Figma screenshot image and cross-reference. For
screenshot-contextnodes, describe what existing UI is visible. Catch any gaps Phase 1 missed.Phase 3 — Cleaned output: Produce the Layer Classification table, Screenshot Regions table, and a cleaned reference code (screenshot layers stripped, real elements preserved).
If ALL nodes are designed (no screenshots detected): print Design quality: clean — no screenshot layers detected and skip to Step 8. Do NOT add the ## Design Quality section to figma-extract.md.
If any screenshots detected: The cleaned reference code replaces the raw code in the ## Reference Code section. Add ## Design Quality section to figma-extract.md (between ## Screenshot and ## Reference Code) with the classification table and screenshot region descriptions.
8. Design-vs-Story Relevance Check
This step is mandatory. Consult references/relevance-check.md for the full scoring algorithm, mismatch report format, and output file conventions. Summary:
- Count keyword matches between story context (Step 4) and Figma design content
- LOW (< 2 matches): warn user, write
figma-mismatch.md, add## Relevance Warningto figma-extract.md - OK (>= 2 matches): continue silently
9. Analyze Dynamic Content & Build Breakpoint Tables
Consult references/dynamic-content.md for detection heuristics and references/breakpoint-tables.md for table format.
9a. Dynamic Content Detection
Scan the design context reference code from Step 6 and identify elements with placeholder content. For each, record which CSS properties are content-dependent. Tag these values with ≈ in all output sections.
9b. Breakpoint CSS Override Tables (multi-viewport only)
When multi-viewport extraction is active, diff the design context across viewports to produce mobile-first CSS override tables:
- Extract element + property + value triples from each viewport's reference code
- Mobile baseline = all mobile triples
- Tablet overrides = only triples where tablet differs from mobile
- Desktop overrides = only triples where desktop differs from tablet
Mark content-dependent values with ≈. Use viewport frame widths as breakpoint boundaries (or project breakpoints from research.md if available).
Skip this step for single-viewport extractions.
10. Write figma-extract.md
Create $SPEC_DIR/prototype/ directory if it doesn't exist.
Read .ai/templates/spec/figma-extract.md.template and follow that structure exactly. The template uses HTML comments as authoring instructions — follow them but do not include them in the output. Key rules:
- Single-viewport: use the single "Reference Code" section, omit per-viewport sections and Breakpoint CSS Overrides
- Multi-viewport: use per-viewport sections (Desktop Variant, Mobile Variant, etc.), include Breakpoint CSS Overrides, omit the single "Reference Code" section
- Dynamic Content Elements is mandatory in both modes — scan reference code for placeholders, tag content-dependent values with ≈
- Breakpoint CSS Overrides is multi-viewport only — diff CSS values across viewports in mobile-first order
- Omit
## Relevance Warningif no mismatch detected - Omit
## Annotations & Constraints(single-viewport) if none found
11. Present Summary
## figma-extract.md created
**Component:** <node name>
**Node ID:** <selectedNodeId>
<if multi-viewport>**Viewports:** <list, e.g. "desktop (1440px), mobile (375px)"></if>
- Reference code: <lines of code extracted> <if multi-viewport>(per viewport)</if>
- Design tokens: <count> variables
- Dynamic content elements: <count> marked with ≈ tolerance
<if multi-viewport>- Breakpoint tables: <count> breakpoints with CSS override diffs</if>
- Screenshots: <if single>prototype/figma-reference.png<else>prototype/figma-reference-desktop.png, prototype/figma-reference-mobile.png</if>
- Assets: <count> download URLs (<count> downloaded locally)
<if screenshots detected>- Design quality: hybrid — <N> screenshot layers stripped, <M> real elements preserved</if>
<if clean design>- Design quality: clean — no screenshot layers</if>
<if mismatch>- ⚠️ Design-story mismatch detected — see figma-mismatch.md</if>
<if url override>- ⚠️ Using user-provided URL (differs from story)</if>
### Next: `/dx-figma-prototype` to generate HTML/CSS prototype, then `/dx-figma-verify` to verify
MCP Fallback & Error Handling
Consult references/mcp-fallback.md for the full fallback strategy and error handling. Key rules:
- Desktop MCP only — never fall back to
mcp__claude_ai_Figma__*(cloud) - Graceful degradation — if one MCP call fails, continue with whatever is available
- Partial extraction is better than no extraction
Success Criteria
-
figma-extract.mdexists in spec directory - ≥1 reference screenshot saved
- Design tokens extracted (colors, spacing, typography)
- Component mapping documented
Rules
- Extract everything — be thorough, this is the only Figma interaction
- Save screenshots as files — not just descriptions, actual image files via the hook
- Download assets — the hook downloads localhost:3845 image URLs from get_design_context
- Smart node selection — use story context to auto-drill-down when possible
- One interruption max — only ask the user if auto-selection fails
- Always check relevance — compare design against story context, warn on mismatch
- Track URL source — record whether URL came from story or user override
- Idempotent — check existing output before re-extracting
- Graceful degradation — partial extraction is better than no extraction