Skip to main content
ClaudeWave
Skill1.1k repo starsupdated 21d ago

excalidraw

This Claude Code skill generates `.excalidraw` diagram files and exports them to PNG or SVG formats for creating flowcharts, architecture diagrams, and system visualizations. Use it when users explicitly request diagrams or visualizations, or proactively when explaining systems with three or more interacting components, multi-step processes, or complex relationships. The skill supports two export methods: Kroki API for zero-installation SVG output or local excalidraw-brute-export-cli for PNG and SVG generation.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/dtsola/xiaoyaosearch /tmp/excalidraw && cp -r /tmp/excalidraw/.claude/skills/excalidraw-skill ~/.claude/skills/excalidraw
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Excalidraw Diagrams

## Overview

Generate `.excalidraw` JSON files and export to PNG/SVG.

**Two export options:**
- **Kroki API** (`curl`) — zero install, SVG output only
- **excalidraw-brute-export-cli** — local Firefox-based, PNG + SVG

**Supported formats:** PNG (local CLI only), SVG (both options). PDF is NOT supported.

## When to Use

**Explicit triggers:** user says "画图", "diagram", "visualize", "flowchart", "draw", "架构图", "流程图"

**Proactive triggers:**
- Explaining a system with 3+ interacting components
- Describing a multi-step process or decision tree
- Comparing architectures or approaches side by side

**Skip when:** a simple list or table suffices, or user is in a quick Q&A flow

## Prerequisites

### Option A: Kroki API (recommended — zero install, SVG only)

```bash
# Just needs curl (pre-installed on macOS/Linux/Windows Git Bash)
curl --version
```

No additional setup. SVG rendered via `https://kroki.io`.

### Option B: Local CLI (required for PNG)

The CLI uses **Firefox** (not Chromium). Check and install:

```bash
npm install -g excalidraw-brute-export-cli
npx playwright install firefox
```

**macOS patch (one-time, required):**
```bash
CLI_MAIN=$(npm root -g)/excalidraw-brute-export-cli/src/main.js
sed -i '' 's/keyboard.press("Control+O")/keyboard.press("Meta+O")/' "$CLI_MAIN"
sed -i '' 's/keyboard.press("Control+Shift+E")/keyboard.press("Meta+Shift+E")/' "$CLI_MAIN"
```

**Windows/Linux:** No patch needed.

## Workflow

1. **Check deps** — use Kroki (curl) for SVG; use local CLI for PNG
2. **Plan** — identify diagram type, pick a visual pattern, choose color palette
3. **Generate** — write `.excalidraw` JSON file (section-by-section for large diagrams)
4. **Export** — run Kroki or CLI command
5. **Report** — tell user the output file path

## Design Principles

### Default style

- `roughness: 0` — clean, modern look for all technical diagrams (use `1` only when user requests hand-drawn/casual style)
- `fontFamily: 2` (Helvetica) — professional look; use `1` (Virgil) only for casual/sketch style, `3` (Cascadia) for code snippets
- `fillStyle: "solid"` — default fill

### Font size hierarchy

| Level | Size | Use for |
|-------|------|---------|
| Title | 28px | Diagram title |
| Header | 24px | Section/group headers |
| Label | 20px | Primary element labels |
| Description | 16px | Secondary text, descriptions |
| Note | 14px | Annotations, fine print |

### Color palette

Follow the **60-30-10 rule**: 60% whitespace/neutral, 30% primary accent, 10% highlight.

**Semantic fill colors** (use with `strokeColor` one shade darker):

| Category | Fill | Stroke | Use for |
|----------|------|--------|---------|
| Primary / Input | `#dbeafe` | `#1e40af` | Entry points, APIs, user-facing |
| Success / Data | `#dcfce7` | `#166534` | Data stores, success states |
| Warning / Decision | `#fef9c3` | `#854d0e` | Decision points, conditions |
| Error / Critical | `#fee2e2` | `#991b1b` | Errors, alerts, critical paths |
| External / Storage | `#f3e8ff` | `#6b21a8` | External services, databases, AI/ML |
| Process / Default | `#e0f2fe` | `#0369a1` | Standard process steps |
| Trigger / Start | `#fed7aa` | `#c2410c` | Start nodes, triggers, events |
| Neutral / Container | `#f1f5f9` | `#475569` | Groups, swimlanes, backgrounds |

**Text colors:**

| Level | Color |
|-------|-------|
| Title | `#1e293b` |
| Label | `#334155` |
| Description | `#64748b` |

**Rule: Do not invent new colors.** Pick from this palette.

### Arrow semantics

| Style | Meaning |
|-------|---------|
| Solid (`strokeStyle: null`) | Primary flow, main path |
| Dashed (`"dashed"`) | Response, async, callback |
| Dotted (`"dotted"`) | Optional, reference, weak dependency |

## Excalidraw JSON Structure

### File skeleton

```json
{
  "type": "excalidraw",
  "version": 2,
  "source": "claude-code",
  "elements": [],
  "appState": { "viewBackgroundColor": "#ffffff" }
}
```

### Element types

| type      | use for                          |
|-----------|----------------------------------|
| rectangle | boxes, components, modules       |
| ellipse   | start/end nodes, databases       |
| diamond   | decision points                  |
| arrow     | directed connections             |
| line      | undirected connections           |
| text      | standalone labels                |

### Element sizing

Calculate element width from label text to prevent truncation:

```
Latin text:  width = max(160, charCount * 9)
CJK text:   width = max(160, charCount * 18)
Mixed text:  estimate each character individually, sum up
```

Height: use `60` for single-line labels, add `24` per additional line.

### Required properties (all elements)

```json
{
  "id": "auth_service",
  "type": "rectangle",
  "x": 100, "y": 100,
  "width": 160, "height": 60,
  "angle": 0,
  "strokeColor": "#1e40af",
  "backgroundColor": "#dbeafe",
  "fillStyle": "solid",
  "strokeWidth": 2,
  "roughness": 0,
  "opacity": 100,
  "seed": 100001,
  "boundElements": [
    { "id": "arrow_to_db", "type": "arrow" },
    { "id": "label_auth", "type": "text" }
  ]
}
```

Use **descriptive string IDs** (e.g., `"api_gateway"`, `"arrow_gw_to_auth"`) instead of random strings.

Give each element a unique `seed` (integer). Namespace by section: 100xxx, 200xxx, 300xxx.

### JSON field rules

- `boundElements`: use `null` when empty, never `[]`
- `updated`: always use `1`, never timestamps
- Do NOT include: `frameId`, `index`, `versionNonce`, `rawText`
- `points` in arrows: always start at `[0, 0]`
- `seed`: must be a positive integer, unique per element

### Text inside shapes (contained text)

When text belongs inside a shape, bind them bidirectionally:

```json
{
  "id": "label_auth",
  "type": "text",
  "text": "Auth Service",
  "fontSize": 20,
  "fontFamily": 2,
  "textAlign": "center",
  "verticalAlign": "middle",
  "strokeColor": "#1e293b",
  "containerId": "auth_service"
}
```

**CRITICAL: Text `strokeColor` is the text color.** Always set it explicitly to a d