Excalidraw 技能
步骤 0:选择接口
三个接口驱动同一个实时画布。选择第一个适用的:
- MCP 工具 — 如果
excalidraw/*工具(例如batch_create_elements)在你的工具列表中,优先使用它们:结果直接进入你的上下文,截图以图像形式返回,无需接触磁盘。 - CLI(当没有 MCP 工具时的默认选项):
无需设置 — 任何涉及画布的命令都会自动启动画布服务器(首次npx -y mcp-excalidraw-server <command>npx运行会下载包)。如果 CLI 已全局安装(npm i -g mcp-excalidraw-server),也可以使用更短的别名excalidraw-canvas <command>。 - REST API(最后手段,例如从应用程序代码调用):HTTP 端点位于
http://127.0.0.1:3000— 有关载荷,请参阅references/cheatsheet.md。服务器必须已经运行。
画布 URL 来自 EXPRESS_SERVER_URL(默认为 http://127.0.0.1:3000)。提醒用户在浏览器中打开该 URL — 截图、图像导出、Mermaid 转换和视口控制都需要一个打开的标签页(当缺少时,CLI 会以退出码 4 退出)。
CLI 快速参考
结果是 JSON 输出到 stdout — 除了 describe(纯文本)和省略 --out 时的原始内容输出(export 场景 JSON,screenshot --format svg 输出原始 SVG)。诊断信息输出到 stderr。退出码:0 正常,1 错误,2 用法错误,3 画布不可达,4 需要浏览器标签页。
| 任务 | 命令 |
|---|---|
| 启动 / 停止 / 检查服务器 | start, stop, status |
| 创建元素(批量) | add elements.json 或 echo '[...]' | add 或 add --one '{...}' |
| 单次调用中的多重操作补丁 | apply patch.json — {"create":[...],"update":[{"id":"a","set":{...}}],"delete":[...]} |
| 读取单个 / 查询多个 | get <id>, query [--type t] [--bbox x0,y0,x1,y1] [--filter k=v] [--filter-json '{...}'] |
| 更新 / 删除 | update <id> --set '{...}', delete <id> [...] |
| 理解场景 | describe(纯文本摘要:ID、位置、标签、连接) |
| 查看场景 | screenshot [--out f.png](省略 --out 的 PNG → 临时文件路径以 JSON 形式返回;省略 --out 的 SVG → 原始 SVG) |
| 布局操作 | `arrange align |
| 场景文件 | export [--out scene.excalidraw], `import [scene.excalidraw |
| Mermaid → 画布 | `mermaid [diagram.mmd |
| 快照 | `snapshot save |
| 共享链接 | share(加密上传 → excalidraw.com URL) |
| 清除画布 | clear --yes |
| 安装 / 升级此技能 | install-skill --dir <skills-root>(智能体选择项目/全局根目录) |
元素格式(CLI 和 MCP)
CLI 和 MCP 工具接受相同的智能体友好格式,并自动进行规范化:
- 标签:在任何形状上添加
"text": "My Label"— 自动转换为 Excalidraw 的绑定标签格式。 - 箭头绑定:
"startElementId": "a"/"endElementId": "b"— 箭头自动路由到元素边缘。 - fontFamily:传递字符串名称(
"helvetica"、"cascadia"、"excalifont"等)或字符串数字"1"–"8"。 - points:接受
[[x,y], ...]元组和[{"x":..,"y":..}]对象。 - 补丁更新:在
apply中,更新条目可以使用直接字段({"id":"a","x":120})或set对象({"id":"a","set":{"x":120}})。不要在同一个更新条目中混合使用两种形式。
原始 REST 更严格:标签必须为 "label": {"text": "..."},绑定必须为 "start": {"id": "..."} / "end": {"id": "..."}。只在直接使用 API 进行 POST 时才需要担心这一点。
坐标系统
画布使用二维坐标网格:(0, 0) 是原点,x 向右增加,y 向下增加。在编写任何 JSON 之前规划好布局。
通用间距指南:
- 层级之间的垂直间距:80–120px(确保箭头不会挤占标签)
- 同级之间的水平间距:40–60px 最小值;给带标签的箭头留出 120px+ 的空间
- 形状宽度:
max(160, labelCharCount * 12)以保持标签在一行内 - 形状高度:单行标签 60px,双行标签 80px
- 背景/区域内边距:围绕包含元素的各边 50px
专业外观的样式设置:
- 形状上的
"fillStyle": "solid"可提供清晰的纯色填充 — 默认为草稿式的阴影图案 - 将柔和的
backgroundColor填充与其较暗的strokeColor配对(色板请参阅速查表) - 区域边框和异步箭头上的
"strokeStyle": "dashed"表示“边界/背景”
布局反模式(对复杂图表至关重要)
这些是产生不可读图表的最常见错误。避免所有错误。
1. 不要在大背景区域矩形上使用 label.text(或 text)
当你在背景矩形上放置标签时,Excalidraw 会创建一个绑定文本元素,该元素居中于该形状的中间 — 正好在你的服务框将被放置的位置。文本与区域内的所有内容重叠,并且无法重新定位。
错误做法:
{"id": "vpc-zone", "type": "rectangle", "x": 50, "y": 50, "width": 800, "height": 400, "text": "VPC (10.0.0.0/16)"}
正确做法 — 使用一个锚定在区域顶部的独立文本元素:
{"id": "vpc-zone", "type": "rectangle", "x": 50, "y": 50, "width": 800, "height": 400, "backgroundColor": "#e3f2fd"},
{"id": "vpc-label", "type": "text", "x": 70, "y": 60, "width": 300, "height": 30, "text": "VPC (10.0.0.0/16)", "fontSize": 18}
独立的文本元素位于区域的顶角,不会干扰放置在内部的元素。
2. 避免在复杂图表中使用跨区域箭头
从某个布局区域中的元素到远处区域中元素的箭头会绘制一条穿过中间所有内容的长对角线。在多区域基础设施图中,这会产生难以理解的意大利面条式乱线。
**设计规则:**将箭头保持在同一区域或层级内。要显示跨区域关系,请使用注释文本或分隔区域,使它们的边缘相邻(之间没有元素),并沿着边缘路由箭头。
如果必须跨区域连接,请使用沿周长移动的肘形箭头 — 切勿穿过另一个区域的中间。
3. 谨慎使用箭头标签
箭头标签放置在箭头的中间点。在短箭头上,它们会与两端的形状重叠。在拥挤的图表中,它们会与附近的元素碰撞。
- 仅当关系名称确实至关重要时才添加箭头标签(例如,协议、端口号、数据方向)。
- 如果你要为每个箭头都添加标签,请重新考虑 — 这通常会增加视觉噪音,而不是清晰度。
- 保持箭头标签 ≤ 12 个字符。在密集图表中最好完全省略它们。
质量:为什么重要(以及如何检查)
Excalidraw 图表是视觉沟通。如果文本被截断、元素重叠或箭头穿过无关的形状,图表就会变得混乱且不专业 — 这完全违背了绘制它的目的。因此,在每批元素之后,在添加更多元素之前都要进行验证。
质量检查清单
每次 add / apply / batch_create_elements 后,截图并检查:
- 文本截断 — 所有标签文本是否完全可见?文本截断意味着形状太小。增加
width和/或height。 - 重叠 — 是否有任何形状共享相同的空间?背景区域必须完全包含子元素并带有内边距。
- 箭头交叉 — 箭头是否穿过无关的元素?如果是,请使用曲线或肘形箭头绕过它们(请参阅下面的箭头路由)。
- 箭头标签重叠 — 箭头标签位于中间点。如果它们与形状重叠,请缩短标签或调整箭头路径。
- 间距 — 元素之间至少保持 40px 的间距。拥挤的布局难以阅读。
- 可读性 — 正文字体大小 ≥ 16,标题字体大小 ≥ 20。
- 区域标签放置 — 如果你在背景区域矩形上使用了
text/label.text,则区域标签将居中于区域的中间,与内部所有内容重叠。修复:删除绑定的文本元素,并在区域顶部添加一个独立的文本元素(请参阅上面的布局反模式)。
如果你发现任何问题:停止,修复,重新截图,然后继续。 说“我发现了[问题],正在修复”,而不是掩盖问题。只有在所有检查都通过后才继续。
工作流:绘制新图表
Mermaid 与直接创建 — 使用哪一个?
使用 mermaid / create_from_mermaid 当:用户已有 Mermaid 图表,或者结构可以清晰地映射到具有标准 Mermaid 语法的流程图/序列图/ER 图时。它速度快且自动处理转换,尽管你对精确布局的控制较少。
直接创建元素 当:你需要精确的布局控制,图表类型不能很好地映射到 Mermaid(例如,自定义架构、带注释的云图),或者你希望元素定位在特定的坐标网格中时。
步骤(以 CLI 为例;MCP 工具是一一对应的 — 请参阅速查表)
- 规划你的坐标网格 — 在编写 JSON 之前,先规划好层级和 x 位置。(MCP 模式:调用
read_diagram_guide获取颜色/尺寸;相同的指南位于references/cheatsheet.md中。) - 可选的全新开始:
npx -y mcp-excalidraw-server clear --yes - 在单次调用中创建形状和箭头。自定义
id字段(例如"id": "auth-svc")使后续更新变得容易:(npx -y mcp-excalidraw-server add - <<'EOF' [ {"id": "lb", "type": "rectangle", "x": 300, "y": 50, "width": 180, "height": 60, "text": "Load Balancer"}, {"id": "svc-a", "type": "rectangle", "x": 100, "y": 200, "width": 160, "height": 60, "text": "Web Server 1"}, {"id": "svc-b", "type": "rectangle", "x": 450, "y": 200, "width": 160, "height": 60, "text": "Web Server 2"}, {"id": "db", "type": "rectangle", "x": 275, "y": 350, "width": 210, "height": 60, "text": "PostgreSQL"}, {"type": "arrow", "x": 0, "y": 0, "startElementId": "lb", "endElementId": "svc-a"}, {"type": "arrow", "x": 0, "y": 0, "startElementId": "lb", "endElementId": "svc-b"}, {"type": "arrow", "x": 0, "y": 0, "startElementId": "svc-a", "endElementId": "db"}, {"type": "arrow", "x": 0, "y": 0, "startElementId": "svc-b", "endElementId": "db"} ] EOF-位置参数是可选的 — 如果没有文件参数,add会读取 stdin。) - 使用
max(160, labelLength * 12)设置形状宽度。 screenshot→ 查看文件 → 运行质量检查清单 → 在下一批之前修复问题。
箭头路由 — 避免重叠
在复杂图表中,直线箭头可能会穿过元素。必要时使用曲线或肘形箭头:
曲线箭头(平滑的圆弧绕过障碍物):
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0, 0], [50, -40], [200, 0]],
"roundness": {"type": 2}
}
中间路径点 [50, -40] 将箭头向上抬起。roundness: {type: 2} 使其平滑。
肘形箭头(直角 / L 形路由):
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0, 0], [0, -50], [200, -50], [200, 0]],
"elbowed": true
}
何时使用哪种:
- 扇出(一个源 → 多个目标):带有路径点的曲线箭头,分散以避免重叠
- 跨通道(连接到侧面板):肘形箭头,先向上,再横向,然后向下
- 长水平连接:带有轻微垂直偏移的曲线箭头
**规则:**如果箭头会穿过无关的形状,请添加一个路径点以绕过它。
工作流:迭代优化
将 describe 与 screenshot 配对使用是此技能强大的原因。
describe(MCP 中的describe_scene)→ 结构化文本:元素 ID、类型、位置、标签、连接。在程序化更新之前用它来了解画布上的内容(查找 ID,了解边界框)。screenshot(MCP 中的get_canvas_screenshot)→ 实际渲染画布的 PNG。用于视觉质量验证 — 它准确显示用户所看到的内容,包括截断、重叠和箭头路由。CLI 将保存的文件路径打印为 JSON;读取/查看该文件。
反馈循环:
add elements
→ screenshot → view → "auth-svc 上文本截断"
→ update auth-svc --set '{"width": 220}' → screenshot → "auth-svc 和 rate-limiter 之间重叠"
→ update rate-limiter --set '{"x": 520}' → screenshot → "所有检查通过"
→ proceed
工作流:优化现有图表
- 使用
describe了解当前状态 — 记下元素 ID 和位置。 - 通过
id或标签文本(而不是 x/y 坐标 — 它们会变化)识别元素。 - 使用
update <id> --set '{...}'调整大小/重新着色/移动;使用delete <id>删除;或者将所有内容捆绑在单个apply补丁中。当你移动或调整端点大小时,绑定的箭头会自动重新路由 — 无需删除并重新创建它们。 - 使用
screenshot确认更改看起来正确。 - 如果更新失败:使用
get <id>检查 ID 是否存在;如果已锁定,使用arrange unlock --ids <id>解锁。
工作流:Mermaid 转换
echo 'graph TD
A[Client] --> B[API]
B --> C[(DB)]' | npx -y mcp-excalidraw-server mermaid
需要打开一个浏览器标签页(转换在前端运行;退出码 4 提示你打开画布 URL)。之后使用 screenshot 验证布局。如果自动布局不佳(节点拥挤,边交叉),使用 describe 找到问题元素,并使用 update 重新定位它们。
工作流:文件 I/O
- 导出场景:
export --out diagram.excalidraw(省略--out→ JSON 输出到 stdout) - 导入场景:
import diagram.excalidraw(追加)或import diagram.excalidraw --replace - 图像:
screenshot --out diagram.png/screenshot --format svg --out diagram.svg(需要浏览器标签页) - 共享链接:
share— 加密场景并返回一个可共享的 excal
…(翻译时内容已截断)