sketchmark 0.1.2 → 0.1.4
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/README.md +461 -200
- package/dist/ast/types.d.ts +17 -0
- package/dist/ast/types.d.ts.map +1 -1
- package/dist/index.cjs +708 -188
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +706 -189
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/markdown/parser.d.ts +16 -0
- package/dist/markdown/parser.d.ts.map +1 -0
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/tokenizer.d.ts +1 -1
- package/dist/parser/tokenizer.d.ts.map +1 -1
- package/dist/renderer/canvas/index.d.ts.map +1 -1
- package/dist/renderer/svg/index.d.ts.map +1 -1
- package/dist/scene/index.d.ts +15 -0
- package/dist/scene/index.d.ts.map +1 -1
- package/dist/share/encrypted.d.ts +11 -0
- package/dist/share/encrypted.d.ts.map +1 -0
- package/dist/sketchmark.iife.js +708 -188
- package/package.json +69 -66
package/README.md
CHANGED
|
@@ -31,14 +31,18 @@ end
|
|
|
31
31
|
- [Node Shapes](#node-shapes)
|
|
32
32
|
- [Edges](#edges)
|
|
33
33
|
- [Groups](#groups)
|
|
34
|
+
- [Bare Groups](#bare-groups)
|
|
34
35
|
- [Tables](#tables)
|
|
35
36
|
- [Notes](#notes)
|
|
36
37
|
- [Charts](#charts)
|
|
38
|
+
- [Markdown Blocks](#markdown-blocks)
|
|
37
39
|
- [Themes](#themes)
|
|
40
|
+
- [Typography](#typography)
|
|
38
41
|
- [Animation Steps](#animation-steps)
|
|
39
42
|
- [Layout System](#layout-system)
|
|
40
43
|
- [Animation System](#animation-system)
|
|
41
44
|
- [Theme Palettes](#theme-palettes)
|
|
45
|
+
- [Font System](#font-system)
|
|
42
46
|
- [API Reference](#api-reference)
|
|
43
47
|
- [Export](#export)
|
|
44
48
|
- [Examples](#examples)
|
|
@@ -71,7 +75,7 @@ const instance = render({
|
|
|
71
75
|
a --> b label="connects"
|
|
72
76
|
`,
|
|
73
77
|
renderer: 'svg',
|
|
74
|
-
svgOptions: { showTitle: true, interactive: true,transparent: true },
|
|
78
|
+
svgOptions: { showTitle: true, interactive: true, transparent: true },
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
// Step through animation
|
|
@@ -79,18 +83,20 @@ instance.anim.next();
|
|
|
79
83
|
instance.anim.play(800);
|
|
80
84
|
```
|
|
81
85
|
|
|
82
|
-
**CDN / no bundler:**
|
|
86
|
+
**CDN / no bundler with import map:**
|
|
83
87
|
|
|
84
88
|
```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
|
|
|
90
|
+
|
|
91
|
+
{ "imports": { "sketchmark": "https://unpkg.com/sketchmark/dist/index.js" } }
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
import { render } from 'sketchmark';
|
|
89
95
|
render({
|
|
90
96
|
container: document.getElementById('diagram'),
|
|
91
97
|
dsl: `diagram\nbox a label="Hello"\nbox b label="World"\na --> b`,
|
|
92
98
|
});
|
|
93
|
-
|
|
99
|
+
|
|
94
100
|
```
|
|
95
101
|
|
|
96
102
|
**CommonJS:**
|
|
@@ -125,41 +131,54 @@ end
|
|
|
125
131
|
| `config gap` | `config gap=60` | Gap between root-level items (default: 80) |
|
|
126
132
|
| `config margin` | `config margin=40` | Outer canvas margin (default: 60) |
|
|
127
133
|
| `config theme` | `config theme=ocean` | Global palette (see [Theme Palettes](#theme-palettes)) |
|
|
134
|
+
| `config font` | `config font=caveat` | Diagram-wide font (see [Font System](#font-system)) |
|
|
128
135
|
|
|
129
136
|
---
|
|
130
137
|
|
|
131
138
|
### Node Shapes
|
|
132
139
|
|
|
133
140
|
```
|
|
134
|
-
box
|
|
135
|
-
circle
|
|
136
|
-
diamond
|
|
137
|
-
hexagon
|
|
138
|
-
triangle
|
|
139
|
-
cylinder
|
|
140
|
-
parallelogram id
|
|
141
|
-
text
|
|
142
|
-
image
|
|
141
|
+
box id label="..." [theme=X] [width=N] [height=N]
|
|
142
|
+
circle id label="..."
|
|
143
|
+
diamond id label="..."
|
|
144
|
+
hexagon id label="..."
|
|
145
|
+
triangle id label="..."
|
|
146
|
+
cylinder id label="..."
|
|
147
|
+
parallelogram id label="..."
|
|
148
|
+
text id label="..."
|
|
149
|
+
image id label="..." url="https://..."
|
|
143
150
|
```
|
|
144
151
|
|
|
145
152
|
**Common properties:**
|
|
146
153
|
|
|
147
154
|
| Property | Example | Description |
|
|
148
155
|
|---|---|---|
|
|
149
|
-
| `label` | `label="API Gateway"` | Display text |
|
|
150
|
-
| `theme` | `theme=primary` | Named theme
|
|
156
|
+
| `label` | `label="API Gateway"` | Display text. Use `\n` for line breaks |
|
|
157
|
+
| `theme` | `theme=primary` | Named theme |
|
|
151
158
|
| `width` | `width=140` | Override auto-width in px |
|
|
152
159
|
| `height` | `height=55` | Override auto-height in px |
|
|
153
160
|
| `fill` | `fill="#e8f4ff"` | Background fill color |
|
|
154
161
|
| `stroke` | `stroke="#0044cc"` | Border color |
|
|
155
162
|
| `color` | `color="#003399"` | Text color |
|
|
156
|
-
| `font
|
|
163
|
+
| `font` | `font=caveat` | Font family or built-in name |
|
|
164
|
+
| `font-size` | `font-size=12` | Label font size in px |
|
|
165
|
+
| `font-weight` | `font-weight=600` | Font weight |
|
|
166
|
+
| `letter-spacing` | `letter-spacing=2` | Letter spacing in px |
|
|
167
|
+
| `text-align` | `text-align=left` | `left`, `center`, `right` |
|
|
168
|
+
| `vertical-align` | `vertical-align=top` | `top`, `middle`, `bottom` |
|
|
169
|
+
| `line-height` | `line-height=1.6` | Line height multiplier |
|
|
170
|
+
|
|
171
|
+
> **`text` shape:** No border or background. Long labels auto word-wrap. Use `width=` to control the wrap width.
|
|
172
|
+
|
|
173
|
+
> **`image` shape:** Renders an image clipped to a rounded rect. Requires `url=` property.
|
|
157
174
|
|
|
158
175
|
**Example:**
|
|
159
176
|
```
|
|
160
177
|
box gateway label="API Gateway" theme=warning width=150 height=55
|
|
161
178
|
circle user label="User" fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
162
179
|
cylinder db label="PostgreSQL" theme=success width=140 height=65
|
|
180
|
+
image logo label="Logo" url="https://example.com/logo.png" width=80 height=80
|
|
181
|
+
text caption label="This auto-wraps across multiple lines." width=300
|
|
163
182
|
```
|
|
164
183
|
|
|
165
184
|
---
|
|
@@ -167,7 +186,7 @@ cylinder db label="PostgreSQL" theme=success width=140 height=65
|
|
|
167
186
|
### Edges
|
|
168
187
|
|
|
169
188
|
```
|
|
170
|
-
fromId connector toId [label="..."]
|
|
189
|
+
fromId connector toId [label="..."] [stroke="#color"] [stroke-width=N]
|
|
171
190
|
```
|
|
172
191
|
|
|
173
192
|
**Connectors:**
|
|
@@ -182,12 +201,25 @@ fromId connector toId [label="..."]
|
|
|
182
201
|
| `--` | none | solid |
|
|
183
202
|
| `---` | none | dashed |
|
|
184
203
|
|
|
204
|
+
**Edge style properties:**
|
|
205
|
+
|
|
206
|
+
| Property | Description |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `label` | Text label on the edge |
|
|
209
|
+
| `stroke` | Line and arrowhead color |
|
|
210
|
+
| `stroke-width` | Line thickness |
|
|
211
|
+
| `color` | Label text color |
|
|
212
|
+
| `font` | Label font |
|
|
213
|
+
| `font-size` | Label font size |
|
|
214
|
+
| `theme` | Apply a named theme to the edge |
|
|
215
|
+
|
|
185
216
|
**Example:**
|
|
186
217
|
```
|
|
187
218
|
client --> gateway label="HTTPS"
|
|
188
219
|
gateway <-> auth label="verify"
|
|
189
|
-
|
|
190
|
-
|
|
220
|
+
a -- b
|
|
221
|
+
db --- replica
|
|
222
|
+
api --> db stroke="#0044cc" stroke-width=2 theme=primary
|
|
191
223
|
```
|
|
192
224
|
|
|
193
225
|
---
|
|
@@ -200,13 +232,10 @@ Groups are containers that arrange children using a flexbox-style layout.
|
|
|
200
232
|
group id [label="..."] [layout=row|column|grid] [gap=N] [padding=N]
|
|
201
233
|
[justify=start|center|end|space-between|space-around]
|
|
202
234
|
[align=start|center|end]
|
|
203
|
-
[columns=N]
|
|
204
|
-
[
|
|
205
|
-
[theme=X]
|
|
235
|
+
[columns=N] [width=N] [height=N] [theme=X]
|
|
236
|
+
[font=X] [font-size=N] [letter-spacing=N]
|
|
206
237
|
{
|
|
207
|
-
|
|
208
|
-
box child2 label="..."
|
|
209
|
-
group nested { ... }
|
|
238
|
+
...children...
|
|
210
239
|
}
|
|
211
240
|
```
|
|
212
241
|
|
|
@@ -214,17 +243,18 @@ group id [label="..."] [layout=row|column|grid] [gap=N] [padding=N]
|
|
|
214
243
|
|
|
215
244
|
| Property | Default | Description |
|
|
216
245
|
|---|---|---|
|
|
246
|
+
| `label` | — | Label at top-left. Omit or `""` for no label and no reserved space |
|
|
217
247
|
| `layout` | `column` | `row`, `column`, or `grid` |
|
|
218
248
|
| `gap` | `10` | Space between children in px |
|
|
219
249
|
| `padding` | `26` | Inner padding in px |
|
|
220
|
-
| `justify` | `start` | Main-axis distribution
|
|
221
|
-
| `align` | `start` | Cross-axis alignment
|
|
222
|
-
| `columns` | `1` |
|
|
223
|
-
| `width` | auto | Minimum width — enables `justify`
|
|
250
|
+
| `justify` | `start` | Main-axis distribution |
|
|
251
|
+
| `align` | `start` | Cross-axis alignment |
|
|
252
|
+
| `columns` | `1` | Columns when `layout=grid` |
|
|
253
|
+
| `width` | auto | Minimum width — enables `justify` |
|
|
224
254
|
| `height` | auto | Minimum height |
|
|
225
255
|
| `theme` | — | Named theme for border/background |
|
|
226
256
|
|
|
227
|
-
>
|
|
257
|
+
> **`justify`** requires an explicit `width` larger than total child width to have a visible effect.
|
|
228
258
|
|
|
229
259
|
**Example:**
|
|
230
260
|
```
|
|
@@ -235,48 +265,85 @@ group services label="Microservices" layout=column gap=16 padding=30 theme=muted
|
|
|
235
265
|
}
|
|
236
266
|
```
|
|
237
267
|
|
|
238
|
-
**Grid
|
|
268
|
+
**Grid:**
|
|
239
269
|
```
|
|
240
|
-
group icons layout=grid columns=3 gap=20 padding=24
|
|
270
|
+
group icons layout=grid columns=3 gap=20 padding=24
|
|
241
271
|
{
|
|
242
|
-
box a label="A"
|
|
243
|
-
box b label="B"
|
|
244
|
-
box c label="C"
|
|
245
|
-
box d label="D" width=100 height=60
|
|
272
|
+
box a label="A" width=100 height=60
|
|
273
|
+
box b label="B" width=100 height=60
|
|
274
|
+
box c label="C" width=100 height=60
|
|
246
275
|
}
|
|
247
276
|
```
|
|
248
277
|
|
|
249
|
-
**
|
|
278
|
+
**Space-between with explicit width:**
|
|
250
279
|
```
|
|
251
280
|
group nav layout=row justify=space-between width=500 padding=20 gap=10
|
|
252
281
|
{
|
|
253
|
-
box home
|
|
254
|
-
box about
|
|
282
|
+
box home label="Home" width=80 height=40
|
|
283
|
+
box about label="About" width=80 height=40
|
|
255
284
|
box contact label="Contact" width=80 height=40
|
|
256
285
|
}
|
|
257
286
|
```
|
|
258
287
|
|
|
259
288
|
---
|
|
260
289
|
|
|
290
|
+
### Bare Groups
|
|
291
|
+
|
|
292
|
+
`bare` is a layout-only container — no label, no border, no background, no padding by default. All group layout properties apply.
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
bare id [layout=...] [gap=N] [padding=N] [justify=...] [align=...] [columns=N]
|
|
296
|
+
{
|
|
297
|
+
...children...
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Any explicitly set style overrides the bare defaults:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
# fully invisible layout container
|
|
305
|
+
bare page layout=row gap=60
|
|
306
|
+
{
|
|
307
|
+
markdown intro width=340
|
|
308
|
+
"""
|
|
309
|
+
# Title
|
|
310
|
+
Some prose here.
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
group diagram layout=column gap=20 padding=30 theme=muted
|
|
314
|
+
{
|
|
315
|
+
box a label="A" theme=primary width=130 height=52
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# bare with a visible border
|
|
320
|
+
bare wrapper layout=row gap=20 stroke="#cccccc" padding=16
|
|
321
|
+
{
|
|
322
|
+
box x label="X" width=100 height=50
|
|
323
|
+
box y label="Y" width=100 height=50
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
261
329
|
### Tables
|
|
262
330
|
|
|
263
331
|
```
|
|
264
|
-
table id [label="..."] [theme=X]
|
|
332
|
+
table id [label="..."] [theme=X] [font=X] [font-size=N] [text-align=left|center|right]
|
|
265
333
|
{
|
|
266
334
|
header Col1 Col2 Col3
|
|
267
335
|
row val1 val2 val3
|
|
268
|
-
row val4 val5 val6
|
|
269
336
|
}
|
|
270
337
|
```
|
|
271
338
|
|
|
272
339
|
**Example:**
|
|
273
340
|
```
|
|
274
|
-
table pricing label="Pricing Plans"
|
|
341
|
+
table pricing label="Pricing Plans" font=dm-mono text-align=right
|
|
275
342
|
{
|
|
276
|
-
header Plan
|
|
277
|
-
row Free
|
|
278
|
-
row Pro
|
|
279
|
-
row Enterprise $299
|
|
343
|
+
header Plan Price Requests
|
|
344
|
+
row Free $0 1k/day
|
|
345
|
+
row Pro $29 100k/day
|
|
346
|
+
row Enterprise $299 Unlimited
|
|
280
347
|
}
|
|
281
348
|
```
|
|
282
349
|
|
|
@@ -284,11 +351,23 @@ table pricing label="Pricing Plans"
|
|
|
284
351
|
|
|
285
352
|
### Notes
|
|
286
353
|
|
|
287
|
-
|
|
354
|
+
Sticky notes with a folded corner.
|
|
288
355
|
|
|
289
356
|
```
|
|
290
|
-
note id label="Single line
|
|
357
|
+
note id label="Single line" [theme=X]
|
|
291
358
|
note id label="Line one\nLine two\nLine three"
|
|
359
|
+
note id label="..." [width=N] [height=N]
|
|
360
|
+
[font=X] [font-size=N] [letter-spacing=N]
|
|
361
|
+
[text-align=left|center|right]
|
|
362
|
+
[vertical-align=top|middle|bottom]
|
|
363
|
+
[line-height=1.4]
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Example:**
|
|
367
|
+
```
|
|
368
|
+
note n1 label="Rate limited\nto 1000 req/s\nper tenant"
|
|
369
|
+
note n2 label="Postgres 16\nwith pg_vector" width=200 height=100 font-size=13
|
|
370
|
+
note n3 label="Centered" text-align=center vertical-align=middle width=180 height=80
|
|
292
371
|
```
|
|
293
372
|
|
|
294
373
|
---
|
|
@@ -307,38 +386,90 @@ data
|
|
|
307
386
|
[
|
|
308
387
|
["Label", "Series1", "Series2"],
|
|
309
388
|
["Jan", 120, 80 ],
|
|
310
|
-
["Feb", 150, 95 ]
|
|
311
|
-
["Mar", 130, 110 ]
|
|
389
|
+
["Feb", 150, 95 ]
|
|
312
390
|
]
|
|
313
391
|
```
|
|
314
392
|
|
|
315
|
-
**Pie / donut
|
|
393
|
+
**Pie / donut:**
|
|
316
394
|
```
|
|
317
|
-
pie-chart revenue title="Revenue Split"
|
|
395
|
+
pie-chart revenue title="Revenue Split" width=280 height=240
|
|
318
396
|
data
|
|
319
397
|
[
|
|
320
|
-
["Product",
|
|
321
|
-
["Services",
|
|
322
|
-
["Support",
|
|
398
|
+
["Product A", 42],
|
|
399
|
+
["Services", 30],
|
|
400
|
+
["Support", 25]
|
|
323
401
|
]
|
|
324
402
|
```
|
|
325
403
|
|
|
326
|
-
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### Markdown Blocks
|
|
407
|
+
|
|
408
|
+
Prose content with Markdown-style formatting, rendered inside the diagram layout.
|
|
409
|
+
|
|
327
410
|
```
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
411
|
+
markdown id [width=N] [padding=N] [font=X]
|
|
412
|
+
[text-align=left|center|right] [color=X]
|
|
413
|
+
"""
|
|
414
|
+
# Heading 1
|
|
415
|
+
## Heading 2
|
|
416
|
+
### Heading 3
|
|
417
|
+
|
|
418
|
+
Paragraph with **bold** and *italic* text.
|
|
419
|
+
|
|
420
|
+
Another paragraph.
|
|
421
|
+
"""
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Supported syntax:**
|
|
425
|
+
|
|
426
|
+
| Syntax | Result |
|
|
427
|
+
|---|---|
|
|
428
|
+
| `# text` | H1 heading |
|
|
429
|
+
| `## text` | H2 heading |
|
|
430
|
+
| `### text` | H3 heading |
|
|
431
|
+
| `**text**` | Bold |
|
|
432
|
+
| `*text*` | Italic |
|
|
433
|
+
| blank line | Vertical spacing |
|
|
434
|
+
|
|
435
|
+
**Example:**
|
|
436
|
+
```
|
|
437
|
+
bare page layout=row gap=60
|
|
438
|
+
{
|
|
439
|
+
markdown intro width=320 font=caveat padding=0
|
|
440
|
+
"""
|
|
441
|
+
# Sketchmark
|
|
442
|
+
|
|
443
|
+
A text-based diagram DSL that renders
|
|
444
|
+
**hand-drawn** SVG diagrams.
|
|
445
|
+
|
|
446
|
+
## Animation
|
|
447
|
+
|
|
448
|
+
Every element supports *step-by-step*
|
|
449
|
+
animation — **draw**, highlight, fade, move.
|
|
450
|
+
"""
|
|
451
|
+
|
|
452
|
+
group diagram layout=column gap=20 padding=30 theme=muted
|
|
453
|
+
{
|
|
454
|
+
box parser label="Parser" theme=primary width=130 height=52
|
|
455
|
+
box scene label="Scene" theme=success width=130 height=52
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
parser --> scene label="AST"
|
|
460
|
+
|
|
461
|
+
step draw intro
|
|
462
|
+
step highlight parser
|
|
463
|
+
step draw parser-->scene
|
|
464
|
+
step highlight scene
|
|
465
|
+
end
|
|
335
466
|
```
|
|
336
467
|
|
|
337
468
|
---
|
|
338
469
|
|
|
339
470
|
### Themes
|
|
340
471
|
|
|
341
|
-
Define reusable style presets
|
|
472
|
+
Define reusable style presets and apply them to any element.
|
|
342
473
|
|
|
343
474
|
```
|
|
344
475
|
theme primary fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
@@ -348,7 +479,33 @@ theme danger fill="#ffe8e8" stroke="#cc0000" color="#900000"
|
|
|
348
479
|
theme muted fill="#f5f5f5" stroke="#999999" color="#444444"
|
|
349
480
|
```
|
|
350
481
|
|
|
351
|
-
Apply: `box
|
|
482
|
+
Apply to any element: `box a theme=primary`, `group g theme=muted`, `note n theme=warning`, `a --> b theme=danger`
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
### Typography
|
|
487
|
+
|
|
488
|
+
Typography properties work on all text-bearing elements.
|
|
489
|
+
|
|
490
|
+
| Property | Applies to | Description |
|
|
491
|
+
|---|---|---|
|
|
492
|
+
| `font` | all | Font family or built-in name |
|
|
493
|
+
| `font-size` | all | Font size in px |
|
|
494
|
+
| `font-weight` | all | `400`, `500`, `600`, `700` |
|
|
495
|
+
| `letter-spacing` | all | Letter spacing in px |
|
|
496
|
+
| `text-align` | nodes, notes, table cells, markdown | `left`, `center`, `right` |
|
|
497
|
+
| `vertical-align` | nodes, notes | `top`, `middle`, `bottom` |
|
|
498
|
+
| `line-height` | nodes, notes, markdown | Multiplier e.g. `1.4` |
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
# diagram-wide font
|
|
502
|
+
config font=caveat
|
|
503
|
+
|
|
504
|
+
# per-element overrides
|
|
505
|
+
box title label="Heading" font=playfair font-size=20 text-align=left
|
|
506
|
+
box body label="Body text" font=system vertical-align=top
|
|
507
|
+
note n label="Annotation" font=caveat font-size=13 line-height=1.6
|
|
508
|
+
```
|
|
352
509
|
|
|
353
510
|
---
|
|
354
511
|
|
|
@@ -358,38 +515,65 @@ Apply: `box myNode label="..." theme=primary`
|
|
|
358
515
|
step action target [options]
|
|
359
516
|
```
|
|
360
517
|
|
|
518
|
+
All actions work on **all element types** — nodes, groups, tables, notes, charts, and edges.
|
|
519
|
+
|
|
361
520
|
**Actions:**
|
|
362
521
|
|
|
363
522
|
| Action | Syntax | Description |
|
|
364
523
|
|---|---|---|
|
|
365
|
-
| `highlight` | `step highlight
|
|
366
|
-
| `fade` | `step fade
|
|
367
|
-
| `unfade` | `step unfade
|
|
368
|
-
| `draw` | `step draw
|
|
369
|
-
| `draw` | `step draw a-->b` | Animate edge
|
|
370
|
-
| `erase` | `step erase
|
|
371
|
-
| `show` | `step show
|
|
372
|
-
| `hide` | `step hide
|
|
373
|
-
| `pulse` | `step pulse
|
|
374
|
-
| `color` | `step color
|
|
375
|
-
| `move` | `step move
|
|
376
|
-
| `scale` | `step scale
|
|
377
|
-
| `rotate` | `step rotate
|
|
524
|
+
| `highlight` | `step highlight id` | Pulsing glow |
|
|
525
|
+
| `fade` | `step fade id` | Fade to 22% opacity |
|
|
526
|
+
| `unfade` | `step unfade id` | Restore full opacity |
|
|
527
|
+
| `draw` | `step draw id` | Stroke-draw reveal |
|
|
528
|
+
| `draw` | `step draw a-->b` | Animate edge in |
|
|
529
|
+
| `erase` | `step erase id` | Fade to invisible |
|
|
530
|
+
| `show` | `step show id` | Make hidden element visible |
|
|
531
|
+
| `hide` | `step hide id` | Hide element |
|
|
532
|
+
| `pulse` | `step pulse id` | Single brightness flash |
|
|
533
|
+
| `color` | `step color id fill="#ff0000"` | Change fill color |
|
|
534
|
+
| `move` | `step move id dx=50 dy=0` | Translate by dx/dy px |
|
|
535
|
+
| `scale` | `step scale id factor=1.5` | Scale (absolute) |
|
|
536
|
+
| `rotate` | `step rotate id deg=45` | Rotate (cumulative) |
|
|
378
537
|
|
|
379
538
|
**Options:**
|
|
380
539
|
|
|
381
|
-
| Option |
|
|
382
|
-
|
|
383
|
-
| `duration
|
|
384
|
-
| `dx
|
|
385
|
-
| `dy
|
|
386
|
-
| `factor
|
|
387
|
-
| `deg
|
|
540
|
+
| Option | Description |
|
|
541
|
+
|---|---|
|
|
542
|
+
| `duration=600` | Animation duration in ms |
|
|
543
|
+
| `dx=100` | X offset for `move` |
|
|
544
|
+
| `dy=-80` | Y offset for `move` |
|
|
545
|
+
| `factor=1.5` | Scale multiplier |
|
|
546
|
+
| `deg=45` | Rotation degrees |
|
|
547
|
+
|
|
548
|
+
**Behaviour:**
|
|
549
|
+
- `move` — cumulative. `dx=50` twice = 100px total
|
|
550
|
+
- `scale` — absolute. `factor=1.0` always resets to normal
|
|
551
|
+
- `rotate` — cumulative. `deg=-45` rotates back
|
|
552
|
+
- `color` — use `fill=` syntax: `step color id fill="#ff0000"`
|
|
553
|
+
|
|
554
|
+
**Slide-in entrance:**
|
|
555
|
+
```
|
|
556
|
+
step move id dx=0 dy=80 # snap below final position
|
|
557
|
+
step draw id # reveal at offset
|
|
558
|
+
step move id dx=0 dy=-80 # animate up into place
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Wobble-and-fail:**
|
|
562
|
+
```
|
|
563
|
+
step rotate id deg=8
|
|
564
|
+
step rotate id deg=-8
|
|
565
|
+
step rotate id deg=8
|
|
566
|
+
step rotate id deg=25 # cumulative = 33°
|
|
567
|
+
step fade id
|
|
568
|
+
```
|
|
388
569
|
|
|
389
|
-
**
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
570
|
+
**Edge animations:**
|
|
571
|
+
```
|
|
572
|
+
step highlight a-->b
|
|
573
|
+
step color a-->b fill="#ff0000"
|
|
574
|
+
step fade a-->b
|
|
575
|
+
step move a-->b dx=0 dy=-20 duration=400
|
|
576
|
+
```
|
|
393
577
|
|
|
394
578
|
---
|
|
395
579
|
|
|
@@ -397,12 +581,10 @@ step action target [options]
|
|
|
397
581
|
|
|
398
582
|
### Root layout
|
|
399
583
|
|
|
400
|
-
Controls how top-level items (groups, standalone nodes) are arranged:
|
|
401
|
-
|
|
402
584
|
```
|
|
403
|
-
layout row
|
|
404
|
-
layout column
|
|
405
|
-
layout grid
|
|
585
|
+
layout row # items flow left to right (default)
|
|
586
|
+
layout column # items flow top to bottom
|
|
587
|
+
layout grid # grid — set columns with: config columns=N
|
|
406
588
|
```
|
|
407
589
|
|
|
408
590
|
### Group layout
|
|
@@ -417,73 +599,48 @@ group g layout=row justify=space-between width=500 gap=16 padding=20
|
|
|
417
599
|
|
|
418
600
|
| Value | Effect |
|
|
419
601
|
|---|---|
|
|
420
|
-
| `start` | Pack
|
|
421
|
-
| `center` | Center
|
|
422
|
-
| `end` | Pack
|
|
602
|
+
| `start` | Pack to start (default) |
|
|
603
|
+
| `center` | Center in container |
|
|
604
|
+
| `end` | Pack to end |
|
|
423
605
|
| `space-between` | First at start, last at end, equal gaps between |
|
|
424
606
|
| `space-around` | Equal space around each child |
|
|
425
607
|
|
|
426
|
-
> Requires `width` wider than total child width to be visible.
|
|
427
|
-
|
|
428
608
|
### `align` values
|
|
429
609
|
|
|
430
610
|
| Value | Effect |
|
|
431
611
|
|---|---|
|
|
432
|
-
| `start` |
|
|
433
|
-
| `center` |
|
|
434
|
-
| `end` |
|
|
612
|
+
| `start` | Cross-axis start (default) |
|
|
613
|
+
| `center` | Cross-axis center |
|
|
614
|
+
| `end` | Cross-axis end |
|
|
435
615
|
|
|
436
616
|
---
|
|
437
617
|
|
|
438
618
|
## Animation System
|
|
439
619
|
|
|
440
|
-
The `AnimationController` is returned as `instance.anim` from `render()`.
|
|
441
|
-
|
|
442
620
|
```typescript
|
|
443
|
-
const
|
|
444
|
-
const { anim } = instance;
|
|
621
|
+
const { anim } = render({ container, dsl });
|
|
445
622
|
|
|
446
623
|
anim.next(); // advance one step
|
|
447
624
|
anim.prev(); // go back one step
|
|
448
625
|
anim.reset(); // return to initial state
|
|
449
|
-
anim.goTo(3); // jump to
|
|
626
|
+
anim.goTo(3); // jump to step index
|
|
450
627
|
await anim.play(800); // auto-play, 800ms per step
|
|
451
628
|
|
|
452
|
-
anim.currentStep // current
|
|
453
|
-
anim.total // total
|
|
629
|
+
anim.currentStep // current index (-1 = not started)
|
|
630
|
+
anim.total // total step count
|
|
454
631
|
anim.canNext // boolean
|
|
455
632
|
anim.canPrev // boolean
|
|
456
633
|
|
|
457
|
-
// listen to events
|
|
458
634
|
anim.on((event) => {
|
|
459
635
|
// event.type: 'step-change' | 'animation-reset' |
|
|
460
636
|
// 'animation-start' | 'animation-end' | 'step-complete'
|
|
461
|
-
console.log(event.stepIndex, event.step);
|
|
462
637
|
});
|
|
463
638
|
```
|
|
464
639
|
|
|
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
640
|
---
|
|
482
641
|
|
|
483
642
|
## Theme Palettes
|
|
484
643
|
|
|
485
|
-
Set a global palette with `config theme=NAME`. Available palettes:
|
|
486
|
-
|
|
487
644
|
| Name | Description |
|
|
488
645
|
|---|---|
|
|
489
646
|
| `light` | Warm parchment (default) |
|
|
@@ -494,9 +651,65 @@ Set a global palette with `config theme=NAME`. Available palettes:
|
|
|
494
651
|
| `slate` | Cool grays |
|
|
495
652
|
| `rose` | Pinks and magentas |
|
|
496
653
|
| `midnight` | GitHub-dark style blues |
|
|
654
|
+
| `sketch` | Graphite pencil-on-paper |
|
|
497
655
|
|
|
498
656
|
```
|
|
499
|
-
config theme=
|
|
657
|
+
config theme=sketch
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
List all palette names at runtime:
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
import { THEME_NAMES } from 'sketchmark';
|
|
664
|
+
// ['light', 'dark', 'ocean', 'forest', 'sunset', 'slate', 'rose', 'midnight', 'sketch']
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## Font System
|
|
670
|
+
|
|
671
|
+
### Built-in fonts
|
|
672
|
+
|
|
673
|
+
| Name | Style |
|
|
674
|
+
|---|---|
|
|
675
|
+
| `caveat` | Hand-drawn, casual |
|
|
676
|
+
| `handlee` | Hand-drawn, friendly |
|
|
677
|
+
| `indie-flower` | Hand-drawn, playful |
|
|
678
|
+
| `patrick-hand` | Hand-drawn, clean |
|
|
679
|
+
| `dm-mono` | Monospace, refined |
|
|
680
|
+
| `jetbrains` | Monospace, code-like |
|
|
681
|
+
| `instrument` | Serif, editorial |
|
|
682
|
+
| `playfair` | Serif, elegant |
|
|
683
|
+
| `system` | System UI sans-serif |
|
|
684
|
+
| `mono` | Courier New |
|
|
685
|
+
| `serif` | Georgia |
|
|
686
|
+
|
|
687
|
+
Built-in fonts load automatically from Google Fonts on first use.
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
config font=caveat # diagram-wide
|
|
691
|
+
|
|
692
|
+
box a label="Hand-drawn" font=caveat
|
|
693
|
+
box b label="Code style" font=dm-mono font-size=11
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### Custom fonts
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
import { registerFont } from 'sketchmark';
|
|
700
|
+
|
|
701
|
+
// font already loaded in the page via or @import
|
|
702
|
+
registerFont('brand', '"Brand Sans", sans-serif');
|
|
703
|
+
|
|
704
|
+
// then use in DSL
|
|
705
|
+
// config font=brand
|
|
706
|
+
// box a font=brand
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Or pass a full CSS family directly in DSL (must be quoted):
|
|
710
|
+
|
|
711
|
+
```
|
|
712
|
+
box a label="Hello" font="'Pacifico', cursive"
|
|
500
713
|
```
|
|
501
714
|
|
|
502
715
|
---
|
|
@@ -505,57 +718,57 @@ config theme=ocean
|
|
|
505
718
|
|
|
506
719
|
### `render(options): DiagramInstance`
|
|
507
720
|
|
|
508
|
-
One-call API. Parses DSL, builds scene, lays out, renders, and returns a controller.
|
|
509
|
-
|
|
510
721
|
```typescript
|
|
511
722
|
import { render } from 'sketchmark';
|
|
512
723
|
|
|
513
724
|
const instance = render({
|
|
514
|
-
container: '#my-div',
|
|
515
|
-
dsl: '...',
|
|
516
|
-
renderer: 'svg',
|
|
517
|
-
injectCSS: true,
|
|
725
|
+
container: '#my-div',
|
|
726
|
+
dsl: '...',
|
|
727
|
+
renderer: 'svg', // 'svg' (default) | 'canvas'
|
|
728
|
+
injectCSS: true,
|
|
518
729
|
svgOptions: {
|
|
519
|
-
showTitle:
|
|
520
|
-
interactive:
|
|
521
|
-
roughness:
|
|
522
|
-
bowing:
|
|
523
|
-
theme:
|
|
524
|
-
|
|
730
|
+
showTitle: true,
|
|
731
|
+
interactive: true,
|
|
732
|
+
roughness: 1.3,
|
|
733
|
+
bowing: 0.7,
|
|
734
|
+
theme: 'light', // 'light' | 'dark' | 'auto'
|
|
735
|
+
transparent: false, // remove background rect
|
|
736
|
+
onNodeClick: (nodeId) => {},
|
|
525
737
|
},
|
|
526
738
|
canvasOptions: {
|
|
527
|
-
scale:
|
|
528
|
-
roughness:
|
|
739
|
+
scale: 2,
|
|
740
|
+
roughness: 1.3,
|
|
741
|
+
transparent: false,
|
|
529
742
|
},
|
|
530
743
|
onNodeClick: (nodeId) => {},
|
|
531
744
|
onReady: (anim, svg) => {},
|
|
532
745
|
});
|
|
533
746
|
```
|
|
534
747
|
|
|
748
|
+
`theme: 'auto'` follows OS `prefers-color-scheme`. `transparent: true` removes the background so the diagram floats over the page.
|
|
749
|
+
|
|
535
750
|
**`DiagramInstance`:**
|
|
536
751
|
|
|
537
752
|
```typescript
|
|
538
|
-
instance.scene // SceneGraph
|
|
753
|
+
instance.scene // SceneGraph
|
|
539
754
|
instance.anim // AnimationController
|
|
540
|
-
instance.svg // SVGSVGElement
|
|
541
|
-
instance.canvas // HTMLCanvasElement
|
|
755
|
+
instance.svg // SVGSVGElement
|
|
756
|
+
instance.canvas // HTMLCanvasElement
|
|
542
757
|
instance.update(dsl) // re-render with new DSL
|
|
543
|
-
instance.exportSVG() // download
|
|
544
|
-
instance.exportPNG() // download
|
|
758
|
+
instance.exportSVG() // download SVG
|
|
759
|
+
instance.exportPNG() // download PNG
|
|
545
760
|
```
|
|
546
761
|
|
|
547
762
|
---
|
|
548
763
|
|
|
549
|
-
### Pipeline API
|
|
550
|
-
|
|
551
|
-
Use these if you need to control each step manually:
|
|
764
|
+
### Pipeline API
|
|
552
765
|
|
|
553
766
|
```typescript
|
|
554
767
|
import { parse, buildSceneGraph, layout, renderToSVG } from 'sketchmark';
|
|
555
768
|
|
|
556
|
-
const ast = parse(dslString);
|
|
557
|
-
const scene = buildSceneGraph(ast);
|
|
558
|
-
layout(scene);
|
|
769
|
+
const ast = parse(dslString);
|
|
770
|
+
const scene = buildSceneGraph(ast);
|
|
771
|
+
layout(scene);
|
|
559
772
|
const svg = renderToSVG(scene, containerEl, options);
|
|
560
773
|
```
|
|
561
774
|
|
|
@@ -563,9 +776,6 @@ const svg = renderToSVG(scene, containerEl, options);
|
|
|
563
776
|
|
|
564
777
|
### `parse(dsl: string): DiagramAST`
|
|
565
778
|
|
|
566
|
-
Tokenizes and parses DSL source into an AST.
|
|
567
|
-
Throws `ParseError` with line/col information on invalid syntax.
|
|
568
|
-
|
|
569
779
|
```typescript
|
|
570
780
|
import { parse, ParseError } from 'sketchmark';
|
|
571
781
|
|
|
@@ -580,54 +790,30 @@ try {
|
|
|
580
790
|
|
|
581
791
|
---
|
|
582
792
|
|
|
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
793
|
## Export
|
|
608
794
|
|
|
609
795
|
```typescript
|
|
610
796
|
import { exportSVG, exportPNG, exportHTML, getSVGBlob } from 'sketchmark';
|
|
611
797
|
|
|
612
|
-
exportSVG(
|
|
613
|
-
await exportPNG(
|
|
614
|
-
exportHTML(
|
|
798
|
+
exportSVG(svgEl, { filename: 'diagram.svg' });
|
|
799
|
+
await exportPNG(svgEl, { filename: 'diagram.png', scale: 2 });
|
|
800
|
+
exportHTML(svgEl, dslSource, { filename: 'diagram.html' });
|
|
615
801
|
|
|
616
|
-
|
|
617
|
-
const blob = getSVGBlob(svgElement);
|
|
802
|
+
const blob = getSVGBlob(svgEl);
|
|
618
803
|
```
|
|
619
804
|
|
|
620
|
-
|
|
805
|
+
Via instance:
|
|
806
|
+
|
|
621
807
|
```typescript
|
|
622
|
-
instance.exportSVG('
|
|
623
|
-
await instance.exportPNG('
|
|
808
|
+
instance.exportSVG('diagram.svg');
|
|
809
|
+
await instance.exportPNG('diagram.png');
|
|
624
810
|
```
|
|
625
811
|
|
|
626
812
|
---
|
|
627
813
|
|
|
628
814
|
## Examples
|
|
629
815
|
|
|
630
|
-
### Basic architecture
|
|
816
|
+
### Basic architecture
|
|
631
817
|
|
|
632
818
|
```
|
|
633
819
|
diagram
|
|
@@ -644,8 +830,8 @@ box gateway label="API Gateway" theme=muted width=140 height=55
|
|
|
644
830
|
|
|
645
831
|
group services label="Services" layout=column gap=16 padding=30 theme=muted
|
|
646
832
|
{
|
|
647
|
-
box auth
|
|
648
|
-
box data
|
|
833
|
+
box auth label="Auth Service" theme=primary width=130 height=50
|
|
834
|
+
box data label="Data Service" theme=primary width=130 height=50
|
|
649
835
|
}
|
|
650
836
|
|
|
651
837
|
cylinder db label="PostgreSQL" theme=success width=140 height=65
|
|
@@ -655,7 +841,6 @@ gateway --> auth
|
|
|
655
841
|
gateway --> data
|
|
656
842
|
auth --> db label="SQL"
|
|
657
843
|
data --> db label="SQL"
|
|
658
|
-
|
|
659
844
|
end
|
|
660
845
|
```
|
|
661
846
|
|
|
@@ -693,21 +878,64 @@ lb --> g1 label="0%"
|
|
|
693
878
|
step highlight lb
|
|
694
879
|
step draw lb-->b1
|
|
695
880
|
step highlight b1
|
|
696
|
-
|
|
697
|
-
# green slides in from below
|
|
698
881
|
step move g1 dx=0 dy=60
|
|
699
882
|
step move g2 dx=0 dy=60
|
|
700
883
|
step draw g1
|
|
701
884
|
step move g1 dx=0 dy=-60 duration=500
|
|
702
885
|
step draw g2
|
|
703
886
|
step move g2 dx=0 dy=-60 duration=500
|
|
704
|
-
|
|
705
|
-
# traffic shifts
|
|
706
887
|
step fade b1
|
|
707
888
|
step fade b2
|
|
708
889
|
step draw lb-->g1
|
|
709
890
|
step highlight g1
|
|
891
|
+
end
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
---
|
|
895
|
+
|
|
896
|
+
### Markdown with diagram
|
|
897
|
+
|
|
898
|
+
```
|
|
899
|
+
diagram
|
|
900
|
+
layout row
|
|
901
|
+
config gap=60
|
|
710
902
|
|
|
903
|
+
theme primary fill="#e8f4ff" stroke="#0044cc" color="#003399"
|
|
904
|
+
theme success fill="#e8ffe8" stroke="#007700" color="#004400"
|
|
905
|
+
theme muted fill="#f5f5f5" stroke="#999999" color="#444444"
|
|
906
|
+
|
|
907
|
+
bare page layout=row gap=60
|
|
908
|
+
{
|
|
909
|
+
markdown intro width=320 font=caveat padding=0
|
|
910
|
+
"""
|
|
911
|
+
# Sketchmark
|
|
912
|
+
|
|
913
|
+
A text-based diagram DSL that renders
|
|
914
|
+
**hand-drawn** SVG diagrams using rough.js.
|
|
915
|
+
|
|
916
|
+
## Animation
|
|
917
|
+
|
|
918
|
+
Every element supports **step-by-step**
|
|
919
|
+
animation — draw, highlight, fade, move.
|
|
920
|
+
"""
|
|
921
|
+
|
|
922
|
+
group diagram layout=column gap=20 padding=30 theme=muted
|
|
923
|
+
{
|
|
924
|
+
box parser label="Parser" theme=primary width=130 height=52
|
|
925
|
+
box scene label="Scene" theme=success width=130 height=52
|
|
926
|
+
box render label="Renderer" theme=muted width=130 height=52
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
parser --> scene label="AST"
|
|
931
|
+
scene --> render label="SceneGraph"
|
|
932
|
+
|
|
933
|
+
step draw intro
|
|
934
|
+
step highlight parser
|
|
935
|
+
step draw parser-->scene
|
|
936
|
+
step highlight scene
|
|
937
|
+
step draw scene-->render
|
|
938
|
+
step highlight render
|
|
711
939
|
end
|
|
712
940
|
```
|
|
713
941
|
|
|
@@ -737,7 +965,40 @@ data
|
|
|
737
965
|
["Product B", 31],
|
|
738
966
|
["Product C", 27]
|
|
739
967
|
]
|
|
968
|
+
end
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
---
|
|
972
|
+
|
|
973
|
+
### Sketch theme
|
|
974
|
+
|
|
975
|
+
```
|
|
976
|
+
diagram
|
|
977
|
+
title label="System Architecture"
|
|
978
|
+
config theme=sketch
|
|
979
|
+
config font=caveat
|
|
980
|
+
layout row
|
|
981
|
+
config gap=60
|
|
982
|
+
|
|
983
|
+
group root layout=row gap=60 padding=0
|
|
984
|
+
{
|
|
985
|
+
box client label="Client App" width=140 height=55
|
|
986
|
+
box gateway label="API Gateway" width=140 height=55
|
|
987
|
+
|
|
988
|
+
group services layout=column gap=16 padding=30
|
|
989
|
+
{
|
|
990
|
+
box auth label="Auth Service" width=140 height=55
|
|
991
|
+
box billing label="Billing Service" width=140 height=55
|
|
992
|
+
}
|
|
740
993
|
|
|
994
|
+
cylinder db label="PostgreSQL" width=140 height=65
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
client --> gateway label="HTTPS"
|
|
998
|
+
gateway --> auth
|
|
999
|
+
gateway --> billing
|
|
1000
|
+
auth --> db label="SQL"
|
|
1001
|
+
billing --> db label="SQL"
|
|
741
1002
|
end
|
|
742
1003
|
```
|
|
743
1004
|
|