Skip to content
Development
Skill

/excalidraw

Hand-drawn Excalidraw JSON diagrams (arch, flow, seq).

From plugin
kevinnft-ai-agent-skills
14169 skills
Install
$ npx -y skills add kevinnft/ai-agent-skills --skill excalidraw --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/excalidraw

Context preview

The summary Claude sees to decide when to auto-load this skill.

Hand-drawn Excalidraw JSON diagrams (arch, flow, seq).

SKILL.md

excalidraw.SKILL.md
name: excalidraw
description: "Hand-drawn Excalidraw JSON diagrams (arch, flow, seq)."
version: 1.0.0
author: Hermes Agent
license: MIT
dependencies: []
metadata:
  hermes:
    tags: [Excalidraw, Diagrams, Flowcharts, Architecture, Visualization, JSON]
    related_skills: []
origin: original
source_repo: kevinnft/ai-agent-skills
source_url: https://github.com/kevinnft/ai-agent-skills
source_license: MIT
language: en

Excalidraw Diagram Skill

Create 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.

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.

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`

Saving a Diagram

Wrap your elements array in the standard `.excalidraw` envelope and save with `write_file`:

{
  "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`.

Uploading for a Shareable Link

Run the upload script (located in this skill's `scripts/` directory) via terminal:

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`).

---

Element Format Reference

Required Fields (all elements)

`type`, `id` (unique string), `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.

Element Types

**Rectangle**:

{ "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**:

{ "type": "ellipse", "id": "e1", "x": 100, "y": 100, "width": 150, "height": 150 }

**Diamond**:

{ "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:

{ "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:

{ "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):

{ "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**:

{ "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"`

Arrow Bindings (connect arrows to shapes)

{
  "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]`

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
Read more
Ships withkevinnft-ai-agent-skills

191 attribution-first agent skills for Hermes Agent, Claude Code, Cursor — one installer, 28 categories, searchable catalog. See NOTICE for upstream attribution.

Get the whole plugin

Other skills on kevinnft-ai-agent-skills.