Skip to content

Commit d3ce9c8

Browse files
committed
docs: add iteration features page and fix arrow overlap in examples
- Add "Iterating on Diagrams" page documenting sidecar workflow, fromFile editing, change summaries, stats, validation, and Mermaid import - Fix CI/CD and data pipeline examples: switch from LR layout (arrows overlapping text) to TB layout with incremental rows - Regenerate all example PNGs
1 parent 301a0d2 commit d3ce9c8

File tree

9 files changed

+167
-20
lines changed

9 files changed

+167
-20
lines changed

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default defineConfig({
1818
{ label: "Overview", slug: "index" },
1919
{ label: "Getting Started", slug: "getting-started" },
2020
{ label: "Examples", slug: "examples" },
21+
{ label: "Iterating on Diagrams", slug: "iterating" },
2122
{ label: "Comparison", slug: "comparison" },
2223
{ label: "SDK Reference", slug: "sdk-reference" },
2324
{ label: "Color Presets", slug: "color-presets" },

docs/generate-examples.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ async function generateAwsInfra() {
5454
}
5555

5656
async function generateDataPipeline() {
57-
const d = new Diagram({ direction: "LR" });
57+
const d = new Diagram();
5858
const kafka = d.addBox("Kafka", { row: 0, col: 0, color: "queue" });
59-
const flink = d.addBox("Flink", { row: 0, col: 1, color: "backend" });
60-
const clickhouse = d.addBox("ClickHouse", { row: 0, col: 2, color: "database" });
61-
const grafana = d.addBox("Grafana", { row: 0, col: 3, color: "frontend" });
59+
const flink = d.addBox("Flink", { row: 1, col: 0, color: "backend" });
60+
const clickhouse = d.addBox("ClickHouse", { row: 2, col: 0, color: "database" });
61+
const grafana = d.addBox("Grafana", { row: 3, col: 0, color: "frontend" });
6262

6363
d.connect(kafka, flink, "stream");
6464
d.connect(flink, clickhouse, "write");
@@ -82,12 +82,12 @@ async function generateSequence() {
8282
}
8383

8484
async function generateCicd() {
85-
const d = new Diagram({ direction: "LR" });
85+
const d = new Diagram();
8686
const github = d.addBox("GitHub", { row: 0, col: 0, color: "external" });
87-
const build = d.addBox("Build", { row: 0, col: 1, color: "backend" });
88-
const test = d.addBox("Test", { row: 0, col: 2, color: "ai" });
89-
const staging = d.addBox("Staging", { row: 0, col: 3, color: "cache" });
90-
const prod = d.addBox("Production", { row: 0, col: 4, color: "database" });
87+
const build = d.addBox("Build", { row: 1, col: 0, color: "backend" });
88+
const test = d.addBox("Test", { row: 2, col: 0, color: "ai" });
89+
const staging = d.addBox("Staging", { row: 3, col: 0, color: "cache" });
90+
const prod = d.addBox("Production", { row: 4, col: 0, color: "database" });
9191

9292
d.connect(github, build, "push");
9393
d.connect(build, test, "artifacts");

docs/public/examples/aws-infra.png

-266 Bytes
Loading

docs/public/examples/cicd.png

4.24 KB
Loading
1.99 KB
Loading
1.51 KB
Loading

docs/public/examples/sequence.png

1.2 KB
Loading

docs/src/content/docs/examples.mdx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ return d.render();
6464

6565
## Data Pipeline
6666

67-
A left-to-right streaming data pipeline from Kafka through Flink to ClickHouse and Grafana. Uses `direction: "LR"` for horizontal flow.
67+
A streaming data pipeline from Kafka through Flink to ClickHouse and Grafana. Each stage flows top-to-bottom with labeled connections.
6868

6969
```typescript
70-
const d = new Diagram({ direction: "LR" });
70+
const d = new Diagram();
7171
const kafka = d.addBox("Kafka", { row: 0, col: 0, color: "queue" });
72-
const flink = d.addBox("Flink", { row: 0, col: 1, color: "backend" });
73-
const clickhouse = d.addBox("ClickHouse", { row: 0, col: 2, color: "database" });
74-
const grafana = d.addBox("Grafana", { row: 0, col: 3, color: "frontend" });
72+
const flink = d.addBox("Flink", { row: 1, col: 0, color: "backend" });
73+
const clickhouse = d.addBox("ClickHouse", { row: 2, col: 0, color: "database" });
74+
const grafana = d.addBox("Grafana", { row: 3, col: 0, color: "frontend" });
7575

7676
d.connect(kafka, flink, "stream");
7777
d.connect(flink, clickhouse, "write");
@@ -104,15 +104,15 @@ return d.render();
104104

105105
## CI/CD Pipeline
106106

107-
A horizontal CI/CD pipeline from GitHub through build, test, staging, to production. Each stage uses a different color to indicate its role.
107+
A CI/CD pipeline from GitHub through build, test, staging, to production. Each stage uses a different color to indicate its role.
108108

109109
```typescript
110-
const d = new Diagram({ direction: "LR" });
110+
const d = new Diagram();
111111
const github = d.addBox("GitHub", { row: 0, col: 0, color: "external" });
112-
const build = d.addBox("Build", { row: 0, col: 1, color: "backend" });
113-
const test = d.addBox("Test", { row: 0, col: 2, color: "ai" });
114-
const staging = d.addBox("Staging", { row: 0, col: 3, color: "cache" });
115-
const prod = d.addBox("Production", { row: 0, col: 4, color: "database" });
112+
const build = d.addBox("Build", { row: 1, col: 0, color: "backend" });
113+
const test = d.addBox("Test", { row: 2, col: 0, color: "ai" });
114+
const staging = d.addBox("Staging", { row: 3, col: 0, color: "cache" });
115+
const prod = d.addBox("Production", { row: 4, col: 0, color: "database" });
116116

117117
d.connect(github, build, "push");
118118
d.connect(build, test, "artifacts");
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
title: Iterating on Diagrams
3+
description: How drawmode helps LLMs refine and edit diagrams across multiple turns
4+
---
5+
6+
drawmode includes several features designed to help LLMs iterate on diagrams — editing existing work, tracking changes, and getting feedback on what was modified.
7+
8+
## Two Editing Workflows
9+
10+
### Workflow 1: Sidecar Source (Recommended)
11+
12+
When you render to `.excalidraw`, drawmode saves the TypeScript source alongside it as a `.drawmode.ts` sidecar file:
13+
14+
```
15+
diagram.excalidraw ← Excalidraw JSON (for viewing)
16+
diagram.drawmode.ts ← TypeScript source (for editing)
17+
```
18+
19+
To iterate, the LLM reads the `.drawmode.ts` file, modifies the code, and re-executes. This is the preferred workflow because the TypeScript source is always easier to modify than binary Excalidraw JSON.
20+
21+
### Workflow 2: fromFile (No Source Available)
22+
23+
When no sidecar exists, `fromFile()` reconstructs a Diagram from raw Excalidraw JSON:
24+
25+
```typescript
26+
const d = await Diagram.fromFile("diagram.excalidraw");
27+
const ids = d.findByLabel("Old Service");
28+
if (ids.length > 0) d.updateNode(ids[0], { label: "New Service", color: "ai" });
29+
d.removeNode(d.findByLabel("Deprecated")[0]);
30+
return d.render({ path: "diagram.excalidraw" });
31+
```
32+
33+
This parses all nodes, edges, groups, and frames from the file, letting the LLM query and modify them programmatically.
34+
35+
## Querying the Graph
36+
37+
Find and inspect existing elements before modifying them:
38+
39+
```typescript
40+
// Search by label (substring match)
41+
const ids = d.findByLabel("API");
42+
43+
// Exact match
44+
const ids = d.findByLabel("PostgreSQL", { exact: true });
45+
46+
// Get all node IDs
47+
const allNodes = d.getNodes();
48+
49+
// Get all edges
50+
const allEdges = d.getEdges();
51+
// → [{ from: "n1", to: "n2", label: "queries" }, ...]
52+
53+
// Inspect a specific node
54+
const info = d.getNode(id);
55+
// → { label, type, width, height, backgroundColor, strokeColor, row, col }
56+
```
57+
58+
## Modifying Elements
59+
60+
### Update Nodes
61+
62+
Change any property on an existing node:
63+
64+
```typescript
65+
d.updateNode(id, { label: "API Gateway v2", color: "ai" });
66+
d.updateNode(id, { width: 200, strokeStyle: "dashed" });
67+
d.updateNode(id, { x: 300, y: 100 }); // absolute positioning
68+
```
69+
70+
### Update Edges
71+
72+
Modify edge properties. Use `matchLabel` to disambiguate when multiple edges connect the same pair:
73+
74+
```typescript
75+
d.updateEdge(apiId, dbId, { label: "writes", style: "dashed" });
76+
d.updateEdge(apiId, cacheId, { strokeColor: "#e03131" }, "reads");
77+
```
78+
79+
### Remove Elements
80+
81+
Delete nodes (and their connected edges) or specific edges:
82+
83+
```typescript
84+
d.removeNode(deprecatedId); // also removes all connected edges
85+
d.removeEdge(apiId, dbId); // remove first matching edge
86+
d.removeEdge(apiId, dbId, "reads"); // remove by label
87+
d.removeGroup(groupId); // remove group, keep children
88+
d.removeFrame(frameId); // remove frame, keep children
89+
```
90+
91+
## Change Summary
92+
93+
When overwriting an existing `.excalidraw` file, drawmode automatically computes a diff and reports what changed:
94+
95+
```
96+
+ Added: "Cache Layer" (rectangle), "Load Balancer" (rectangle)
97+
- Removed: "Old Service" (rectangle)
98+
~ Modified: "API" → "API Gateway v2"
99+
~ Moved: "Database"
100+
+ 2 edge(s) added
101+
- 1 edge(s) removed
102+
Unchanged: 8 node(s)
103+
```
104+
105+
This summary is returned in the MCP tool response, helping the LLM verify its changes and decide if further iteration is needed.
106+
107+
A `.bak` backup is also created automatically before overwriting, so changes are always reversible.
108+
109+
## Diagram Statistics
110+
111+
Every render includes statistics in the response:
112+
113+
```
114+
12 nodes, 15 edges, 3 groups
115+
```
116+
117+
This gives the LLM a quick sanity check — if the count is unexpectedly low or high, something may have gone wrong.
118+
119+
## Validation Warnings
120+
121+
The Zig WASM validator checks rendered output for structural issues. Warnings are surfaced in the MCP response:
122+
123+
```
124+
⚠ Element "n3" has no connections
125+
⚠ Arrow "e2" has invalid binding
126+
```
127+
128+
These guide the LLM to fix problems in the next iteration.
129+
130+
## Mermaid Import
131+
132+
As an alternative starting point, `fromMermaid()` converts Mermaid syntax into a Diagram:
133+
134+
```typescript
135+
const d = Diagram.fromMermaid(`
136+
graph TD
137+
A[API Gateway] --> B[Auth Service]
138+
A --> C[Order Service]
139+
B --> D[(Database)]
140+
`);
141+
// Now modify using the full SDK
142+
d.updateNode(d.findByLabel("API Gateway")[0], { color: "backend" });
143+
return d.render();
144+
```
145+
146+
Supported Mermaid features: `graph TD/LR/RL/BT`, node shapes (`[]`, `{}`, `(())`, `[()]`), edges (`-->`, `---`, `-..->`, `==>`), edge labels (`|label|`), subgraphs, and chained edges.

0 commit comments

Comments
 (0)