
Excalidraw Skill
- 1 installs
- Updated March 9, 2026
- bennjph/excalidraw-skills
excalidraw-skill is a skill that lets an agent create, edit, refine, and export Excalidraw diagrams on a live canvas through MCP tools or a REST API fallback.
About
This skill gives an agent a programmatic toolkit for creating, editing, and refining Excalidraw diagrams on a live canvas, working over MCP tools or a REST API fallback. It supports element-level CRUD, alignment, grouping, snapshots, Mermaid-to-Excalidraw conversion, and image export, and it iteratively refines diagrams by reading back describe_scene and screenshots. A developer uses it to programmatically lay out and polish architecture or flow diagrams instead of drawing them by hand. It requires a running canvas server at EXPRESS_SERVER_URL, default http://localhost:3000.
- Creates and edits Excalidraw diagrams via MCP or a REST fallback with live canvas sync
- Self-refines using describe_scene and get_canvas_screenshot to see its own work
- Enforces a mandatory 8-point quality gate (truncation, overlap, arrow routing, spacing)
Excalidraw Skill by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,609 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Jul 7, 2026 (Skillselion catalog sync)
excalidraw-skill capabilities & compatibility
Free; needs a local canvas server running at http://localhost:3000
- Capabilities
- diagram creation · diagram export · mermaid conversion · canvas editing
- Use cases
- documentation · ui design · web design
- Runs
- Runs locally
- Pricing
- Free
What excalidraw-skill says it does
Programmatic canvas toolkit for creating, editing, and refining Excalidraw diagrams via MCP tools with real-time canvas sync.
Requires a running canvas server (EXPRESS_SERVER_URL, default http://localhost:3000).
npx skills add https://github.com/bennjph/excalidraw-skills --skill excalidraw-skillAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | March 9, 2026 |
| Repository | bennjph/excalidraw-skills ↗ |
What it does
Programmatically create, refine, and export Excalidraw diagrams on a live canvas via MCP or REST.
Who is it for?
Programmatically drawing and iteratively refining diagrams, converting Mermaid to Excalidraw, and exporting to .excalidraw, PNG, or SVG.
Skip if: Use without a running canvas server; several operations like screenshots require MCP mode and a browser.
When should I use this skill?
The agent needs to draw or lay out diagrams on a live canvas, refine them visually, or export and import Excalidraw files.
What you get
A clean, readable diagram that passes an explicit quality gate for truncation, overlap, arrow routing, spacing, and readability.
- Excalidraw diagrams on a live canvas, exportable to .excalidraw, PNG, or SVG
By the numbers
- 8-point quality checklist
- Minimum 40px gap between elements
Files
Excalidraw Skill (Claude Code)
v2 — upgraded with style presets, diagram templates, Mermaid-first workflow, and design intelligence.
Step 0: Detect Connection Mode
Before doing anything, determine which mode is available. Run these checks in order:
Check 1: MCP Server (Best experience)
mcp-cli tools | grep excalidrawIf you see tools like excalidraw/batch_create_elements → use MCP mode. Call MCP tools directly.
Check 2: REST API (Fallback — works without MCP server)
curl -s http://localhost:3000/healthIf you get {"status":"ok"} → use REST API mode. Use HTTP endpoints (curl / fetch) from the cheatsheet.
Check 3: Nothing works → Guide user to install
If neither works, tell the user:
The Excalidraw canvas server is not running. To set up:
1. Clone: git clone https://github.com/yctimlin/mcp_excalidraw && cd mcp_excalidraw2. Build: npm ci && npm run build3. Start canvas: HOST=0.0.0.0 PORT=3000 npm run canvas4. Open http://localhost:3000 in a browser5. (Recommended) Install the MCP server for the best experience:
```
claude mcp add excalidraw -s user -e EXPRESS_SERVER_URL=http://localhost:3000 -- node /path/to/mcp_excalidraw/dist/index.js
```
MCP vs REST API Quick Reference
| Operation | MCP Tool | REST API Equivalent |
|---|---|---|
| Create elements | batch_create_elements | POST /api/elements/batch with {"elements": [...]} |
| Get all elements | query_elements | GET /api/elements |
| Get one element | get_element | GET /api/elements/:id |
| Update element | update_element | PUT /api/elements/:id |
| Delete element | delete_element | DELETE /api/elements/:id |
| Clear canvas | clear_canvas | DELETE /api/elements/clear |
| Describe scene | describe_scene | GET /api/elements (parse manually) |
| Export scene | export_scene | GET /api/elements (save to file) |
| Import scene | import_scene | POST /api/elements/sync with {"elements": [...]} |
| Snapshot | snapshot_scene | POST /api/snapshots with {"name": "..."} |
| Restore snapshot | restore_snapshot | GET /api/snapshots/:name then POST /api/elements/sync |
| Screenshot | get_canvas_screenshot | Only via MCP (needs browser) |
| Design guide | read_diagram_guide | Not available — see cheatsheet for guidelines |
| Viewport | set_viewport | POST /api/viewport (needs browser) |
| Export image | export_to_image | POST /api/export/image (needs browser) |
| Export URL | export_to_excalidraw_url | Only via MCP |
REST API Gotchas (Critical — read before using REST API)
1. Labels: Use "label": {"text": "My Label"} (not "text": "My Label"). MCP tools auto-convert, REST API does not. 2. Arrow binding: Use "start": {"id": "svc-a"}, "end": {"id": "svc-b"} (not "startElementId"/"endElementId"). MCP tools accept startElementId and convert, REST API requires the start/end object format directly. 3. fontFamily: Must be a string (e.g. "1") or omit it entirely. Do NOT pass a number like 1. 4. Updating labels: When updating a shape via PUT /api/elements/:id, include the full label in the update body to preserve it. Omitting label from the update won't delete it, but re-sending ensures it renders correctly. 5. Screenshot in REST mode: POST /api/export/image returns {"data": "<base64>"}. Save to file and read it back for visual verification. Requires browser open.
Quality Gate (MANDATORY — read before creating any diagram)
After EVERY iteration (each batch of elements added), you MUST run a quality check before proceeding. NEVER say "looks great" unless ALL checks pass.
Quality Checklist — verify ALL before adding more elements:
1. Text truncation: Is ALL text fully visible? Labels must fit inside their shapes. If text is cut off or wrapping badly → increase width and/or height. 2. Overlap: Do ANY elements overlap each other? Check that no rectangles, ellipses, or text elements share the same space. Background zones must fully contain their children with padding. 3. Arrow crossing: Do arrows cross through unrelated elements or overlap with text labels? If yes → use curved/elbowed arrows with waypoints to route around obstacles (see "Arrow Routing" section). Never accept crossing arrows. 4. Arrow-text overlap: Do any arrow labels ("charge", "event", etc.) overlap with shapes? Arrow labels are positioned at the midpoint — if they overlap, either remove the label, shorten it, or adjust the arrow path. 5. Spacing: Is there at least 40px gap between elements? Cramped layouts are unreadable. 6. Readability: Can all labels be read at normal zoom? Font size >= 16 for body text, >= 20 for titles. 7. Isomorphism Test: If you removed all text, would the visual structure alone communicate the concept? Fan-outs should look like fan-outs. Timelines should look linear. Convergence should funnel. Shape must mirror meaning. 8. Education Test: Does the viewer learn something concrete, or just see labels in boxes? Technical diagrams should include evidence — actual code snippets, JSON, API signatures — not generic placeholders.
If ANY issue is found:
- STOP adding new elements
- Fix the issue first (resize, reposition, delete and recreate)
- Re-verify with a new screenshot
- Only proceed to next iteration after ALL quality checks pass
Sizing Rules (prevent truncation):
- Shape width:
max(160, labelTextLength * 9)pixels. For multi-word labels like "API Gateway (Kong)", count all characters. - Shape height: 60px for single line, 80px for 2 lines, 100px for 3 lines.
- Background zones: Add 50px padding on ALL sides around contained elements.
- Element spacing: 60px vertical between tiers, 40px horizontal between siblings.
- Side panels: Place at least 80px away from main diagram elements.
- Arrow labels: Keep labels short (1-2 words). Long arrow labels overlap with other elements.
Layout Planning (prevent overlap):
Before creating elements, plan your coordinate grid on paper first:
- Tier 1 (y=50-130): Client apps
- Tier 2 (y=200-280): Gateway/Edge
- Tier 3 (y=350-440): Services (spread wide: each service ~180px apart)
- Tier 4 (y=510-590): Data stores
- Side panels: x < 0 (left) or x > mainDiagramRight + 80 (right)
Do NOT place side panels (observability, external APIs) at the same x-range as the main diagram — they WILL overlap.
Quick Start
1. Run Step 0 above to detect your connection mode. 2. Open the canvas URL in a browser (required for image export/screenshot). 3. MCP mode: Use MCP tools for all operations. REST mode: Use HTTP endpoints from cheatsheet. 4. For full tool/endpoint reference, read references/cheatsheet.md.
Style Presets (Choose ONE before drawing)
Pick a preset to apply consistently across all elements. Override individual properties as needed.
| Preset | roughness | fontFamily | strokeWidth | fillStyle | Best For |
|---|---|---|---|---|---|
| sketch-note | 1 | 1 (Virgil) | 2 | hachure | Blog posts, visual notes, brainstorming |
| technical | 0 | 3 (Cascadia) | 2 | solid | Architecture docs, system design, API docs |
| minimalist | 0 | 2 (Helvetica) | 1 | solid | Corporate decks, professional reports |
| playful | 1 | 8 (Comic Shanns) | 2 | zigzag | Educational content, presentations, casual |
| editorial | 0 | 2 (Helvetica) | 1 | solid | Stakeholder reports, formal docs |
| dark-mode | 0 | 3 (Cascadia) | 2 | solid | Developer blogs, code architecture |
Dark Mode Setup
First element must be a massive background rectangle:
{"type": "rectangle", "x": -4000, "y": -3000, "width": 10000, "height": 7500,
"backgroundColor": "#1e1e2e", "fillStyle": "solid", "strokeWidth": 0, "opacity": 100}Then use light text (#e5e5e5), bright accent fills (#1e3a5f blue, #1a4d2e green, #2d1b69 purple).
Color Recipes (per diagram purpose)
| Recipe | Stroke → Fill pairs |
|---|---|
| Architecture | Frontend: #1971c2→#a5d8ff, Backend: #9c36b5→#eebefa, Data: #0c8599→#99e9f2, Async: #e8590c→#ffd8a8 |
| Flowchart | Start: #2f9e44→#b2f2bb, Process: #1971c2→#a5d8ff, Decision: #e8590c→#ffd8a8, End: #e03131→#ffc9c9 |
| Mind Map | Hub: #9c36b5→#eebefa, Branch1: #1971c2→#a5d8ff, Branch2: #2f9e44→#b2f2bb, Branch3: #e8590c→#ffd8a8 |
| Grayscale+Accent | Shapes: #1e1e1e→#ffffff, Accent: #1971c2→#a5d8ff, Secondary: #868e96→#e9ecef |
| Before/After | Before: #e03131→#ffc9c9, After: #2f9e44→#b2f2bb, Neutral: #868e96→#e9ecef |
| Dark Theme | Shapes: #868e96→#343a40, Accent1: #4dabf7→#1971c2, Accent2: #69db7c→#2f9e44, Text: #f8f9fa |
Rule: Limit to 3-4 fill colors per diagram. Darker strokes pair with lighter fills (shade 8 + shade 2).
Diagram Type Templates (Pre-Calculated Grids)
Use these coordinate grids to skip layout planning. Widths assume max(160, labelLength * 9).
Architecture (Layered, 4 tiers)
Zone: x=0, y=0, w=800, h=700, fill=#f8f9fa, opacity=30
Tier 1: y=30 — Client/UI layer (2-3 boxes, 200px apart horizontally)
Tier 2: y=170 — Gateway/API layer (1-2 boxes centered)
Tier 3: y=310 — Service layer (3-5 boxes, 180px apart)
Tier 4: y=460 — Data layer (2-3 boxes, 200px apart)
Side: x=850 — Observability/external (offset 50px right of zone)Flowchart (Top-Down, up to 8 steps)
Start: x=300, y=30 — ellipse 120x60, green
Step 1: x=280, y=140 — rect 160x70, blue
Decision: x=290, y=260 — diamond 120x120, orange
Yes→: x=280, y=430 — rect (below)
No→: x=500, y=260 — rect (right, same y as diamond)
Step N: y += 150 per step
End: last y + 150 — ellipse, redMind Map (Radial, hub + 4 branches)
Hub: x=350, y=300 — 280x140, hero size
Branch 1: x=0, y=50 — 180x80 (top-left)
Branch 2: x=700, y=50 — 180x80 (top-right)
Branch 3: x=0, y=520 — 180x80 (bottom-left)
Branch 4: x=700, y=520 — 180x80 (bottom-right)
Sub-nodes: offset 200px outward from each branchSequence (3 participants)
Actor A: x=50, y=30 — 120x40
Actor B: x=300, y=30 — 120x40
Actor C: x=550, y=30 — 120x40
Lifelines: vertical dashed lines from each actor, y=70 downward
Messages: horizontal arrows between lifelines, y += 60 per messageTimeline (Horizontal)
Line: x=50, y=250, points=[[0,0],[900,0]] — strokeWidth 2
Dots: y=250, spaced 150px apart on the line — ellipse 16x16
Labels: alternate above (y=180) and below (y=290) each dotComparison (Side-by-Side)
Left col: x=0, w=380 — "Before" zone, red-tinted
Right col: x=420, w=380 — "After" zone, green-tinted
Row 1: y=60 — matching elements at same y
Row 2: y=200
Row 3: y=340
Arrow: horizontal from left col → right col at y=midpointMax Node Counts (before splitting into sub-diagrams)
| Type | Max Nodes | If larger → |
|---|---|---|
| Architecture | 6-15 | Split into sub-diagrams |
| Flowchart | 10-25 | Break into phases |
| Mind map | 5-12 per level | Use sub-branches |
Workflow: Draw A Diagram
MCP Mode
1. Call `read_diagram_guide` first to load design best practices. 2. Plan your coordinate grid (see Quality Gate → Layout Planning) before writing any JSON. 3. Optional: clear_canvas to start fresh. 4. Use batch_create_elements with shapes AND arrows in one call. 5. Assign custom `id` to shapes (e.g. "id": "auth-svc"). Set text field to label shapes. 6. Size shapes for their text — use width: max(160, textLength * 9). 7. Bind arrows using startElementId / endElementId — arrows auto-route. 8. set_viewport with scrollToContent: true to auto-fit the diagram. 9. Run Quality Checklist — get_canvas_screenshot and critically evaluate. Fix issues before proceeding.
REST API Mode
1. Read references/cheatsheet.md for design guidelines. 2. Plan your coordinate grid (see Quality Gate → Layout Planning) before writing any JSON. 3. Optional: curl -X DELETE http://localhost:3000/api/elements/clear 4. Create elements in one call (use @file.json for large payloads):
curl -X POST http://localhost:3000/api/elements/batch \
-H "Content-Type: application/json" \
-d '{"elements": [
{"id": "svc-a", "type": "rectangle", "x": 0, "y": 0, "width": 160, "height": 60, "label": {"text": "Service A"}},
{"id": "svc-b", "type": "rectangle", "x": 0, "y": 200, "width": 160, "height": 60, "label": {"text": "Service B"}},
{"type": "arrow", "x": 0, "y": 0, "start": {"id": "svc-a"}, "end": {"id": "svc-b"}}
]}'5. Use `"label": {"text": "..."}` for shape labels (not "text": "..."). 6. Bind arrows with `"start": {"id": "..."}` / `"end": {"id": "..."}` — server auto-routes edges. 7. Size shapes for their text — use width: max(160, labelTextLength * 9). 8. Run Quality Checklist — take screenshot, critically evaluate. Fix issues before adding more elements.
Arrow Binding (Recommended)
Bind arrows to shapes for auto-routed edges. The format differs between MCP and REST API:
MCP Mode — use startElementId / endElementId:
{"elements": [
{"id": "svc-a", "type": "rectangle", "x": 0, "y": 0, "width": 120, "height": 60, "text": "Service A"},
{"id": "svc-b", "type": "rectangle", "x": 0, "y": 200, "width": 120, "height": 60, "text": "Service B"},
{"type": "arrow", "x": 0, "y": 0, "startElementId": "svc-a", "endElementId": "svc-b", "text": "calls"}
]}REST API Mode — use start: {id} / end: {id} and label: {text}:
{"elements": [
{"id": "svc-a", "type": "rectangle", "x": 0, "y": 0, "width": 120, "height": 60, "label": {"text": "Service A"}},
{"id": "svc-b", "type": "rectangle", "x": 0, "y": 200, "width": 120, "height": 60, "label": {"text": "Service B"}},
{"type": "arrow", "x": 0, "y": 0, "start": {"id": "svc-a"}, "end": {"id": "svc-b"}}
]}Arrows without binding use manual x, y, points coordinates.
Workflow: Mermaid-First (Fastest Path)
For flowcharts, sequence diagrams, and class diagrams, start with Mermaid syntax and convert:
1. Write the diagram in Mermaid syntax. 2. Call create_from_mermaid with the Mermaid definition. 3. set_viewport with scrollToContent: true. 4. get_canvas_screenshot — evaluate layout. 5. Refine with update_element / delete_element (elements are now editable Excalidraw objects). 6. Apply style preset: update roughness, fontFamily, colors on each element.
Native conversion (editable elements): graph TD/LR, sequenceDiagram, classDiagram Fallback (embedded SVG, NOT editable): All other Mermaid types (pie, gantt, state, ER, etc.)
For non-native types, use the manual batch_create_elements workflow instead.
Arrow Routing — Avoid Overlaps (Critical for complex diagrams)
Straight arrows (2-point) cause crossing and overlap in complex diagrams. Use curved or elbowed arrows instead:
Option 1: Curved arrows — add intermediate waypoints + roundness:
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0, 0], [50, -40], [200, 0]],
"roundness": {"type": 2},
"strokeColor": "#1971c2"
}Option 2: Elbowed arrows — right-angle routing (L-shaped or Z-shaped):
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0, 0], [0, -50], [200, -50], [200, 0]],
"roundness": {"type": 2},
"strokeColor": "#1971c2"
}When to use which:
- Fan-out arrows (one source → many targets): Use curved arrows with waypoints spread vertically to avoid overlapping each other.
- Cross-lane arrows (connecting to side panels): Use elbowed arrows that route around the main diagram — go UP first, then ACROSS, then DOWN.
- Inter-service arrows (horizontal connections): Use curved arrows with a slight vertical offset to avoid crossing through adjacent elements.
Rule of thumb: If an arrow would cross through an unrelated element, add a waypoint to route around it. Never accept crossing arrows — always fix them.
Workflow: Iterative Refinement (Key Differentiator)
The feedback loop that makes this skill unique. Each iteration MUST include a quality check.
MCP Mode (full feedback loop)
1. Add elements (batch_create_elements, create_element). 2. set_viewport with scrollToContent: true. 3. get_canvas_screenshot — critically evaluate against the Quality Checklist. 4. If issues found → fix them (update_element, delete_element, resize, reposition). 5. get_canvas_screenshot again — re-verify fix. 6. Only proceed to next iteration when ALL quality checks pass.
REST API Mode (partial feedback loop)
1. Add elements via POST /api/elements/batch. 2. POST /api/viewport with {"scrollToContent": true}. 3. Take screenshot: POST /api/export/image → save PNG → critically evaluate against Quality Checklist. 4. If issues found → fix via PUT /api/elements/:id or delete and recreate. 5. Re-screenshot and re-verify. 6. Only proceed to next iteration when ALL quality checks pass.
How to critically evaluate a screenshot:
- Look at EVERY label — is any text cut off or overflowing its container?
- Look at EVERY arrow — does any arrow pass through an unrelated element?
- Look at ALL element pairs — do any overlap or touch?
- Look at spacing — is anything crammed together?
- Be honest. If you see ANY issue, say "I see [issue], fixing it" — not "looks great".
Workflow: Refine An Existing Diagram
1. describe_scene to understand current state. 2. Identify targets by id, type, or label text (not x/y coordinates). 3. update_element to move/resize/recolor, delete_element to remove. 4. get_canvas_screenshot to verify changes visually. 5. If updates fail: check element id exists (get_element), element isn't locked (unlock_elements).
Workflow: File I/O (Diagrams-as-Code)
- Export to .excalidraw format:
export_scenewith optionalfilePath. - Import from .excalidraw:
import_scenewithmode: "replace"or"merge". - Export to image:
export_to_imagewithformat: "png"or"svg"(requires browser open). - CLI export:
node scripts/export-elements.cjs --out diagram.elements.json - CLI import:
node scripts/import-elements.cjs --in diagram.elements.json --mode batch|sync
Workflow: Snapshots (Save/Restore Canvas State)
1. snapshot_scene with a name before risky changes. 2. Make changes, describe_scene / get_canvas_screenshot to evaluate. 3. restore_snapshot to rollback if needed.
Workflow: Duplication
duplicate_elementswithelementIdsand optionaloffsetX/offsetY(default 20,20).- Useful for creating repeated patterns or copying existing layouts.
Points Format for Arrows/Lines
The points field accepts both formats:
- Tuple:
[[0, 0], [100, 50]] - Object:
[{"x": 0, "y": 0}, {"x": 100, "y": 50}]
Both are normalized to tuples automatically.
Workflow: Share Diagram (excalidraw.com URL)
1. Create your diagram using any of the above workflows. 2. export_to_excalidraw_url — uploads encrypted scene, returns a shareable URL. 3. Share the URL — anyone can open it in excalidraw.com to view and edit.
Workflow: Viewport Control
set_viewportwithscrollToContent: true— auto-fit all elements (zoom-to-fit).set_viewportwithscrollToElementId: "my-element"— center view on a specific element.set_viewportwithzoom: 1.5, offsetX: 100, offsetY: 200— manual camera control.
Advanced Techniques
Fill Styles
| fillStyle | Visual | Best For |
|---|---|---|
solid | Flat color | Clean, professional |
hachure | Diagonal hatching | Classic hand-drawn (default) |
cross-hatch | Cross-hatching | Dense emphasis |
zigzag | Zigzag pattern | Playful, energetic |
dots | Dotted pattern | Light, airy |
dashed | Dashed pattern | De-emphasized, secondary |
Rounded Corners
Add "roundness": {"type": 3} to shapes for softer, polished appearance. Recommended for most styles.
Zone / Background Rectangles
- Use opacity 30-35 (not 100) — creates grouping without dominating.
- Fill with light gray (#f8f9fa or #e9ecef), stroke with #868e96.
- Add 50px padding on ALL sides around contained elements.
- Label zones with 20px fontSize standalone text (not inside the zone shape).
Complex Shapes from Primitives
| Shape | Recipe | Group? |
|---|---|---|
| Database cylinder | Ellipse (top) + Rectangle (body) + Ellipse (bottom, same fill) | Yes |
| Cloud | 3-4 overlapping ellipses, same fill/stroke | Yes |
| Stick figure | Ellipse 20x20 (head) + Rectangle 22x26 (body) | Yes |
Visual Pattern Library
| Pattern | Shape Behavior | When to Use |
|---|---|---|
| Fan-Out | Radial arrows from central hub | One-to-many relationships |
| Convergence | Funnel/merge to single point | Many-to-one aggregation |
| Tree | Trunk lines with branches | Hierarchies, taxonomies |
| Spiral/Cycle | Arrows returning to start | Feedback loops, iterations |
| Assembly Line | Before → Process → After | Transformations, pipelines |
| Side-by-Side | Parallel structures | Comparisons, trade-offs |
| Timeline | Central line with dots + labels | Sequential events |
Container Discipline
- Default to free-floating text. Add containers only when the box carries semantic meaning.
- Target <30% of text elements inside containers.
- Use lines as structural elements (tree trunks, timelines).
- Typography alone creates hierarchy — use fontSize + color, not boxes.
Opacity Tricks
- Barely-visible frames: opacity 30-35 on background zones.
- "Many" effect: slightly offset semi-transparent copies suggest plurality.
- Secondary elements: opacity 50-70 for annotations and non-primary arrows.
References
references/cheatsheet.md: Complete MCP tool list (26 tools) + REST API endpoints + payload shapes.research/design-research.md: 923 lines covering Open Colors palette, 13 diagram types, 6 visual styles, typography, 40+ sources.
Related skills
FAQ
What are the two connection modes?
MCP server mode (best experience, call MCP tools directly) and a REST API fallback at http://localhost:3000 that uses HTTP endpoints when no MCP server is available.
What does the quality gate check?
After every iteration it verifies text truncation, element overlap, arrow crossing, arrow-text overlap, spacing of at least 40px, readability, an isomorphism test, and an education test.