sketchmark 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +748 -0
- package/dist/animation/index.d.ts +56 -0
- package/dist/animation/index.d.ts.map +1 -0
- package/dist/ast/index.d.ts +2 -0
- package/dist/ast/index.d.ts.map +1 -0
- package/dist/ast/types.d.ts +159 -0
- package/dist/ast/types.d.ts.map +1 -0
- package/dist/export/index.d.ts +21 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/index.cjs +4706 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4669 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.d.ts +4 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/parser/index.d.ts +9 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/tokenizer.d.ts +10 -0
- package/dist/parser/tokenizer.d.ts.map +1 -0
- package/dist/renderer/canvas/index.d.ts +14 -0
- package/dist/renderer/canvas/index.d.ts.map +1 -0
- package/dist/renderer/canvas/roughChartCanvas.d.ts +16 -0
- package/dist/renderer/canvas/roughChartCanvas.d.ts.map +1 -0
- package/dist/renderer/roughChart.d.ts +57 -0
- package/dist/renderer/roughChart.d.ts.map +1 -0
- package/dist/renderer/svg/index.d.ts +13 -0
- package/dist/renderer/svg/index.d.ts.map +1 -0
- package/dist/renderer/svg/roughChartSVG.d.ts +12 -0
- package/dist/renderer/svg/roughChartSVG.d.ts.map +1 -0
- package/dist/scene/index.d.ts +118 -0
- package/dist/scene/index.d.ts.map +1 -0
- package/dist/sketchmark.iife.js +4710 -0
- package/dist/theme/index.d.ts +35 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
# sketchmark
|
|
2
|
+
|
|
3
|
+
A text-based diagram DSL that renders hand-drawn SVG and Canvas diagrams using [rough.js](https://roughjs.com). Write diagrams as plain text, get sketchy, expressive visuals with a full animation system.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
diagram
|
|
7
|
+
title label="System Architecture"
|
|
8
|
+
|
|
9
|
+
box client label="Client App" theme=primary
|
|
10
|
+
box gateway label="API Gateway" theme=warning
|
|
11
|
+
box db label="PostgreSQL" theme=success
|
|
12
|
+
|
|
13
|
+
client --> gateway label="HTTPS"
|
|
14
|
+
gateway --> db label="SQL"
|
|
15
|
+
|
|
16
|
+
step highlight client
|
|
17
|
+
step draw client-->gateway
|
|
18
|
+
step highlight gateway
|
|
19
|
+
step draw gateway-->db
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Table of Contents
|
|
26
|
+
|
|
27
|
+
- [Installation](#installation)
|
|
28
|
+
- [Quick Start](#quick-start)
|
|
29
|
+
- [DSL Reference](#dsl-reference)
|
|
30
|
+
- [Diagram Header](#diagram-header)
|
|
31
|
+
- [Node Shapes](#node-shapes)
|
|
32
|
+
- [Edges](#edges)
|
|
33
|
+
- [Groups](#groups)
|
|
34
|
+
- [Tables](#tables)
|
|
35
|
+
- [Notes](#notes)
|
|
36
|
+
- [Charts](#charts)
|
|
37
|
+
- [Themes](#themes)
|
|
38
|
+
- [Animation Steps](#animation-steps)
|
|
39
|
+
- [Layout System](#layout-system)
|
|
40
|
+
- [Animation System](#animation-system)
|
|
41
|
+
- [Theme Palettes](#theme-palettes)
|
|
42
|
+
- [API Reference](#api-reference)
|
|
43
|
+
- [Export](#export)
|
|
44
|
+
- [Examples](#examples)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install sketchmark roughjs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
rough.js is a peer dependency — it must be available at runtime.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
**With a bundler (Vite, webpack, Next.js):**
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { render } from 'sketchmark';
|
|
64
|
+
|
|
65
|
+
const instance = render({
|
|
66
|
+
container: document.getElementById('diagram'),
|
|
67
|
+
dsl: `
|
|
68
|
+
diagram
|
|
69
|
+
box a label="Hello"
|
|
70
|
+
box b label="World"
|
|
71
|
+
a --> b label="connects"
|
|
72
|
+
`,
|
|
73
|
+
renderer: 'svg',
|
|
74
|
+
svgOptions: { showTitle: true, interactive: true,transparent: true },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Step through animation
|
|
78
|
+
instance.anim.next();
|
|
79
|
+
instance.anim.play(800);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**CDN / no bundler:**
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<script src="https://unpkg.com/roughjs@4.6.6/bundled/rough.js"></script>
|
|
86
|
+
<script type="module">
|
|
87
|
+
import { render } from 'https://unpkg.com/sketchmark/dist/index.js';
|
|
88
|
+
|
|
89
|
+
render({
|
|
90
|
+
container: document.getElementById('diagram'),
|
|
91
|
+
dsl: `diagram\nbox a label="Hello"\nbox b label="World"\na --> b`,
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**CommonJS:**
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const { parse, buildSceneGraph, layout } = require('sketchmark');
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## DSL Reference
|
|
105
|
+
|
|
106
|
+
Every diagram starts with `diagram` and ends with `end`.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
diagram
|
|
110
|
+
title label="My Diagram"
|
|
111
|
+
layout row
|
|
112
|
+
config gap=60
|
|
113
|
+
|
|
114
|
+
... nodes, edges, groups, steps ...
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Diagram Header
|
|
120
|
+
|
|
121
|
+
| Keyword | Example | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `title` | `title label="My Diagram"` | Title shown above the diagram |
|
|
124
|
+
| `layout` | `layout row` | Root layout direction: `row`, `column`, `grid` |
|
|
125
|
+
| `config gap` | `config gap=60` | Gap between root-level items (default: 80) |
|
|
126
|
+
| `config margin` | `config margin=40` | Outer canvas margin (default: 60) |
|
|
127
|
+
| `config theme` | `config theme=ocean` | Global palette (see [Theme Palettes](#theme-palettes)) |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### Node Shapes
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
box id label="..." [theme=X] [width=N] [height=N]
|
|
135
|
+
circle id label="..."
|
|
136
|
+
diamond id label="..."
|
|
137
|
+
hexagon id label="..."
|
|
138
|
+
triangle id label="..."
|
|
139
|
+
cylinder id label="..."
|
|
140
|
+
parallelogram id label="..."
|
|
141
|
+
text id label="..."
|
|
142
|
+
image id label="..." url="https://..."
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Common properties:**
|
|
146
|
+
|
|
147
|
+
| Property | Example | Description |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `label` | `label="API Gateway"` | Display text |
|
|
150
|
+
| `theme` | `theme=primary` | Named theme (defined with `theme` keyword) |
|
|
151
|
+
| `width` | `width=140` | Override auto-width in px |
|
|
152
|
+
| `height` | `height=55` | Override auto-height in px |
|
|
153
|
+
| `fill` | `fill="#e8f4ff"` | Background fill color |
|
|
154
|
+
| `stroke` | `stroke="#0044cc"` | Border color |
|
|
155
|
+
| `color` | `color="#003399"` | Text color |
|
|
156
|
+
| `font-size` | `font-size=12` | Label font size |
|
|
157
|
+
|
|
158
|
+
**Example:**
|
|
159
|
+
```
|
|
160
|
+
box gateway label="API Gateway" theme=warning width=150 height=55
|
|
161
|
+
circle user label="User" fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
162
|
+
cylinder db label="PostgreSQL" theme=success width=140 height=65
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Edges
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
fromId connector toId [label="..."]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Connectors:**
|
|
174
|
+
|
|
175
|
+
| Connector | Arrow | Line |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `->` | end | solid |
|
|
178
|
+
| `<-` | start | solid |
|
|
179
|
+
| `<->` | both | solid |
|
|
180
|
+
| `-->` | end | dashed |
|
|
181
|
+
| `<-->` | both | dashed |
|
|
182
|
+
| `--` | none | solid |
|
|
183
|
+
| `---` | none | dashed |
|
|
184
|
+
|
|
185
|
+
**Example:**
|
|
186
|
+
```
|
|
187
|
+
client --> gateway label="HTTPS"
|
|
188
|
+
gateway <-> auth label="verify"
|
|
189
|
+
db --- replica label="sync"
|
|
190
|
+
a --- b
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Groups
|
|
196
|
+
|
|
197
|
+
Groups are containers that arrange children using a flexbox-style layout.
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
group id [label="..."] [layout=row|column|grid] [gap=N] [padding=N]
|
|
201
|
+
[justify=start|center|end|space-between|space-around]
|
|
202
|
+
[align=start|center|end]
|
|
203
|
+
[columns=N]
|
|
204
|
+
[width=N] [height=N]
|
|
205
|
+
[theme=X]
|
|
206
|
+
{
|
|
207
|
+
box child1 label="..."
|
|
208
|
+
box child2 label="..."
|
|
209
|
+
group nested { ... }
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Properties:**
|
|
214
|
+
|
|
215
|
+
| Property | Default | Description |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `layout` | `column` | `row`, `column`, or `grid` |
|
|
218
|
+
| `gap` | `10` | Space between children in px |
|
|
219
|
+
| `padding` | `26` | Inner padding in px |
|
|
220
|
+
| `justify` | `start` | Main-axis distribution of children |
|
|
221
|
+
| `align` | `start` | Cross-axis alignment of children |
|
|
222
|
+
| `columns` | `1` | Number of columns when `layout=grid` |
|
|
223
|
+
| `width` | auto | Minimum width — enables `justify` distribution |
|
|
224
|
+
| `height` | auto | Minimum height |
|
|
225
|
+
| `theme` | — | Named theme for border/background |
|
|
226
|
+
|
|
227
|
+
> **Note on `justify`:** Requires an explicit `width` larger than the children's total width to have visible effect. Without extra space, all five values look identical.
|
|
228
|
+
|
|
229
|
+
**Example:**
|
|
230
|
+
```
|
|
231
|
+
group services label="Microservices" layout=column gap=16 padding=30 theme=muted
|
|
232
|
+
{
|
|
233
|
+
box auth label="Auth Service" theme=primary width=140 height=55
|
|
234
|
+
box billing label="Billing Service" theme=primary width=140 height=55
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Grid layout:**
|
|
239
|
+
```
|
|
240
|
+
group icons layout=grid columns=3 gap=20 padding=24 width=400
|
|
241
|
+
{
|
|
242
|
+
box a label="A" width=100 height=60
|
|
243
|
+
box b label="B" width=100 height=60
|
|
244
|
+
box c label="C" width=100 height=60
|
|
245
|
+
box d label="D" width=100 height=60
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Justify example:**
|
|
250
|
+
```
|
|
251
|
+
group nav layout=row justify=space-between width=500 padding=20 gap=10
|
|
252
|
+
{
|
|
253
|
+
box home label="Home" width=80 height=40
|
|
254
|
+
box about label="About" width=80 height=40
|
|
255
|
+
box contact label="Contact" width=80 height=40
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### Tables
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
table id [label="..."] [theme=X]
|
|
265
|
+
{
|
|
266
|
+
header Col1 Col2 Col3
|
|
267
|
+
row val1 val2 val3
|
|
268
|
+
row val4 val5 val6
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Example:**
|
|
273
|
+
```
|
|
274
|
+
table pricing label="Pricing Plans"
|
|
275
|
+
{
|
|
276
|
+
header Plan Price Requests
|
|
277
|
+
row Free $0 1k/day
|
|
278
|
+
row Pro $29 100k/day
|
|
279
|
+
row Enterprise $299 Unlimited
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### Notes
|
|
286
|
+
|
|
287
|
+
Single or multiline sticky notes.
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
note id label="Single line note" [theme=X]
|
|
291
|
+
note id label="Line one\nLine two\nLine three"
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### Charts
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
bar-chart id [title="..."] [width=N] [height=N] [theme=X]
|
|
300
|
+
line-chart id ...
|
|
301
|
+
area-chart id ...
|
|
302
|
+
pie-chart id ...
|
|
303
|
+
donut-chart id ...
|
|
304
|
+
scatter-chart id ...
|
|
305
|
+
|
|
306
|
+
data
|
|
307
|
+
[
|
|
308
|
+
["Label", "Series1", "Series2"],
|
|
309
|
+
["Jan", 120, 80 ],
|
|
310
|
+
["Feb", 150, 95 ],
|
|
311
|
+
["Mar", 130, 110 ]
|
|
312
|
+
]
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Pie / donut data format:**
|
|
316
|
+
```
|
|
317
|
+
pie-chart revenue title="Revenue Split"
|
|
318
|
+
data
|
|
319
|
+
[
|
|
320
|
+
["Product", 45],
|
|
321
|
+
["Services", 30],
|
|
322
|
+
["Support", 25]
|
|
323
|
+
]
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Scatter data format:**
|
|
327
|
+
```
|
|
328
|
+
scatter-chart perf title="Performance"
|
|
329
|
+
data
|
|
330
|
+
[
|
|
331
|
+
["headers", "x", "y"],
|
|
332
|
+
["Server A", 10, 95],
|
|
333
|
+
["Server B", 20, 87]
|
|
334
|
+
]
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### Themes
|
|
340
|
+
|
|
341
|
+
Define reusable style presets with `theme`, then apply them to any node or group.
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
theme primary fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
345
|
+
theme success fill="#e8ffe8" stroke="#007700" color="#004400"
|
|
346
|
+
theme warning fill="#fff9e6" stroke="#f0a500" color="#7a5000"
|
|
347
|
+
theme danger fill="#ffe8e8" stroke="#cc0000" color="#900000"
|
|
348
|
+
theme muted fill="#f5f5f5" stroke="#999999" color="#444444"
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Apply: `box myNode label="..." theme=primary`
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### Animation Steps
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
step action target [options]
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Actions:**
|
|
362
|
+
|
|
363
|
+
| Action | Syntax | Description |
|
|
364
|
+
|---|---|---|
|
|
365
|
+
| `highlight` | `step highlight nodeId` | Pulsing glow on a node |
|
|
366
|
+
| `fade` | `step fade nodeId` | Fade node to 22% opacity |
|
|
367
|
+
| `unfade` | `step unfade nodeId` | Restore full opacity |
|
|
368
|
+
| `draw` | `step draw nodeId` | Animate node appearing (stroke-draw) |
|
|
369
|
+
| `draw` | `step draw a-->b` | Animate edge appearing |
|
|
370
|
+
| `erase` | `step erase nodeId` | Fade element to invisible |
|
|
371
|
+
| `show` | `step show nodeId` | Make hidden element visible |
|
|
372
|
+
| `hide` | `step hide nodeId` | Hide element |
|
|
373
|
+
| `pulse` | `step pulse nodeId` | Single brightness flash |
|
|
374
|
+
| `color` | `step color nodeId #ff0000` | Change fill color |
|
|
375
|
+
| `move` | `step move nodeId dx=50 dy=0` | Translate by dx/dy px |
|
|
376
|
+
| `scale` | `step scale nodeId factor=1.5` | Scale (absolute, 1.0 = normal) |
|
|
377
|
+
| `rotate` | `step rotate nodeId deg=45` | Rotate (cumulative degrees) |
|
|
378
|
+
|
|
379
|
+
**Options:**
|
|
380
|
+
|
|
381
|
+
| Option | Example | Description |
|
|
382
|
+
|---|---|---|
|
|
383
|
+
| `duration` | `duration=600` | Animation duration in ms |
|
|
384
|
+
| `dx` | `dx=100` | X offset for `move` |
|
|
385
|
+
| `dy` | `dy=-80` | Y offset for `move` |
|
|
386
|
+
| `factor` | `factor=1.5` | Scale multiplier for `scale` |
|
|
387
|
+
| `deg` | `deg=45` | Degrees for `rotate` (cumulative) |
|
|
388
|
+
|
|
389
|
+
**Notes on `move` / `scale` / `rotate`:**
|
|
390
|
+
- `move` is cumulative — `dx=50` twice = 100px total
|
|
391
|
+
- `scale` is absolute — `factor=1.5` always means 1.5×, `factor=1.0` resets to normal
|
|
392
|
+
- `rotate` is cumulative — `deg=45` twice = 90° total, `deg=-45` rotates back
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Layout System
|
|
397
|
+
|
|
398
|
+
### Root layout
|
|
399
|
+
|
|
400
|
+
Controls how top-level items (groups, standalone nodes) are arranged:
|
|
401
|
+
|
|
402
|
+
```
|
|
403
|
+
layout row # left to right (default)
|
|
404
|
+
layout column # top to bottom
|
|
405
|
+
layout grid # grid, use config columns=N
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Group layout
|
|
409
|
+
|
|
410
|
+
Each group is an independent flex container:
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
group g layout=row justify=space-between width=500 gap=16 padding=20
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### `justify` values
|
|
417
|
+
|
|
418
|
+
| Value | Effect |
|
|
419
|
+
|---|---|
|
|
420
|
+
| `start` | Pack children to the start (default) |
|
|
421
|
+
| `center` | Center children in the container |
|
|
422
|
+
| `end` | Pack children to the end |
|
|
423
|
+
| `space-between` | First at start, last at end, equal gaps between |
|
|
424
|
+
| `space-around` | Equal space around each child |
|
|
425
|
+
|
|
426
|
+
> Requires `width` wider than total child width to be visible.
|
|
427
|
+
|
|
428
|
+
### `align` values
|
|
429
|
+
|
|
430
|
+
| Value | Effect |
|
|
431
|
+
|---|---|
|
|
432
|
+
| `start` | Align to the start of the cross-axis (default) |
|
|
433
|
+
| `center` | Center on the cross-axis |
|
|
434
|
+
| `end` | Align to the end of the cross-axis |
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Animation System
|
|
439
|
+
|
|
440
|
+
The `AnimationController` is returned as `instance.anim` from `render()`.
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
const instance = render({ container, dsl });
|
|
444
|
+
const { anim } = instance;
|
|
445
|
+
|
|
446
|
+
anim.next(); // advance one step
|
|
447
|
+
anim.prev(); // go back one step
|
|
448
|
+
anim.reset(); // return to initial state
|
|
449
|
+
anim.goTo(3); // jump to specific step index
|
|
450
|
+
await anim.play(800); // auto-play, 800ms per step
|
|
451
|
+
|
|
452
|
+
anim.currentStep // current step index (-1 = not started)
|
|
453
|
+
anim.total // total number of steps
|
|
454
|
+
anim.canNext // boolean
|
|
455
|
+
anim.canPrev // boolean
|
|
456
|
+
|
|
457
|
+
// listen to events
|
|
458
|
+
anim.on((event) => {
|
|
459
|
+
// event.type: 'step-change' | 'animation-reset' |
|
|
460
|
+
// 'animation-start' | 'animation-end' | 'step-complete'
|
|
461
|
+
console.log(event.stepIndex, event.step);
|
|
462
|
+
});
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**Slide-in entrance pattern:**
|
|
466
|
+
```
|
|
467
|
+
step move nodeId dx=0 dy=80 # push below final position
|
|
468
|
+
step draw nodeId # reveal at offset
|
|
469
|
+
step move nodeId dx=0 dy=-80 # animate into final position
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Wobble then fail pattern:**
|
|
473
|
+
```
|
|
474
|
+
step rotate nodeId deg=8
|
|
475
|
+
step rotate nodeId deg=-8
|
|
476
|
+
step rotate nodeId deg=8
|
|
477
|
+
step rotate nodeId deg=25 # cumulative = 33°, looks like toppling
|
|
478
|
+
step fade nodeId
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Theme Palettes
|
|
484
|
+
|
|
485
|
+
Set a global palette with `config theme=NAME`. Available palettes:
|
|
486
|
+
|
|
487
|
+
| Name | Description |
|
|
488
|
+
|---|---|
|
|
489
|
+
| `light` | Warm parchment (default) |
|
|
490
|
+
| `dark` | Dark warm background |
|
|
491
|
+
| `ocean` | Cool blues |
|
|
492
|
+
| `forest` | Greens |
|
|
493
|
+
| `sunset` | Warm oranges and reds |
|
|
494
|
+
| `slate` | Cool grays |
|
|
495
|
+
| `rose` | Pinks and magentas |
|
|
496
|
+
| `midnight` | GitHub-dark style blues |
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
config theme=ocean
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## API Reference
|
|
505
|
+
|
|
506
|
+
### `render(options): DiagramInstance`
|
|
507
|
+
|
|
508
|
+
One-call API. Parses DSL, builds scene, lays out, renders, and returns a controller.
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
import { render } from 'sketchmark';
|
|
512
|
+
|
|
513
|
+
const instance = render({
|
|
514
|
+
container: '#my-div', // CSS selector, HTMLElement, or SVGSVGElement
|
|
515
|
+
dsl: '...', // DSL source text
|
|
516
|
+
renderer: 'svg', // 'svg' (default) | 'canvas'
|
|
517
|
+
injectCSS: true, // inject animation CSS into <head>
|
|
518
|
+
svgOptions: {
|
|
519
|
+
showTitle: true,
|
|
520
|
+
interactive: true, // hover effects + click handlers
|
|
521
|
+
roughness: 1.3,
|
|
522
|
+
bowing: 0.7,
|
|
523
|
+
theme: 'light', // 'light' | 'dark'
|
|
524
|
+
onNodeClick: (nodeId) => {},
|
|
525
|
+
},
|
|
526
|
+
canvasOptions: {
|
|
527
|
+
scale: 2, // pixel density
|
|
528
|
+
roughness: 1.3,
|
|
529
|
+
},
|
|
530
|
+
onNodeClick: (nodeId) => {},
|
|
531
|
+
onReady: (anim, svg) => {},
|
|
532
|
+
});
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**`DiagramInstance`:**
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
instance.scene // SceneGraph — all positioned nodes, edges, groups
|
|
539
|
+
instance.anim // AnimationController
|
|
540
|
+
instance.svg // SVGSVGElement (if renderer='svg')
|
|
541
|
+
instance.canvas // HTMLCanvasElement (if renderer='canvas')
|
|
542
|
+
instance.update(dsl) // re-render with new DSL
|
|
543
|
+
instance.exportSVG() // download as SVG file
|
|
544
|
+
instance.exportPNG() // download as PNG file
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
### Pipeline API (low-level)
|
|
550
|
+
|
|
551
|
+
Use these if you need to control each step manually:
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
import { parse, buildSceneGraph, layout, renderToSVG } from 'sketchmark';
|
|
555
|
+
|
|
556
|
+
const ast = parse(dslString); // DSL → AST
|
|
557
|
+
const scene = buildSceneGraph(ast); // AST → SceneGraph
|
|
558
|
+
layout(scene); // compute x/y positions
|
|
559
|
+
const svg = renderToSVG(scene, containerEl, options);
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
### `parse(dsl: string): DiagramAST`
|
|
565
|
+
|
|
566
|
+
Tokenizes and parses DSL source into an AST.
|
|
567
|
+
Throws `ParseError` with line/col information on invalid syntax.
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
import { parse, ParseError } from 'sketchmark';
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
const ast = parse(dsl);
|
|
574
|
+
} catch (e) {
|
|
575
|
+
if (e instanceof ParseError) {
|
|
576
|
+
console.error(`Line ${e.line}, Col ${e.col}: ${e.message}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
### `buildSceneGraph(ast): SceneGraph`
|
|
584
|
+
|
|
585
|
+
Converts AST to a SceneGraph with unpositioned nodes and groups.
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
### `layout(scene): SceneGraph`
|
|
590
|
+
|
|
591
|
+
Computes x/y positions for all elements. Mutates and returns the SceneGraph.
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
### `renderToSVG(scene, container, options?): SVGSVGElement`
|
|
596
|
+
|
|
597
|
+
Renders scene to SVG using rough.js.
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
### `renderToCanvas(scene, canvas, options?): void`
|
|
602
|
+
|
|
603
|
+
Renders scene to an HTML Canvas element using rough.js.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Export
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
import { exportSVG, exportPNG, exportHTML, getSVGBlob } from 'sketchmark';
|
|
611
|
+
|
|
612
|
+
exportSVG(svgElement, { filename: 'diagram.svg' });
|
|
613
|
+
await exportPNG(svgElement, { filename: 'diagram.png', scale: 2 });
|
|
614
|
+
exportHTML(svgElement, dslSource, { filename: 'diagram.html' });
|
|
615
|
+
|
|
616
|
+
// Get blob without downloading
|
|
617
|
+
const blob = getSVGBlob(svgElement);
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Or via the instance:
|
|
621
|
+
```typescript
|
|
622
|
+
instance.exportSVG('my-diagram.svg');
|
|
623
|
+
await instance.exportPNG('my-diagram.png');
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## Examples
|
|
629
|
+
|
|
630
|
+
### Basic architecture diagram
|
|
631
|
+
|
|
632
|
+
```
|
|
633
|
+
diagram
|
|
634
|
+
title label="System Architecture"
|
|
635
|
+
layout row
|
|
636
|
+
config gap=60
|
|
637
|
+
|
|
638
|
+
theme primary fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
639
|
+
theme success fill="#e8ffe8" stroke="#007700" color="#004400"
|
|
640
|
+
theme muted fill="#f5f5f5" stroke="#999999" color="#444444"
|
|
641
|
+
|
|
642
|
+
box client label="Client App" theme=primary width=140 height=55
|
|
643
|
+
box gateway label="API Gateway" theme=muted width=140 height=55
|
|
644
|
+
|
|
645
|
+
group services label="Services" layout=column gap=16 padding=30 theme=muted
|
|
646
|
+
{
|
|
647
|
+
box auth label="Auth Service" theme=primary width=130 height=50
|
|
648
|
+
box data label="Data Service" theme=primary width=130 height=50
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
cylinder db label="PostgreSQL" theme=success width=140 height=65
|
|
652
|
+
|
|
653
|
+
client --> gateway label="HTTPS"
|
|
654
|
+
gateway --> auth
|
|
655
|
+
gateway --> data
|
|
656
|
+
auth --> db label="SQL"
|
|
657
|
+
data --> db label="SQL"
|
|
658
|
+
|
|
659
|
+
end
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
### Animated deployment
|
|
665
|
+
|
|
666
|
+
```
|
|
667
|
+
diagram
|
|
668
|
+
title label="Blue-Green Deployment"
|
|
669
|
+
layout row
|
|
670
|
+
config gap=50
|
|
671
|
+
|
|
672
|
+
theme primary fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
673
|
+
theme success fill="#e8ffe8" stroke="#007700" color="#004400"
|
|
674
|
+
theme muted fill="#f5f5f5" stroke="#999999" color="#444444"
|
|
675
|
+
|
|
676
|
+
box lb label="Load Balancer" theme=muted width=150 height=55
|
|
677
|
+
|
|
678
|
+
group blue label="Blue (live)" layout=column gap=16 padding=26 theme=primary
|
|
679
|
+
{
|
|
680
|
+
box b1 label="API v1" theme=primary width=120 height=50
|
|
681
|
+
box b2 label="Worker v1" theme=primary width=120 height=50
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
group green label="Green (new)" layout=column gap=16 padding=26 theme=success
|
|
685
|
+
{
|
|
686
|
+
box g1 label="API v2" theme=success width=120 height=50
|
|
687
|
+
box g2 label="Worker v2" theme=success width=120 height=50
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
lb --> b1 label="100%"
|
|
691
|
+
lb --> g1 label="0%"
|
|
692
|
+
|
|
693
|
+
step highlight lb
|
|
694
|
+
step draw lb-->b1
|
|
695
|
+
step highlight b1
|
|
696
|
+
|
|
697
|
+
# green slides in from below
|
|
698
|
+
step move g1 dx=0 dy=60
|
|
699
|
+
step move g2 dx=0 dy=60
|
|
700
|
+
step draw g1
|
|
701
|
+
step move g1 dx=0 dy=-60 duration=500
|
|
702
|
+
step draw g2
|
|
703
|
+
step move g2 dx=0 dy=-60 duration=500
|
|
704
|
+
|
|
705
|
+
# traffic shifts
|
|
706
|
+
step fade b1
|
|
707
|
+
step fade b2
|
|
708
|
+
step draw lb-->g1
|
|
709
|
+
step highlight g1
|
|
710
|
+
|
|
711
|
+
end
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
### Charts
|
|
717
|
+
|
|
718
|
+
```
|
|
719
|
+
diagram
|
|
720
|
+
layout row
|
|
721
|
+
config gap=40
|
|
722
|
+
|
|
723
|
+
bar-chart revenue title="Monthly Revenue" width=340 height=240
|
|
724
|
+
data
|
|
725
|
+
[
|
|
726
|
+
["Month", "2023", "2024"],
|
|
727
|
+
["Jan", 42000, 58000 ],
|
|
728
|
+
["Feb", 38000, 61000 ],
|
|
729
|
+
["Mar", 51000, 67000 ],
|
|
730
|
+
["Apr", 46000, 72000 ]
|
|
731
|
+
]
|
|
732
|
+
|
|
733
|
+
pie-chart share title="Market Share" width=280 height=240
|
|
734
|
+
data
|
|
735
|
+
[
|
|
736
|
+
["Product A", 42],
|
|
737
|
+
["Product B", 31],
|
|
738
|
+
["Product C", 27]
|
|
739
|
+
]
|
|
740
|
+
|
|
741
|
+
end
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## License
|
|
747
|
+
|
|
748
|
+
MIT
|