Add tldraw file skill

This commit is contained in:
2026-05-08 16:07:26 +01:00
parent 9fa79c25e1
commit 5b58110ac6

375
tldraw-file/SKILL.md Normal file
View File

@@ -0,0 +1,375 @@
---
name: tldraw-file
description: Create, repair, validate, or generate valid `.tldr` files that tldraw can open. Use when the user asks for a tldraw diagram, `.tldr` file, corrupted tldraw repair, or a diagram they can open in tldraw.
argument-hint: "[diagram request, file path, or validation target]"
user-invocable: true
---
# tldraw File
Use this skill when the user asks to create, repair, validate, or generate a tldraw document/file.
Examples:
- "Make me a tldraw diagram"
- "Create a `.tldr` file"
- "tldraw says this file is corrupted"
- "Generate a diagram I can open in tldraw"
## Core Rule
Do not hand-wave validity. A `.tldr` file must be validated with tldraw's own schema/importer, not just `JSON.parse`.
A file can be valid JSON and still be corrupted to tldraw.
## Temporary Setup
If the current project does not already depend on `tldraw`, install it in `/tmp/opencode`, not in the user's repo.
```bash
# Work outside the repo
bun init -y
bun add tldraw
```
Use `/tmp/opencode` as the working directory for validation scripts.
## `.tldr` File Shape
A current `.tldr` JSON file has this top-level shape:
```json
{
"tldrawFileFormatVersion": 1,
"schema": {
"schemaVersion": 2,
"sequences": {
"com.tldraw.store": 5,
"com.tldraw.asset": 1,
"com.tldraw.camera": 1,
"com.tldraw.document": 2,
"com.tldraw.instance": 26,
"com.tldraw.instance_page_state": 5,
"com.tldraw.page": 1,
"com.tldraw.instance_presence": 6,
"com.tldraw.pointer": 1,
"com.tldraw.shape": 4,
"com.tldraw.user": 1,
"com.tldraw.asset.image": 6,
"com.tldraw.asset.video": 5,
"com.tldraw.asset.bookmark": 2,
"com.tldraw.shape.arrow": 8,
"com.tldraw.shape.bookmark": 2,
"com.tldraw.shape.draw": 4,
"com.tldraw.shape.embed": 4,
"com.tldraw.shape.frame": 1,
"com.tldraw.shape.geo": 11,
"com.tldraw.shape.group": 0,
"com.tldraw.shape.highlight": 3,
"com.tldraw.shape.image": 5,
"com.tldraw.shape.line": 5,
"com.tldraw.shape.note": 12,
"com.tldraw.shape.text": 4,
"com.tldraw.shape.video": 4,
"com.tldraw.binding.arrow": 1
}
},
"records": []
}
```
Records must be an array of valid tldraw records. Each record needs at least:
```json
{
"id": "shape:example",
"typeName": "shape"
}
```
Actual records must also satisfy their shape-specific schema.
## Required Base Records
Include at least:
```json
{
"gridSize": 10,
"name": "",
"meta": {},
"id": "document:document",
"typeName": "document"
}
```
```json
{
"id": "page:page",
"name": "Page",
"index": "a1",
"meta": {},
"typeName": "page"
}
```
Every shape should have:
```json
{
"parentId": "page:page",
"index": "a2",
"typeName": "shape"
}
```
## Rich Text
Use tldraw rich text for labels.
Helper shape:
```json
{
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Label"
}
]
}
]
}
```
For compatibility, also include the legacy `text` prop with the same plain text.
## Geo Shape Template
Use geo shapes for most boxes. They are easier than notes and less fragile.
```json
{
"x": 100,
"y": 100,
"rotation": 0,
"isLocked": false,
"opacity": 1,
"meta": {},
"id": "shape:box",
"type": "geo",
"props": {
"geo": "rectangle",
"w": 260,
"h": 90,
"color": "blue",
"labelColor": "black",
"fill": "solid",
"dash": "solid",
"size": "m",
"font": "sans",
"align": "middle",
"verticalAlign": "middle",
"growY": 0,
"url": "",
"scale": 1,
"richText": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "My box"
}
]
}
]
},
"text": "My box"
},
"parentId": "page:page",
"index": "a2",
"typeName": "shape"
}
```
## Text Shape Template
```json
{
"x": 100,
"y": 40,
"rotation": 0,
"isLocked": false,
"opacity": 1,
"meta": {},
"id": "shape:title",
"type": "text",
"props": {
"color": "black",
"size": "xl",
"font": "sans",
"textAlign": "start",
"autoSize": true,
"w": 900,
"scale": 1,
"richText": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Diagram Title"
}
]
}
]
},
"text": "Diagram Title"
},
"parentId": "page:page",
"index": "a1",
"typeName": "shape"
}
```
## Arrow Shape Template
Arrows require `labelColor`. Missing it can make tldraw report the file as corrupted.
```json
{
"x": 400,
"y": 200,
"rotation": 0,
"isLocked": false,
"opacity": 1,
"meta": {},
"id": "shape:arrow",
"type": "arrow",
"props": {
"kind": "arc",
"color": "black",
"labelColor": "black",
"fill": "none",
"dash": "solid",
"size": "m",
"arrowheadStart": "none",
"arrowheadEnd": "arrow",
"bend": 0,
"start": {
"x": 0,
"y": 0
},
"end": {
"x": 120,
"y": 0
},
"labelPosition": 0.5,
"font": "sans",
"scale": 1,
"richText": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "label"
}
]
}
]
},
"text": "label"
},
"parentId": "page:page",
"index": "a3",
"typeName": "shape"
}
```
## Valid Colors
For `color` and `labelColor`, use only known tldraw colors:
- `black`
- `grey`
- `light-violet`
- `violet`
- `blue`
- `light-blue`
- `yellow`
- `orange`
- `green`
- `light-green`
- `light-red`
- `red`
- `white`
Invalid or missing `labelColor` can corrupt the file.
## Notes
Avoid note shapes unless you know the current schema. They require additional props and are more version-sensitive. Prefer geo rectangles with `fill: solid` or `fill: semi`.
## Validation
First validate JSON syntax:
```bash
bun -e "const f='/path/to/file.tldr'; const data=await Bun.file(f).text(); JSON.parse(data); console.log('valid json')"
```
Then validate with tldraw's store/schema:
```bash
bun -e "import { createTLStore } from 'tldraw'; const file=JSON.parse(await Bun.file('/path/to/file.tldr').text()); const snapshot={store:Object.fromEntries(file.records.map(r=>[r.id,r])), schema:file.schema}; try { const store=createTLStore({snapshot}); console.log('ok records', store.allRecords().length); } catch(e){ console.error(e); process.exit(1)} process.exit(0)"
```
Finally validate with the same importer path tldraw uses for `.tldr` files:
```bash
bun -e "import { createTLStore } from 'tldraw'; import { parseTldrawJsonFile } from './node_modules/tldraw/dist-esm/lib/utils/tldr/file.mjs'; const json=await Bun.file('/path/to/file.tldr').text(); const schema=createTLStore().schema; const result=parseTldrawJsonFile({json, schema}); console.log(result.ok ? 'parse ok' : result.error); process.exit(result.ok ? 0 : 1)"
```
Run importer validation from the temp directory where tldraw is installed, for example `/tmp/opencode`.
## Common Corruption Causes
- File is valid JSON but does not match tldraw schema.
- Missing `labelColor` on arrow shapes.
- Missing required shape props for note shapes.
- Old schema sequence numbers copied from another tldraw version.
- Invalid color names.
- Shape `parentId` points to a missing page.
- Duplicate record IDs.
- Records object used instead of records array in `.tldr` file format.
- `richText` missing where current schemas expect it.
## Recommended Workflow
1. Create or update `.tldr` with `apply_patch`.
2. Run JSON validation.
3. Run `createTLStore({ snapshot })` validation.
4. Run `parseTldrawJsonFile` validation.
5. If tldraw says corrupted, trust tldraw and inspect the validation error path.
6. Fix the specific schema path, not just the JSON.
## Practical Diagram Advice
- Use geo rectangles for sections and entities.
- Use text for headings.
- Use simple arrow shapes for flow.
- Keep IDs stable and readable: `shape:admin-review`, `shape:stream-category`.
- Use indexed records like `a1`, `a2`, `a3`.
- Keep diagrams editable rather than pixel-perfect.