reladraw 0.26.1 → 0.28.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.
Files changed (50) hide show
  1. package/.claude/skills/reladraw/SKILL.md +7 -5
  2. package/.claude/skills/reladraw/reference/syntax.md +55 -7
  3. package/README.md +2 -2
  4. package/SYNTAX.md +55 -7
  5. package/dist/cli.js +15 -1
  6. package/dist/examples.d.ts +26 -0
  7. package/dist/examples.js +56 -0
  8. package/dist/page-data.d.ts +130 -0
  9. package/dist/page-data.js +226 -0
  10. package/dist/page.d.ts +46 -2
  11. package/dist/page.js +1992 -252
  12. package/dist/serve.d.ts +18 -0
  13. package/dist/serve.js +544 -0
  14. package/dist/viewer.js +1 -1
  15. package/examples/arch.reladraw +95 -0
  16. package/examples/around.reladraw +101 -0
  17. package/examples/borders.reladraw +28 -0
  18. package/examples/bundles.reladraw +49 -0
  19. package/examples/circles.reladraw +37 -0
  20. package/examples/coincident.reladraw +66 -0
  21. package/examples/contents.reladraw +52 -0
  22. package/examples/corridors.reladraw +48 -0
  23. package/examples/deck.reladraw +26 -0
  24. package/examples/flowchart.reladraw +23 -0
  25. package/examples/frames.reladraw +79 -0
  26. package/examples/gap.reladraw +21 -0
  27. package/examples/gaps.reladraw +25 -0
  28. package/examples/icons.reladraw +35 -0
  29. package/examples/lanes.reladraw +54 -0
  30. package/examples/lines.reladraw +73 -0
  31. package/examples/linetexts.reladraw +48 -0
  32. package/examples/marks.reladraw +39 -0
  33. package/examples/names.reladraw +23 -0
  34. package/examples/outlines.reladraw +56 -0
  35. package/examples/overhang.reladraw +24 -0
  36. package/examples/overlays.reladraw +75 -0
  37. package/examples/parts.reladraw +31 -0
  38. package/examples/passes.reladraw +56 -0
  39. package/examples/points.reladraw +28 -0
  40. package/examples/regions.reladraw +14 -0
  41. package/examples/routing.reladraw +88 -0
  42. package/examples/shapes.reladraw +38 -0
  43. package/examples/snug.reladraw +8 -0
  44. package/examples/text.reladraw +69 -0
  45. package/examples/themes.reladraw +16 -0
  46. package/examples/urls.reladraw +35 -0
  47. package/examples/venn.reladraw +15 -0
  48. package/package.json +2 -1
  49. package/dist/search.d.ts +0 -104
  50. package/dist/search.js +0 -490
@@ -0,0 +1,38 @@
1
+ // What a node is drawn as. `shape:` is the outline it is drawn with; `icon:` is
2
+ // a picture it is drawn as, with no box at all.
3
+
4
+ style artifact fill: theme-secondary-subtle border: theme-border shape: document
5
+
6
+ // The fold is a fixed size rather than a fraction of the box, so it looks the
7
+ // same on all three of these.
8
+ node narrow "Report" style: artifact
9
+ node medium "Nightly database dump" right of narrow (gap: tight) style: artifact
10
+ node wide "A very much longer file name than either of the other two" right of medium (gap: tight) style: artifact
11
+
12
+ // A picture has no outline, no fill and no padding. The text goes underneath.
13
+ node services "" below narrow shape: none
14
+ node services.web "web" icon: cube
15
+ node services.api "api" right of services.web (gap: tight) icon: cube
16
+ node services.worker "worker" right of services.api (gap: tight) icon: cube
17
+
18
+ // No text at all: a picture usually is the statement, so it gets no caption.
19
+ node bare1 below services icon: cube
20
+ node bare2 below bare1 (gap: tight) icon: cube
21
+
22
+ // A picture body is an ordinary node, so it takes edges and sides like any
23
+ // other. That is what it buys over a badge, which cannot be the end of an arrow.
24
+ node sink "collector" right of bare1 and bare2 (gap: wide)
25
+ edge bare1 -> sink from: right to: left
26
+ edge bare2 -> sink from: right to: left
27
+
28
+ // Any icon works as a body, not just the cube.
29
+ node store below bare2 icon: database
30
+ node drive right of store (gap: tight) icon: disk
31
+
32
+ // `(inside bottom)` puts the title under the contents, centered along that side.
33
+ // The lower cube is centered under the upper pair by naming both of them and
34
+ // nothing else.
35
+ node pool "Worker pool" (inside bottom) right of store and drive (gap: wide)
36
+ node pool.one icon: cube
37
+ node pool.two right of pool.one (gap: tight) icon: cube
38
+ node pool.three below pool.one and pool.two (gap: tight) icon: cube
@@ -0,0 +1,8 @@
1
+ // A node sits exactly where its placements say: a gap is the distance asked
2
+ // for, not a minimum.
3
+
4
+ node anchor "anchor"
5
+ node far "far" right of anchor
6
+ node near "near" right of far
7
+
8
+ node trailing "one tight gap from near" left of near (gap: tight) below anchor (gap: tight) overlap: allow shape: none
@@ -0,0 +1,69 @@
1
+ // An edge's text takes no room of its own: the gap it sits in is the one the
2
+ // placements say, so a text that needs room is given it by stating the gap.
3
+
4
+ style plain fill: theme-fill border: theme-border
5
+
6
+ // A `normal` gap is sized for two nodes to breathe, not to hold a word, so a
7
+ // word that needs more is given it by stating the gap, here in units.
8
+ node parser "Parser" style: plain
9
+ node resolver "Resolver" right of parser (gap: 10) style: plain
10
+ edge parser -> resolver "statements" from: right to: left
11
+
12
+ // Going downward the text is only a line deep, and it hangs out either side.
13
+ //
14
+ // Written with `<-`, which draws the same picture as `writer -> disk`. It just
15
+ // puts the node the line is about first. `from:` is still the first name
16
+ // written, so it names Disk's side.
17
+ node writer "Writer" right of resolver (gap: wide) style: plain
18
+ node disk "Disk" below writer (gap: wide) style: plain
19
+ edge disk <- writer "flushed to disk" from: top to: bottom
20
+
21
+ // Corner to corner, the text sits at the middle of the line, so the gap is
22
+ // stated on both axes.
23
+ node high "High" right of writer (gap: wide) style: plain
24
+ node low "Low" below high (gap: wide) right of high (gap: wide) style: plain
25
+ edge high -> low "diagonal"
26
+
27
+
28
+ // --- What the brackets after a text say ------------------------------------
29
+ // A container's title says which side it sits against, and `align` where along
30
+ // that side, which also ranges its lines against each other.
31
+
32
+ style dim text: (color: theme-muted)
33
+
34
+ node shelf "Shelf" (inside bottom, align: right) below disk (gap: wide) left even with parser style: plain
35
+ node shelf.one "first" style: plain
36
+ node shelf.two "second" below shelf.one (gap: tight) style: plain
37
+
38
+ // A box is usually the size of its own text. A picture beside the text is two
39
+ // lines tall, and lining the picture's top or bottom up with the text's puts
40
+ // the text at the top or bottom of the box. Joined to the text, the picture and
41
+ // the text are centered in the box together.
42
+ node tall "Top" right of shelf (gap: wide) style: plain
43
+ node tall.disk icon: disk 1 right of tall text top even with tall text join-with: tall text
44
+ node deep "Bottom" below tall (gap: tight) style: plain
45
+ node deep.disk icon: disk 1 right of deep text bottom even with deep text join-with: deep text
46
+
47
+ // Marked words take their style's size as well as its color. A line that is
48
+ // all small is spaced as a small line, and a small word mid-line sits on the
49
+ // same baseline as its neighbors.
50
+ style note text: (size: small, color: theme-muted)
51
+ node synced "Shared folder / [note]synced 2 min ago[/note] / 3 [note]files[/note] waiting" below deep (gap: tight) style: plain
52
+
53
+ // `size` and `wrap` are properties of the text too. The wrap is a count of
54
+ // characters, not a distance: it says how much fits on a line and nothing
55
+ // about where anything sits.
56
+ node aside "A quiet remark that folds itself, with [dim]one word[/dim] quieter than the rest." (size: small, wrap: 28) right of tall (gap: wide) shape: none
57
+
58
+ // A literal bracket is written \[, since [ opens markup.
59
+ node literal "sizes \[small, normal, large]" below aside (gap: tight) shape: none
60
+
61
+ // An edge's text takes the same brackets. A size may be a multiple of normal,
62
+ // such as 1.2, or pixels, such as 12px, as well as a name.
63
+ edge tall -> aside "carried" (color: theme-muted, size: 12px) from: right to: left
64
+
65
+ // `reads: up` or `down` turns a text a quarter turn, so a title on a left or
66
+ // right side takes a column one line wide rather than one word wide.
67
+ node rack "Rack" (inside left, reads: up) right of aside (gap: wide) top even with tall layout: column (gap: tight) style: plain
68
+ node rack.web "web" style: plain
69
+ node rack.db "db" style: plain
@@ -0,0 +1,16 @@
1
+ // A diagram that states no color of its own, so every color in it is the
2
+ // theme's. Render it in each theme to compare them.
3
+
4
+ style quiet text: (color: theme-muted, size: small)
5
+
6
+ node web "Web app" badge: laptop
7
+ node api "API server" 10 right of web
8
+ node cluster "Workers" (inside top, align: left) 6 below api
9
+ node cluster.a "worker a"
10
+ node cluster.b "worker b" right of cluster.a (gap: tight)
11
+ node db "Records" icon: database 10 right of api
12
+ node note "Backed up nightly / to cold storage" below db shape: none style: quiet
13
+
14
+ edge web -> api "HTTPS"
15
+ edge api -> cluster "jobs"
16
+ edge api -> db "queries"
@@ -0,0 +1,35 @@
1
+ // `url:` makes a node or an edge clickable. The whole thing is the target — the
2
+ // box and everything drawn in it, or an edge's text — and nothing about it
3
+ // looks any different, because a destination is content rather than appearance
4
+ // and nothing else in the language lets content reach the ink.
5
+ //
6
+ // The value is quoted. Without the quotes everything from the `//` onwards is a
7
+ // comment, which is why the error for the bare form talks about punctuation.
8
+
9
+ style plain fill: theme-fill border: theme-border
10
+
11
+ node docs "Documentation" style: plain url: "https://example.com/docs"
12
+
13
+ // A container's destination reaches its children: `intro` has none of its own
14
+ // and follows the container, while `deep` overrules it inside its own box.
15
+ node site "Handbook" (inside top, align: left) right of docs (gap: wide) layout: column (align-children: left) url: "https://example.com/"
16
+ node site.intro "Introduction" style: plain
17
+ node site.deep "Deep dive" style: plain url: "https://example.com/deep"
18
+
19
+ // A picture and a bodiless node take one too. There is no kind that cannot.
20
+ node store icon: database below docs (gap: wide) url: "https://example.com/store"
21
+ node aside "and this line is a link as well" shape: none right of store url: "https://example.com/aside"
22
+
23
+ // An edge's text is what carries the destination. An edge with no text may
24
+ // have one too: an unseen wider copy of the line takes the click.
25
+ edge docs -> store "read first" from: bottom to: top url: "https://example.com/order"
26
+
27
+ // A long address is declared once under a name, with its name and badge, and
28
+ // used by that name. A declaration may also list several links, a bundle, and
29
+ // a `url:` mixes names and quoted addresses in the order written.
30
+ url orders-docs "https://docs.example.com/orders/v2/reference/endpoints" (name: "Docs", icon: "D" (fill: #3a6ea5, text: white))
31
+ url orders-code "https://github.com/example/orders/tree/main/services/api" (name: "Code", icon: "C")
32
+ url orders-links orders-docs orders-code "https://wiki.example.com/teams/orders" (name: "Wiki")
33
+
34
+ node api "Orders API" style: plain below store (gap: wide) url: orders-links
35
+ node worker "Worker" style: plain right of api url: orders-docs "https://example.com/runbooks/worker" (name: "Runbook")
@@ -0,0 +1,15 @@
1
+ // A PDF template is made at design time and used at runtime, so it sits where the two overlap.
2
+
3
+ node phases "" layout: venn (gap: 12)
4
+ node phases.design "Design time" (inside top, align: left)
5
+ node phases.both ""
6
+ node phases.runtime "Runtime" (inside top, align: right)
7
+
8
+ node phases.design.editor "Editor"
9
+ node phases.both.template "PDF template"
10
+ node phases.runtime.python "Python Lib" even with phases.both.template
11
+ node phases.runtime.report "Report PDF" below phases.runtime.python (gap: wide)
12
+
13
+ edge phases.design.editor -> phases.both.template "generate"
14
+ edge phases.both.template -> phases.runtime.python "import"
15
+ edge phases.runtime.python -> phases.runtime.report "generate"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reladraw",
3
- "version": "0.26.1",
3
+ "version": "0.28.0",
4
4
  "description": "A diagram language where you say where things go.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,7 @@
11
11
  "files": [
12
12
  ".claude/skills",
13
13
  "dist",
14
+ "examples/*.reladraw",
14
15
  "NOTICE",
15
16
  "SYNTAX.md"
16
17
  ],
package/dist/search.d.ts DELETED
@@ -1,104 +0,0 @@
1
- /**
2
- * Finding a line's way through the open space between boxes.
3
- *
4
- * Every box is a wall. A line may turn only where two tracks cross, and the
5
- * tracks are few: a line a little way out from each side of each wall, one
6
- * down the middle of each gap between walls, and the lines through the two
7
- * ends. That is the whole of the open space a right-angled line ever needs,
8
- * reduced to a grid of a few hundred points for a diagram of ordinary size.
9
- *
10
- * The line leaves its start heading straight out and arrives at its end heading
11
- * straight in, with a straight stretch at each end at least `stub` long, so an
12
- * arrowhead always lands on a straight piece. Between those two stretches it
13
- * takes the cheapest way through the grid, where cost is length plus a charge
14
- * for every turn and for every line already placed that it crosses. On a
15
- * right-angled grid many ways tie on length — a staircase is exactly as long as
16
- * one bend — and the turn charge breaks those ties toward the fewest bends,
17
- * which is the line a person would draw. What still ties after that goes over
18
- * the top rather than under, and round the right rather than the left.
19
- *
20
- * A way through a box is not a losing option here. It is not a way at all.
21
- */
22
- export interface SearchPoint {
23
- x: number;
24
- y: number;
25
- }
26
- /** A box the line may not enter, as its extent. Touching its border is allowed. */
27
- export interface SearchWall {
28
- minX: number;
29
- minY: number;
30
- maxX: number;
31
- maxY: number;
32
- }
33
- /** One end of the line: a point on a box's side, and the unit direction out of it. */
34
- export interface SearchEnd {
35
- x: number;
36
- y: number;
37
- dx: number;
38
- dy: number;
39
- }
40
- export interface SearchOptions {
41
- /** How far the line runs straight out of each end before it may turn. */
42
- stub: number;
43
- /** How far outside a wall a track runs beside it, where there is room. */
44
- clear: number;
45
- /** What a turn costs, in the same units as length. */
46
- turn: number;
47
- /**
48
- * Walls the stretches at the two ends may pass through: the line's own boxes,
49
- * which it has to cross the margin of to leave, and any box holding an end.
50
- */
51
- ownStart: SearchWall[];
52
- ownEnd: SearchWall[];
53
- /**
54
- * Lines already placed. A line may cross one but not run along it within
55
- * `lane` of it; tracks are added a lane either side of each, so a later line
56
- * sharing a stretch takes the next lane out.
57
- */
58
- taken: SearchPoint[][];
59
- lane: number;
60
- /**
61
- * For each line in `taken`, for each of its stretches, half the depth across
62
- * it of a text riding there, and 0 where none does. A line running beside a
63
- * stretch carrying a text keeps clear of the text, not just of the line.
64
- */
65
- takenHalves?: number[][];
66
- /**
67
- * A gap the line must pass through: somewhere it crosses the line at `at`
68
- * on the `run` axis, travelling along `run`, at a level between `lo` and `hi`.
69
- */
70
- gate?: SearchGate;
71
- /**
72
- * Half the depth of this line's own text, which rides in the gate: inside it,
73
- * the line keeps that much further from the lines beside it.
74
- */
75
- ownHalf?: number;
76
- /**
77
- * How far the line may go at all: the diagram with room round it. A wall
78
- * reaching past this — a clause's fence, which runs to the edge of the page —
79
- * cannot be gone round at its far end.
80
- */
81
- bounds?: SearchWall;
82
- /**
83
- * A cost the line is no use at unless it comes in under: the cheapest way
84
- * already found between another pair of sides. The search gives up as soon
85
- * as it cannot.
86
- */
87
- limit?: number;
88
- }
89
- /** A gap a line must pass through. See `SearchOptions.gate`. */
90
- export interface SearchGate {
91
- run: 'x' | 'y';
92
- at: number;
93
- lo: number;
94
- hi: number;
95
- }
96
- export interface SearchResult {
97
- points: SearchPoint[];
98
- cost: number;
99
- }
100
- /**
101
- * The cheapest right-angled line from `start` to `end` that enters no wall, or
102
- * undefined when there is none.
103
- */
104
- export declare function searchRoute(start: SearchEnd, end: SearchEnd, walls: SearchWall[], options: SearchOptions): SearchResult | undefined;