SKILL.md
SKILL.mdBrowse 5 files
2,275 tokens
7,297 bytes
Token encoding: o200k_base
Snapshot 24fd22b
1---2name: excalidraw3description: "Hand-drawn Excalidraw JSON diagrams (arch, flow, seq)."4version: 1.0.15author: Hermes Agent6license: MIT7dependencies: []8platforms: [linux, macos, windows]9metadata:10 hermes:11 tags: [Excalidraw, Diagrams, Flowcharts, Architecture, Visualization, JSON]12 related_skills: []13 14---15 16# Excalidraw Diagram Skill17 18Create diagrams by writing standard Excalidraw element JSON and saving as `.excalidraw` files. These files can be drag-and-dropped onto [excalidraw.com](https://excalidraw.com) for viewing and editing. No accounts, no API keys, no rendering libraries -- just JSON.19 20## When to use21 22Generate `.excalidraw` files for architecture diagrams, flowcharts, sequence diagrams, concept maps, and more. Files can be opened at excalidraw.com or uploaded for shareable links.23 24## Workflow25 261. **Load this skill** (you already did)272. **Write the elements JSON** -- an array of Excalidraw element objects283. **Save the file** using `write_file` to create a `.excalidraw` file294. **Optionally upload** for a shareable link using `scripts/upload.py` via `terminal`30 31### Saving a Diagram32 33Wrap your elements array in the standard `.excalidraw` envelope and save with `write_file`:34 35```json36{37 "type": "excalidraw",38 "version": 2,39 "source": "hermes-agent",40 "elements": [ ...your elements array here... ],41 "appState": {42 "viewBackgroundColor": "#ffffff"43 }44}45```46 47Save to any path, e.g. `~/diagrams/my_diagram.excalidraw`.48 49### Uploading for a Shareable Link50 51Run the upload script (located in this skill's `scripts/` directory) via terminal:52 53```bash54python skills/creative/excalidraw/scripts/upload.py ~/diagrams/my_diagram.excalidraw55```56 57This uploads to excalidraw.com (no account needed) and prints a shareable URL. Requires the `cryptography` pip package (`pip install cryptography`).58 59---60 61## Element Format Reference62 63### Required Fields (all elements)64`type`, `id` (unique string), `x`, `y`, `width`, `height`65 66### Defaults (skip these -- they're applied automatically)67- `strokeColor`: `"#1e1e1e"`68- `backgroundColor`: `"transparent"`69- `fillStyle`: `"solid"`70- `strokeWidth`: `2`71- `roughness`: `1` (hand-drawn look)72- `opacity`: `100`73 74Canvas background is white.75 76### Element Types77 78**Rectangle**:79```json80{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 100 }81```82- `roundness: { "type": 3 }` for rounded corners83- `backgroundColor: "#a5d8ff"`, `fillStyle: "solid"` for filled84 85**Ellipse**:86```json87{ "type": "ellipse", "id": "e1", "x": 100, "y": 100, "width": 150, "height": 150 }88```89 90**Diamond**:91```json92{ "type": "diamond", "id": "d1", "x": 100, "y": 100, "width": 150, "height": 150 }93```94 95**Labeled shape (container binding)** -- create a text element bound to the shape:96 97> **WARNING:** Do NOT use `"label": { "text": "..." }` on shapes. This is NOT a valid98> Excalidraw property and will be silently ignored, producing blank shapes. You MUST99> use the container binding approach below.100 101The shape needs `boundElements` listing the text, and the text needs `containerId` pointing back:102```json103{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 80,104 "roundness": { "type": 3 }, "backgroundColor": "#a5d8ff", "fillStyle": "solid",105 "boundElements": [{ "id": "t_r1", "type": "text" }] },106{ "type": "text", "id": "t_r1", "x": 105, "y": 110, "width": 190, "height": 25,107 "text": "Hello", "fontSize": 20, "fontFamily": 1, "strokeColor": "#1e1e1e",108 "textAlign": "center", "verticalAlign": "middle",109 "containerId": "r1", "originalText": "Hello", "autoResize": true }110```111- Works on rectangle, ellipse, diamond112- Text is auto-centered by Excalidraw when `containerId` is set113- The text `x`/`y`/`width`/`height` are approximate -- Excalidraw recalculates them on load114- `originalText` should match `text`115- Always include `fontFamily: 1` (Virgil/hand-drawn font)116 117**Labeled arrow** -- same container binding approach:118```json119{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,120 "points": [[0,0],[200,0]], "endArrowhead": "arrow",121 "boundElements": [{ "id": "t_a1", "type": "text" }] },122{ "type": "text", "id": "t_a1", "x": 370, "y": 130, "width": 60, "height": 20,123 "text": "connects", "fontSize": 16, "fontFamily": 1, "strokeColor": "#1e1e1e",124 "textAlign": "center", "verticalAlign": "middle",125 "containerId": "a1", "originalText": "connects", "autoResize": true }126```127 128**Standalone text** (titles and annotations only -- no container):129```json130{ "type": "text", "id": "t1", "x": 150, "y": 138, "text": "Hello", "fontSize": 20,131 "fontFamily": 1, "strokeColor": "#1e1e1e", "originalText": "Hello", "autoResize": true }132```133- `x` is the LEFT edge. To center at position `cx`: `x = cx - (text.length * fontSize * 0.5) / 2`134- Do NOT rely on `textAlign` or `width` for positioning135 136**Arrow**:137```json138{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0,139 "points": [[0,0],[200,0]], "endArrowhead": "arrow" }140```141- `points`: `[dx, dy]` offsets from element `x`, `y`142- `endArrowhead`: `null` | `"arrow"` | `"bar"` | `"dot"` | `"triangle"`143- `strokeStyle`: `"solid"` (default) | `"dashed"` | `"dotted"`144 145### Arrow Bindings (connect arrows to shapes)146 147```json148{149 "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 150, "height": 0,150 "points": [[0,0],[150,0]], "endArrowhead": "arrow",151 "startBinding": { "elementId": "r1", "fixedPoint": [1, 0.5] },152 "endBinding": { "elementId": "r2", "fixedPoint": [0, 0.5] }153}154```155 156`fixedPoint` coordinates: `top=[0.5,0]`, `bottom=[0.5,1]`, `left=[0,0.5]`, `right=[1,0.5]`157 158### Drawing Order (z-order)159- Array order = z-order (first = back, last = front)160- Emit progressively: background zones → shape → its bound text → its arrows → next shape161- BAD: all rectangles, then all texts, then all arrows162- GOOD: bg_zone → shape1 → text_for_shape1 → arrow1 → arrow_label_text → shape2 → text_for_shape2 → ...163- Always place the bound text element immediately after its container shape164 165### Sizing Guidelines166 167**Font sizes:**168- Minimum `fontSize`: **16** for body text, labels, descriptions169- Minimum `fontSize`: **20** for titles and headings170- Minimum `fontSize`: **14** for secondary annotations only (sparingly)171- NEVER use `fontSize` below 14172 173**Element sizes:**174- Minimum shape size: 120x60 for labeled rectangles/ellipses175- Leave 20-30px gaps between elements minimum176- Prefer fewer, larger elements over many tiny ones177 178### Color Palette179 180See `references/colors.md` for full color tables. Quick reference:181 182| Use | Fill Color | Hex |183|-----|-----------|-----|184| Primary / Input | Light Blue | `#a5d8ff` |185| Success / Output | Light Green | `#b2f2bb` |186| Warning / External | Light Orange | `#ffd8a8` |187| Processing / Special | Light Purple | `#d0bfff` |188| Error / Critical | Light Red | `#ffc9c9` |189| Notes / Decisions | Light Yellow | `#fff3bf` |190| Storage / Data | Light Teal | `#c3fae8` |191 192### Tips193- Use the color palette consistently across the diagram194- **Text contrast is CRITICAL** -- never use light gray on white backgrounds. Minimum text color on white: `#757575`195- Do NOT use emoji in text -- they don't render in Excalidraw's font196- For dark mode diagrams, see `references/dark-mode.md`197- For larger examples, see `references/examples.md`198 199 200 Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root AGENTS.md.