Analyze Figma designs. Score how dev-friendly and AI-friendly they are. Get actionable issues before writing code.
Share your Figma design to help improve scoring accuracy.
Try it in your browser — no install needed.
npm install -g canicode
canicode init --token YOUR_FIGMA_TOKEN
canicode analyze "https://www.figma.com/design/ABC123/MyDesign?node-id=1-234"Run
canicode docs setupfor the full setup guide — CLI, MCP Server, Claude Skills, and all options.
39 rules across 6 categories check every node in the Figma tree:
| Category | Rules | What it checks |
|---|---|---|
| Layout | 11 | Auto-layout usage, responsive behavior, nesting depth |
| Design Token | 7 | Color/font/shadow tokenization, spacing consistency |
| Component | 6 | Component reuse, detached instances, variant coverage |
| Naming | 5 | Semantic names, default names, naming conventions |
| AI Readability | 5 | Structure clarity, z-index reliance, empty frames |
| Handoff Risk | 5 | Hardcoded values, truncation handling, placeholder images |
Each issue is classified: Blocking > Risk > Missing Info > Suggestion.
Scores use density + diversity weighting per category, combined into an overall grade (S/A+/A/B+/B/C+/C/D/F). Rule scores are calibrated against actual code conversion difficulty — see Calibration for how scores are validated.
| What | How | Example |
|---|---|---|
| Presets | Built-in score profiles | canicode analyze <url> --preset strict |
| Config overrides | Adjust scores, severity, exclude nodes | canicode analyze <url> --config ./config.json |
| Custom rules | Add your own checks with pattern matching | canicode analyze <url> --custom-rules ./rules.json |
| Combine | Use all together | canicode analyze <url> --preset ai-ready --config ./config.json --custom-rules ./rules.json |
| Preset | What it does |
|---|---|
relaxed |
Downgrades blocking → risk, scores −50% |
dev-friendly |
Layout and handoff rules only |
ai-ready |
Structure and naming weights +150% |
strict |
All rules enabled, scores +150% |
Custom rules tip: Ask any LLM "Write a canicode custom rule that checks X" — it can generate the JSON for you. See
docs/CUSTOMIZATION.mdfor the full guide.
Five ways to use CanICode. Pick one.
Install from Figma Community — analyze directly inside Figma. No tokens needed.
Go to let-sunny.github.io/canicode, paste a Figma URL, and get results instantly in your browser.
npx canicode analyze "https://www.figma.com/design/ABC123/MyDesign?node-id=1-234"
# Or install globally
npm install -g canicode
canicode analyze "https://www.figma.com/design/ABC123/MyDesign?node-id=1-234"To enable "Comment on Figma" buttons in reports, set your Figma token:
canicode init --token figd_xxxxxxxxxxxxxGet your token: Figma → Settings → Security → Personal access tokens → Generate new token
Claude Code (recommended — with official Figma MCP, no token needed):
# 1. Install canicode MCP server
claude mcp add canicode -- npx -y -p canicode canicode-mcp
# 2. Install official Figma MCP (enables token-free analysis)
claude mcp add -s project -t http figma https://mcp.figma.com/mcpClaude Code (with Figma API token):
claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode canicode-mcpCursor (~/.cursor/mcp.json):
{
"mcpServers": {
"canicode": {
"command": "npx",
"args": ["-y", "-p", "canicode", "canicode-mcp"],
"env": {
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxx"
}
}
}
}Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"canicode": {
"command": "npx",
"args": ["-y", "-p", "canicode", "canicode-mcp"],
"env": {
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxx"
}
}
}
}Then ask: "Analyze this Figma design: https://www.figma.com/design/..."
With
FIGMA_TOKENset, the HTML report includes "Comment on Figma" buttons that post analysis findings directly to Figma nodes.
Data Sources
| Flag | Source | Token required |
|---|---|---|
| (none) | Figma REST API | Yes |
--api |
Figma REST API (explicit) | Yes |
For token-free analysis, use the canicode MCP server with the official Figma MCP, or the /canicode skill in Claude Code.
Token priority:
--tokenflag (one-time override)FIGMA_TOKENenv var (CI/CD)~/.canicode/config.json(canicode init)
Presets
| Preset | Behavior |
|---|---|
relaxed |
Downgrades blocking to risk, reduces scores by 50% |
dev-friendly |
Focuses on layout and handoff rules only |
ai-ready |
Boosts structure and naming rule weights by 150% |
strict |
Enables all rules, increases all scores by 150% |
canicode analyze <url> --preset strictConfig Overrides
Override rule scores, severity, node exclusions, and global settings:
canicode analyze <url> --config ./my-config.json{
"excludeNodeNames": ["chatbot", "ad-banner", "wip"],
"gridBase": 4,
"rules": {
"no-auto-layout": { "score": -15, "severity": "blocking" },
"default-name": { "enabled": false }
}
}| Option | Description |
|---|---|
gridBase |
Spacing grid unit (default: 4) |
colorTolerance |
Color difference tolerance (default: 10) |
excludeNodeTypes |
Node types to skip |
excludeNodeNames |
Node name patterns to skip |
rules.<id>.score |
Override rule score |
rules.<id>.severity |
Override rule severity |
rules.<id>.enabled |
Enable/disable a rule |
See examples/config.json | docs/CUSTOMIZATION.md | Run canicode docs config
Custom Rules
Add project-specific checks with declarative pattern matching:
canicode analyze <url> --custom-rules ./my-rules.json[
{
"id": "icon-not-component",
"category": "component",
"severity": "blocking",
"score": -10,
"match": {
"type": ["FRAME", "GROUP"],
"maxWidth": 48,
"maxHeight": 48,
"hasChildren": true,
"nameContains": "icon"
},
"message": "\"{name}\" is an icon but not a component",
"why": "Icons that are not components cannot be reused consistently.",
"impact": "Developers will hardcode icon SVGs instead of using a shared component.",
"fix": "Convert this icon to a component and publish it to the design system library."
}
]Conditions use AND logic — all must match for the rule to fire. Available conditions: type, notType, nameContains, nameNotContains, namePattern, minWidth, maxWidth, minHeight, maxHeight, hasAutoLayout, hasChildren, minChildren, maxChildren, isComponent, isInstance, hasComponentId, isVisible, hasFills, hasStrokes, hasEffects, minDepth, maxDepth.
Combine with config overrides:
canicode analyze <url> --config ./config.json --custom-rules ./rules.jsonTip: Ask any LLM "Write a canicode custom rule that checks X" with the conditions above — it can generate the JSON for you.
Scoring Algorithm
Final Score = (Density Score × 0.7) + (Diversity Score × 0.3)
Density Score = 100 - (weighted issue count / node count) × 100
Diversity Score = (1 - unique violated rules / total rules in category) × 100
Severity weights issues — a single blocking issue counts 3x more than a suggestion. Scores are calculated per category and combined into an overall grade (S/A+/A/B+/B/C+/C/D/F).
Weights and rule scores are validated through a 4-agent calibration pipeline. See docs/CALIBRATION.md for details.
MCP Server Details
The canicode-mcp server exposes two tools: analyze and list-rules.
Route A — Figma MCP relay (no token):
Claude Code → Figma MCP get_metadata → XML node tree
Claude Code → canicode MCP analyze(designData: XML) → result
Route B — REST API direct (token):
Claude Code → canicode MCP analyze(input: URL) → internal fetch → result
Route A requires two MCP servers (figma + canicode). Route B requires one + a saved token.
The analyze tool accepts designData (XML/JSON from Figma MCP) or input (Figma URL / fixture path). When both are provided, designData takes priority.
Save Fixture
Save Figma file data as JSON for offline analysis:
canicode save-fixture https://www.figma.com/design/ABC123/MyDesignTech Stack
| Layer | Tool |
|---|---|
| Runtime | Node.js (>= 18) |
| Language | TypeScript (strict mode) |
| Package Manager | pnpm |
| Validation | Zod |
| Testing | Vitest |
| CLI | cac |
| Build | tsup |
Calibration (Internal)
Rule scores are validated against actual code conversion difficulty via a calibration pipeline. This runs inside Claude Code using /calibrate-loop — not exposed as a CLI command.
The pipeline uses 4 subagents:
- Runner — Analyzes a fixture and extracts issue data
- Converter — Converts flagged Figma nodes to code via Figma MCP
- Critic — Reviews proposed score adjustments
- Arbitrator — Makes final decisions and commits changes
Development
git clone https://github.com/let-sunny/canicode.git
cd canicode
pnpm install
pnpm buildpnpm dev # watch mode
pnpm test # run tests
pnpm lint # type check- Phase 1 — 39 rules, density-based scoring, HTML reports, presets, scoped analysis
- Phase 2 — 4-agent calibration pipeline,
/calibrate-loopdebate loop - Phase 3 — Config overrides, MCP server, Claude Skills
- Phase 4 — Figma comment from report (per-issue "Comment" button in HTML report, posts to Figma node via API)
- Phase 5 — Custom rules with pattern matching (node name/type/attribute conditions)
- Phase 6 — Screenshot comparison (Figma vs AI-generated code, visual diff)
- Bug reports: GitHub Issues
- Questions and discussions: GitHub Issues
- Privacy: See PRIVACY.md for details on data collection and how to opt out
MIT

