Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Generate Excalidraw .excalidraw JSON diagram files from natural language descriptions of processes and systems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/excalidraw-schema.md
1# Excalidraw JSON Schema Reference23This document describes the structure of Excalidraw `.excalidraw` files for diagram generation.45## Top-Level Structure67```typescript8interface ExcalidrawFile {9type: "excalidraw";10version: number; // Always 211source: string; // "https://excalidraw.com"12elements: ExcalidrawElement[];13appState: AppState;14files: Record<string, any>; // Usually empty {}15}16```1718## AppState1920```typescript21interface AppState {22viewBackgroundColor: string; // Hex color, e.g., "#ffffff"23gridSize: number; // Typically 2024}25```2627## ExcalidrawElement Base Properties2829All elements share these common properties:3031```typescript32interface BaseElement {33id: string; // Unique identifier34type: ElementType; // See Element Types below35x: number; // X coordinate (pixels from top-left)36y: number; // Y coordinate (pixels from top-left)37width: number; // Width in pixels38height: number; // Height in pixels39angle: number; // Rotation angle in radians (usually 0)40strokeColor: string; // Hex color, e.g., "#1e1e1e"41backgroundColor: string; // Hex color or "transparent"42fillStyle: "solid" | "hachure" | "cross-hatch";43strokeWidth: number; // 1-4 typically44strokeStyle: "solid" | "dashed" | "dotted";45roughness: number; // 0-2, controls hand-drawn effect (1 = default)46opacity: number; // 0-10047groupIds: string[]; // IDs of groups this element belongs to48frameId: null; // Usually null49index: string; // Stacking order identifier50roundness: Roundness | null;51seed: number; // Random seed for deterministic rendering52version: number; // Element version (increment on edit)53versionNonce: number; // Random number changed on edit54isDeleted: boolean; // Should be false55boundElements: any; // Usually null56updated: number; // Timestamp in milliseconds57link: null; // External link (usually null)58locked: boolean; // Whether element is locked59}60```6162## Element Types6364### Rectangle6566```typescript67interface RectangleElement extends BaseElement {68type: "rectangle";69roundness: { type: 3 }; // 3 = rounded corners70text?: string; // Optional text inside71fontSize?: number; // Font size (16-32 typical)72fontFamily?: number; // 1 = Virgil, 2 = Helvetica, 3 = Cascadia73textAlign?: "left" | "center" | "right";74verticalAlign?: "top" | "middle" | "bottom";75}76```7778**Example:**79```json80{81"id": "rect1",82"type": "rectangle",83"x": 100,84"y": 100,85"width": 200,86"height": 100,87"strokeColor": "#1e1e1e",88"backgroundColor": "#a5d8ff",89"text": "My Box",90"fontSize": 20,91"textAlign": "center",92"verticalAlign": "middle",93"roundness": { "type": 3 }94}95```9697### Ellipse9899```typescript100interface EllipseElement extends BaseElement {101type: "ellipse";102text?: string;103fontSize?: number;104fontFamily?: number;105textAlign?: "left" | "center" | "right";106verticalAlign?: "top" | "middle" | "bottom";107}108```109110### Diamond111112```typescript113interface DiamondElement extends BaseElement {114type: "diamond";115text?: string;116fontSize?: number;117fontFamily?: number;118textAlign?: "left" | "center" | "right";119verticalAlign?: "top" | "middle" | "bottom";120}121```122123### Arrow124125```typescript126interface ArrowElement extends BaseElement {127type: "arrow";128points: [number, number][]; // Array of [x, y] coordinates relative to element129startBinding: Binding | null;130endBinding: Binding | null;131roundness: { type: 2 }; // 2 = curved arrow132}133```134135**Example:**136```json137{138"id": "arrow1",139"type": "arrow",140"x": 100,141"y": 100,142"width": 200,143"height": 0,144"points": [145[0, 0],146[200, 0]147],148"roundness": { "type": 2 },149"startBinding": null,150"endBinding": null151}152```153154**Points explanation:**155- First point `[0, 0]` is relative to `(x, y)`156- Subsequent points are relative to the first point157- For straight horizontal arrow: `[[0, 0], [width, 0]]`158- For straight vertical arrow: `[[0, 0], [0, height]]`159160### Line161162```typescript163interface LineElement extends BaseElement {164type: "line";165points: [number, number][];166startBinding: Binding | null;167endBinding: Binding | null;168roundness: { type: 2 } | null;169}170```171172### Text173174```typescript175interface TextElement extends BaseElement {176type: "text";177text: string;178fontSize: number;179fontFamily: number; // 1-3180textAlign: "left" | "center" | "right";181verticalAlign: "top" | "middle" | "bottom";182roundness: null; // Text has no roundness183}184```185186**Example:**187```json188{189"id": "text1",190"type": "text",191"x": 100,192"y": 100,193"width": 150,194"height": 25,195"text": "Hello World",196"fontSize": 20,197"fontFamily": 1,198"textAlign": "left",199"verticalAlign": "top",200"roundness": null201}202```203204**Width/Height calculation:**205- Width ≈ `text.length * fontSize * 0.6`206- Height ≈ `fontSize * 1.2 * numberOfLines`207208## Bindings209210Bindings connect arrows to shapes:211212```typescript213interface Binding {214elementId: string; // ID of bound element215focus: number; // -1 to 1, position along edge216gap: number; // Distance from element edge217}218```219220## Common Colors221222| Color Name | Hex Code | Use Case |223|------------|----------|----------|224| Black | `#1e1e1e` | Default stroke |225| Light Blue | `#a5d8ff` | Primary entities |226| Light Green | `#b2f2bb` | Process steps |227| Yellow | `#ffd43b` | Important/Central |228| Light Red | `#ffc9c9` | Warnings/Errors |229| Cyan | `#96f2d7` | Secondary items |230| Transparent | `transparent` | No fill |231| White | `#ffffff` | Background |232233## ID Generation234235IDs should be unique strings. Common patterns:236237```javascript238// Timestamp-based239const id = Date.now().toString(36) + Math.random().toString(36).substr(2);240241// Sequential242const id = "element-" + counter++;243244// Descriptive245const id = "step-1", "entity-user", "arrow-1-to-2";246```247248## Seed Generation249250Seeds are used for deterministic randomness in hand-drawn effect:251252```javascript253const seed = Math.floor(Math.random() * 2147483647);254```255256## Version and VersionNonce257258```javascript259const version = 1; // Increment when element is edited260const versionNonce = Math.floor(Math.random() * 2147483647);261```262263## Coordinate System264265- Origin `(0, 0)` is top-left corner266- X increases to the right267- Y increases downward268- All units are in pixels269270## Recommended Spacing271272| Context | Spacing |273|---------|---------|274| Horizontal gap between elements | 200-300px |275| Vertical gap between rows | 100-150px |276| Minimum margin from edge | 50px |277| Arrow-to-box clearance | 20-30px |278279## Font Families280281| ID | Name | Description |282|----|------|-------------|283| 1 | Virgil | Hand-drawn style (default) |284| 2 | Helvetica | Clean sans-serif |285| 3 | Cascadia | Monospace |286287## Validation Rules288289✅ **Required:**290- All IDs must be unique291- `type` must match actual element type292- `version` must be an integer ≥ 1293- `opacity` must be 0-100294295⚠️ **Recommended:**296- Keep `roughness` at 1 for consistency297- Use `strokeWidth` of 2 for clarity298- Set `isDeleted` to `false`299- Set `locked` to `false`300- Keep `frameId`, `boundElements`, `link` as `null`301302## Complete Minimal Example303304```json305{306"type": "excalidraw",307"version": 2,308"source": "https://excalidraw.com",309"elements": [310{311"id": "box1",312"type": "rectangle",313"x": 100,314"y": 100,315"width": 200,316"height": 100,317"angle": 0,318"strokeColor": "#1e1e1e",319"backgroundColor": "#a5d8ff",320"fillStyle": "solid",321"strokeWidth": 2,322"strokeStyle": "solid",323"roughness": 1,324"opacity": 100,325"groupIds": [],326"frameId": null,327"index": "a0",328"roundness": { "type": 3 },329"seed": 1234567890,330"version": 1,331"versionNonce": 987654321,332"isDeleted": false,333"boundElements": null,334"updated": 1706659200000,335"link": null,336"locked": false,337"text": "Hello",338"fontSize": 20,339"fontFamily": 1,340"textAlign": "center",341"verticalAlign": "middle"342}343],344"appState": {345"viewBackgroundColor": "#ffffff",346"gridSize": 20347},348"files": {}349}350```351