---
slug: "excalidraw-skill-excalidraw-skill"
source_type: "skill_md"
source_url: "https://cdn.jsdelivr.net/gh/albert-zen/excalidraw-skill@main/SKILL.md"
repo: "https://github.com/albert-zen/excalidraw-skill"
source_file: "SKILL.md"
branch: "main"
---
---
name: excalidraw-diagram-gen
description: Generate Excalidraw diagram JSON. Use when user requests flowcharts, architecture diagrams, sequence diagrams, ER diagrams, or asks to convert descriptions into Excalidraw format.
---

# Excalidraw Diagram Generation

Generate complete .excalidraw JSON files from user input.

## Input Types

1. Natural language description
2. Image (when vision capable)

## Output Format

Output complete .excalidraw JSON:

```json
{
  "type": "excalidraw",
  "version": 2,
  "source": "llm-generated",
  "elements": [...],
  "appState": {
    "viewBackgroundColor": "#ffffff",
    "gridSize": null
  },
  "files": {}
}
```

## Layout Algorithm

<layout_rules>
1. Starting coordinates (100, 100)
2. Node spacing: horizontal 200px, vertical 150px
3. Flowcharts layout top-to-bottom or left-to-right
4. Architecture diagrams partition by tier
5. Node width 120-200px, height 60-80px
6. Text centered within container
7. For large diagrams, use `frame` to partition sections; set children `frameId` to frame `id`
8. Frame ordering: all frame children must appear before the frame element in `elements[]`
</layout_rules>

## Element Generation Rules

<element_rules>
Each element must include:
- `id`: unique string, format `elem_${type}_${index}`
- `type`: rectangle | diamond | ellipse | arrow | line | text | frame
- `x`, `y`: coordinates
- `width`, `height`: dimensions
- `angle`: 0
- `strokeColor`: "#1e1e1e"
- `backgroundColor`: "#a5d8ff" for shapes, "#ffec99" for decisions
- `fillStyle`: "solid"
- `strokeWidth`: 2
- `strokeStyle`: "solid"
- `roundness`: `null` (or `{ "type": 3 }` for rounded rectangles)
- `roughness`: 0 (use 1 only when user asks for hand-drawn look)
- `opacity`: 100
- `seed`: random integer
- `version`: 1
- `versionNonce`: random integer
- `isDeleted`: false
- `groupIds`: []
- `frameId`: null
- `boundElements`: `null` or bound arrows/text
- `updated`: current timestamp
- `link`: null
- `locked`: false
- `index`: null
</element_rules>

<arrow_rules>
Arrow element additional properties:
- `points`: [[0,0], [dx, dy]] relative coordinate array
- `startBinding`/`endBinding`: `{ elementId, fixedPoint, mode: "inside" }`
  - Choose `fixedPoint` by comparing start/end centers:
    - if `abs(dx) >= abs(dy)`: start right `[1, 0.5]` -> end left `[0, 0.5]` (or reversed if dx < 0)
    - else: start bottom `[0.5, 1]` -> end top `[0.5, 0]` (or reversed if dy < 0)
- `startArrowhead`: null
- `endArrowhead`: "arrow"
- `elbowed`: false
</arrow_rules>

<line_rules>
Line element additional properties:
- `points`: [[0,0], [dx, dy]] relative coordinate array
- `startBinding`/`endBinding`: `{ elementId, fixedPoint, mode: "inside" }` or null
- `startArrowhead`: null
- `endArrowhead`: null
- `polygon`: false
</line_rules>

<frame_rules>
Frame element additional properties:
- `type`: "frame"
- `name`: string or null
- Typical style: `backgroundColor: "transparent"`, `strokeStyle: "dashed"`, `roughness: 0`, `locked: true`
- Children elements inside the frame must set `frameId: frame.id`
- Ordering requirement: frame children first, then the frame element
</frame_rules>

<text_rules>
Text element additional properties:
- `fontSize`: 20
- `fontFamily`: 2 (use 1 only when user asks for casual/hand-drawn look)
- `text`: display text
- `textAlign`: "center"
- `verticalAlign`: "middle"
- `containerId`: container element ID (when bound to shape)
- `originalText`: same as text
- `autoResize`: true
- `lineHeight`: 1.25
</text_rules>

<semantic_styles>
Line/arrow semantics:
- Primary flow: `strokeStyle: "solid"`
- Return/async/optional: `strokeStyle: "dashed"`
- Dependency/reference: `strokeStyle: "dotted"`

Color semantics (suggested):
- Info/input/user: background `#a5d8ff`
- Success/data/store: background `#b2f2bb`
- Decision/warn: background `#ffec99`
- Error/stop: background `#ffc9c9`
</semantic_styles>

<style_presets>
Default (technical/pro): `roughness: 0`, `fontFamily: 2`, `gridSize: null`
Casual (sketch): `roughness: 1`, `fontFamily: 1`
</style_presets>

## Binding Rules

<binding_rules>
1. Text bound to container: set text's `containerId` to container ID, container's `boundElements` includes `{ id: textId, type: "text" }`
2. Arrow bound to shape: set arrow's `startBinding`/`endBinding` to shape info, shape's `boundElements` includes `{ id: arrowId, type: "arrow" }`
3. fixedPoint coordinates: [0.5, 0] = top center, [0.5, 1] = bottom center, [0, 0.5] = left center, [1, 0.5] = right center
</binding_rules>

## Diagram Type Templates

<flowchart_template>
Node type mapping:
- Start/End: ellipse, backgroundColor "#b2f2bb"
- Process: rectangle, backgroundColor "#a5d8ff"
- Decision: diamond, backgroundColor "#ffec99"
- Subprocess: rectangle + double border effect

Swimlanes (optional):
- Use lane containers as large rectangles with `backgroundColor: "transparent"`, `strokeStyle: "dashed"`, `locked: true`
- Lane title as a text element near top-left of lane
- Keep nodes visually within their lane (or group with a `frame`)
</flowchart_template>

<architecture_template>
Tier layout:
- Client tier y=100
- Service tier y=300
- Data tier y=500
Nodes arranged horizontally within each tier, spacing 200px
</architecture_template>

<sequence_template>
Participants arranged horizontally y=100, spacing 200px
Message arrows increment vertically, y += 80 per message
Lifelines represented with dashed lines

Lifeline element:
- `type: "line"`, `strokeStyle: "dashed"`, `strokeWidth: 1`, `roughness: 0`, `polygon: false`

Message conventions:
- Call: solid arrow
- Return: dashed arrow
</sequence_template>

## Output Requirements

1. MUST generate valid JSON importable to Excalidraw
2. MUST ensure all element IDs unique
3. MUST set binding relationships correctly
4. MUST use relative coordinates for arrow points
5. NEVER generate image type elements
6. NEVER omit required fields
7. Avoid `freedraw` unless user explicitly asks (large diagrams)

## Acceptance Checklist

- [ ] JSON syntax valid
- [ ] All elements have unique IDs
- [ ] Binding relationships bidirectionally consistent
- [ ] Arrow connections correct
- [ ] Layout has no overlaps
