Figma to Mobile
Convert Figma designs to mobile UI code with interactive clarification.
Supported: Android Compose, Android XML, iOS SwiftUI, iOS UIKit.
Prerequisites
FIGMA_TOKENenvironment variable set (Figma > Settings > Personal Access Tokens) ⚠️ Your Figma token is sensitive — treat it like a password. Never paste it into chat messages (they may be logged). Set it via your shell rc file or OpenClaw env config.- Python 3.8+ with
requestspackage
Trigger & Input
This skill activates when a user explicitly asks to convert a Figma design to mobile UI code and provides a Figma link. It does NOT activate on casual mentions of Figma links, pasted URLs in logs, or design references without a conversion request.
The user may also include inline hints alongside the link, such as:
- Target platform: "Android XML", "Compose", "SwiftUI", "UIKit"
- Layout preferences: "use ConstraintLayout", "prefer StackView"
- Component notes: "the switch is our custom CompactSwitch", "this is a dynamic list"
- Any other context about the design
If the user provides hints, respect them and skip the corresponding questions. For example, if the user says "Android XML, the 3 cards are a RecyclerView list", do NOT ask about output format or whether the cards are dynamic/static.
Not Applicable
This skill is NOT for:
- Screenshot / image → code: it works only with Figma design links via the Figma REST API, not with screenshots or image files.
- Layout code without a Figma link: generic "write me a login screen" requests have no design to interpret.
- Casual mentions or pasted URLs without a conversion request — see Trigger & Input above.
- Pure design discussion or Figma feature questions: no code is generated.
Deliverables
After a successful conversion, the user receives:
- Generated UI code files — platform-idiomatic (Compose / XML / SwiftUI / UIKit / Flutter). Multiple files are presented with a clear filename header (see Step 3).
scan-report.json— project resource scan results, only when the user agrees to a project scan (Step 2.5).feedback-log.md— correction log written to the project root, only with user consent (Step 4).
Workflow
Step 1: Fetch & Analyze
When user provides Figma link(s):
-
Determine the input type:
A. Link without specific node-id (no
node-id, ornode-id=0-1): This link points to the entire page, not a specific frame. Tell the user:This link points to the whole page. Please select the frame you want in Figma, right-click it, and choose "Copy link to selection", then send that link. If you want to convert multiple frames, send multiple links.
B. Single frame link (has specific
node-id):python scripts/figma_fetch.py "https://www.figma.com/design/<fileKey>/<name>?node-id=<id>"→ returns that frame's design data. Proceed to analysis.
C. Multiple links (user sends 2+ URLs): Determine the relationship by frame names and user context: same-page states →
--comparemode (multi-state code); parent+overlay → independent layout files; independent pages → fetch one at a time, ask which to convert first. If unsure, ask the user.Detailed multi-frame rules: Read
references/multi-frame.md -
If the link has no specific node-id, ask the user to re-copy from the specific frame (see A above). Do NOT call the API.
-
Analyze the structure: identify sections, repeated patterns, component types
-
Note INSTANCE nodes — they indicate reusable components. Check
variantPropertiesfor component state (e.g. State=Default, Size=Large) — these map to multi-state code -
Note gradient/shadow data — flag for the user if complex
-
Apply Figma node interpretation rules before generating code
Detailed interpretation rules: Read references/figma-interpretation.md
Step 1.5: Structure Summary
Before asking any questions, present a brief structure summary to the user so they can confirm your understanding:
I see: [navigation bar with back button + title] → [2 content sections: user profile card, settings list (8 items)] → [bottom action button]. Total ~25 nodes.
Keep it to 2-3 lines. Mention:
- Major sections identified (nav bar, content areas, footer)
- Repeated patterns ("8 similar list items", "3 tab labels")
- Notable elements (gradients, complex illustrations, stacked cards)
If the user says "that's wrong" or corrects the structure, adjust understanding before proceeding to Step 2.
If the design has ≤10 leaf nodes (visible elements that map to actual views), skip this step — the structure is simple enough to proceed directly.
Step 2: Confirm & Clarify
Question priority (strict order — ask earlier questions first):
-
Output format (MUST ask first unless user already specified) → Android XML / Compose / SwiftUI / UIKit This determines all subsequent analysis phrasing and code output.
-
Structural ambiguities (only ask what you're genuinely unsure about) → "These N items look similar — dynamic list or fixed layout?" → "This area: single image asset or icon-on-background combo?"
-
Component choices (only if platform-relevant) → "Any custom components to use? (otherwise I'll use platform defaults)"
Rules for questions:
- Skip any question the user already answered via inline hints
- Max 3-5 questions total, fewer is better
- Each question gives concrete options with one-line pros/cons
- Every question includes an open option: "or tell me more about this"
- Use natural language, no JSON or technical dumps
- If everything is clear (user gave full context + simple structure), skip Step 2 entirely
Confidence guide — when to ask vs. when to just generate:
- ≥3 sibling nodes with similar structure → likely a list → ASK (dynamic vs static)
- INSTANCE nodes sharing same componentId → reusable component → MENTION but can default
- Single clear hierarchy, no ambiguity → high confidence → SKIP questions, go to Step 3
- Gradient/complex shadow in design → MENTION in summary ("I see a gradient here, I'll approximate it as X")
Step 2.5: Project Scan — Ask First
⚠️ Always ask the user before scanning their project. Scanning reads local files; the user should know and agree.
"你的项目在 /path/to/project 对吗?要不要我先扫描一下项目里已有的资源 (颜色、文案、图片、自定义组件),这样生成代码时可以直接复用已有的东西?"
If the user agrees:
python scripts/project_scan.py /path/to/project --json --output scan-report.json
Then read scan-report.json and references/scan-usage.md.
If the user declines: proceed with hardcoded values per generation rules.
How to present scan results (with sample phrasing): Read references/scan-usage.md
If no project path is known yet, don't scan. Proceed with hardcoded generation.
Step 3: Generate Code
After user confirms (or if no questions needed), generate code files.
Detailed generation rules: Read references/generation-rules.md
If multiple files are needed, output each with a clear filename header:
📄 activity_notification_settings.xml
[code]
📄 item_expert_notification.xml
[code]
Step 4: Iterate & Capture Feedback
After showing code, ask briefly:
Matches the design? Any adjustments?
The user can then give feedback to refine the output. Common iterations:
- "间距大了" → adjust specific spacing
- "Switch 换成我们的 CustomSwitch" → swap component
- "把标题栏去掉" → remove section
- "换成 Compose 版本" → regenerate in different format
- "颜色不对,这里应该是 #333333" → fix specific values
Continue iterating until the user is satisfied.
Iteration output rule:
- If the file has already been written to disk → read the current file, apply only the minimal patch, output just the changed lines with clear context (file path + line range). Do NOT regenerate the whole file.
- If the code only exists in the conversation (not written to disk) → output only the changed snippet with a comment indicating where it replaces (e.g.,
// replaces lines 12-18 in activity_main.xml). Do NOT repeat the entire file. - Only regenerate the full file if the user explicitly asks (e.g., "重新生成完整文件", "show me the full file").
⚠️ Before logging any feedback, tell the user:
"I'll save this correction locally to
feedback-log.mdto improve future output. It stores before/after snippets — is that OK?" Only proceed if the user agrees.
⚠️ IMPORTANT: Every time the user corrects your output (layout issue, wrong component, spacing problem, etc.), you MUST log it to feedback-log.md before proceeding with the fix (after user consent). Do not skip this step — the log is how the skill learns and improves over time.
Feedback format, logging rules, and analysis: Read references/feedback-log.md
API Request Limits
The bundled scripts/figma_fetch.py enforces these limits automatically:
- Timeout: 30s per request
- Retries: up to 3 attempts on connection/SSL errors (backoff 5s/10s/15s)
- Rate limit: ≥2s between requests; on HTTP 429, wait per
Retry-Afterheader (cap 30s) - Adaptive depth: refetches with deeper depth (up to 15) when children look truncated
When a rate limit is exceeded, the script reports:
{
"status": "error",
"error": "RATE_LIMIT_EXCEEDED",
"message": "Figma API rate limit exceeded",
"retry_after_seconds": 30,
"plan_tier": "FREE",
"limit_type": "requests_per_minute"
}
Error Handling
Quick reference — full details in references/error-handling.md:
- FIGMA_TOKEN not set (
FIGMA_TOKEN_NOT_SET) → guide user to set env var; never paste token into chat - 403/401 → token expired/revoked; regenerate in Figma Settings → Security
- Invalid URL → show valid format:
https://www.figma.com/design/<fileKey>/<name>?node-id=<id> - API error / node too large / depth auto-increased → see
references/error-handling.md
Tips
- Token safety: never paste
FIGMA_TOKENinto chat — set it as an environment variable (see Prerequisites). - Rate limits: keep ≥2s between Figma API calls; the script enforces this, so avoid parallel fetches to save time.
- Multi-frame: compare shared components across frames before generating code to avoid duplication.
