# Formato Excalidraw — esquema JSON detalhado

Referencia tecnica do formato. Leia quando precisar gerar/editar JSON manualmente.

## Estrutura raiz

```json
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [],
  "appState": {},
  "files": {}
}
```

- `type`: sempre `"excalidraw"` (cena) ou `"excalidrawlib"` (library)
- `version`: 2 (atual)
- `elements`: lista de elementos visuais
- `appState`: configuracao do canvas (background, grid, theme)
- `files`: dicionario de imagens embutidas (base64)

## appState relevante

```json
{
  "viewBackgroundColor": "#FAF8F3",
  "gridSize": 20,
  "gridStep": 5,
  "theme": "light",
  "exportEmbedScene": true,
  "exportWithDarkMode": false
}
```

## Elemento base (todos os tipos compartilham)

```json
{
  "id": "abc123-XYZ",
  "type": "rectangle",
  "x": 100,
  "y": 100,
  "width": 200,
  "height": 100,
  "angle": 0,
  "strokeColor": "#1A1A1A",
  "backgroundColor": "transparent",
  "fillStyle": "solid",
  "strokeWidth": 2,
  "strokeStyle": "solid",
  "roughness": 0,
  "opacity": 100,
  "groupIds": [],
  "frameId": null,
  "roundness": null,
  "seed": 12345,
  "version": 1,
  "versionNonce": 67890,
  "isDeleted": false,
  "boundElements": [],
  "updated": 1716220800000,
  "link": null,
  "locked": false
}
```

### Campos criticos

- **id**: string unica, 16 chars alfanum + `-_`
- **type**: `rectangle`, `diamond`, `ellipse`, `text`, `arrow`, `line`, `frame`, `freedraw`, `image`, `magicframe`
- **angle**: em radianos (0 a 2π), nao graus
- **strokeColor / backgroundColor**: hex 6 chars OU `"transparent"`
- **fillStyle**: `solid`, `hachure`, `cross-hatch`, `zigzag`
- **strokeStyle**: `solid`, `dashed`, `dotted`
- **roughness**: 0 (architect), 1 (artist), 2 (cartoonist)
- **roundness**: `null` ou `{"type": 1|2|3}` (3 = padrao retangulos)
- **boundElements**: lista de `{"type": "text"|"arrow", "id": "..."}` — relacao com texto/setas ancoradas
- **frameId**: id do frame container ou `null`

## Tipos de elemento

### Rectangle/Diamond/Ellipse
Sao identicos exceto pelo `type`. Diamond eh losango, Ellipse eh oval.

### Text
```json
{
  "type": "text",
  "text": "Conteudo",
  "fontSize": 20,
  "fontFamily": 2,
  "textAlign": "left",
  "verticalAlign": "top",
  "baseline": 18,
  "containerId": null,
  "originalText": "Conteudo",
  "lineHeight": 1.25,
  "autoResize": true
}
```

- **fontFamily**: `1` = Virgil (handwritten), `2` = Helvetica, `3` = Cascadia, `4` = Lilita, `5` = Excalifont
- **textAlign**: `left`, `center`, `right`
- **verticalAlign**: `top`, `middle`, `bottom`
- **containerId**: id do shape que contem este texto (texto ancorado se move junto)

### Arrow / Line
```json
{
  "type": "arrow",
  "points": [[0, 0], [200, 100]],
  "lastCommittedPoint": null,
  "startBinding": {"elementId": "abc", "focus": 0, "gap": 4},
  "endBinding": {"elementId": "def", "focus": 0, "gap": 4},
  "startArrowhead": null,
  "endArrowhead": "arrow",
  "elbowed": true
}
```

- **points**: lista de `[x, y]` relativos ao `x, y` do elemento. Sempre comeca `[0,0]`.
- **startBinding/endBinding**: ancora a seta em outro shape. `focus: -1..1` posiciona onde toca; `gap` eh distancia.
- **elbowed**: `true` = seta em angulo reto (premium B2B)
- **endArrowhead**: `arrow`, `bar`, `dot`, `triangle`, `triangle_outline`, ou `null`

### Frame
```json
{
  "type": "frame",
  "name": "FASE 01 — DESCOBERTA",
  "strokeColor": "#87837C",
  "strokeStyle": "dashed",
  "backgroundColor": "transparent"
}
```

Elementos com `frameId` igual ao `id` deste frame movem juntos.

## Padroes obrigatorios

1. **Cada elemento precisa de id unico** — usar `gerar_id()` do helper
2. **boundElements deve ser sincronizado**: se texto T tem `containerId: R`, entao R precisa ter `T` em `boundElements`
3. **Setas com binding** atualizam `boundElements` dos shapes ancorados
4. **Coords no grid (20px)**: x e y multiplos de 20 sempre que possivel
5. **strokeWidth >= 2** pra ter peso visual

## Library (.excalidrawlib)

```json
{
  "type": "excalidrawlib",
  "version": 2,
  "source": "imperatriz-skill",
  "libraryItems": [
    {
      "status": "published",
      "name": "Card Premium",
      "id": "abc123",
      "created": 1716220800000,
      "elements": [...]
    }
  ]
}
```

Cada `libraryItem.elements` segue o mesmo formato que `cena.elements`. Excalidraw posiciona automaticamente no canvas ao arrastar.

## Formato Obsidian (.excalidraw.md)

Plugin do zsviczian embrulha em frontmatter + code fence:

```markdown
---
excalidraw-plugin: parsed
tags: [excalidraw, imperatriz]
---
==⚠  Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==

# Text Elements

%%
# Drawing
\`\`\`json
{JSON da cena aqui}
\`\`\`
%%
```

Beneficio: vira nota nativa do vault, backlinks funcionam, pode ser embebido em outras notas com `![[nome-do-diagrama]]`.

## Validacao rapida

Antes de salvar, verificar:
- `json.loads()` nao quebra
- Cada elemento tem `id`, `type`, `x`, `y`, `width`, `height`, `seed`
- Setas tem `points` comecando em `[0,0]`
- Textos com `containerId` tem o shape correspondente com `boundElements` apontando de volta
- `viewBackgroundColor` nao eh branco puro (`#FFFFFF`)

## Para abrir manualmente

- `.excalidraw` → arrasta pro excalidraw.com OU File > Open
- `.excalidrawlib` → Library Panel > "..." > Open library
- `.excalidraw.md` → abre no Obsidian (precisa do plugin)
- `.png/.svg` com cena embutida → arrasta pro excalidraw.com (extrai vetores automaticamente)
