CanICode
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.
How It Works
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.
Everything is Configurable
| 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.
Getting Started
Five ways to use CanICode. Pick one.
Figma Plugin (under review)
Install from Figma Community — analyze directly inside Figma. No tokens needed.
Web (no install)
Go to let-sunny.github.io/canicode, paste a Figma URL, and get results instantly in your browser.
CLI (standalone)
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_xxxxxxxxxxxxx
Get your token: Figma → Settings → Security → Personal access tokens → Generate new token
MCP Server (Claude Code / Cursor / Claude Desktop)
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/mcp
Claude Code (with Figma API token):
claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode canicode-mcp
Cursor (~/.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 strict
Config 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.json
Tip: 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/MyDesign
Tech 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 build
pnpm dev # watch mode
pnpm test # run tests
pnpm lint # type check
Roadmap
- 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)
Support
- Bug reports: GitHub Issues
- Questions and discussions: GitHub Issues
- Privacy: See PRIVACY.md for details on data collection and how to opt out
License
MIT