AI authoring
Documents are plain markdown, so anything that writes markdown can write them: notes fields, generated reports, agent output. The one dialect worth teaching a generator is diagrams.
Emit skeletons
Generators should write ```diagram blocks: a coordinate-free
skeleton with boxes, connectors and palette colour names. The editor lays
it out on import and stores the result as a concrete ```drawing
block. Use ```drawing (format version 2) only to edit an
existing concrete payload or when exact positions matter.
```diagram
{"direction":"right","boxes":[
{"id":"web","label":"CLIENT","text":"Web App","color":"blue"},
{"id":"api","label":"SERVICE","text":"API","color":"green"},
{"id":"db","type":"cylinder","text":"Postgres","color":"purple"}
],"connectors":[
{"from":"web","to":"api","text":"REST"},
{"from":"api","to":"db","routing":"elbow"}
]}
```
The complete rules for both payloads are in Diagrams and,
authoritatively, in DRAWING_FORMAT.md, which ships in the npm package
next to the README and is written to be pasted into a prompt.
What a generated skeleton becomes once the editor opens it (the
Markdown view shows the expanded ```drawing block it stores):
Validate with the JSON Schemas
DRAWING_SKELETON_JSON_SCHEMA and DRAWING_DATA_JSON_SCHEMA (JSON Schema
draft-07) are the same contracts as the spec. Use them to validate
generated payloads, or as structured-output / tool schemas so a model can
only produce valid diagrams:
import { DRAWING_SKELETON_JSON_SCHEMA } from '@zuilib/text-editor'
const tool = {
name: 'draw_diagram',
description: 'Add an architecture diagram to the document',
input_schema: DRAWING_SKELETON_JSON_SCHEMA,
}
Work with payloads in code
| Function | Purpose |
|---|---|
parseDrawingSkeleton(json) | Parse a skeleton string / object; throws on a malformed one |
isDrawingSkeleton(value) | Type guard |
expandSkeleton(skeleton) | Lay out and expand to DrawingData (what the editor does on import) |
parseDrawingData(json) | The editor's lenient parser for concrete payloads: invalid shapes drop out, never throws |
serializeDrawingData(data) | Inverse of the above |
normalizeDrawingData(data) | Re-anchor bound connector endpoints |
drawingToMermaid(data, options?) | Export a Mermaid flowchart |
Everything above runs without a DOM (the router, bindings and skeleton expansion are pure), so it works in Node, workers and tests.
Generation checklist
- Prefer a
```diagramskeleton. Fall back to```drawingonly to edit an existing concrete payload or when you need exact positions. - One JSON object per fence, no comments or trailing commas.
- Every
idunique; every connector references an existing box id. - Put box text in
label/text/footer, not in floatingtextshapes.actoronly hastext. - Pick the attach edge with
{"id":"…","side":"bottom"}only when it matters (a decision's "yes" / "no"); omit it otherwise. - Use
"routing":"elbow"for flowcharts. - For concrete payloads: boxes at least 120 × 70 when they carry text
(use the default sizes), about 60px between cards,
canvasHeightlarge enough for every shape plus ~20px, shapes within x ∈ [0, 700] unlesscanvasWidthis set.
Tables and settings
Write GFM pipe tables. Add a settings comment on the line directly above only when you want a non-default width or density:
<!-- width: content; density: compact -->
| Key | Value |
| --- | --- |
| Region | eu-west-1 |
Claude Code skill
The monorepo ships a ready-made Claude Code skill
(.claude/skills/text-editor-documents/) that teaches an agent this
dialect: markdown conventions, the skeleton format, and when to use
drawings. Copy it into consuming repositories so agents there author
documents the editor renders correctly.