211 lines
4.8 KiB
Markdown
211 lines
4.8 KiB
Markdown
|
|
# Excalidraw JSON Format Reference
|
||
|
|
|
||
|
|
Complete reference for Excalidraw JSON structure and element types.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## File Structure
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "excalidraw",
|
||
|
|
"version": 2,
|
||
|
|
"source": "claude-code-excalidraw-skill",
|
||
|
|
"elements": [],
|
||
|
|
"appState": {
|
||
|
|
"gridSize": 20,
|
||
|
|
"viewBackgroundColor": "#ffffff"
|
||
|
|
},
|
||
|
|
"files": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Element Types
|
||
|
|
|
||
|
|
| Type | Use For | Arrow Reliability |
|
||
|
|
|------|---------|-------------------|
|
||
|
|
| `rectangle` | Services, components, databases, containers, orchestrators, decision points | Excellent |
|
||
|
|
| `ellipse` | Users, external systems, start/end points | Good |
|
||
|
|
| `text` | Labels inside shapes, titles, annotations | N/A |
|
||
|
|
| `arrow` | Data flow, connections, dependencies | N/A |
|
||
|
|
| `line` | Grouping boundaries, separators | N/A |
|
||
|
|
|
||
|
|
### BANNED: Diamond Shapes
|
||
|
|
|
||
|
|
**NEVER use `type: "diamond"` in generated diagrams.**
|
||
|
|
|
||
|
|
Diamond arrow connections are fundamentally broken in raw Excalidraw JSON:
|
||
|
|
- Excalidraw applies `roundness` to diamond vertices during rendering
|
||
|
|
- Visual edges appear offset from mathematical edge points
|
||
|
|
- No offset formula reliably compensates
|
||
|
|
- Arrows appear disconnected/floating
|
||
|
|
|
||
|
|
**Use styled rectangles instead** for visual distinction:
|
||
|
|
|
||
|
|
| Semantic Meaning | Rectangle Style |
|
||
|
|
|------------------|-----------------|
|
||
|
|
| Orchestrator/Hub | Coral (`#ffa8a8`/`#c92a2a`) + strokeWidth: 3 |
|
||
|
|
| Decision Point | Orange (`#ffd8a8`/`#e8590c`) + dashed stroke |
|
||
|
|
| Central Router | Larger size + bold color |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Required Element Properties
|
||
|
|
|
||
|
|
Every element MUST have these properties:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "unique-id-string",
|
||
|
|
"type": "rectangle",
|
||
|
|
"x": 100,
|
||
|
|
"y": 100,
|
||
|
|
"width": 200,
|
||
|
|
"height": 80,
|
||
|
|
"angle": 0,
|
||
|
|
"strokeColor": "#1971c2",
|
||
|
|
"backgroundColor": "#a5d8ff",
|
||
|
|
"fillStyle": "solid",
|
||
|
|
"strokeWidth": 2,
|
||
|
|
"strokeStyle": "solid",
|
||
|
|
"roughness": 1,
|
||
|
|
"opacity": 100,
|
||
|
|
"groupIds": [],
|
||
|
|
"frameId": null,
|
||
|
|
"roundness": { "type": 3 },
|
||
|
|
"seed": 1,
|
||
|
|
"version": 1,
|
||
|
|
"versionNonce": 1,
|
||
|
|
"isDeleted": false,
|
||
|
|
"boundElements": null,
|
||
|
|
"updated": 1,
|
||
|
|
"link": null,
|
||
|
|
"locked": false
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Text Inside Shapes (Labels)
|
||
|
|
|
||
|
|
**Every labeled shape requires TWO elements:**
|
||
|
|
|
||
|
|
### Shape with boundElements
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "{component-id}",
|
||
|
|
"type": "rectangle",
|
||
|
|
"x": 500,
|
||
|
|
"y": 200,
|
||
|
|
"width": 200,
|
||
|
|
"height": 90,
|
||
|
|
"strokeColor": "#1971c2",
|
||
|
|
"backgroundColor": "#a5d8ff",
|
||
|
|
"boundElements": [{ "type": "text", "id": "{component-id}-text" }],
|
||
|
|
// ... other required properties
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Text with containerId
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "{component-id}-text",
|
||
|
|
"type": "text",
|
||
|
|
"x": 505, // shape.x + 5
|
||
|
|
"y": 220, // shape.y + (shape.height - text.height) / 2
|
||
|
|
"width": 190, // shape.width - 10
|
||
|
|
"height": 50,
|
||
|
|
"text": "{Component Name}\n{Subtitle}",
|
||
|
|
"fontSize": 16,
|
||
|
|
"fontFamily": 1,
|
||
|
|
"textAlign": "center",
|
||
|
|
"verticalAlign": "middle",
|
||
|
|
"containerId": "{component-id}",
|
||
|
|
"originalText": "{Component Name}\n{Subtitle}",
|
||
|
|
"lineHeight": 1.25,
|
||
|
|
// ... other required properties
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### DO NOT Use the `label` Property
|
||
|
|
|
||
|
|
The `label` property is for the JavaScript API, NOT raw JSON files:
|
||
|
|
|
||
|
|
```json
|
||
|
|
// WRONG - will show empty boxes
|
||
|
|
{ "type": "rectangle", "label": { "text": "My Label" } }
|
||
|
|
|
||
|
|
// CORRECT - requires TWO elements
|
||
|
|
// 1. Shape with boundElements reference
|
||
|
|
// 2. Separate text element with containerId
|
||
|
|
```
|
||
|
|
|
||
|
|
### Text Positioning
|
||
|
|
|
||
|
|
- Text `x` = shape `x` + 5
|
||
|
|
- Text `y` = shape `y` + (shape.height - text.height) / 2
|
||
|
|
- Text `width` = shape `width` - 10
|
||
|
|
- Use `\n` for multi-line labels
|
||
|
|
- Always use `textAlign: "center"` and `verticalAlign: "middle"`
|
||
|
|
|
||
|
|
### ID Naming Convention
|
||
|
|
|
||
|
|
Always use pattern: `{shape-id}-text` for text element IDs.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Dynamic ID Generation
|
||
|
|
|
||
|
|
IDs and labels are generated from codebase analysis:
|
||
|
|
|
||
|
|
| Discovered Component | Generated ID | Generated Label |
|
||
|
|
|---------------------|--------------|-----------------|
|
||
|
|
| Express API server | `express-api` | `"API Server\nExpress.js"` |
|
||
|
|
| PostgreSQL database | `postgres-db` | `"PostgreSQL\nDatabase"` |
|
||
|
|
| Redis cache | `redis-cache` | `"Redis\nCache Layer"` |
|
||
|
|
| S3 bucket for uploads | `s3-uploads` | `"S3 Bucket\nuploads/"` |
|
||
|
|
| Lambda function | `lambda-processor` | `"Lambda\nProcessor"` |
|
||
|
|
| React frontend | `react-frontend` | `"React App\nFrontend"` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Grouping with Dashed Rectangles
|
||
|
|
|
||
|
|
For logical groupings (namespaces, VPCs, pipelines):
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "group-ai-pipeline",
|
||
|
|
"type": "rectangle",
|
||
|
|
"x": 100,
|
||
|
|
"y": 500,
|
||
|
|
"width": 1000,
|
||
|
|
"height": 280,
|
||
|
|
"strokeColor": "#9c36b5",
|
||
|
|
"backgroundColor": "transparent",
|
||
|
|
"strokeStyle": "dashed",
|
||
|
|
"roughness": 0,
|
||
|
|
"roundness": null,
|
||
|
|
"boundElements": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Group labels are standalone text (no containerId) at top-left:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "group-ai-pipeline-label",
|
||
|
|
"type": "text",
|
||
|
|
"x": 120,
|
||
|
|
"y": 510,
|
||
|
|
"text": "AI Processing Pipeline (Cloud Run)",
|
||
|
|
"textAlign": "left",
|
||
|
|
"verticalAlign": "top",
|
||
|
|
"containerId": null
|
||
|
|
}
|
||
|
|
```
|