reladraw 0.27.0 → 0.29.0
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/.claude/skills/reladraw/SKILL.md +7 -5
- package/.claude/skills/reladraw/reference/syntax.md +56 -6
- package/README.md +2 -2
- package/SYNTAX.md +56 -6
- package/dist/cli.js +15 -1
- package/dist/examples.d.ts +26 -0
- package/dist/examples.js +56 -0
- package/dist/page-data.d.ts +130 -0
- package/dist/page-data.js +226 -0
- package/dist/page.d.ts +46 -2
- package/dist/page.js +1595 -265
- package/dist/search.d.ts +104 -0
- package/dist/search.js +490 -0
- package/dist/serve.d.ts +18 -0
- package/dist/serve.js +544 -0
- package/dist/viewer.js +3 -1
- package/examples/arch.reladraw +95 -0
- package/examples/around.reladraw +101 -0
- package/examples/borders.reladraw +28 -0
- package/examples/bundles.reladraw +49 -0
- package/examples/circles.reladraw +37 -0
- package/examples/coincident.reladraw +66 -0
- package/examples/contents.reladraw +52 -0
- package/examples/corridors.reladraw +48 -0
- package/examples/deck.reladraw +26 -0
- package/examples/flowchart.reladraw +23 -0
- package/examples/frames.reladraw +79 -0
- package/examples/gap.reladraw +21 -0
- package/examples/gaps.reladraw +25 -0
- package/examples/icons.reladraw +35 -0
- package/examples/lanes.reladraw +54 -0
- package/examples/lines.reladraw +73 -0
- package/examples/linetexts.reladraw +48 -0
- package/examples/marks.reladraw +39 -0
- package/examples/names.reladraw +23 -0
- package/examples/outlines.reladraw +56 -0
- package/examples/overhang.reladraw +24 -0
- package/examples/overlays.reladraw +75 -0
- package/examples/parts.reladraw +31 -0
- package/examples/passes.reladraw +56 -0
- package/examples/points.reladraw +28 -0
- package/examples/regions.reladraw +14 -0
- package/examples/routing.reladraw +88 -0
- package/examples/shapes.reladraw +38 -0
- package/examples/snug.reladraw +8 -0
- package/examples/text.reladraw +69 -0
- package/examples/themes.reladraw +16 -0
- package/examples/urls.reladraw +35 -0
- package/examples/venn.reladraw +15 -0
- package/package.json +2 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Several lines between the same two sides are copies of one line, and fan out
|
|
2
|
+
// side by side instead of lying on top of each other. Copies never cross.
|
|
3
|
+
|
|
4
|
+
style plain fill: theme-fill border: theme-border
|
|
5
|
+
|
|
6
|
+
// A reciprocal pair around a corner. Each copy is shifted to the left of the
|
|
7
|
+
// way it travels, so the order reverses between the two ends: further left
|
|
8
|
+
// along Gateway's bottom is further down Queue's left.
|
|
9
|
+
node gateway "Gateway" style: plain
|
|
10
|
+
node queue "Queue" 5 below gateway 22 right of gateway style: plain
|
|
11
|
+
edge gateway -> queue "publishes" (at: 2/3) from: bottom to: left line: (path: square, corners: rounded)
|
|
12
|
+
edge queue -> gateway "receives" (at: 2/3) from: left to: bottom line: (path: square, corners: rounded)
|
|
13
|
+
|
|
14
|
+
// Two lines facing each other, where the order runs the same way at both ends.
|
|
15
|
+
node client "Client" below queue (gap: wide) left even with gateway style: plain
|
|
16
|
+
node server "Server" 10 right of client style: plain
|
|
17
|
+
edge client -> server "request" (below edge) from: right to: left
|
|
18
|
+
edge server -> client "response" (above edge) from: left to: right
|
|
19
|
+
|
|
20
|
+
// Five copies down a vertical run, spread evenly along the two sides. The
|
|
21
|
+
// texts read along their lines, since level they would be wider than a lane.
|
|
22
|
+
node fan "Fan of five, spread wide" below client (gap: wide) left even with gateway style: plain
|
|
23
|
+
node hub "Hub of the same five" below fan (gap: wide) style: plain
|
|
24
|
+
edge fan -> hub "one" (reads: along) from: bottom to: top
|
|
25
|
+
edge fan -> hub "two" (reads: along) from: bottom to: top
|
|
26
|
+
edge fan -> hub "three" (reads: along) from: bottom to: top
|
|
27
|
+
edge fan -> hub "four" (reads: along) from: bottom to: top
|
|
28
|
+
edge fan -> hub "five" (reads: along) from: bottom to: top
|
|
29
|
+
|
|
30
|
+
// Two lines pointing the same way. Nothing tells them apart, so the order they
|
|
31
|
+
// are written in decides. Swap these two lines and the texts swap lanes.
|
|
32
|
+
node left_wall "Producer" below hub (gap: wide) left even with gateway style: plain
|
|
33
|
+
node right_wall "Consumer" 9 right of left_wall style: plain
|
|
34
|
+
edge left_wall -> right_wall "bulk" (below edge) from: right to: left
|
|
35
|
+
edge left_wall -> right_wall "control" (above edge) from: right to: left
|
|
36
|
+
|
|
37
|
+
// Sharing one side only doesn't make copies. The far ends differ, and their
|
|
38
|
+
// order along the side decides which end is which.
|
|
39
|
+
node spoke "Spoke" below left_wall (gap: 16) left even with gateway style: plain
|
|
40
|
+
node up "Up" above spoke right of spoke (gap: wide) style: plain
|
|
41
|
+
node down "Down" below spoke right of spoke (gap: wide) style: plain
|
|
42
|
+
edge spoke -> up from: right to: left
|
|
43
|
+
edge spoke -> down from: right to: left
|
|
44
|
+
|
|
45
|
+
// Five copies need sides long enough to hold them. Nothing grows a box to
|
|
46
|
+
// make room, so these two are given the height; at their own height the ends
|
|
47
|
+
// would crowd together, drawn and reported.
|
|
48
|
+
node narrow "Narrow" below down (gap: wide) left even with gateway height: 10 style: plain
|
|
49
|
+
node also "Also" 9 right of narrow height: 10 style: plain
|
|
50
|
+
edge narrow -> also "first" from: right to: left
|
|
51
|
+
edge narrow -> also "second" from: right to: left
|
|
52
|
+
edge narrow -> also "third" from: right to: left
|
|
53
|
+
edge narrow -> also "fourth" from: right to: left
|
|
54
|
+
edge narrow -> also "fifth" from: right to: left
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Everything about how a line is drawn, in its bracket: line: (…). A line is
|
|
2
|
+
// straight unless the bracket says otherwise. A shape is the rule for joining
|
|
3
|
+
// what the file fixed — where the line leaves and which way it heads, where it
|
|
4
|
+
// arrives, and any sides it passes.
|
|
5
|
+
|
|
6
|
+
// Out of A's top and into B's left, three ways.
|
|
7
|
+
node a1 "A"
|
|
8
|
+
node b1 "B" right of a1 above a1 (gap: wide)
|
|
9
|
+
edge a1 -> b1 "curved" from: top to: left line: (path: curved)
|
|
10
|
+
|
|
11
|
+
node a2 "A" right of a1 (gap: 18)
|
|
12
|
+
node b2 "B" right of a2 above a2 (gap: wide)
|
|
13
|
+
edge a2 -> b2 "square" from: top to: left line: (path: square)
|
|
14
|
+
|
|
15
|
+
node a3 "A" right of a2 (gap: 18)
|
|
16
|
+
node b3 "B" right of a3 above a3 (gap: wide)
|
|
17
|
+
edge a3 -> b3 "straight" from: top to: left line: (path: straight)
|
|
18
|
+
|
|
19
|
+
// Rounded corners, and a square line naming no sides: across first, then down.
|
|
20
|
+
node c1 "C" below a1 (gap: 8)
|
|
21
|
+
node d1 "D" right of c1 below c1 (gap: wide)
|
|
22
|
+
edge c1 -> d1 "rounded" from: bottom to: left line: (path: square, corners: rounded)
|
|
23
|
+
|
|
24
|
+
node c2 "C" right of c1 (gap: 18)
|
|
25
|
+
node d2 "D" right of c2 below c2 (gap: wide)
|
|
26
|
+
edge c2 -> d2 "no sides" (at: 1/5, right of edge) line: (path: square)
|
|
27
|
+
|
|
28
|
+
// A stop: the line runs along Middle's bottom. Square turns where its shape
|
|
29
|
+
// says; straight joins the stop's two ends to its own with straight pieces.
|
|
30
|
+
// Both run a normal gap under Middle, twice the default, to leave the text room.
|
|
31
|
+
node p1 "P" below c1 (gap: 18)
|
|
32
|
+
node q1 "Q" right of p1 (gap: 18)
|
|
33
|
+
node m1 "Middle" right of p1 left of q1 even with p1
|
|
34
|
+
edge p1 -> q1 "square" from: right to: left via: m1 bottom (gap: normal) line: (path: square)
|
|
35
|
+
|
|
36
|
+
node p2 "P" below p1 (gap: 8)
|
|
37
|
+
node q2 "Q" right of p2 (gap: 18)
|
|
38
|
+
node m2 "Middle" right of p2 left of q2 even with p2
|
|
39
|
+
edge p2 -> q2 "straight" from: right to: left via: m2 bottom (gap: normal) line: (path: straight, corners: rounded)
|
|
40
|
+
|
|
41
|
+
// Patterns and thicknesses.
|
|
42
|
+
node f1 "F" below p2 (gap: 8)
|
|
43
|
+
node g1 "G" right of f1 (gap: 18)
|
|
44
|
+
edge f1 -> g1 "dashed" line: (pattern: dashed)
|
|
45
|
+
node f2 "F" below f1 (gap: normal)
|
|
46
|
+
node g2 "G" right of f2 (gap: 18)
|
|
47
|
+
edge f2 -> g2 "dotted" line: (pattern: dotted)
|
|
48
|
+
node f3 "F" below f2 (gap: normal)
|
|
49
|
+
node g3 "G" right of f3 (gap: 18)
|
|
50
|
+
edge f3 -> g3 "dash-dot" line: (pattern: dash-dot)
|
|
51
|
+
node h1 "H" right of g1 (gap: 12)
|
|
52
|
+
node k1 "K" right of h1 (gap: 18)
|
|
53
|
+
edge h1 -> k1 "thin" line: (thickness: thin)
|
|
54
|
+
node h2 "H" below h1 (gap: normal)
|
|
55
|
+
node k2 "K" right of h2 (gap: 18)
|
|
56
|
+
edge h2 -> k2 "thick" line: (thickness: thick, color: #d2904e)
|
|
57
|
+
node h3 "H" below h2 (gap: normal)
|
|
58
|
+
node k3 "K" right of h3 (gap: 18)
|
|
59
|
+
edge h3 -> k3 "4px, dashed" line: (thickness: 4px, pattern: dashed)
|
|
60
|
+
|
|
61
|
+
// Crossings: the later line jumps the earlier one.
|
|
62
|
+
node w "W" below f3 (gap: 12)
|
|
63
|
+
node e "E" right of w (gap: 35)
|
|
64
|
+
node n1 "N1" below g3 (gap: 8)
|
|
65
|
+
node n2 "N2" right of n1 (gap: 2.5)
|
|
66
|
+
node n3 "N3" right of n2 (gap: 2.5)
|
|
67
|
+
node s1 "S1" below n1 (gap: 13)
|
|
68
|
+
node s2 "S2" right of s1 (gap: 2.5)
|
|
69
|
+
node s3 "S3" right of s2 (gap: 2.5)
|
|
70
|
+
edge w -> e
|
|
71
|
+
edge n1 -> s1 "arc" line: (crossing: arc)
|
|
72
|
+
edge n2 -> s2 "square" line: (crossing: square)
|
|
73
|
+
edge n3 -> s3 "gap" line: (crossing: gap)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Texts on lines. With nothing said a text sits at the middle of its line,
|
|
2
|
+
// on it, and several spread evenly. Its bracket says where else: a fraction
|
|
3
|
+
// along the line, along one named leg or along its longest level piece, a gap from either end, where a way
|
|
4
|
+
// straight out from a box meets the line, a gap off a box, or beside the
|
|
5
|
+
// line on a stated side. The line is drawn first and never moves for a text.
|
|
6
|
+
|
|
7
|
+
style plain fill: theme-fill border: theme-border
|
|
8
|
+
|
|
9
|
+
// Near each end, clear of the arrowhead, above the line; one in the middle.
|
|
10
|
+
node customer "Customer" style: plain
|
|
11
|
+
node order "Order" right of customer (gap: 20) style: plain
|
|
12
|
+
edge customer -> order "1" (at: start, above edge) "places" "0..*" (at: end, above edge)
|
|
13
|
+
|
|
14
|
+
// On a named leg, level with a box: the text goes where a way straight right
|
|
15
|
+
// from Confirm meets the climb into Broker, then right of it.
|
|
16
|
+
node accept "Accept order" below customer (gap: wide) style: plain
|
|
17
|
+
node broker "Broker" right of accept (gap: 12) style: plain
|
|
18
|
+
node confirm "Confirm" below accept (gap: tight) left of accept (gap: wide) style: plain
|
|
19
|
+
edge accept -> broker "publish message" (on: climb, straight right from confirm, right of edge)
|
|
20
|
+
from: bottom to: bottom line: (corners: rounded)
|
|
21
|
+
via: 7 below accept bottom, 7 below broker bottom, leg climb
|
|
22
|
+
|
|
23
|
+
// Resting on a box: the text's bottom a gap above Service, left of the
|
|
24
|
+
// line coming down into it.
|
|
25
|
+
node service "Service" below confirm (gap: 16) style: plain
|
|
26
|
+
node queue "Queue" right of service (gap: 10) 6 above service style: plain
|
|
27
|
+
edge queue -> service "ack" (above service, on the line, left of edge) from: left to: top line: (path: square)
|
|
28
|
+
|
|
29
|
+
// Which way a text reads: turned up beside a tall line, and along a slope.
|
|
30
|
+
node top "Top" right of queue (gap: wide) style: plain
|
|
31
|
+
node bottom "Bottom" below top (gap: 10) style: plain
|
|
32
|
+
edge top -> bottom "ten units" (left of edge, reads: up)
|
|
33
|
+
node low "Low" right of top (gap: wide) 8 below top style: plain
|
|
34
|
+
node high "High" right of low (gap: 12) above low (gap: 4) style: plain
|
|
35
|
+
edge low -> high "climbing" (reads: along)
|
|
36
|
+
|
|
37
|
+
// On the longest level piece: the middle of this line would land by the
|
|
38
|
+
// corner, where the text would stand off in open space.
|
|
39
|
+
node ask "Ask" below service (gap: 12) style: plain
|
|
40
|
+
node answer "Answer" below ask (gap: tight) right of ask (gap: 10) style: plain
|
|
41
|
+
edge answer -> ask "retry" (on: longest level) from: left to: left line: (path: square, corners: rounded)
|
|
42
|
+
|
|
43
|
+
// How far off its line: "1 above edge" rises one unit from its spot on the
|
|
44
|
+
// line and may still cross it, "1/2 clear above edge" goes half the way
|
|
45
|
+
// that would clear it. The text hides the line where they cross.
|
|
46
|
+
node near "Near" right of answer (gap: wide) above answer (gap: 2) style: plain
|
|
47
|
+
node far "Far" 10 below and 16 right of near style: plain
|
|
48
|
+
edge near -> far "one up" (at: 1/4, 1 above edge) "half clear" (at: 3/4, 1/2 clear above edge)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// What can be drawn at each end of a line. The arrow is a mark, a line, a mark:
|
|
2
|
+
// a word or a glyph at either end of one or two dashes, either end left off.
|
|
3
|
+
|
|
4
|
+
style label text: (color: theme-muted)
|
|
5
|
+
|
|
6
|
+
node plain "plain"
|
|
7
|
+
node plain2 "a -- b" right of plain (gap: wide) style: label
|
|
8
|
+
edge plain -- plain2
|
|
9
|
+
|
|
10
|
+
node arrows "arrows" below plain
|
|
11
|
+
node arrows2 "a <-> b" right of arrows (gap: wide) style: label
|
|
12
|
+
edge arrows <-> arrows2
|
|
13
|
+
|
|
14
|
+
node uml "inherits" below arrows
|
|
15
|
+
node uml2 "a --|> b" right of uml (gap: wide) style: label
|
|
16
|
+
edge uml --|> uml2
|
|
17
|
+
|
|
18
|
+
node whole "composed" below uml
|
|
19
|
+
node whole2 "a diamond--> b" right of whole (gap: wide) style: label
|
|
20
|
+
edge whole diamond--> whole2
|
|
21
|
+
|
|
22
|
+
node part "aggregates" below whole
|
|
23
|
+
node part2 "a odiamond-- b" right of part (gap: wide) style: label
|
|
24
|
+
edge part odiamond-- part2
|
|
25
|
+
|
|
26
|
+
node dots "dots" below part
|
|
27
|
+
node dots2 "a *--o b" right of dots (gap: wide) style: label
|
|
28
|
+
edge dots *--o dots2
|
|
29
|
+
|
|
30
|
+
node bars "bars" below dots
|
|
31
|
+
node bars2 "a |--| b" right of bars (gap: wide) style: label
|
|
32
|
+
edge bars |--| bars2
|
|
33
|
+
|
|
34
|
+
// A style can carry marks too. It fills only the ends the arrow leaves blank,
|
|
35
|
+
// so here the arrow's own head stays and the style adds a dot at the start.
|
|
36
|
+
style tracked from-mark: dot to-mark: oarrow
|
|
37
|
+
node styled "styled" below bars
|
|
38
|
+
node styled2 "a --> b, with a style" right of styled (gap: wide) style: label
|
|
39
|
+
edge styled --> styled2 style: tracked
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// A node with no text of its own takes its name as its text.
|
|
2
|
+
|
|
3
|
+
node parser
|
|
4
|
+
node resolver 12 right of parser
|
|
5
|
+
node renderer 12 right of resolver
|
|
6
|
+
edge parser -> resolver "statements"
|
|
7
|
+
edge resolver -> renderer "geometry"
|
|
8
|
+
|
|
9
|
+
// A dotted name shows only its last segment. The containment is already drawn.
|
|
10
|
+
|
|
11
|
+
node server "My Server Machine" (inside top, align: left) below parser (gap: wide)
|
|
12
|
+
node server.docker
|
|
13
|
+
node server.backup right of server.docker (gap: tight)
|
|
14
|
+
|
|
15
|
+
// Empty quotes are the other half: a node that is deliberately blank.
|
|
16
|
+
|
|
17
|
+
node pool "" right of server (gap: wide) shape: none
|
|
18
|
+
node pool.one icon: cube
|
|
19
|
+
node pool.two right of pool.one (gap: tight) icon: cube
|
|
20
|
+
|
|
21
|
+
// A stated text still wins.
|
|
22
|
+
|
|
23
|
+
node store "Records" below pool.one and pool.two badge: database
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Every outline `shape:` names. A shape geometry has a word for is named by
|
|
2
|
+
// it, and takes settings in a bracket for what its box doesn't decide; a
|
|
3
|
+
// flowchart shape with no geometric word is `flow-` and what it means, drawn
|
|
4
|
+
// as the standard draws it. Each grows until its text fits at its middle.
|
|
5
|
+
|
|
6
|
+
node diamond "valid?" shape: diamond
|
|
7
|
+
node flat "valid?" right of diamond (gap: tight) shape: diamond width: 18 height: 5
|
|
8
|
+
node pill "start" right of flat (gap: tight) shape: pill
|
|
9
|
+
node para "read input" right of pill (gap: tight) shape: parallelogram
|
|
10
|
+
node left "read input" right of para (gap: tight) shape: parallelogram (slant: 3, lean: left)
|
|
11
|
+
|
|
12
|
+
node hexagon "set up" below diamond (gap: wide) shape: hexagon
|
|
13
|
+
node pointy "set up" right of hexagon (gap: tight) shape: hexagon (point: 3)
|
|
14
|
+
node trap "sign off" right of pointy (gap: tight) shape: trapezoid
|
|
15
|
+
node trapup "sign off" right of trap (gap: tight) shape: trapezoid (taper: 3, narrow: top)
|
|
16
|
+
// The text sits at a triangle's middle, a third of the way from its base.
|
|
17
|
+
node up "split" right of trapup (gap: tight) shape: triangle (aim: up)
|
|
18
|
+
node down "merge" right of up (gap: tight) shape: triangle
|
|
19
|
+
node aimed "next" right of down (gap: tight) shape: triangle (aim: right)
|
|
20
|
+
|
|
21
|
+
node db "orders" below hexagon (gap: wide) shape: cylinder
|
|
22
|
+
node queue "queue" right of db (gap: tight) shape: cylinder (cap: 1.5, lying)
|
|
23
|
+
node oval "cache" right of queue (gap: tight) shape: circle width: 16 height: 6
|
|
24
|
+
node doc "report" right of oval (gap: tight) shape: document (fold: 1.5)
|
|
25
|
+
|
|
26
|
+
node sub "handle" below db (gap: wide) shape: flow-subprocess
|
|
27
|
+
node wavy "report" right of sub (gap: tight) shape: flow-document
|
|
28
|
+
node page "p. 2" right of wavy (gap: tight) shape: flow-off-page
|
|
29
|
+
node delay "wait" right of page (gap: tight) shape: flow-delay
|
|
30
|
+
node manual "type code" right of delay (gap: tight) shape: flow-manual-input
|
|
31
|
+
node stored "store" right of manual (gap: tight) shape: flow-stored-data
|
|
32
|
+
|
|
33
|
+
node loop "each file" below sub (gap: wide) shape: flow-loop-start
|
|
34
|
+
node next "next" right of loop (gap: tight) shape: flow-loop-end
|
|
35
|
+
node card "card" right of next (gap: tight) shape: flow-card
|
|
36
|
+
node screen "screen" right of card (gap: tight) shape: flow-display
|
|
37
|
+
node tape "T" right of screen (gap: tight) shape: flow-tape
|
|
38
|
+
node paper "tape" right of tape (gap: tight) shape: flow-punched-tape
|
|
39
|
+
// Collate's middle is where its two halves meet, so its text sits on a patch.
|
|
40
|
+
node collate "collate" right of paper (gap: tight) shape: flow-collate
|
|
41
|
+
|
|
42
|
+
// Lines on a shape's sides and corners. A corner is where the line from the
|
|
43
|
+
// shape's middle to that corner of its box meets the outline.
|
|
44
|
+
node hub "route?" below loop (gap: wide) shape: diamond
|
|
45
|
+
node north "in" above hub (gap: normal) shape: none
|
|
46
|
+
node east "no" right of hub (gap: wide)
|
|
47
|
+
node south1 "a" below hub (gap: wide)
|
|
48
|
+
node south2 "b" right of south1 (gap: tight)
|
|
49
|
+
node south3 "c" right of south2 (gap: tight)
|
|
50
|
+
node note "see policy" right of north (gap: wide) shape: none
|
|
51
|
+
edge north -> hub
|
|
52
|
+
edge hub -> east from: right
|
|
53
|
+
edge hub -> south1 from: bottom
|
|
54
|
+
edge hub -> south2 from: bottom
|
|
55
|
+
edge hub -> south3 from: bottom
|
|
56
|
+
edge note -> hub to: top-right
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Lines that leave the area the nodes cover. The page grows to hold them, on
|
|
2
|
+
// every side a line goes past.
|
|
3
|
+
|
|
4
|
+
default edge line: (path: square, corners: rounded)
|
|
5
|
+
|
|
6
|
+
style plain fill: theme-fill border: theme-border
|
|
7
|
+
|
|
8
|
+
node a "A" style: plain
|
|
9
|
+
node b "B" right of a (gap: wide) width: 5 style: plain
|
|
10
|
+
node c "C" right of b style: plain
|
|
11
|
+
|
|
12
|
+
node d "D" below a and c style: plain
|
|
13
|
+
|
|
14
|
+
// A long arch over everything, with the text at the top of it.
|
|
15
|
+
edge a -> b "over the top" from: top to: top
|
|
16
|
+
|
|
17
|
+
// The same shape across a narrow gap.
|
|
18
|
+
edge b -> c from: top to: top
|
|
19
|
+
|
|
20
|
+
// Out the left and back into the left, so the loop hangs off the left edge.
|
|
21
|
+
edge d -> a "round the side" (at: 1/4) from: left to: left
|
|
22
|
+
|
|
23
|
+
// Out the right and round into the bottom, under the bottom row.
|
|
24
|
+
edge c -> d "under" (at: 2/3) from: right to: bottom
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// A placement's target may be a *part* of a node — its text, one of its four
|
|
2
|
+
// sides, or one of its nine points — written as a separate word after the
|
|
3
|
+
// node's name. Three direction words go with a part:
|
|
4
|
+
//
|
|
5
|
+
// inside wholly within, against that part
|
|
6
|
+
// outside wholly beyond it
|
|
7
|
+
// on centered on it, so a node on a corner straddles it
|
|
8
|
+
//
|
|
9
|
+
// `inside` and `outside` are shorthands whose expansion is derived rather than
|
|
10
|
+
// listed: inside is the direction from the named part toward the box's center,
|
|
11
|
+
// outside is away from it. `inside right` is `left of`, `inside top-right` is
|
|
12
|
+
// `below-left of`, and nobody writes a table.
|
|
13
|
+
|
|
14
|
+
style mark shape: none text: (color: theme-muted)
|
|
15
|
+
style spacer fill: none border: none
|
|
16
|
+
style link shape: none text: (color: #6fa8dc)
|
|
17
|
+
|
|
18
|
+
// All nine points at once. The board is held open by six invisible children
|
|
19
|
+
// with nothing in them, which is also the point being made: a box is sized by
|
|
20
|
+
// what it *holds*, and the nine marks stamped on it are not held by anything.
|
|
21
|
+
node board "" fill: theme-fill border: theme-border
|
|
22
|
+
node board.nw "" style: spacer
|
|
23
|
+
node board.n "" style: spacer right of board.nw (gap: 10)
|
|
24
|
+
node board.ne "" style: spacer right of board.n (gap: 10)
|
|
25
|
+
node board.sw "" style: spacer below board.nw (gap: wide)
|
|
26
|
+
node board.s "" style: spacer right of board.sw (gap: 10) below board.n (gap: wide)
|
|
27
|
+
node board.se "" style: spacer right of board.s (gap: 10) below board.ne (gap: wide)
|
|
28
|
+
|
|
29
|
+
node p1 "top-left" inside board top-left style: mark
|
|
30
|
+
node p2 "top-center" inside board top-center style: mark
|
|
31
|
+
node p3 "top-right" inside board top-right style: mark
|
|
32
|
+
node p4 "left-center" inside board left-center style: mark
|
|
33
|
+
node p5 "center" on board center style: mark
|
|
34
|
+
node p6 "right-center" inside board right-center style: mark
|
|
35
|
+
node p7 "bottom-left" inside board bottom-left style: mark
|
|
36
|
+
node p8 "bottom-center" inside board bottom-center style: mark
|
|
37
|
+
node p9 "bottom-right" inside board bottom-right style: mark
|
|
38
|
+
|
|
39
|
+
// The case the design record names: an ordinary box with its text in the middle
|
|
40
|
+
// and, centered at the bottom inside it, a small link.
|
|
41
|
+
node bob "Bob the builder" below board
|
|
42
|
+
node bob.card "" style: spacer
|
|
43
|
+
node bob_link "bob.example.com" inside bob bottom-center style: link url: "https://bob.example.com"
|
|
44
|
+
|
|
45
|
+
// The inset is a named gap on the placement, and `none` puts the node hard
|
|
46
|
+
// against the edge, the same as the gap on any other placement.
|
|
47
|
+
node plate "A wide plate to stamp on" right of bob (gap: wide)
|
|
48
|
+
node flush "flush" inside plate top-right (gap: none) style: mark
|
|
49
|
+
|
|
50
|
+
// `on` is the thing the old dedicated overlay word could not say: the node's
|
|
51
|
+
// center on the point, so it straddles the corner instead of tucking inside.
|
|
52
|
+
node dot "A box with a dot on its corner" below plate (gap: wide)
|
|
53
|
+
node straddle "*" on dot top-right style: mark
|
|
54
|
+
|
|
55
|
+
// A side is a segment rather than a point, so the axis it does not name is
|
|
56
|
+
// left free — this sits against the right edge and centers down it. The box
|
|
57
|
+
// is made wide enough that the mark clears the children.
|
|
58
|
+
node column "A tall box" right of dot (gap: wide) layout: column width: 25
|
|
59
|
+
node column.one "one"
|
|
60
|
+
node column.two "two"
|
|
61
|
+
node column.three "three"
|
|
62
|
+
node column_mark "inside right" inside column right style: mark
|
|
63
|
+
|
|
64
|
+
// `outside` is the same rule read the other way: wholly beyond the named
|
|
65
|
+
// part, which is how a caption sits clear of one edge and no other.
|
|
66
|
+
node under "outside bottom" outside column bottom style: mark
|
|
67
|
+
|
|
68
|
+
// A part target works on a picture as readily as on a box. The count is
|
|
69
|
+
// bigger than the small picture, so it sits on the corner rather than inside.
|
|
70
|
+
node unit icon: cube right of plate
|
|
71
|
+
node tag "x3" on unit bottom-right style: mark
|
|
72
|
+
|
|
73
|
+
// Saying `inside` or `on` says the overlap is meant, for that pair and nothing
|
|
74
|
+
// else: anything else `flush` lands on is still reported.
|
|
75
|
+
edge bob -> plate from: right to: left
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// A color names the part it colors: fill, border, text, line. A text says its
|
|
2
|
+
// own in the brackets after it; a style, having no text of its own, says it as
|
|
3
|
+
// `text: (color: …)`.
|
|
4
|
+
|
|
5
|
+
// All three parts of a node.
|
|
6
|
+
style dim text: (color: theme-muted)
|
|
7
|
+
|
|
8
|
+
node ledger "Ledger / [dim]append only[/dim]" fill: theme-primary-subtle border: theme-primary
|
|
9
|
+
|
|
10
|
+
// Text on its own.
|
|
11
|
+
node plain "Plain" (color: #ff9d4d) right of ledger (gap: wide)
|
|
12
|
+
|
|
13
|
+
// A node with no body is text and nothing else, so its text is its only color.
|
|
14
|
+
// `border:` here is an error rather than a no-op.
|
|
15
|
+
node remark "no body, so text is the only part" (color: #66ccff) below ledger shape: none
|
|
16
|
+
|
|
17
|
+
// A style shared between nodes and edges writes one key per kind. The node takes
|
|
18
|
+
// the border, the edge takes the line, and neither sees the other's word.
|
|
19
|
+
style traced border: #d2904e line: #d2904e
|
|
20
|
+
|
|
21
|
+
// A picture body is a picture and the text under it.
|
|
22
|
+
node store "store" (color: #ff9d4d) right of plain (gap: wide) icon: database
|
|
23
|
+
|
|
24
|
+
// An edge's text takes the line's color unless its own brackets say otherwise.
|
|
25
|
+
node worker "Worker" below remark (gap: wide) style: traced
|
|
26
|
+
node queue "Queue" 18 right of worker
|
|
27
|
+
edge worker -> queue "inherits the line" style: traced from: right to: left
|
|
28
|
+
|
|
29
|
+
node reader "Reader" below worker (gap: wide)
|
|
30
|
+
node cache "Cache" 18 right of reader
|
|
31
|
+
edge reader -> cache "says its own" (color: theme-text) line: #ff9d4d from: right to: left
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Saying where a line passes, with via:. A side is a run along it, just
|
|
2
|
+
// outside, from the end nearer the line; a point is one spot the line goes
|
|
3
|
+
// through. Between the stops it names, a curved line takes one sweep.
|
|
4
|
+
|
|
5
|
+
default edge line: (path: curved)
|
|
6
|
+
|
|
7
|
+
// A row, with the line sent underneath it: a run under each end box.
|
|
8
|
+
node parser "Parser"
|
|
9
|
+
node resolver "Resolver" right of parser
|
|
10
|
+
node renderer "Renderer" right of resolver
|
|
11
|
+
|
|
12
|
+
edge parser -> renderer "underneath" from: left to: right via: parser bottom, renderer bottom
|
|
13
|
+
|
|
14
|
+
// Two runs on opposite sides: down A's left, then down B's right, so the line
|
|
15
|
+
// crosses over in the gap between.
|
|
16
|
+
node a "A" below parser (gap: 14)
|
|
17
|
+
node b "B" below a (gap: wide)
|
|
18
|
+
|
|
19
|
+
edge a -> b "an S" from: top to: bottom via: a left, b right
|
|
20
|
+
|
|
21
|
+
// Out of the top and round the left.
|
|
22
|
+
node p "P" right of a (gap: 18)
|
|
23
|
+
node q "Q" below p (gap: normal)
|
|
24
|
+
|
|
25
|
+
edge p -> q "the left" from: top to: top via: p left (gap: normal)
|
|
26
|
+
|
|
27
|
+
// One point, over the middle of Peak's top: the line rises to it and falls.
|
|
28
|
+
// A curve swings in below the point on either side of it, so the point is
|
|
29
|
+
// a normal gap up, clear of Peak's corners, rather than the default tight.
|
|
30
|
+
node t1 "T1" below b (gap: 16)
|
|
31
|
+
node t2 "T2" right of t1 (gap: 13)
|
|
32
|
+
node peak "Peak" right of t1 left of t2 above t1 (gap: tight)
|
|
33
|
+
|
|
34
|
+
edge t1 -> t2 "over a point" from: right to: left via: peak top-center (gap: normal)
|
|
35
|
+
|
|
36
|
+
// Runs under both ends, so the line stays low past Peak2 between them.
|
|
37
|
+
node u1 "U1" right of t2 (gap: wide)
|
|
38
|
+
node u2 "U2" right of u1 (gap: 13)
|
|
39
|
+
node peak2 "Peak2" right of u1 left of u2 above u1 (gap: tight)
|
|
40
|
+
|
|
41
|
+
edge u1 -> u2 "under both" from: left to: right via: u1 bottom, u2 bottom
|
|
42
|
+
|
|
43
|
+
// An end naming no side leaves from the one facing the other box.
|
|
44
|
+
node x "X" below t1 (gap: 12)
|
|
45
|
+
node z "Z" right of x
|
|
46
|
+
node y "Y" right of z
|
|
47
|
+
|
|
48
|
+
edge x -> y "no sides named" via: z bottom
|
|
49
|
+
|
|
50
|
+
// The point between two boxes: the line threads the gap between LN and LM.
|
|
51
|
+
node la "LA" right of y (gap: wide)
|
|
52
|
+
node ln "LN" below la (gap: wide)
|
|
53
|
+
node lm "LM" right of ln (gap: wide)
|
|
54
|
+
node lb "LB" below lm (gap: wide)
|
|
55
|
+
|
|
56
|
+
edge la -> lb "between" from: bottom to: top via: between ln and lm
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Points and regions: a place said in words, worked out from named things, so
|
|
2
|
+
// moving them moves it. Render with --guides to see the construction.
|
|
3
|
+
|
|
4
|
+
node gw "Gateway" height: 12
|
|
5
|
+
|
|
6
|
+
// A fraction of the way along the side the direction faces.
|
|
7
|
+
node users "Users" right of gw 1/4 down (gap: wide)
|
|
8
|
+
node orders "Orders" right of gw 3/4 down (gap: wide)
|
|
9
|
+
|
|
10
|
+
// A named point, with a text of its own: above the dot unless it says which way.
|
|
11
|
+
point split "by path" (below) between gw and orders
|
|
12
|
+
|
|
13
|
+
// Part against part: centers exactly 5 apart, as on a timeline.
|
|
14
|
+
node v1 "v1" center 5 below gw bottom-center
|
|
15
|
+
node v2 "v2" center 5 right of v1 center
|
|
16
|
+
node v3 "v3" center 5 right of v2 center
|
|
17
|
+
|
|
18
|
+
// Where a line straight down from one thing meets one straight right from another.
|
|
19
|
+
node tag "latest" shape: none on down from orders and right from v3
|
|
20
|
+
|
|
21
|
+
// A region is drawn in front of the boxes it doesn't name and behind the ones it does.
|
|
22
|
+
// Its text takes a title's words, and inside, the region makes room for it.
|
|
23
|
+
region services "services" (inside top, align: left) users top-left to orders bottom-right padding: 1
|
|
24
|
+
|
|
25
|
+
// A guide does everything but draw: a rail the versions hang from, and a line
|
|
26
|
+
// shown only while working.
|
|
27
|
+
guide region rail v1 top-left to v3 top-right
|
|
28
|
+
guide edge gw -> users
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Naming several targets places a node against the region that bounds them all.
|
|
2
|
+
|
|
3
|
+
node one "first"
|
|
4
|
+
node two "second" below one
|
|
5
|
+
node three "third with a longer label" below two
|
|
6
|
+
|
|
7
|
+
// A direction clears the furthest of them. This one says nothing about its own
|
|
8
|
+
// vertical position, so it centers on the region, as a lone direction does.
|
|
9
|
+
node spans "even with all three, and clear of the widest" (wrap: 24) right of one and three (gap: wide) shape: none
|
|
10
|
+
|
|
11
|
+
// An alignment uses the region as a position. "top" is its top edge, not its middle.
|
|
12
|
+
node tops "top even with the second box" (wrap: 20) right of two (gap: tight) top even with two shape: none
|
|
13
|
+
|
|
14
|
+
node beside "centered on the top two" right of spans (gap: wide) even with one and two
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Every routing bug reported so far, one row each, the line's text saying
|
|
2
|
+
// where it was reported. Each of these was drawn through a box, on top of
|
|
3
|
+
// another line, or hard against a box's edge. Lines no longer find their own
|
|
4
|
+
// way round anything: each row states its course, and the line follows it.
|
|
5
|
+
|
|
6
|
+
default edge line: (path: square, corners: rounded)
|
|
7
|
+
|
|
8
|
+
// Hacker News, 2026-09-26: ends facing away across a row. The line ran
|
|
9
|
+
// straight through the middle node, its text sitting on it. It now runs along
|
|
10
|
+
// the tops of the two end boxes, so it passes over the row.
|
|
11
|
+
node parser "Parser"
|
|
12
|
+
node resolver "Resolver" right of parser
|
|
13
|
+
node renderer "Renderer" right of resolver
|
|
14
|
+
edge parser -> renderer "Hacker News" from: left to: right via: parser top, renderer top
|
|
15
|
+
|
|
16
|
+
// GitHub issue #2: stacked, sides at right angles. The line came straight up
|
|
17
|
+
// through the lower node. Leaving the bottom and arriving at the left, it now
|
|
18
|
+
// steps out and comes round.
|
|
19
|
+
node p "P" below parser (gap: wide)
|
|
20
|
+
node q "Q" below p (gap: 7)
|
|
21
|
+
edge p -> q "issue #2" (at: 5/8, left of edge) from: bottom to: left
|
|
22
|
+
|
|
23
|
+
// GitHub issue #2: both ends on the same side, one node behind the other. The
|
|
24
|
+
// line went straight through the node behind.
|
|
25
|
+
node r "R" right of p (gap: wide)
|
|
26
|
+
node s "S" right of r (gap: 19)
|
|
27
|
+
edge r -> s "issue #2, same side" (above edge) from: left to: left via: r top
|
|
28
|
+
|
|
29
|
+
node v "V" right of s (gap: wide)
|
|
30
|
+
node w "W" below v
|
|
31
|
+
edge v -> w from: bottom to: bottom via: w right
|
|
32
|
+
|
|
33
|
+
// A fan of three, 2026-09-27. The lines to the top and bottom nodes ran level
|
|
34
|
+
// with the middle one, straight through it, out past the column and back.
|
|
35
|
+
// All three now leave from one point and fan out, written as one statement so
|
|
36
|
+
// the stretch they share is said rather than happened on.
|
|
37
|
+
node a "A" below q (gap: wide)
|
|
38
|
+
node c "C" right of a (gap: wide)
|
|
39
|
+
node b "B" above c (gap: 1)
|
|
40
|
+
node d "D" below c (gap: 1)
|
|
41
|
+
edge a -> b, c, d "fan" (at: start, above edge) from: right-center to: left
|
|
42
|
+
|
|
43
|
+
// The Cache case, 2026-09-27. The curved line dipped through Cache, while the
|
|
44
|
+
// same line drawn square happened to clear it. It now runs under Cache.
|
|
45
|
+
node web "Web" right of c (gap: wide)
|
|
46
|
+
node api "API" right of web
|
|
47
|
+
node db "Postgres" right of api
|
|
48
|
+
node cache "Cache" below api
|
|
49
|
+
edge web -> db "cache case" from: bottom to: bottom via: cache bottom
|
|
50
|
+
|
|
51
|
+
// A line back round the side of a row, 2026-09-26: it crossed the node it
|
|
52
|
+
// was going round.
|
|
53
|
+
node e "E" below a (gap: 22)
|
|
54
|
+
node f "F" right of e (gap: 16)
|
|
55
|
+
node g "G" below e and f
|
|
56
|
+
edge g -> e "round the side" (at: 1/4) from: left to: left
|
|
57
|
+
|
|
58
|
+
// Two lines into one box, 2026-09-27. The longer one's curve swung across
|
|
59
|
+
// the other's twice. The longer one now comes in from above.
|
|
60
|
+
node x1 "X" right of z (gap: wide)
|
|
61
|
+
node a1 "A" below x1
|
|
62
|
+
node b1 "B" right of a1 (gap: normal) below a1 (gap: tight)
|
|
63
|
+
edge a1 -> b1 from: right to: left
|
|
64
|
+
edge x1 -> b1 from: right to: top
|
|
65
|
+
|
|
66
|
+
// No side named, with a box in the way. The line used to be straight from
|
|
67
|
+
// center to center, through whatever lay between.
|
|
68
|
+
node x "X" right of f (gap: wide)
|
|
69
|
+
node y "Y" right of x
|
|
70
|
+
node z "Z" right of y
|
|
71
|
+
edge x -> z "no sides named" (above edge) via: y top
|
|
72
|
+
|
|
73
|
+
// Three lines told the same thing, 2026-09-27. They were drawn on one path,
|
|
74
|
+
// so the three read as one line with three arrowheads. Copies of one line now
|
|
75
|
+
// fan out, nested so that none crosses another.
|
|
76
|
+
node ra "A" below g (gap: wide) width: 6
|
|
77
|
+
node rb "B" right of ra width: 6
|
|
78
|
+
edge ra -> rb from: bottom to: bottom
|
|
79
|
+
edge ra -> rb from: bottom to: bottom
|
|
80
|
+
edge ra -> rb from: bottom to: bottom
|
|
81
|
+
|
|
82
|
+
// Through a named gap, 2026-09-28. The line ran about 2px from Lower, then
|
|
83
|
+
// came into Lowest's right side down Lowest's own edge. It now passes the
|
|
84
|
+
// point between the two and comes into the side from outside.
|
|
85
|
+
node west "West" right of rb (gap: wide)
|
|
86
|
+
node lower "Lower" below west (gap: tight)
|
|
87
|
+
node lowest "Lowest" below lower (gap: normal)
|
|
88
|
+
edge west -> lowest "between" from: left to: right via: between lower and lowest
|