excalidraw

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Excalidraw Diagram Skill

Excalidraw图表绘制技能

Create diagrams by writing standard Excalidraw element JSON and saving as
.excalidraw
files. These files can be drag-and-dropped onto excalidraw.com for viewing and editing. No accounts, no API keys, no rendering libraries -- just JSON.
通过编写标准的Excalidraw元素JSON并保存为
.excalidraw
文件来创建图表。这些文件可拖拽到excalidraw.com进行查看和编辑。无需账号、无需API密钥、无需渲染库——只需JSON即可。

When to use

适用场景

Generate
.excalidraw
files for architecture diagrams, flowcharts, sequence diagrams, concept maps, and more. Files can be opened at excalidraw.com or uploaded for shareable links.
生成
.excalidraw
文件用于架构图、流程图、序列图、概念图等。文件可在excalidraw.com打开,或上传生成可分享链接。

Workflow

操作流程

  1. Load this skill (you already did)
  2. Write the elements JSON -- an array of Excalidraw element objects
  3. Save the file using
    write_file
    to create a
    .excalidraw
    file
  4. Optionally upload for a shareable link using
    scripts/upload.py
    via
    terminal
  1. 加载本技能(你已完成此步骤)
  2. 编写元素JSON——一个Excalidraw元素对象数组
  3. 保存文件:使用
    write_file
    创建
    .excalidraw
    文件
  4. 可选上传:通过
    terminal
    运行
    scripts/upload.py
    生成可分享链接

Saving a Diagram

保存图表

Wrap your elements array in the standard
.excalidraw
envelope and save with
write_file
:
json
{
  "type": "excalidraw",
  "version": 2,
  "source": "hermes-agent",
  "elements": [ ...your elements array here... ],
  "appState": {
    "viewBackgroundColor": "#ffffff"
  }
}
Save to any path, e.g.
~/diagrams/my_diagram.excalidraw
.
将元素数组包裹在标准的
.excalidraw
结构中,并用
write_file
保存:
json
{
  "type": "excalidraw",
  "version": 2,
  "source": "hermes-agent",
  "elements": [ ...你的元素数组放在这里... ],
  "appState": {
    "viewBackgroundColor": "#ffffff"
  }
}
可保存到任意路径,例如
~/diagrams/my_diagram.excalidraw

Uploading for a Shareable Link

上传生成可分享链接

Run the upload script (located in this skill's
scripts/
directory) via terminal:
bash
python skills/diagramming/excalidraw/scripts/upload.py ~/diagrams/my_diagram.excalidraw
This uploads to excalidraw.com (no account needed) and prints a shareable URL. Requires the
cryptography
pip package (
pip install cryptography
).

通过终端运行本技能
scripts/
目录下的上传脚本:
bash
python skills/diagramming/excalidraw/scripts/upload.py ~/diagrams/my_diagram.excalidraw
此操作会将文件上传到excalidraw.com(无需账号)并打印可分享URL。需要安装
cryptography
pip包(执行
pip install cryptography
)。

Element Format Reference

元素格式参考

Required Fields (all elements)

所有元素必填字段

type
,
id
(unique string),
x
,
y
,
width
,
height
type
,
id
(唯一字符串),
x
,
y
,
width
,
height

Defaults (skip these -- they're applied automatically)

默认值(可省略——会自动应用)

  • strokeColor
    :
    "#1e1e1e"
  • backgroundColor
    :
    "transparent"
  • fillStyle
    :
    "solid"
  • strokeWidth
    :
    2
  • roughness
    :
    1
    (hand-drawn look)
  • opacity
    :
    100
Canvas background is white.
  • strokeColor
    :
    "#1e1e1e"
  • backgroundColor
    :
    "transparent"
  • fillStyle
    :
    "solid"
  • strokeWidth
    :
    2
  • roughness
    :
    1
    (手绘风格)
  • opacity
    :
    100
画布背景为白色。

Element Types

元素类型

Rectangle:
json
{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 100 }
  • roundness: { "type": 3 }
    for rounded corners
  • backgroundColor: "#a5d8ff"
    ,
    fillStyle: "solid"
    for filled
Ellipse:
json
{ "type": "ellipse", "id": "e1", "x": 100, "y": 100, "width": 150, "height": 150 }
Diamond:
json
{ "type": "diamond", "id": "d1", "x": 100, "y": 100, "width": 150, "height": 150 }
Labeled shape (container binding) -- create a text element bound to the shape:
WARNING: Do NOT use
"label": { "text": "..." }
on shapes. This is NOT a valid Excalidraw property and will be silently ignored, producing blank shapes. You MUST use the container binding approach below.
The shape needs
boundElements
listing the text, and the text needs
containerId
pointing back:
json
{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 80,
  "roundness": { "type": 3 }, "backgroundColor": "#a5d8ff", "fillStyle": "solid",
  "boundElements": [{ "id": "t_r1", "type": "text" }] },
{ "type": "text", "id": "t_r1", "x": 105, "y": 110, "width": 190, "height": 25,
  "text": "Hello", "fontSize": 20, "fontFamily": 1, "strokeColor": "#1e1e1e",
  "textAlign": "center", "verticalAlign": "middle",
  "containerId": "r1", "originalText": "Hello", "autoResize": true }
  • Works on rectangle, ellipse, diamond
  • Text is auto-centered by Excalidraw when
    containerId
    is set
  • The text
    x
    /
    y
    /
    width
    /
    height
    are approximate -- Excalidraw recalculates them on load
  • originalText
    should match
    text
  • Always include
    fontFamily: 1
    (Virgil/hand-drawn font)
Labeled arrow -- same container binding approach:
json
{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,
  "points": [[0,0],[200,0]], "endArrowhead": "arrow",
  "boundElements": [{ "id": "t_a1", "type": "text" }] },
{ "type": "text", "id": "t_a1", "x": 370, "y": 130, "width": 60, "height": 20,
  "text": "connects", "fontSize": 16, "fontFamily": 1, "strokeColor": "#1e1e1e",
  "textAlign": "center", "verticalAlign": "middle",
  "containerId": "a1", "originalText": "connects", "autoResize": true }
Standalone text (titles and annotations only -- no container):
json
{ "type": "text", "id": "t1", "x": 150, "y": 138, "text": "Hello", "fontSize": 20,
  "fontFamily": 1, "strokeColor": "#1e1e1e", "originalText": "Hello", "autoResize": true }
  • x
    is the LEFT edge. To center at position
    cx
    :
    x = cx - (text.length * fontSize * 0.5) / 2
  • Do NOT rely on
    textAlign
    or
    width
    for positioning
Arrow:
json
{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,
  "points": [[0,0],[200,0]], "endArrowhead": "arrow" }
  • points
    :
    [dx, dy]
    offsets from element
    x
    ,
    y
  • endArrowhead
    :
    null
    |
    "arrow"
    |
    "bar"
    |
    "dot"
    |
    "triangle"
  • strokeStyle
    :
    "solid"
    (default) |
    "dashed"
    |
    "dotted"
矩形:
json
{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 100 }
  • 设置
    roundness: { "type": 3 }
    可实现圆角
  • 设置
    backgroundColor: "#a5d8ff"
    ,
    fillStyle: "solid"
    可实现填充效果
椭圆:
json
{ "type": "ellipse", "id": "e1", "x": 100, "y": 100, "width": 150, "height": 150 }
菱形:
json
{ "type": "diamond", "id": "d1", "x": 100, "y": 100, "width": 150, "height": 150 }
带标签形状(容器绑定)——创建与形状绑定的文本元素:
注意: 请勿在形状上使用
"label": { "text": "..." }
。这不是有效的 Excalidraw属性,会被静默忽略,导致形状显示为空。你必须 使用以下容器绑定方法。
形状需要通过
boundElements
列出文本元素,文本元素需要通过
containerId
指向形状:
json
{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 80,
  "roundness": { "type": 3 }, "backgroundColor": "#a5d8ff", "fillStyle": "solid",
  "boundElements": [{ "id": "t_r1", "type": "text" }] },
{ "type": "text", "id": "t_r1", "x": 105, "y": 110, "width": 190, "height": 25,
  "text": "Hello", "fontSize": 20, "fontFamily": 1, "strokeColor": "#1e1e1e",
  "textAlign": "center", "verticalAlign": "middle",
  "containerId": "r1", "originalText": "Hello", "autoResize": true }
  • 适用于矩形、椭圆、菱形
  • 设置
    containerId
    后,Excalidraw会自动将文本居中
  • 文本的
    x
    /
    y
    /
    width
    /
    height
    为近似值——Excalidraw会在加载时重新计算
  • originalText
    应与
    text
    一致
  • 务必包含
    fontFamily: 1
    (Virgil手绘字体)
带标签箭头——使用相同的容器绑定方法:
json
{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,
  "points": [[0,0],[200,0]], "endArrowhead": "arrow",
  "boundElements": [{ "id": "t_a1", "type": "text" }] },
{ "type": "text", "id": "t_a1", "x": 370, "y": 130, "width": 60, "height": 20,
  "text": "connects", "fontSize": 16, "fontFamily": 1, "strokeColor": "#1e1e1e",
  "textAlign": "center", "verticalAlign": "middle",
  "containerId": "a1", "originalText": "connects", "autoResize": true }
独立文本(仅用于标题和注释——无容器):
json
{ "type": "text", "id": "t1", "x": 150, "y": 138, "text": "Hello", "fontSize": 20,
  "fontFamily": 1, "strokeColor": "#1e1e1e", "originalText": "Hello", "autoResize": true }
  • x
    为文本左边缘。若要在位置
    cx
    居中:
    x = cx - (text.length * fontSize * 0.5) / 2
  • 请勿依赖
    textAlign
    width
    进行定位
箭头:
json
{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,
  "points": [[0,0],[200,0]], "endArrowhead": "arrow" }
  • points
    : 相对于元素
    x
    ,
    y
    [dx, dy]
    偏移量
  • endArrowhead
    :
    null
    |
    "arrow"
    |
    "bar"
    |
    "dot"
    |
    "triangle"
  • strokeStyle
    :
    "solid"
    (默认)|
    "dashed"
    |
    "dotted"

Arrow Bindings (connect arrows to shapes)

箭头绑定(将箭头连接到形状)

json
{
  "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 150, "height": 0,
  "points": [[0,0],[150,0]], "endArrowhead": "arrow",
  "startBinding": { "elementId": "r1", "fixedPoint": [1, 0.5] },
  "endBinding": { "elementId": "r2", "fixedPoint": [0, 0.5] }
}
fixedPoint
coordinates:
top=[0.5,0]
,
bottom=[0.5,1]
,
left=[0,0.5]
,
right=[1,0.5]
json
{
  "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 150, "height": 0,
  "points": [[0,0],[150,0]], "endArrowhead": "arrow",
  "startBinding": { "elementId": "r1", "fixedPoint": [1, 0.5] },
  "endBinding": { "elementId": "r2", "fixedPoint": [0, 0.5] }
}
fixedPoint
坐标:
顶部=[0.5,0]
,
底部=[0.5,1]
,
左侧=[0,0.5]
,
右侧=[1,0.5]

Drawing Order (z-order)

绘制顺序(层级顺序)

  • Array order = z-order (first = back, last = front)
  • Emit progressively: background zones → shape → its bound text → its arrows → next shape
  • BAD: all rectangles, then all texts, then all arrows
  • GOOD: bg_zone → shape1 → text_for_shape1 → arrow1 → arrow_label_text → shape2 → text_for_shape2 → ...
  • Always place the bound text element immediately after its container shape
  • 数组顺序=层级顺序(第一个元素在最底层,最后一个在最顶层)
  • 按顺序绘制:背景区域 → 形状 → 绑定的文本 → 箭头 → 下一个形状
  • 错误做法:先绘制所有矩形,再绘制所有文本,最后绘制所有箭头
  • 正确做法:bg_zone → shape1 → shape1的文本 → arrow1 → arrow1的标签文本 → shape2 → shape2的文本 → ...
  • 务必将绑定的文本元素紧跟在其容器形状之后

Sizing Guidelines

尺寸指南

Font sizes:
  • Minimum
    fontSize
    : 16 for body text, labels, descriptions
  • Minimum
    fontSize
    : 20 for titles and headings
  • Minimum
    fontSize
    : 14 for secondary annotations only (sparingly)
  • NEVER use
    fontSize
    below 14
Element sizes:
  • Minimum shape size: 120x60 for labeled rectangles/ellipses
  • Leave 20-30px gaps between elements minimum
  • Prefer fewer, larger elements over many tiny ones
字体大小:
  • 正文字体、标签、描述的最小
    fontSize
    16
  • 标题的最小
    fontSize
    20
  • 次要注释的最小
    fontSize
    14(谨慎使用)
  • 请勿使用小于14的
    fontSize
元素尺寸:
  • 带标签的矩形/椭圆最小尺寸:120x60
  • 元素之间至少保留20-30px的间距
  • 优先选择数量少、尺寸大的元素,而非大量小元素

Color Palette

调色板

See
references/colors.md
for full color tables. Quick reference:
UseFill ColorHex
Primary / InputLight Blue
#a5d8ff
Success / OutputLight Green
#b2f2bb
Warning / ExternalLight Orange
#ffd8a8
Processing / SpecialLight Purple
#d0bfff
Error / CriticalLight Red
#ffc9c9
Notes / DecisionsLight Yellow
#fff3bf
Storage / DataLight Teal
#c3fae8
完整颜色表请查看
references/colors.md
。快速参考:
用途填充色十六进制值
主要/输入浅蓝色
#a5d8ff
成功/输出浅绿色
#b2f2bb
警告/外部浅橙色
#ffd8a8
处理/特殊浅紫色
#d0bfff
错误/关键浅红色
#ffc9c9
备注/决策浅黄色
#fff3bf
存储/数据浅蓝绿色
#c3fae8

Tips

小贴士

  • Use the color palette consistently across the diagram
  • Text contrast is CRITICAL -- never use light gray on white backgrounds. Minimum text color on white:
    #757575
  • Do NOT use emoji in text -- they don't render in Excalidraw's font
  • For dark mode diagrams, see
    references/dark-mode.md
  • For larger examples, see
    references/examples.md
  • 在图表中统一使用调色板
  • 文本对比度至关重要——请勿在白色背景上使用浅灰色文本。白色背景上的最小文本颜色:
    #757575
  • 请勿在文本中使用表情符号——它们无法在Excalidraw的字体中渲染
  • 如需深色模式图表,请查看
    references/dark-mode.md
  • 如需更多示例,请查看
    references/examples.md