Install
openclaw skills install @elsemk/figma-to-staticConvert Figma design files to pixel-level mobile-first static HTML/CSS pages. Use when: (1) user provides a Figma file link and wants a static web page, (2) user sends design screenshots/assets and says "按设计图还原", (3) user asks to build a landing page from Figma, (4) iterating on Figma-to-code pixel accuracy. Handles: Figma MCP-first extraction (metadata/context/screenshots) with REST API fallback, layered DOM reconstruction (not whole-image paste), visual diff pipeline with region heatmap for quality validation, mobile-first responsive layout. NOT for: React/Vue/SPA frameworks, server-side rendering, interactive JS-heavy pages.
openclaw skills install @elsemk/figma-to-staticanthropic/claude-opus-4-6highWhen handling Claude/Figma MCP authentication, follow these rules with zero improvisation:
code#state) over full callback URL.done / 好了 / 完成 / ok) as invalid auth evidence.In chat/remote/headless environments:
code#state.scripts/extract_auth_url.py; never hand-retype long URLs.scripts/auth_session_guard.py to detect conflicts or stale state.code#state until REPL state is explicitly verified as waiting-for-code.
python3 scripts/claude_repl_state.py --stdin.safeForCodeSubmission=true, lock the auth URL/state and ask the user for code.Stop immediately and explain the issue if any of the following is true:
state does not match the active auth stateWhen an abort condition is met, do not “try one more thing” inside the same flow. Kill or abandon stale session(s), start one clean session, and ask for only one auth artifact.
During auth, report progress in this shape:
Claude 登录 / Figma MCP 配置 / Figma MCP 授权 / MCP 工具验证成功 / 阻塞 / 需用户操作code#state / callback URL / nothingmax-width, background stretches.assets/ css/ html/<img> unless the design element is truly an image (photo/illustration). Text, buttons, status indicators → real DOM. Navigation bars and menus must always be real DOM — they need to align with content width and have interactive states.get_screenshot for visual assets (video covers, banners, illustrations). Use MCP get_design_context for components that need real DOM (nav, menus, footers) — it returns structured data with asset URLs for individual icons/logos.flexbox, grid, margin, padding, and normal document flow. Only use position: absolute as last resort (e.g., decorative badges on cards, small floating labels).<img> must have explicit width/height attributes or CSS aspect-ratio to prevent layout shift (CLS)..block__element--modifier (e.g. .signin-card__label, .hero-topbar__brand). Never use .s1, .btn2, .c-red abbreviations.html/index.html, html/activity.html, html/profile.html, etc.html/index.html).css/styles.css and assets/ directory.feat: add <section-name> section or fix: adjust <section-name> <what>The page is "done" when ALL of the following are met:
Check Figma access in strict priority order (must attempt MCP first):
Priority 1 (required first attempt): Claude CLI + Figma MCP
# Explicit token mode (recommended)
export FIGMA_MCP_TOKEN=...
python3 scripts/fetch_figma_mcp.py --action tools
# OR opt-in read from Claude credential file
python3 scripts/fetch_figma_mcp.py --allow-claude-credentials --action tools
bash scripts/setup_claude_mcp.sh
bash scripts/setup_claude_mcp.sh --start-loginpython3 scripts/auth_session_guard.py --mode claude-loginpython3 scripts/claude_auth_lock.py acquire --session-id <session-id> --auth-url "<authorize-url>"claude REPL session over repeated claude auth login attempts.code#state) first.python3 scripts/claude_repl_state.py --stdinstate=waiting-for-code and safeForCodeSubmission=truehttps://platform.claude.com/oauth/code/callback?code=...&state=...npm install -g @anthropic-ai/claude-codeclaude auth loginclaude, then /login, keep that same REPL session alive, and paste Authentication Code (code#state) when prompted.claude auth login and claude REPL during the same auth attempt.claude mcp add --scope user --transport http figma https://mcp.figma.com/mcpclaude/mcpfigma and complete Authenticate/Connect flowclaude mcp list (expect figma ... Connected)python3 scripts/fetch_figma_mcp.py --allow-claude-credentials --action tools.references/figma-mcp-usage.md for details.Priority 2: Figma REST API (fallback, detailed CSS properties)
curl -s -o /dev/null -w "%{http_code}" \
-H "X-Figma-Token: $FIGMA_TOKEN" \
"https://api.figma.com/v1/me"
python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "NODE1,NODE2" --quota-aware --batch-size 3 --max-retry-after 60--batch-size 1~2) or switch to --metadata-only skeleton flow.Priority 3: User-provided assets (fallback)
Before troubleshooting remote/chat/headless MCP auth, read:
references/mcp-auth-state-machine.mdWhen MCP is not ready, guide the user in this exact order:
Auth policy while replying:
One-click setup (recommended first, default path)
bash scripts/setup_claude_mcp.shpython3 scripts/auth_session_guard.py --mode claude-loginbash scripts/setup_claude_mcp.sh --start-loginpython3 scripts/claude_auth_lock.py acquire --session-id <session-id> --auth-url "<authorize-url>"claude REPL session:
claudepython3 scripts/claude_repl_state.py --stdinwaiting-for-code, do not ask user for auth data yet/login if neededpython3 scripts/extract_auth_url.py --stdinpython3 scripts/claude_auth_lock.py acquire --session-id <session-id> --auth-url "<authorize-url>"code#state) into Paste code here if prompted >code#state, callback URL, or localhost callback URL).python3 scripts/claude_repl_state.py --stdin; only continue when it reports waiting-for-code.python3 scripts/claude_auth_lock.py verify-code --code-state "<code#state>"python3 scripts/claude_auth_lock.py verify-callback --callback-url "<callback-url>"Check Claude usage quota early (avoid dead-end loops)
claude --print "quota-check"You've hit your limit / reset time:
FIGMA_TOKEN) with skeleton-first + quota-aware pullingIf one-click setup fails, use manual checks
references/mcp-auth-state-machine.md strictly; do not improvise auth retries.claude command not found:
npm install -g @anthropic-ai/claude-codeclaude --versionclaude auth loginclaude → /login → keep the same REPL alive → paste Authentication Code (code#state)claude mcp add --scope user --transport http figma https://mcp.figma.com/mcpNeeds authentication:
claude → /mcp → figma → Authenticate/Connectclaude mcp list (must be Connected)Script cannot find token
export FIGMA_MCP_TOKEN=...python3 scripts/fetch_figma_mcp.py --action toolspython3 scripts/fetch_figma_mcp.py --allow-claude-credentials --action toolsStill blocked after MCP auth is truly stabilized
claude auth status shows logged inclaude mcp list shows figma ... Connectedwhoami result matches the intended Figma accountfetch_figma_mcp.pyexport FIGMA_TOKEN=...python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "NODE1,NODE2" --quota-aware --batch-size 2 --sleep-ms 1500 --max-retry-after 60Retry-After, stop image pull and continue with metadata-only skeleton:
python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "NODE1,NODE2" --metadata-onlyCallback invalid / stale diagnostics (must check before retry loop)
claude auth login sessions created different statespython3 scripts/auth_session_guard.py --mode claude-loginpython3 scripts/extract_auth_url.py --stdinpython3 scripts/parse_claude_oauth_callback.py --auth-url "<latest_auth_url>" --callback-url "<user_callback_url>"Before asking custom rules, validate link/file/node first:
# Fast syntax check (no token required)
python3 scripts/validate_figma_input.py --figma-url "<figma-url>"
# Strong check (requires FIGMA_TOKEN): verify file accessibility + full-page heuristic
FIGMA_TOKEN=... python3 scripts/validate_figma_input.py --figma-url "<figma-url>" --check-api
Decision rules:
INVALID_URL / FILE_INVALID_OR_UNAUTHORIZED / NODE_INVALID → stop and ask user for corrected link/access.FULL_PAGE_ASSESSMENT: likely partial/component → ask user to confirm whether they want component restore or provide page-level node-id.node-id, default target is whole file/page and continue.Before generating code, offer user an optional rule intake. If user leaves it blank, proceed with defaults.
Collect only these six fields:
Adaptive strategy
mobile-first / desktop-first / mobile-only / desktop-onlymobile-firstBreakpoints
375, 768, 1200375, 768, 1200Layout width strategy
fixed width / fluid / max-width centeredmax-width centeredTypography sizing strategy
px / rem / clampclamp for responsive text, with pixel-accurate base ratioInteractive states
none / basic (:hover,:active,:disabled) / fullbasicBrowser compatibility target
modern evergreen only / include Safari stableinclude Safari stableIf any field is empty, keep the default and continue execution without blocking.
Quick prompt template:
可选自定义生成规则(可留空,留空=默认):
1) 端适配策略(mobile-first/desktop-first/mobile-only/desktop-only):
2) 断点(例如 375,768,1200):
3) 页面宽度策略(fixed/fluid/max-width centered):
4) 字体策略(px/rem/clamp):
5) 交互态(none/basic/full):
6) 浏览器兼容目标(modern only/include Safari stable):
Required (at least one):
If Figma MCP available (preferred):
# Choose auth mode once:
# A) export FIGMA_MCP_TOKEN=...
# B) MCP_AUTH="--allow-claude-credentials"
# Step 1: Batch pull metadata+screenshot+context in one MCP session
python3 scripts/fetch_figma_mcp.py ${MCP_AUTH:-} \
--file-key FILE_KEY \
--node-ids "NODE_ID NAV_NODE_ID COVER1 COVER2" \
--action bundle \
--out-dir ./mcp-assets
# Step 2: Parse/download context assets automatically (SVG normalization included)
python3 scripts/parse_design_context.py \
--context-glob "./mcp-assets/context-*.txt" \
--assets-dir ./assets \
--manifest ./source/context-assets.json
# Step 3: Optional targeted screenshots for image-heavy sections
python3 scripts/fetch_figma_mcp.py ${MCP_AUTH:-} \
--file-key FILE_KEY \
--node-ids "BANNER1 FOOTER" \
--action screenshot \
--out-dir ./assets
If REST API available (for detailed CSS extraction):
python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "NODE1,NODE2" --quota-aware --batch-size 2 --sleep-ms 1500 --max-retry-after 60python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "NODE1,NODE2" --metadata-onlyscripts/figma_to_css.py on the exported nodes.json.If ZIP provided:
source/, rename files meaningfully, copy usable assets to assets/.Critical rule: always build the skeleton before polishing pixels.
Identify sections from the full-page design:
Build the skeleton — placeholder-only HTML/CSS:
<section> per block with a colored background or placeholder text.overflow-x: hidden on body, scrollable rows marked.Take skeleton screenshot → send to user for confirmation.
Layer in details per confirmed section:
Missing assets? Try to fetch before asking:
assets/ or source/ (cache first).python3 scripts/fetch_figma_rest.py --file-key FILE_KEY --nodes "<node-id>" --quota-aware --batch-size 1quota-status.json shows degraded), continue skeleton and ask user for direct asset file.NEVER generate fake assets.
First apply resolved rule-intake profile (user values or defaults), then generate files.
Generate three directories:
html/index.html (or html/<page>.html for multi-page)
<section> per design block.<meta viewport> with width=device-width, initial-scale=1.css/styles.css
:root variables for max-width and theme colors.overflow-x: hidden on html, body, .page-shell to prevent horizontal scroll.overflow-x: clip on .stage containers; only specific scrollable rows get overflow-x: auto.clamp() for responsive typography.@media (min-width: 801px) for PC centered layout.assets/*
figma-01.png).After fetching nodes.json, run the auto-extraction script:
python3 scripts/figma_to_css.py --nodes rest-assets/nodes.json --out source/figma-extracted.css
This parses every node and outputs CSS property blocks for:
Use the extracted CSS as a reference when writing styles.css. Do NOT copy-paste blindly — adapt to the actual DOM structure.
Do not guess. Read nodes.json, then map values to CSS.
Use this reference for full mapping table + strict rules:
references/css-extraction-rules.mdAfter each major iteration:
# 1. Screenshot current render
google-chrome --headless=new --disable-gpu --no-sandbox \
--window-size=800,5338 \
--screenshot=compare/current.png \
http://127.0.0.1:PORT/html/
# 2. Compare with region heatmap + structure metrics (default 5x5 grid)
python3 scripts/visual_diff.py \
--current compare/current.png \
--target assets/design-main.png \
--diff compare/diff.png \
--regions 5 \
--threshold 30 \
--json-out compare/metrics.json
The tool outputs:
Focus iteration on red regions first, then raise composite similarity.
When running on a cloud server, start a temporary HTTP server for public preview:
# Find an available port (e.g. 8090 if 8080 is taken)
python3 -m http.server PORT --bind 0.0.0.0
0.0.0.0 (not 127.0.0.1) so it's accessible via public IP.lsof -i :PORT or ss -tlnp).http://<PUBLIC_IP>:PORT/html/ link.After each code generation iteration, before reporting results:
google-chrome --headless=new --disable-gpu --no-sandbox \
--window-size=800,5338 \
--screenshot=compare/current.png \
http://127.0.0.1:PORT/html/
Send the screenshot to the user via the messaging platform (Telegram/Discord/etc.) using the media/file sending tool — do NOT just send a URL, send the actual image.
Then optionally run visual diff against target and mention the similarity score.
This ensures the user can verify visual quality without opening a browser on every iteration.
overflow-x: hidden where needed).Full checklist: references/anti-patterns.md
scripts/validate_figma_input.py — Validate Figma URL/file/node; optionally classify whether target is full-page vs component (--check-api).scripts/fetch_figma_mcp.py — Primary. MCP fetcher with token auto-refresh, batch node extraction (--node-ids), and bundle mode (--action bundle).scripts/auth_session_guard.py — Detect conflicting Claude sessions and refuse fresh login attempts while an active auth lock or existing Claude process is present.scripts/claude_auth_lock.py — Persist the one active Claude auth state (sessionId + authorize URL/state) and validate incoming code#state or callback URLs before submission.scripts/claude_repl_state.py — Classify raw Claude REPL output (theme picker / login method picker / waiting-for-code / ambiguous) and block auth handoff unless the REPL is actually waiting for code.scripts/extract_auth_url.py — Extract an unbroken Claude OAuth authorize URL from raw terminal output; use instead of hand-copying wrapped URLs.scripts/parse_claude_oauth_callback.py — Validate callback URL or code#state against the active authorize URL to detect stale/invalid callbacks.scripts/parse_design_context.py — Parse MCP context files, download asset URLs, and normalize SVG stretch issues.scripts/fetch_figma_rest.py — Extract node metadata + images via Figma REST API (needs FIGMA_TOKEN), with quota-aware batching, retry-after guardrail, metadata-only degradation, and local cache reuse.scripts/figma_to_css.py — Auto-parse REST nodes.json → CSS property blocks.scripts/visual_diff.py — Compare render vs target with MAE + SSIM + heatmap.references/figma-mcp-usage.md — Figma MCP tools reference, setup, auth modes, and batch usage.references/css-extraction-rules.md — Strict property mapping and non-negotiable CSS extraction rules.references/file-structure.md — Standard project directory layout.references/css-patterns.md — Reusable CSS patterns for common design elements.references/anti-patterns.md — Full anti-pattern checklist for QA passes.