Programmatic canvas toolkit for creating, editing, and refining Excalidraw diagrams via MCP tools with real-time canvas sync. Use when an agent needs to (1) draw or lay out diagrams on a live canvas, (2) iteratively refine diagrams using describe_scene and get_canvas_screenshot to see its own work, (3) export/import .excalidraw files or PNG/SVG images, (4) save/restore canvas snapshots, (5) convert Mermaid to Excalidraw, or (6) perform element-level CRUD, alignment, distribution, grouping, duplication, and locking. Requires a running canvas server (EXPRESS_SERVER_URL, default http://localhost:3000).
npx skills add https://github.com/lingzhi227/agent-research-skills --skill excalidraw-skill
Before doing anything, determine which mode is available. Run these checks in order:
mcp-cli tools | grep excalidraw
If you see tools like excalidraw/batch_create_elements → use MCP mode. Call MCP tools directly.
curl -s http://localhost:3000/health
If you get {"status":"ok"} → use REST API mode. Use HTTP endpoints (curl / fetch) from the cheatsheet.
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_excalidraw
> 2. Build: npm ci && npm run build
> 3. Start canvas: HOST=0.0.0.0 PORT=3000 npm run canvas
> 4. Open http://localhost:3000 in a browser
> 5. (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
> `
| 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 |
"label": {"text": "My Label"} (not "text": "My Label"). MCP tools auto-convert, REST API does not."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."1") or omit it entirely. Do NOT pass a number like 1.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.POST /api/export/image returns {"data": "<base64>"}. Save to file and read it back for visual verification. Requires browser open.After EVERY iteration (each batch of elements added), you MUST run a quality check before proceeding. NEVER say "looks great" unless ALL checks pass.
width and/or height.max(160, labelTextLength * 9) pixels. For multi-word labels like "API Gateway (Kong)", count all characters.Before creating elements, plan your coordinate grid on paper first:
Do NOT place side panels (observability, external APIs) at the same x-range as the main diagram — they WILL overlap.
references/cheatsheet.md.read_diagram_guide first to load design best practices.clear_canvas to start fresh.batch_create_elements with shapes AND arrows in one call.id to shapes (e.g. "id": "auth-svc"). Set text field to label shapes.width: max(160, textLength * 9).startElementId / endElementId — arrows auto-route.set_viewport with scrollToContent: true to auto-fit the diagram.get_canvas_screenshot and critically evaluate. Fix issues before proceeding.references/cheatsheet.md for design guidelines.curl -X DELETE http://localhost:3000/api/elements/clear@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"}}
]}'
"label": {"text": "..."} for shape labels (not "text": "...")."start": {"id": "..."} / "end": {"id": "..."} — server auto-routes edges.width: max(160, labelTextLength * 9).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"}, "label": {"text": "calls"}}
]}
Arrows without binding use manual x, y, points coordinates.
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"
}
The waypoint [50, -40] pushes the arrow upward to arc over elements. roundness: {type: 2} makes it a smooth curve.
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]],
"elbowed": true,
"strokeColor": "#1971c2"
}
When to use which:
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.
The feedback loop that makes this skill unique. Each iteration MUST include a quality check.
batch_create_elements, create_element).set_viewport with scrollToContent: true.get_canvas_screenshot — critically evaluate against the Quality Checklist.update_element, delete_element, resize, reposition).get_canvas_screenshot again — re-verify fix.POST /api/elements/batch.POST /api/viewport with {"scrollToContent": true}.POST /api/export/image → save PNG → critically evaluate against Quality Checklist.PUT /api/elements/:id or delete and recreate.Example flow (MCP):
batch_create_elements → get_canvas_screenshot → "text truncated on 2 shapes"
→ update_element (increase widths) → get_canvas_screenshot → "overlap between X and Y"
→ update_element (reposition) → get_canvas_screenshot → "all checks pass"
→ proceed to next iteration
describe_scene to understand current state.update_element to move/resize/recolor, delete_element to remove.get_canvas_screenshot to verify changes visually.get_element), element isn't locked (unlock_elements).export_scene with optional filePath.import_scene with mode: "replace" or "merge".export_to_image with format: "png" or "svg" (requires browser open).node scripts/export-elements.cjs --out diagram.elements.jsonnode scripts/import-elements.cjs --in diagram.elements.json --mode batch|syncsnapshot_scene with a name before risky changes.describe_scene / get_canvas_screenshot to evaluate.restore_snapshot to rollback if needed.duplicate_elements with elementIds and optional offsetX/offsetY (default 20,20).The points field accepts both formats:
[[0, 0], [100, 50]][{"x": 0, "y": 0}, {"x": 100, "y": 50}]Both are normalized to tuples automatically.
export_to_excalidraw_url — uploads encrypted scene, returns a shareable URL.set_viewport with scrollToContent: true — auto-fit all elements (zoom-to-fit).set_viewport with scrollToElementId: "my-element" — center view on a specific element.set_viewport with zoom: 1.5, offsetX: 100, offsetY: 200 — manual camera control.references/cheatsheet.md: Complete MCP tool list (26 tools) + REST API endpoints + payload shapes.agent-im 会话技能 - 通过 liblib.tv 的 AI 能力生成和编辑图片/视频。覆盖场景包括:生成(文生图、文生视频、图生视频、做动画、画一个xxx、来段xxx)、编辑修改(把xxx换成yyy、去掉xxx、加上xxx、改成xxx、调整xxx、局部修改、改镜头)、风格转换(风格迁移、转绘、换风格)、视频续写延长、复刻视频/TVC/宣传片、短剧/短漫剧生成、音乐MV生成、产品广告/展示片制作、分镜/故事板设计、教育视频/短视频制作。当用户提到 liblib、libtv、上传参考图/视频、查看生成进度时也应触发。关键判断:只要用户的请求涉及 AI 图片或视频的创作、生成、编辑、修改,无论措辞如何(如"画只猫"、"做个海报"、"把纸船换成爱心"、"这个视频帮我改一下"、"帮我复刻这段视频"、"用这首歌做个MV"、"一句话生成短剧"),都必须触发此技能。
This skill should be used when the user asks to "generate video prompts", "create Seedance prompts", "write video descriptions", mentions "Seedance", "seedance", "即梦", "即梦平台", "视频提示词", "视频生成", "AI视频", "短剧", "广告视频", "视频延长", or discusses video prompt engineering, AI video generation, or Seedance 2.0 workflows.
Best practices and techniques for writing effective AI video generation prompts. Covers: Veo, Seedance, Wan, Grok, Kling, Runway, Pika, Sora prompting strategies. Learn: shot types, camera movements, lighting, pacing, style keywords, negative prompts. Use for: improving video quality, getting consistent results, professional video prompts. Triggers: video prompt, how to prompt video, veo prompts, video generation tips, better ai video, video prompt engineering, video prompt guide, video prompt template, ai video tips, video prompt best practices, video prompt examples, cinematography prompts
This skill is a practical, 'use-it-while-debugging' reference for getting a LiveKit + Letta voice agent working reliably.
Download screenshot baselines from the latest CI run and commit them. Use when asked to update, accept, or refresh component screenshot baselines from CI, or after the screenshot-test GitHub Action reports differences. This skill should be run as a subagent.
| Turn vague taste, screenshots, URLs, product notes, or "make it feel like this" references into a grounded DESIGN.md plus an implementation handoff. Use it before prototypes, decks, redesigns, or image remix work when the user needs a reusable visual direction rather than a one-off prompt.
>- Upload local assets (images, mockups, extracted HTML, design markdown) to a Stitch project. ALWAYS use this skill when you need to upload visual assets, HTML pages, or design docs to Stitch, particularly when direct MCP tool calls fail or truncate due to base64 token limits.
This skill helps users automatically extract channel-level and video detail data from a specific YouTube channel via BrowserAct API. Agent should proactively apply this skill when users express needs like extracting channel video data, getting latest or popular videos from a YouTube channel, tracking competitor channel content, extracting video metrics such as views likes comments, retrieving subscriber count and channel info, monitoring posting cadence of a YouTube channel, gathering video data for content strategy analysis, getting earliest videos of a YouTube creator, analyzing engagement signals across a full channel, and downloading structured YouTube video details without manual scraping.
Take lingzhi227/excalidraw-skill from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.