reladraw 0.16.0 → 0.17.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/README.md +11 -7
- package/SYNTAX.md +816 -680
- package/dist/ast.d.ts +342 -18
- package/dist/ast.js +138 -27
- package/dist/checks.d.ts +58 -0
- package/dist/checks.js +891 -0
- package/dist/cli.js +96 -12
- package/dist/constants.d.ts +15 -55
- package/dist/constants.js +30 -78
- package/dist/grammar.d.ts +2 -2
- package/dist/grammar.js +70 -10
- package/dist/index.d.ts +20 -0
- package/dist/index.js +18 -1
- package/dist/lines.d.ts +96 -0
- package/dist/lines.js +1968 -0
- package/dist/linetexts.d.ts +44 -0
- package/dist/linetexts.js +412 -0
- package/dist/model.d.ts +187 -36
- package/dist/model.js +23 -1
- package/dist/parser.js +1777 -107
- package/dist/place.d.ts +501 -0
- package/dist/place.js +2226 -0
- package/dist/render.d.ts +3 -1
- package/dist/render.js +691 -2493
- package/dist/resolve.d.ts +1 -1
- package/dist/resolve.js +1195 -1789
- package/dist/size.d.ts +64 -0
- package/dist/size.js +222 -0
- package/dist/themes.d.ts +17 -0
- package/dist/themes.js +28 -3
- package/package.json +2 -2
- package/dist/constrain.d.ts +0 -56
- package/dist/constrain.js +0 -95
package/SYNTAX.md
CHANGED
|
@@ -1,1006 +1,1013 @@
|
|
|
1
|
-
# Syntax reference — 0.
|
|
1
|
+
# Syntax reference — 0.17.1
|
|
2
2
|
|
|
3
|
-
What the language accepts. The
|
|
3
|
+
What the language accepts. The changelog at the end lists what changed in each published version; 0.17.0's changes are large, and its entry has a table of every old spelling and what to write instead.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
One idea runs through all of it: **the file says where things go, and the tool draws what it says.** It never chooses an arrangement, never moves a box to make room for something, and never finds its own way round anything. Where the result may not read as meant (two boxes on one spot, a line through a box, a text on a text), it draws it as written and prints a *finding* saying where and by how much. The fix is always something you write.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The worked example is `examples/arch.reladraw`, transcribed from the hand-drawn reference beside it. Every file in `examples/` renders without findings.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## The file
|
|
10
|
+
|
|
11
|
+
### Statements and lines
|
|
12
|
+
|
|
13
|
+
A file is a list of statements. Each starts at the beginning of a line, and nothing nests. A long statement may continue onto the lines after it by indenting them:
|
|
10
14
|
|
|
11
15
|
```
|
|
12
|
-
node desktop1 "Desktop 1 / Linux"
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
node desktop1 "Desktop 1 / Linux" (inside top, align: left)
|
|
17
|
+
badge: desktop
|
|
18
|
+
node desktop1.files "shared folder"
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
A line that starts with whitespace continues the statement above it, and a blank line or the next unindented line ends it. How much whitespace makes no difference
|
|
18
|
-
|
|
19
|
-
An indented line with no statement to continue — at the top of the file, or after a blank line or an unindented comment — is an error rather than a statement of its own, and so is an indented line starting with a statement keyword such as `node`. Both are almost always a stray indent, and both say to remove it.
|
|
21
|
+
A line that starts with whitespace continues the statement above it, and a blank line or the next unindented line ends it. How much whitespace makes no difference, so nothing can depend on indentation you can't see. A bracket may stay open across lines. Indentation only lets a statement wrap; it never puts one thing inside another.
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
An indented line with nothing to continue, at the top of the file or after a blank line, is an error, and so is an indented line that starts with a statement keyword such as `node`. Both are almost always a stray indent, and both say to remove it.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
`//` starts a comment, which runs to the end of the line and may trail a statement. An indented comment line sits inside the statement it follows; an unindented one ends it. `#` is not a comment, because it opens a hex color.
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
### The statements
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
| keyword | makes |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `node` | a box, a picture, or a bare text ([Nodes](#nodes)) |
|
|
32
|
+
| `edge` | a line between two things ([Lines](#lines)) |
|
|
33
|
+
| `point` | a named point ([Points and regions](#points-and-regions)) |
|
|
34
|
+
| `region` | a named rectangle ([Points and regions](#points-and-regions)) |
|
|
35
|
+
| `bundle` | a path several lines share ([Bundles](#bundles)) |
|
|
36
|
+
| `guide` | a first word that makes a `node`, `edge`, `point` or `region` reference-only ([Guides](#guides)) |
|
|
37
|
+
| `style` | a named bundle of appearance ([Styles](#styles)) |
|
|
38
|
+
| `default` | appearance every thing of one kind wears ([Defaults](#defaults)) |
|
|
39
|
+
| `diagram` | settings for the whole drawing ([The diagram](#the-diagram)) |
|
|
40
|
+
| `icon` | a picture of your own ([Your own icons](#your-own-icons)) |
|
|
35
41
|
|
|
36
|
-
`
|
|
42
|
+
`box`, `link`, `note`, `deck`, `rect` and `arrow` at the start of a statement are refused by name, each quoting what to write instead.
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
### Heads, keys and phrases
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
A statement is a positional head (the keyword, a name and a text) followed by attributes and placements in any order:
|
|
41
47
|
|
|
42
48
|
```
|
|
43
|
-
node
|
|
49
|
+
node server "Home Server" (inside top) left of cluster badge: desktop
|
|
50
|
+
// ^ ^ ^ ^ ^
|
|
51
|
+
// name text its bracket a placement an attribute
|
|
44
52
|
```
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
What every statement of a kind has is positional; what is optional is a key. A word ending in a colon opens an attribute and nothing else does, so the two never need telling apart by position. A key may touch its value: `gap:tight` is `gap: tight`. Relations stay phrases, `right of api` or `between c and d`, because a phrase is the sentence a person would say and a key like `right-of: a` falls apart with several targets, a gap or a part.
|
|
47
55
|
|
|
48
|
-
|
|
56
|
+
**A value ends when its own shape is complete.** `height: 0.5 group height right of a` reads a size, then a placement. `to: top, right of z` keeps `right of z` inside `to:`, because it is part of that value. So word order stays free and nothing is ambiguous.
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
node parser
|
|
52
|
-
node resolver right of parser
|
|
53
|
-
```
|
|
58
|
+
**A bracket modifies the one thing it follows.** A setting that belongs to one part of a statement is written in brackets right after that part: a placement's `(gap: wide)`, a text's `(size: small, wrap: 30)`, a line's `line: (path: square)`, a layout's `layout: column (gap: none)`, a waypoint's `b top (gap: wide)`. The scope is visible instead of inferred. Inside a bracket the comma is optional.
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
### Names and words
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
A name is unique across nodes, points, regions, lines and bundles. It may not contain `:`, which would make it a key, or `;`, which is reserved. A dot means a child: `server.docker` is inside `server`, and the parent must be declared first. Moving a node to another parent is a rename.
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
Every word the language owns that has more than one part is hyphenated (`from-mark:`, `bottom-left`, `min-height:`, `align-children:`), while a phrase of separate words stays spaced (`left of`, `even with`). A name you choose should look chosen: the examples use underscores (`some_region`). `to_mark:` is refused by name, pointing to `to-mark:`.
|
|
60
65
|
|
|
61
|
-
|
|
66
|
+
**One spelling for each thing.** An alternative spelling is refused by name, pointing to the one the language uses: `below of a` names `below a`, and `left a` names `left of a`.
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
### Texts
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
A text is quoted. ` / `, a slash with whitespace on both sides, breaks the line, so `TCP/IP`, `16/9` and URLs survive as written. The escapes are `\"`, `\\`, `\/` (a spaced slash that doesn't break) and `\[` (a literal bracket, since `[` opens markup).
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
A node with no text shows its name, and a dotted name shows only its last part: `node server.docker` reads "docker". The name is never prettified. `""` says a node deliberately has none. A node drawn as a picture shows no text unless one is written.
|
|
68
73
|
|
|
69
|
-
|
|
70
|
-
node server "Home Server" left of cluster
|
|
71
|
-
node server.mirror "shared folder / mirror"
|
|
72
|
-
node server.deploy "deploy dir"
|
|
73
|
-
```
|
|
74
|
+
A `"""` string takes everything between its marks as written, quotes and line breaks included. It is accepted only for an icon's SVG.
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
### Numbers and the file's unit
|
|
76
77
|
|
|
77
|
-
A
|
|
78
|
+
A distance (a gap, a size, a padding, `2 right of a`) is measured in the file's unit, which is small: an ordinary one-line box is about 4 units tall. The gap words are whole numbers of it:
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
| word | units |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `none` | 0 |
|
|
83
|
+
| `tight` | 2 |
|
|
84
|
+
| `normal` | 4 (the default) |
|
|
85
|
+
| `wide` | 8 |
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
node cluster.hub "Cloud sync"
|
|
84
|
-
node cluster.desktop1 "Desktop 1" above-left of cluster.hub
|
|
87
|
+
A distance below the words is a number, `1 right of a` or `0.5 right of a`, and a number may start at its decimal point, `.5`. A unit is 12 pixels at the normal text size.
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
```
|
|
89
|
+
An appearance number is a multiple of its own normal: `(size: 1.2)` is text 20% bigger, `thickness: 2` a line twice the normal width. So a bare number has two scales, and `thickness: 1` is not `gap: 1`. The one exception is a region's `opacity:`, an amount from `0` (none) to `1.0` (solid), not a multiple of anything.
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
A suffix `px` fixes any of these in pixels, so it doesn't follow the file: `(size: 16px)`, `thickness: 3px`, `(gap: 12px)`. A bare number never means pixels.
|
|
90
92
|
|
|
91
|
-
A
|
|
93
|
+
A fraction is written `1/3` or as a decimal, `0.25`, and is measured from the first-named thing. **No distance is negative**: `-4 right of a` is refused, pointing to `4 left of a`, or to `inside` or `on` for a box meant to overlap.
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
Named values are preferred where they exist: change what `tight` means and every tight gap follows.
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
## Nodes
|
|
96
98
|
|
|
97
99
|
```
|
|
98
|
-
node
|
|
100
|
+
node <name> ["<text>" [(<text settings>)]] [<placement> | <attribute>] ...
|
|
99
101
|
```
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
### The body
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|---|---|
|
|
105
|
-
| nothing | natural widths, ranged left |
|
|
106
|
-
| `contents: (widths: match)` | every child as wide as the widest, ranged left |
|
|
107
|
-
| `contents: (widths: fill)` | every child spans the whole content band; `align` then has no slack to work in. A single column only: children side by side cannot all be the full width, and are refused by name |
|
|
108
|
-
| `contents: (align: center)` | natural widths, the block of them centered |
|
|
109
|
-
| `contents: (widths: match, align: center)` | the tidy centered column |
|
|
105
|
+
Every node has one body, the thing drawn where it is, named by one of two keys.
|
|
110
106
|
|
|
111
|
-
`
|
|
107
|
+
`shape:` is the outline:
|
|
112
108
|
|
|
113
|
-
|
|
109
|
+
| shape | draws |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `rectangle` | the plain box, its corners rounded unless `corners: sharp`; the default |
|
|
112
|
+
| `document` | the box with its top-right corner folded, for an artifact rather than a process; its other corners follow `corners:` |
|
|
113
|
+
| `circle` | a circle sized to hold its text, always round |
|
|
114
|
+
| `none` | no outline, fill or padding: bare text, or an invisible container |
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
`icon:` is a picture the node is drawn *as*, with no box:
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
| icon | means |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `disk` | a physical drive |
|
|
121
|
+
| `desktop` | a workstation |
|
|
122
|
+
| `laptop` | a portable machine |
|
|
123
|
+
| `package` | something stored as a whole: an archive, a bucket, a sync root |
|
|
124
|
+
| `cubes` | several interchangeable units; always three, since it is the symbol for "several", not a count |
|
|
125
|
+
| `cube` | one of them |
|
|
126
|
+
| `database` | a store queried rather than read as files |
|
|
118
127
|
|
|
119
128
|
```
|
|
120
|
-
node
|
|
121
|
-
node aside "Written by a nightly cron job." (
|
|
129
|
+
node dump "db dump / (app 1)" shape: document
|
|
130
|
+
node aside "Written by a nightly cron job." (wrap: 30) shape: none below dump (gap: tight)
|
|
131
|
+
node svc icon: cube right of dump
|
|
122
132
|
```
|
|
123
133
|
|
|
124
|
-
|
|
134
|
+
Writing both keys is an error naming both. An unknown name is refused with the whole set. A name says what a thing is, never what the picture looks like: `document`, not `folded-corner`. The exception is a picture with no single meaning, such as `circle` or `cube`.
|
|
125
135
|
|
|
126
|
-
|
|
136
|
+
A picture can't contain anything. A `shape: none` node with children is an invisible container ([Containers](#containers)). A circle can hold other nodes, centered in it. A side of a circle is the quarter of it about that compass point, so `from: right` means the same on every shape; several line ends on one side spread round that arc, each meeting the circle square on.
|
|
127
137
|
|
|
128
|
-
|
|
129
|
-
edge a -> b "rclone" (color: theme-muted, size: small)
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
A **style** has no text of its own for a bracket to hang off, so it hangs the bracket off a key instead:
|
|
138
|
+
**Corners.** `corners: sharp` draws a box's corners square, and `corners: rounded`, the default, draws them as they always were. It is the same word and values as a line's `corners:`. It reaches every outline with corners: a rectangle, a container, and a document's three round corners, whose fold stays as it is. A circle has none, so `corners:` written on a circle is refused; from a style or a default it lands only on the nodes with corners. A picture and bare text have no outline, so they refuse it too. Like a color, it never moves anything.
|
|
133
139
|
|
|
134
140
|
```
|
|
135
|
-
style
|
|
141
|
+
style plain corners: sharp
|
|
142
|
+
node api "API" style: plain
|
|
143
|
+
node spec "spec" shape: document corners: sharp right of api
|
|
136
144
|
```
|
|
137
145
|
|
|
138
|
-
|
|
146
|
+
**Bare text.** `shape: none` is how to write a note, a caption or a title over a diagram. Its text starts one step smaller than a box's, because an aside at full size reads as a statement; `(size: normal)` overrides that. Nothing bounds bare text the way a border bounds a box, so give a sentence-length one a `wrap:`.
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
### Your own icons
|
|
141
149
|
|
|
142
|
-
`
|
|
150
|
+
`icon <name>` declares a picture, and from then on `icon: <name>` and `badge: <name>` use it as they would a built-in one. The picture is SVG, pasted between `"""` marks or read from a file:
|
|
143
151
|
|
|
144
|
-
|
|
152
|
+
```
|
|
153
|
+
icon crate """
|
|
154
|
+
<svg viewBox="0 0 24 24">
|
|
155
|
+
<path d="M3 7 L12 3 L21 7 L21 17 L12 21 L3 17 Z" fill="none" stroke="currentColor"/>
|
|
156
|
+
</svg>
|
|
157
|
+
"""
|
|
145
158
|
|
|
146
|
-
|
|
159
|
+
node store "Warehouse" badge: crate
|
|
160
|
+
node more icon: crate right of store
|
|
161
|
+
```
|
|
147
162
|
|
|
148
|
-
|
|
163
|
+
- **It keeps its own colors** on every theme. What it leaves to `currentColor` takes the theme's icon color, which is how a one-color icon follows the theme.
|
|
164
|
+
- **It is fitted to the icon's square** by its `viewBox`, or with none by its `width` and `height`; with neither it is refused, since nothing says how big it is.
|
|
165
|
+
- **Its ids and class names are renamed**, so two icons that both call a gradient `a` don't collide.
|
|
166
|
+
- **Script is refused**: a `<script>` element or an `on…` attribute.
|
|
149
167
|
|
|
150
|
-
|
|
168
|
+
A file (`icon rack "./rack.svg"`) is found relative to the diagram's own file. Only the command line can read one; in the playground or a web page, paste the SVG. A declared name replaces a built-in of the same name, and declaring one name twice is an error. Every picture is drawn into the output as path data, so the SVG stays standalone.
|
|
151
169
|
|
|
152
|
-
|
|
170
|
+
### Badges
|
|
153
171
|
|
|
154
|
-
|
|
172
|
+
`badge: <icon>` makes a picture part of the node's label: the whole text, however many lines, with the picture beside it, placed as one unit.
|
|
155
173
|
|
|
156
174
|
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
node pc.files "shared folder / [dim]synced[/dim]"
|
|
175
|
+
node drive "External HD" badge: disk
|
|
160
176
|
```
|
|
161
177
|
|
|
162
|
-
|
|
178
|
+
It is shorthand for a child joined to the text ([Joined to the text](#joined-to-the-text)), and this is what it stands for:
|
|
163
179
|
|
|
164
|
-
|
|
180
|
+
```
|
|
181
|
+
node drive "External HD"
|
|
182
|
+
node drive.badge icon: disk 1 right of drive text join-with: drive text
|
|
183
|
+
```
|
|
165
184
|
|
|
166
|
-
|
|
185
|
+
The text keeps its own position words, so `node d1 "Desktop 1 / Linux" (inside top, align: left) badge: desktop` puts the label, picture and all, in the top-left corner. On a box with nothing else in it the label is centered; on a box with children it takes the title's place and the children go under it. The picture is two lines of text tall and can be named like any child (`below drive.badge`, `edge a -> drive.badge`). Declaring `drive.badge` yourself beside a `badge:` is an error naming both ways out. Only a box can wear one.
|
|
167
186
|
|
|
168
|
-
|
|
187
|
+
With an empty text, `node flag "" badge: disk`, the node is exactly the picture and its padding, since an empty text takes no room.
|
|
169
188
|
|
|
170
|
-
|
|
171
|
-
node sizes "sizes \[small, normal, large]" shape: none
|
|
172
|
-
```
|
|
189
|
+
**A picture that is a thing of its own is a child**, placed like any other: `node drive.mark icon: disk inside drive top-right` in a corner. Placed against the text without `join-with:`, it is not part of the label: the text stays where it would be without it, and the box grows to hold both.
|
|
173
190
|
|
|
174
|
-
###
|
|
191
|
+
### Padding
|
|
175
192
|
|
|
176
|
-
|
|
193
|
+
A stack of cards, which `deck:` used to draw, is a container: [`layout: deck`](#a-stack-of-cards-layout-deck).
|
|
177
194
|
|
|
178
|
-
`
|
|
195
|
+
`padding:` is the room between a box's edge and what it holds, in the file's unit: `padding: 2`. On a region it is measured outward instead ([Points and regions](#points-and-regions)). One side's padding is `padding-top:`, `padding-right:`, `padding-bottom:` or `padding-left:`, over `padding:` on that side only: `padding: 2 padding-right: 4` is 2 all round and 4 on the right. A container's title keeps `padding:` from the edge, so a side's padding widens the room round the children without moving the title out of its corner. A circle has no sides, so a side's padding on one is refused.
|
|
179
196
|
|
|
180
|
-
|
|
181
|
-
| --- | --- |
|
|
182
|
-
| `rectangle` | The plain rounded box. The default, so nothing has to say it. |
|
|
183
|
-
| `document` | The same box with its top-right corner folded — the flowchart symbol saying *this is an artifact, not a process*. |
|
|
184
|
-
| `circle` | A circle just big enough to hold the text, and always round — a longer text makes a bigger circle, never an oval. |
|
|
185
|
-
| `none` | No outline, no fill, no padding. The node is its text and nothing else. |
|
|
197
|
+
## Placing a box
|
|
186
198
|
|
|
187
|
-
|
|
199
|
+
A *placement* says one thing about where a node goes, and a node carries as many as it needs. Nothing else places a box: no line, no text, no neighbor.
|
|
188
200
|
|
|
189
|
-
|
|
190
|
-
| --- | --- |
|
|
191
|
-
| `disk` | A physical drive — the hardware, not the filesystem on it. |
|
|
192
|
-
| `desktop` | A workstation. |
|
|
193
|
-
| `laptop` | A portable machine. |
|
|
194
|
-
| `package` | Something stored as a whole rather than run: an archive, a bucket, a sync root. |
|
|
195
|
-
| `cubes` | Several interchangeable units of the same kind. |
|
|
196
|
-
| `cube` | One of them. |
|
|
197
|
-
| `database` | A store queried rather than read as files. |
|
|
201
|
+
### Directions and gaps
|
|
198
202
|
|
|
199
203
|
```
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
node svc icon: cube
|
|
204
|
+
above X below X left of X right of X
|
|
205
|
+
above-left of X above-right of X below-left of X below-right of X
|
|
203
206
|
```
|
|
204
207
|
|
|
205
|
-
A
|
|
208
|
+
**A gap is exactly what was said.** `right of a` puts the box a `normal` gap from `a`'s right side. The gap goes in the placement's bracket, `right of a (gap: tight)`, or as a distance in front, `2 right of a`; writing both is refused as said twice. A diagonal distance is per axis: `2 below-right of a` is 2 across and 2 down.
|
|
206
209
|
|
|
207
|
-
|
|
210
|
+
**A lone direction also centers on its target.** `right of a` alone puts the box level with `a`'s center, because walking right from something keeps you on its center line. That half gives way as soon as another placement says how high.
|
|
208
211
|
|
|
209
|
-
|
|
212
|
+
```
|
|
213
|
+
node parser
|
|
214
|
+
node resolver right of parser
|
|
215
|
+
node renderer right of resolver (gap: wide)
|
|
216
|
+
node notes "notes" below resolver (gap: tight) shape: none
|
|
217
|
+
```
|
|
210
218
|
|
|
211
|
-
|
|
219
|
+
**A gap belongs to the relationship, not the node.** One box may want different distances on different sides, so each placement carries its own. `gap:` on a node or in a style is refused, quoting the bracket form.
|
|
212
220
|
|
|
213
|
-
|
|
221
|
+
`right of server.docker` places a top-level node against something nested: containers scope names, not placement.
|
|
214
222
|
|
|
215
|
-
|
|
223
|
+
### Several targets at once
|
|
216
224
|
|
|
217
|
-
|
|
225
|
+
A placement may name several targets, joined by `and` or commas: `right of a, b and c`. It places against the box bounding them all, a region nobody had to declare. A lone direction centers on that region, which is how one row is offset against another:
|
|
218
226
|
|
|
219
|
-
|
|
227
|
+
```
|
|
228
|
+
node a icon: cube
|
|
229
|
+
node b right of a (gap: tight) icon: cube
|
|
230
|
+
node c right of b (gap: tight) icon: cube
|
|
231
|
+
node d below a and b (gap: tight) icon: cube
|
|
232
|
+
node e below b and c (gap: tight) icon: cube
|
|
233
|
+
```
|
|
220
234
|
|
|
221
|
-
|
|
235
|
+
A comma promises another target, so `right of a, gap: tight` is refused, naming the comma.
|
|
222
236
|
|
|
223
|
-
|
|
237
|
+
### Lining up: `even with`
|
|
224
238
|
|
|
225
|
-
|
|
239
|
+
`even with a` shares `a`'s horizontal center line and says nothing across. A side word in front lines that side up instead: `top even with a` puts this box's top on `a`'s top. A part after the target lines up with that part: `top even with a bottom`, `top even with a center`. A side on the other axis, `top even with a left`, names no one height and is refused.
|
|
226
240
|
|
|
227
|
-
|
|
241
|
+
To name the axis rather than a side, put `x` or `y` in front. `x even with a` shares `a`'s vertical center line, so this box's middle across is `a`'s middle across, and says nothing about height. `y even with a` says what the bare `even with a` says: the same height.
|
|
228
242
|
|
|
229
243
|
```
|
|
230
|
-
node
|
|
244
|
+
node a
|
|
245
|
+
node b right of a top even with a
|
|
246
|
+
node c below a (gap: wide)
|
|
247
|
+
node d right of c even with c
|
|
231
248
|
```
|
|
232
249
|
|
|
233
|
-
|
|
250
|
+
A fraction of the way across a box is written fraction first: `top even with 3/4 down a` puts this box's top three quarters of the way down `a` (`1/4 up a` says the same). Across, `left even with 1/3 across a`, counted from the left unless `from right` follows.
|
|
234
251
|
|
|
235
|
-
|
|
236
|
-
node drive "External HD"
|
|
237
|
-
node drive.badge icon: disk right of drive text
|
|
238
|
-
```
|
|
252
|
+
`even with a and b` lines up with the region round both. An alignment takes no gap, since sharing a line leaves no distance, and `(gap: …)` on one is refused.
|
|
239
253
|
|
|
240
|
-
|
|
254
|
+
### Part against part
|
|
241
255
|
|
|
242
|
-
|
|
243
|
-
- On a leaf the text and the badge center in the box as one group. On a container the badge sits beside the title in the band, and the band is as tall as the two together.
|
|
244
|
-
- The picture is two lines of the node's text tall, so it follows `(size: …)` down and up with the text.
|
|
245
|
-
- With no text at all — `node flag "" badge: disk` — the badge sits where the text would have been, with no gap beside it, so the node is exactly the badge and its padding. That makes a badge usable as a marker and not only as a title-block ornament.
|
|
246
|
-
- A text sent to one end with `at:` does not take the badge with it. A leaf is as tall as the badge, the badge is centered on the text, and so the text sits in the middle. To give a text room to move, put the picture against a side instead — see `at:` under [The text and its brackets](#the-text-and-its-brackets).
|
|
256
|
+
`center 12 right of a center` puts the two centers exactly 12 apart, the even steps of a timeline whose boxes differ in width. `top 3 below a bottom` is the same for edges. The direction means what it always means, so with nothing else said the box also sits level with `a`'s center. A placement naming parts must give its distance: `center right of a center` is refused ("say how far").
|
|
247
257
|
|
|
248
|
-
|
|
258
|
+
Two distances, one per axis, are accepted in any placement: `3 below and 2 right of a`, or `top-left 3 below and 2 right of a bottom-right`.
|
|
249
259
|
|
|
250
|
-
|
|
260
|
+
**How far along the side it faces.** `right of server 3/4 down` puts the box the usual gap right of `server`, its middle level with a spot three quarters of the way down `server`'s right side. `down` and `up` run along a left or right side, `across` along a top or bottom one. A word that doesn't run along the side the direction faces is refused, listing the words that do.
|
|
251
261
|
|
|
252
|
-
|
|
262
|
+
### Each axis is stated once
|
|
253
263
|
|
|
254
|
-
|
|
264
|
+
A box's position across and its position up and down each come from exactly one statement. Pinning one edge positions the box; pinning two opposite edges, `top even with a bottom even with c`, positions and sizes it, and counts as one statement. Refused by name:
|
|
265
|
+
|
|
266
|
+
- **Said twice.** Two statements on one axis, even where they happen to agree, so a file is never right by coincidence. A bare direction beside a pin doesn't count; see below.
|
|
267
|
+
- **Inside out.** Two pinned edges that would give a negative size.
|
|
268
|
+
- **Circular.** A box measured from something measured from it.
|
|
269
|
+
- **An axis left open.** `right of a left of b` with nothing up and down: centering on one or the other would decide which row the box shares, so the error names the axis.
|
|
270
|
+
|
|
271
|
+
**A direction beside a pin on its own axis gives up its distance and keeps its side.** `below trx` says two things: underneath `trx`, lined up with it across, and one gap down. A pin says how far down instead:
|
|
255
272
|
|
|
256
273
|
```
|
|
257
|
-
|
|
258
|
-
node records "Records" style: store
|
|
274
|
+
node host.bin below host.trx top even with cat0 bottom even with nice
|
|
259
275
|
```
|
|
260
276
|
|
|
261
|
-
|
|
277
|
+
`bin` is under `trx` across, and runs from `cat0`'s top to `nice`'s bottom. The side still has to hold: if the pins put `bin` beside or above `trx`, that is refused. A distance written on the direction, `below host.trx (gap: wide)` or `2 below host.trx`, beside a pin is refused too, since the pin would overrule it.
|
|
262
278
|
|
|
263
|
-
|
|
279
|
+
**Opposite placements on one axis center the box between them**, at its own size: `node c right of a left of b even with a` sits in the middle of the space `a` and `b` already leave. It doesn't move `a` or `b`. If the space is too narrow, `c` overlaps them and that is reported; to make room, state how far apart `a` and `b` are.
|
|
264
280
|
|
|
265
|
-
|
|
266
|
-
icon crate """
|
|
267
|
-
<svg viewBox="0 0 24 24">
|
|
268
|
-
<path d="M3 7 L12 3 L21 7 L21 17 L12 21 L3 17 Z" fill="none" stroke="currentColor"/>
|
|
269
|
-
</svg>
|
|
270
|
-
"""
|
|
281
|
+
A target need not be written first, but there must be an order in which each box can be worked out from boxes already worked out.
|
|
271
282
|
|
|
272
|
-
|
|
283
|
+
### One anchor
|
|
273
284
|
|
|
274
|
-
|
|
275
|
-
node servers icon: rack right of store
|
|
276
|
-
```
|
|
285
|
+
Exactly one box in the file places itself, and every other is placed relative to it, directly or through others. Two unplaced boxes are refused by name. Chaining, `b right of a` then `c right of b`, is the plain way to write a few in a row; `layout:` ([Containers](#containers)) is for "these, in a line, in written order". Place against neighbors rather than hanging many boxes off one small one: a gap from a small box says nothing about the large ones also hanging off it.
|
|
277
286
|
|
|
278
|
-
|
|
287
|
+
### A box goes where it is placed
|
|
279
288
|
|
|
280
|
-
|
|
289
|
+
Nothing moves a box but its own statements. A line's text doesn't widen a gap, an arrowhead doesn't, and a line ending on a side too short for it doesn't grow the box (that is reported as `crowded-edge-ends`). **Nothing pushes overlapping boxes apart**: two boxes whose placements put them on one spot are drawn there and reported as `node-overlap`. `overlap: allow` on a node says the overlap is meant.
|
|
281
290
|
|
|
282
|
-
|
|
283
|
-
- **It is fitted to the icon's square,** in proportion and centered, by its `viewBox`. With no `viewBox`, its `width` and `height` stand in; with neither it is refused, since nothing says how big the drawing is.
|
|
284
|
-
- **Its ids and class names are renamed** on the way in, so two icons that both call a gradient `a` don't pick up each other's.
|
|
285
|
-
- **Script is refused:** a `<script>` element or an `on…` attribute.
|
|
291
|
+
Identical placements don't make a list. `node b right of a` and `node c right of a` put `b` and `c` on one spot, drawn and reported. A list is a container with a layout.
|
|
286
292
|
|
|
287
|
-
|
|
293
|
+
### Against a part of a node
|
|
288
294
|
|
|
289
|
-
|
|
295
|
+
A placement's target may be a part of a node, with one of three words, each taking one part of one thing:
|
|
290
296
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
297
|
+
| | |
|
|
298
|
+
|---|---|
|
|
299
|
+
| `inside hub top-right` | wholly within, against that part |
|
|
300
|
+
| `outside hub right` | wholly beyond it |
|
|
301
|
+
| `on hub bottom-left` | centered on it, straddling it; takes no gap |
|
|
294
302
|
|
|
295
303
|
```
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
left level with X right level with X
|
|
304
|
+
node bob "Bob the builder" (inside top) height: 7
|
|
305
|
+
node bob_link "bob.example.com" (size: small) inside bob bottom-center shape: none
|
|
306
|
+
node mark "!" on bob top-right shape: circle
|
|
300
307
|
```
|
|
301
308
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
`of` is optional after any direction, so `below X` and `below of X` both parse. Write whichever reads as English.
|
|
309
|
+
*Inside* is the direction from the part toward the box's center, so `inside right` is `left of` that side and `inside top-right` is `below-left of` that corner. `inside hub center` and `inside hub text` are refused, having no inward direction. The inset for `inside` is a gap on the placement: `tight` against another node, the parent's padding against one's own parent. Saying `inside` or `on` states the overlap, so it isn't reported.
|
|
305
310
|
|
|
306
|
-
|
|
311
|
+
A direction and a part stay two vocabularies: `above-left of hub` is outside it, `inside hub top-left` is a point of it, and `above hub` could never mean "the top of hub". For several boxes, name the region round them and use its part.
|
|
307
312
|
|
|
308
|
-
|
|
313
|
+
## Points and regions
|
|
309
314
|
|
|
310
|
-
|
|
315
|
+
Anywhere the language wants a position, it takes the same points: a box placed at one, a line passing through one, a line ending at one, a text placed by one.
|
|
311
316
|
|
|
312
|
-
|
|
317
|
+
### The parts of a box
|
|
313
318
|
|
|
314
|
-
|
|
319
|
+
A box's parts are its `text`, its four sides `top`, `bottom`, `left` and `right`, and its nine points:
|
|
315
320
|
|
|
316
321
|
```
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
322
|
+
top-left top-center top-right
|
|
323
|
+
left-center center right-center
|
|
324
|
+
bottom-left bottom-center bottom-right
|
|
320
325
|
```
|
|
321
326
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
This is the step you would otherwise do by hand: shove two things apart to make room, then drag everything back together so the diagram isn't full of holes. The file states the relationships and the distances fall out.
|
|
327
|
+
**A side is a segment and a point is a point.** Bare `top` is the whole side; `top-center` is the one point halfway along it, which is why every midpoint carries `-center`. Naming a side leaves the other axis free. On a circle, a corner is the point on the circle halfway between its two sides.
|
|
325
328
|
|
|
326
|
-
|
|
329
|
+
A part is written as the name, then the part: `b top`, `e bottom-left`, `hub text`.
|
|
327
330
|
|
|
328
|
-
|
|
331
|
+
### Points
|
|
329
332
|
|
|
330
|
-
**
|
|
333
|
+
- **Between two things.** `between a and b` is the center of the space between them: halfway between their facing sides, not their centers. `between a and b at 1/3` is a third of the way across, from `a`. It always joins exactly two things with `and`; `between a, b` is refused.
|
|
334
|
+
- **From two things.** `down from a and left from b` is where a line straight down from `a`'s center meets a line straight left from `b`'s. A line may start from a part (`down from a left`) or a point (`left from 1 above b top-left`); from a whole side, such as `up from c top`, it starts at the side's middle. The direction words also say which way the point lies from each box, and that is checked: lines that don't meet are refused. Either half may be `even with a` instead, the level line through `a`: `up from c and even with tall top` is straight above `c`, level with `tall`'s top. It says no way the point lies, so only the other half is checked.
|
|
335
|
+
- **Moved by a distance.** `2 below c bottom` is 2 units below `c`'s bottom. What is moved is a point or a side, so `2 below c` is refused, asking which. A moved side is still a side: `1 above tall top` works wherever `tall top` does. A named point moves the same way: `2 above over_c`. `c bottom + 2` is refused too, since `+` adds lengths and doesn't say up or down.
|
|
336
|
+
- **On a line.** `req start`, `req end`, `req at 1/3` ([Points on a line](#points-on-a-line)).
|
|
331
337
|
|
|
332
|
-
|
|
338
|
+
A box is placed at a point with `on`, and against one with a direction:
|
|
333
339
|
|
|
334
340
|
```
|
|
335
|
-
node
|
|
341
|
+
node a
|
|
342
|
+
node b right of a (gap: wide) below a
|
|
343
|
+
node c on down from a and left from b shape: circle
|
|
336
344
|
```
|
|
337
345
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
Naming a side in front of it aligns that side instead of the center. `top level with media` puts the node's top side on the media node's top side; `bottom`, `left` and `right` work the same way. `top` and `bottom` bind the vertical, `left` and `right` the horizontal — so `left level with X` and `left of X` are different statements, and the word after `left` is what tells them apart.
|
|
341
|
-
|
|
342
|
-
### Several targets at once
|
|
346
|
+
`c` sits under `a` and level with `b`.
|
|
343
347
|
|
|
344
|
-
|
|
348
|
+
### Named points and regions
|
|
345
349
|
|
|
346
350
|
```
|
|
347
|
-
|
|
348
|
-
|
|
351
|
+
point funnel between c2 and api at 2/3
|
|
352
|
+
region trust web top-left to db bottom-right
|
|
353
|
+
region slot between left_rack and right_rack
|
|
349
354
|
```
|
|
350
355
|
|
|
351
|
-
|
|
356
|
+
A named point can be used by several things (`via: funnel`, `below funnel`), and moving it is one edit. A named point must come out as one point, so `point p a bottom` (a whole side) is refused.
|
|
352
357
|
|
|
353
|
-
|
|
358
|
+
A region is the rectangle spanned by two points, in either order. `region r between a and b` is the space between the two boxes: on an axis where they are apart, the gap; where they overlap, only the stretch they share. `(span: both)` stretches it across both boxes on the other axis. Once named, a region has every part a box has, so `via: r center`, `right of r` and `inside r top-left` need nothing new. `padding:` pushes its edges out.
|
|
354
359
|
|
|
355
|
-
|
|
360
|
+
A region bounds things without owning them: they keep their own parent, aren't moved by it, and may sit in several regions, and a region may span containers. That is what separates it from a container. A point is drawn as a dot and a region as a light tint with a quiet border, unless written as a [guide](#guides). A region's fill, the tint or one it states with `fill:`, is drawn at half opacity, so overlapping regions show both colors and a region never hides what it covers; `opacity: 1.0` makes it solid, and `opacity:` takes any amount from `0` to `1.0`.
|
|
356
361
|
|
|
357
362
|
```
|
|
358
|
-
node
|
|
359
|
-
node
|
|
360
|
-
node
|
|
361
|
-
|
|
362
|
-
node e below b and c gap: tight icon: cube
|
|
363
|
+
node web "Web"
|
|
364
|
+
node api "API" right of web
|
|
365
|
+
node db "DB" below api
|
|
366
|
+
region trust web top-left to db bottom-right padding: 1
|
|
363
367
|
```
|
|
364
368
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
For a direction the region is a floor, so `right of one and three` clears whichever of them sticks out furthest, and it works wherever the targets sit. For an alignment the region is an exact position, and there is one restriction worth knowing: it must not depend on the node being aligned to it. Aligning a node to the region covering `A` and `B` while `B` is placed relative to that same node is refused by name, because there is no order in which each could wait for the other.
|
|
369
|
+
### A point's and a region's text
|
|
368
370
|
|
|
369
|
-
|
|
371
|
+
A point or a region may have a text, quoted after its name, with a bracket like any text's.
|
|
370
372
|
|
|
371
|
-
A
|
|
373
|
+
**A point's text sits above its dot** unless its bracket says which way: `(below)`, `(left)`, `(right)`, or a corner, `(above-right)`, `(above-left)`, `(below-right)`, `(below-left)`. There is no target, since a point's text has nothing else to sit beside. A side centers the text on the dot; a corner puts the text's nearest corner off the dot diagonally. `gap:` is the distance from the dot, half a unit unless it says.
|
|
372
374
|
|
|
373
375
|
```
|
|
374
|
-
node
|
|
376
|
+
node a "A"
|
|
377
|
+
node b "B" right of a (gap: 14)
|
|
378
|
+
point mid "halfway" (above-right, gap: 1) between a and b
|
|
375
379
|
```
|
|
376
380
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
`gap:` written as an ordinary attribute still works and is the node's default, used by every placement that does not name its own:
|
|
381
|
+
**A region's text takes a container title's words**: `inside`, `on` or `outside` a side, `align:` along it, and `gap:` for its distance from the region. With nothing said it sits above the region, outside it, centered. Inside, the region makes room for it, as a container does for its title: it grows a band on that side to hold the text, and widens if the text is wider. Nothing it spans moves, but its own edges do, so whatever is placed against that side of the region moves with them. `(center)` is refused, since a region holds nothing and its middle is whatever it covers.
|
|
380
382
|
|
|
381
383
|
```
|
|
382
|
-
node
|
|
384
|
+
node web "Web"
|
|
385
|
+
node api "API" right of web
|
|
386
|
+
node db "DB" below api
|
|
387
|
+
region trust "trust boundary" (inside top, align: left) web top-left to db bottom-right padding: 1
|
|
383
388
|
```
|
|
384
389
|
|
|
385
|
-
|
|
390
|
+
Both start one step smaller than a box's text, as bare text does, and take `color:`, `size:`, `wrap:`, `align:` and `reads: up` or `down`.
|
|
386
391
|
|
|
387
|
-
|
|
392
|
+
## Containers
|
|
388
393
|
|
|
389
|
-
|
|
390
|
-
node parser "Parser" gap: wide
|
|
391
|
-
node renderer "Renderer" right of parser
|
|
392
|
-
```
|
|
394
|
+
A node is a container when it has children, named with a dot. **A container is the bounding box of its children, plus padding.** The children are arranged in one of two ways, never by inference.
|
|
393
395
|
|
|
394
|
-
|
|
396
|
+
### By hand
|
|
395
397
|
|
|
396
|
-
|
|
398
|
+
With no `layout:`, a container follows the file's own rule: exactly one child is unplaced, the anchor, and every other child is placed relative to it or to other children. A second unplaced child is refused, naming `layout:` as the other answer.
|
|
397
399
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
400
|
+
```
|
|
401
|
+
node server "Server"
|
|
402
|
+
node server.web "web"
|
|
403
|
+
node server.db "database" below server.web
|
|
404
|
+
node server.cache "cache" right of server.db
|
|
405
|
+
```
|
|
401
406
|
|
|
402
|
-
A
|
|
407
|
+
A container scopes names, not placement: a child may be placed against a box outside its container, and a box outside against a child. Here `bin` is as tall as a column of boxes outside `host`:
|
|
403
408
|
|
|
404
|
-
|
|
409
|
+
```
|
|
410
|
+
node host "host"
|
|
411
|
+
node host.trx
|
|
412
|
+
node host.bin left even with host.trx top even with cat0 bottom even with nice
|
|
413
|
+
node src left of host.trx (gap: wide)
|
|
414
|
+
node cat0 below src
|
|
415
|
+
node nice below cat0 (gap: 6)
|
|
416
|
+
```
|
|
405
417
|
|
|
406
|
-
|
|
418
|
+
When no child is unplaced and a child is placed against a box outside, the container is placed by what it holds: it goes wherever that puts the child, and it doesn't count as a box that says nothing about where it goes.
|
|
407
419
|
|
|
408
|
-
|
|
420
|
+
```
|
|
421
|
+
node abc
|
|
422
|
+
node lot below abc (gap: 4)
|
|
423
|
+
node host "host"
|
|
424
|
+
node host.trx right of abc (gap: 6)
|
|
425
|
+
node host.dog right of lot (gap: 6)
|
|
426
|
+
```
|
|
409
427
|
|
|
410
|
-
|
|
428
|
+
A container placed by its own statement can't also be placed by a child against a box outside it on the same axis. Both would say where the container goes, so it is refused as placed twice, even when the two agree; keep one of them.
|
|
411
429
|
|
|
412
|
-
|
|
430
|
+
### By a stated layout
|
|
413
431
|
|
|
414
|
-
|
|
432
|
+
`layout: column` puts every child in a column, in written order, and `layout: row` in a row. A child of a laid-out container never places itself; that is refused.
|
|
415
433
|
|
|
416
|
-
|
|
434
|
+
```
|
|
435
|
+
node svc "Ingestion and enrichment pipeline" layout: column (widths: match)
|
|
436
|
+
node svc.read "read"
|
|
437
|
+
node svc.parse "parse and validate"
|
|
438
|
+
node svc.store "store"
|
|
439
|
+
```
|
|
417
440
|
|
|
418
|
-
|
|
441
|
+
The layout's bracket takes:
|
|
419
442
|
|
|
420
|
-
|
|
443
|
+
| setting | says |
|
|
444
|
+
|---|---|
|
|
445
|
+
| `gap:` | the space between children; by default the same as the container's padding |
|
|
446
|
+
| `widths: match` | every child as wide as the widest |
|
|
447
|
+
| `widths: fill` | every child across the whole box; a column only |
|
|
448
|
+
| `align-children:` | how the children line up with each other: in a column `left`, `center` (the default) or `right`; in a row `top`, `center` or `bottom`; in a venn, the two sets, `top`, `center` or `bottom` |
|
|
449
|
+
| `centers: 5 apart` | space the children by their centers, not their facing sides: the even ticks of a timeline |
|
|
421
450
|
|
|
422
|
-
|
|
451
|
+
`centers:` beside `gap:` is refused as said twice. `layout:` on a node with no children is refused. The bare `align:` in a layout is refused, naming `align-children:` and `gather-children:`, so `align:` means one thing everywhere: where along a side.
|
|
423
452
|
|
|
424
|
-
|
|
453
|
+
### Two sets that overlap: `layout: venn`
|
|
425
454
|
|
|
426
|
-
|
|
455
|
+
A thing that belongs to two groups at once goes in the strip where they overlap. `layout: venn` takes exactly three children, in written order: the left set, the overlap, and the right set. Each keeps one parent and one dotted name, so the shared box is a child of the overlap.
|
|
427
456
|
|
|
428
457
|
```
|
|
429
|
-
|
|
430
|
-
|
|
458
|
+
node phases "" layout: venn
|
|
459
|
+
node phases.design "Design time"
|
|
460
|
+
node phases.both ""
|
|
461
|
+
node phases.runtime "Runtime"
|
|
431
462
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
edge a <-> b // one at each end
|
|
436
|
-
edge a -- b // a plain line
|
|
463
|
+
node phases.design.editor "Editor"
|
|
464
|
+
node phases.both.template "PDF template"
|
|
465
|
+
node phases.runtime.python "Python Lib"
|
|
437
466
|
```
|
|
438
467
|
|
|
439
|
-
|
|
468
|
+
Each set wraps its own children and the overlap's, and the two cross over the overlap. Inside each part, children are placed by hand as in any container, against their own siblings. Nothing lines boxes up across parts unless you say so: a part's anchor may be placed against a box in another part, up and down only, and its whole part moves to keep it there. `node phases.runtime.python "Python Lib" even with phases.both.template` puts Python Lib level with the template, whatever else Runtime holds. Otherwise a shorter set is centered on the taller; `layout: venn (align-children: top)` (or `bottom`) lines the two sets up by their tops instead, as a row lines up its children. The same can be said on a set, `top even with phases.design` (or `bottom even with`) naming the other, which is the only placement a part may have; saying it both ways is refused. Either set may carry it, and either form is refused only when boxes placed across parts already decide where the sets sit. `layout: venn (heights: equal)` gives both sets the same top and bottom, each reaching as far as the other.
|
|
440
469
|
|
|
441
|
-
|
|
470
|
+
A set may also sit a distance lower or higher than the other: `top even with 6 below phases.design top` (or `bottom even with 2 above phases.design bottom`), the other set's same side moved, as any side can be. With `heights: equal` the two are then the same height, staggered by that much. When something inside the set is placed across parts, such as Python Lib `even with phases.both.template`, that decides where the contents go and the stagger places only the set's box, which still has to hold them; one that would cut into them is refused with how far. Across, each crossing border sits the set's padding from what is inside it and a normal gap from what is outside it; `layout: venn (gap: wide)` widens that gap, to make room for a line's text between parts.
|
|
442
471
|
|
|
443
|
-
The
|
|
472
|
+
The overlap has no border of its own. Its title follows every container's rule: drawn if it has one, nothing for `""`, and it sits centered at the top of the strip. The venn itself draws no box unless it states a fill or border. Each part gets a different fill unless it states one: the left set the theme's primary-subtle, the right its secondary-subtle, and the overlap the two laid over each other. A venn's sets crossing, and what is in the overlap sitting inside both, is never reported.
|
|
444
473
|
|
|
445
|
-
|
|
446
|
-
|---|---|---|
|
|
447
|
-
| `arrow` | a filled arrowhead | `>` at the right end, `<` at the left |
|
|
448
|
-
| `oarrow` | an outlined arrowhead | `\|>` at the right end, `<\|` at the left |
|
|
449
|
-
| `dot` | a filled circle | `*` |
|
|
450
|
-
| `odot` | an outlined circle | `o` |
|
|
451
|
-
| `diamond` | a filled diamond | |
|
|
452
|
-
| `odiamond` | an outlined diamond | |
|
|
453
|
-
| `bar` | a stroke across the line | `\|` |
|
|
454
|
-
| `none` | nothing | |
|
|
474
|
+
### A stack of cards: `layout: deck`
|
|
455
475
|
|
|
456
|
-
|
|
476
|
+
A stack of cards says "there are several of these and they are the same". `layout: deck` stacks its children, the first in front and each next one a step up and to the left behind it. When the cards are only texts, `cards:` lists them, front first:
|
|
457
477
|
|
|
458
478
|
```
|
|
459
|
-
|
|
460
|
-
edge a odot--arrow b
|
|
461
|
-
edge a (odot)--(arrow) b
|
|
462
|
-
edge a [odot] -- [arrow] b
|
|
479
|
+
node drives "" layout: deck cards: "Drive 1" "Drive 2" "Drive 3"
|
|
463
480
|
```
|
|
464
481
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
**Marks as attributes.** `from-mark:` and `to-mark:` say the same thing, one end at a time, and they are how a style carries marks:
|
|
482
|
+
That is the same as writing each card as a child, which is how a card that holds anything is written, and then every card is, front first; `cards:` beside cards written out is refused, quoting them:
|
|
468
483
|
|
|
469
484
|
```
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
485
|
+
node drives "" layout: deck
|
|
486
|
+
node drives.1 "Drive 1" layout: column
|
|
487
|
+
node drives.1.backup "backup"
|
|
488
|
+
node drives.2 "Drive 2"
|
|
489
|
+
node drives.3 "Drive 3"
|
|
473
490
|
```
|
|
474
491
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
**A mark written in the arrow is final.** The edge's own `to-mark:` may repeat it but not contradict it — `edge a --> b to-mark: dot` is an error, since both halves are on one line and one of them would be dead text. A style fills only the ends the arrow leaves open: a style giving every end a `bar`, applied to `a --> b`, draws a bar at `a` and still the arrow at `b`.
|
|
478
|
-
|
|
479
|
-
Endpoints may be nested (`desktop1.files`). An edge never says where a node goes and routing is the renderer's problem, with one exception: an edge with text claims room in the gap it crosses, which is the next section.
|
|
492
|
+
`cards:` names them `drives.1`, `drives.2` and on, so a line or a placement can name one card: `edge laptop -> drives.1` ends on the front card. `drives` itself is the whole stack: something placed beside, above or `even with` it measures from the stack, and a line to it ends on the stack's edge. Every card is as big as the biggest, a stated size included, and takes the front card's colors unless it states its own. A card's text sits at its top left, where it shows above the card in front, unless it says where. A card places nothing itself; the deck places it.
|
|
480
493
|
|
|
481
|
-
|
|
494
|
+
The deck draws nothing of its own: no outline, and nothing round its cards. A `fill:` or `border:` on it draws an outline, a padding away from the cards. Its title follows every container's rule, so it is titled with its name unless it says `""`, and it goes above the stack, centered across it, unless it says where. Cards stacked on each other are never reported as overlapping.
|
|
482
495
|
|
|
483
|
-
###
|
|
496
|
+
### Where the children sit
|
|
484
497
|
|
|
485
|
-
|
|
498
|
+
`gather-children:` on the box says where the group of its children sits when the box has spare room, from a stated size or a title wider than they are: against a side (`left`, `right`, `top`, `bottom`), in a corner (`top-left` and the others), or in the middle (`center`, the default). It works on any container, laid out or hand-placed; hand-placed children move as one piece.
|
|
486
499
|
|
|
487
500
|
```
|
|
488
|
-
node
|
|
489
|
-
node
|
|
490
|
-
|
|
501
|
+
node box "Services, gathered left" gather-children: left layout: column (align-children: right)
|
|
502
|
+
node box.a "a"
|
|
503
|
+
node box.b "a longer one"
|
|
491
504
|
```
|
|
492
505
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
Which gap the text lands in is derived, never stated. Two nodes clear of each other on exactly one axis have exactly one corridor between them, and that is the one that widens. It is judged where the nodes finally sit — after anything centered has been centered and anything overlapping pulled apart — and if widening a gap moves something that was centered on what moved, it is centered again. The same holds between the children of a node, however they are placed. Two sitting corner to corner have no single corridor, because the line runs diagonally through open space, so nothing is widened for them. The room is measured along the run: an edge traveling horizontally needs the text's width, one traveling vertically needs only its depth, so a long text across a vertical gap opens it by a single line and hangs out either side.
|
|
496
|
-
|
|
497
|
-
An edge with no text asks for nothing, since every gap is wide enough for an arrowhead. An edge carrying a `between` clause asks for nothing here either — its text rides in the channel it named rather than in the gap between its own two ends, and what that does *not* do yet is at the end of the next section but one.
|
|
506
|
+
That is a column with its right edges even, against the box's left side.
|
|
498
507
|
|
|
499
|
-
###
|
|
508
|
+
### A heading
|
|
500
509
|
|
|
501
|
-
|
|
510
|
+
A box may name one child as its heading, `heading: d1.head`, followed by the position words a title takes. The heading sits where the title would, the box makes room for it, and the other children are arranged under it. Use it for a group that is a title: an icon, a name and a version tag in a row.
|
|
502
511
|
|
|
503
512
|
```
|
|
504
|
-
|
|
513
|
+
node d1 heading: d1.head (inside top, align: left) layout: column
|
|
514
|
+
node d1.head "" shape: none layout: row (gap: tight)
|
|
515
|
+
node d1.head.icon icon: desktop
|
|
516
|
+
node d1.head.name "Desktop 1" (size: normal) shape: none
|
|
517
|
+
node d1.files "shared folder"
|
|
505
518
|
```
|
|
506
519
|
|
|
507
|
-
|
|
520
|
+
The heading child places nothing itself and isn't the anchor. Refused by name: a quoted text beside `heading:` (two headings), a heading that isn't a direct child, and a placement on the heading child.
|
|
508
521
|
|
|
509
|
-
|
|
522
|
+
### Joined to the text
|
|
510
523
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
#### Going round boxes
|
|
514
|
-
|
|
515
|
-
A line never passes through a box. It takes the shortest way between its ends that goes through none, leaving a named side heading straight out and arriving at one heading straight in, with as few turns as that length allows. When the direct line is clear, that is the line you get. When it is not, the line goes round whatever is in the way. A line you have steered with `between` or `below <node>` finds its way the same way, keeping to what you said as well.
|
|
524
|
+
`join-with: a` makes a node and `a` one unit for positioning. The node's placements still say where it sits against `a`; the join says the two move together wherever something places `a`.
|
|
516
525
|
|
|
517
526
|
```
|
|
518
|
-
node
|
|
519
|
-
node
|
|
520
|
-
node renderer "Renderer" right of resolver
|
|
521
|
-
edge parser -> renderer "test edge" from: left to: right
|
|
527
|
+
node tall "Top" height: 8
|
|
528
|
+
node tall.disk icon: disk 1 right of tall text top even with tall text join-with: tall text
|
|
522
529
|
```
|
|
523
530
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
The same rule covers every other case: sides at right angles where one faces away from the other end, two ends naming the same side with one node behind the other, a node back to itself, and a line with no side named that has a box between its ends. Each goes the shortest way round. An end with no side named leaves or arrives by whichever of its box's sides makes the way shortest.
|
|
527
|
-
|
|
528
|
-
Several lines along the same stretch take a lane each, side by side, instead of drawing on top of one another, nested so that none crosses another where it need not. Where one of them carries its text on that stretch, the others keep clear of the text as well as the line. The text rides on the line's longest straight piece that it does not land on a box from, and never changes which way the line goes.
|
|
531
|
+
A unit that includes a box's text is placed by the text's position words: on a leaf it is centered as a pair, on a container it takes the title's place. Joins chain. In a container whose title its side words place and which has an unplaced child, a child placed only against the text, or against what is joined to it, is joined without saying so: `node d1.nw "3" right of d1 text even with d1 text` goes with the title. The box then holds two groups nothing relates, each fully stated; if they land on each other, that is reported as an overlap. `a` must be something one of the node's placements is against, and must be its own container's text or a sibling. A node joined to the text may be placed only against the text and what is joined to it. A box whose every child is joined to its text draws as a leaf. `badge:` is the short form.
|
|
529
532
|
|
|
530
|
-
|
|
533
|
+
### Against its own parent
|
|
531
534
|
|
|
532
|
-
|
|
535
|
+
A child placed against its parent's side or corner, `inside server right` or `inside server top-left`, is placed against the finished box and never grows it. If it covers something, that is reported. To make the box hold something, place it relative to the other children. Something the box holds may not be placed against a thing on its own side or corner, since the box would then depend on itself; that is refused.
|
|
533
536
|
|
|
534
|
-
|
|
537
|
+
A title inside the border counts as content, so the box makes room for it. So does anything placed against the text. A title outside the border hangs off the box and doesn't count.
|
|
535
538
|
|
|
536
|
-
|
|
539
|
+
### Invisible containers
|
|
537
540
|
|
|
538
|
-
|
|
541
|
+
`shape: none` on a container draws no box: its edges are a tight bounding box round the children, with no padding, and anything outside can be placed against the group as one shape. Its text, if it has one, is a bare heading over the children. `node a "" shape: none` is a pure group.
|
|
539
542
|
|
|
540
543
|
```
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
+
node cluster "" shape: none
|
|
545
|
+
node cluster.hub "Cloud sync"
|
|
546
|
+
node cluster.desktop1 "Desktop 1" above-left of cluster.hub (gap: tight)
|
|
547
|
+
node cluster.laptop1 "Laptop 1" below-left of cluster.hub (gap: tight)
|
|
544
548
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
Which edge takes the outer lane is derived where the diagram says anything: two edges pointing opposite ways each keep to one side of their own run, so a reciprocal pair reads as a circulation and re-ordering the two lines changes nothing. Edges pointing the *same* way give the tool nothing to read, and there the order you wrote them in is what decides.
|
|
549
|
+
node server "Home Server" left of cluster (gap: wide)
|
|
550
|
+
```
|
|
548
551
|
|
|
549
|
-
|
|
552
|
+
`server` clears the whole cluster. Placed `left of cluster.hub`, it would only clear the hub. A [guide](#guides) node does the same and can be shown while you work.
|
|
550
553
|
|
|
551
|
-
|
|
554
|
+
## Sizes
|
|
552
555
|
|
|
553
|
-
|
|
556
|
+
A box is sized from its contents unless a size is stated, with `width:` and `height:`. A stated size is a measurement, or two pinned edges ([Each axis is stated once](#each-axis-is-stated-once)).
|
|
554
557
|
|
|
555
|
-
|
|
558
|
+
- **A number**, in the file's unit: `width: 30`.
|
|
559
|
+
- **Another box's measurement**: `height: group height`, or `height: group` for the same dimension. A box's own other dimension is the bare word: `height: 0.75 width`.
|
|
560
|
+
- **Scaled and added**: `height: 0.5 group height`, `height: a + b + c`, `height: group + 2`, `height: 1.25 (a + b + c)`. Multiplication before addition; parentheses only group. `*` is refused, pointing to the bare form.
|
|
561
|
+
- **The larger or smaller of two**: `height: larger of a and b`, `smaller of a and b`.
|
|
562
|
+
- **A span**: `height: a top to c bottom`.
|
|
563
|
+
- **Limits**, each its own key: `min-width:`, `max-width:`, `min-height:`, `max-height:`.
|
|
556
564
|
|
|
557
565
|
```
|
|
558
|
-
node
|
|
559
|
-
node
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
566
|
+
node menu "Menu" layout: column
|
|
567
|
+
node menu.a "Home"
|
|
568
|
+
node menu.b "Settings"
|
|
569
|
+
node menu.c "Sign out"
|
|
570
|
+
node panel "Content" right of menu height: menu width: 2 menu width
|
|
563
571
|
```
|
|
564
572
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
Lane order follows the rule above: opposite-pointing edges keep to their own side of the run, same-pointing ones fall back to the order you wrote them in. A lone edge is in no group and is untouched, and naming a side on either end takes an edge out of the group, since it then has a side of its own to be spread along.
|
|
568
|
-
|
|
569
|
-
Lanes are as wide as the texts riding in them, as with named sides — so two edges between the same two nodes come apart far enough for their captions to clear.
|
|
570
|
-
|
|
571
|
-
Past a point they cannot: every line still has to attach on the same two sides, and those are only as tall as the nodes. When the group wants more room than the edges can give, the attachments squeeze evenly to fit and each line makes up the shortfall in the middle, bowing across its own run by exactly what its ends could not give it. The texts ride at the midpoints, so they still come apart even though the arrowheads crowd together. The innermost line has no shortfall and stays straight, which is what every group small enough for its nodes looks like.
|
|
573
|
+
`group.height` is refused, since the dot names a child. A bracket of limits, `height: group (at most: 30)`, is refused, pointing to `max-height:`. A text that needs more room than a stated size gives is drawn as it is and reported as `text-overflow`; nothing grows a box to fit its text once its size is stated.
|
|
572
574
|
|
|
573
|
-
|
|
575
|
+
## A node's text
|
|
574
576
|
|
|
575
|
-
###
|
|
577
|
+
### Its bracket
|
|
576
578
|
|
|
577
|
-
|
|
579
|
+
Everything a text says about itself goes in brackets right after it:
|
|
578
580
|
|
|
579
581
|
```
|
|
580
|
-
|
|
582
|
+
node aside "Written nightly." (size: small, wrap: 30) shape: none
|
|
581
583
|
```
|
|
582
584
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
```
|
|
590
|
-
edge c -> d "threaded" between a and b vertically
|
|
591
|
-
```
|
|
585
|
+
| setting | takes |
|
|
586
|
+
|---|---|
|
|
587
|
+
| `color` | a color or a theme color |
|
|
588
|
+
| `size` | `small`, `normal` or `large`; a multiple of normal (`1.2`); or pixels (`16px`) |
|
|
589
|
+
| `wrap` | a count of characters to fold at, on top of ` / ` |
|
|
590
|
+
| `align` | how the text's own lines range: `left`, `center`, `right`, or where along a side for a title (below) |
|
|
592
591
|
|
|
593
|
-
`
|
|
592
|
+
`small` is 21/25 of normal and `large` the same step the other way. The names are preferred: bundled into a style, a size says *why* one text is smaller. `wrap:` is a character count, not a distance: it is how a text is made narrow and tall to sit beside something.
|
|
594
593
|
|
|
595
|
-
|
|
594
|
+
A style has no text of its own, so it hangs the bracket off a key: `style aside text: (size: small, color: theme-muted)`. On a node or an edge, `text:` is refused: the bracket goes after the text.
|
|
596
595
|
|
|
597
|
-
|
|
596
|
+
### Where it sits
|
|
598
597
|
|
|
599
|
-
A
|
|
598
|
+
A leaf's text is centered unless its bracket says otherwise. A container's title sits against a side, said with `inside`, `on` or `outside` and the side:
|
|
600
599
|
|
|
601
|
-
|
|
600
|
+
| written | the title sits |
|
|
601
|
+
|---|---|
|
|
602
|
+
| `(inside top)` | along the top inside the border; the default |
|
|
603
|
+
| `(on top)` | on the border line, breaking it, like a form's legend |
|
|
604
|
+
| `(outside top)` | just above the border |
|
|
605
|
+
| `(center)` | in the middle of the box, as a leaf's does |
|
|
602
606
|
|
|
603
|
-
`
|
|
607
|
+
`align:` then says where along the side, and how the title's own lines range: on a top or bottom side `left`, `center` (the default) or `right`; on a left or right side `top`, `center` or `bottom`. A word that doesn't fit the side is refused, listing the three that do. The same words work on a leaf with room to spare: `node t "A tall box" (inside top) height: 20`.
|
|
604
608
|
|
|
605
609
|
```
|
|
606
|
-
node
|
|
607
|
-
node
|
|
608
|
-
node
|
|
609
|
-
|
|
610
|
+
node hub "Hub" (inside top, align: left) layout: row
|
|
611
|
+
node hub.a
|
|
612
|
+
node hub.b
|
|
613
|
+
node legend "Legend" (on top) right of hub
|
|
614
|
+
node legend.a "solid: synced" shape: none
|
|
610
615
|
```
|
|
611
616
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
Write as many as you need, one for each node you have something to say about. The line meets them in the order they sit along its way, so no clause says an order:
|
|
617
|
+
**A title may be placed against the box's own children**, with any placement a child takes, the box implied: `(right even with r.d, top even with r.a)` puts the title in the top-right corner beside `r.a`, with no row of its own. A side word places the title across the side, and `align:` or a placement places it along; two words for one direction are refused. Opposite placements center the title between them, as they center a box: `(right of r.a left of r.b, even with r.a)` sits it in the middle of the gap the two leave. A direction nothing states takes the default, `inside top` and `align: center`.
|
|
615
618
|
|
|
616
619
|
```
|
|
617
|
-
node
|
|
618
|
-
node
|
|
619
|
-
|
|
620
|
+
node r "Deployment" (right even with r.d, top even with r.a)
|
|
621
|
+
node r.a "north-west"
|
|
622
|
+
node r.d "south-east" below-right of r.a
|
|
620
623
|
```
|
|
621
624
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
One clause may name several nodes, and it is not shorthand for several clauses. `below a and b` is below the box bounding both, so it covers the stretch between them too:
|
|
625
|
+
**`reads: up` and `reads: down`** turn a node's text a quarter turn, on a leaf or a title. A turned title on a left or right side takes a column one line wide rather than one word wide. The side and `align:` words still name directions on the page, so `(outside left, reads: up, align: top)` is a turned title against the upper end of the box's left side.
|
|
625
626
|
|
|
626
627
|
```
|
|
627
|
-
node
|
|
628
|
-
node
|
|
629
|
-
node
|
|
630
|
-
edge t1 -> t2 from: bottom to: bottom below t1 above peak below t2
|
|
628
|
+
node rack "Rack 1" (inside left, reads: up) layout: column
|
|
629
|
+
node rack.a "web-1"
|
|
630
|
+
node rack.b "web-2"
|
|
631
631
|
```
|
|
632
632
|
|
|
633
|
-
|
|
633
|
+
`at:` on a node's text is refused by name, quoting the side form, or for `at: center`, quoting `(center)` on a container and saying to write nothing on a leaf.
|
|
634
634
|
|
|
635
|
-
|
|
635
|
+
### Markup
|
|
636
|
+
|
|
637
|
+
A stretch of text can borrow a style's look:
|
|
636
638
|
|
|
637
639
|
```
|
|
638
|
-
|
|
639
|
-
node
|
|
640
|
-
node m "M" below n
|
|
641
|
-
node b "B" right of m (gap: 80)
|
|
642
|
-
edge a -> b left of n above m
|
|
640
|
+
style dim text: (color: theme-muted)
|
|
641
|
+
node files "shared folder / [dim]synced[/dim]"
|
|
643
642
|
```
|
|
644
643
|
|
|
645
|
-
|
|
644
|
+
The opener names a style, never a color, so the marked words borrow a meaning the file already has. A name no style answers to is refused, and so is a style that says nothing about text. The closer repeats the name, so a mismatched close is refused by name. Marks don't nest, and a mark may cross a line break. A bare `[` is an error; write `\[` for a literal one.
|
|
646
645
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
Clauses of one kind may sit on different legs. Here the line goes over P on the way out, down past N, and under M on the way in, turning twice:
|
|
646
|
+
## Lines
|
|
650
647
|
|
|
651
648
|
```
|
|
652
|
-
|
|
653
|
-
node p "P" right of a
|
|
654
|
-
node n "N" below p right of p
|
|
655
|
-
node m "M" below n right of n
|
|
656
|
-
node b "B" right of m
|
|
657
|
-
edge a -> b from: right to: bottom above p right of n below m
|
|
649
|
+
edge [<name>] <from> <arrow> <to> ["<text>" [(<text settings>)] ...] [<attribute>] ...
|
|
658
650
|
```
|
|
659
651
|
|
|
660
|
-
|
|
652
|
+
### The ends and their marks
|
|
661
653
|
|
|
662
|
-
|
|
654
|
+
```
|
|
655
|
+
edge a -> b // an arrow at b
|
|
656
|
+
edge a <- b // an arrow at a
|
|
657
|
+
edge a <-> b // one at each end
|
|
658
|
+
edge a -- b // a plain line
|
|
659
|
+
```
|
|
663
660
|
|
|
664
|
-
|
|
665
|
-
- **A crossing with no room.** Two clauses on opposite sides need a gap between their nodes to cross over in. Placed flush — `gap: 0` — there is none, and the error says to give the placement a gap or drop a clause. The gap is never opened for the line: you wrote how far apart those two are.
|
|
666
|
-
- **A node the line never passes.** `below z` on a line that never goes by Z says nothing.
|
|
667
|
-
- **No way keeps them all.** Where the clauses and the boxes between them leave no way through, the error names every clause.
|
|
668
|
-
- **`between` with a side.** An edge passing between two things already has a side of each.
|
|
669
|
-
- **A part of a node, or a gap.** A line passes a whole box, and passes it as close as reads clearly.
|
|
661
|
+
The arrow is a mark, a shaft, a mark. The shaft is `-` or `--`, and either mark may be left off. A mark is a word, or a glyph standing for one:
|
|
670
662
|
|
|
671
|
-
|
|
663
|
+
| mark | draws | glyph |
|
|
664
|
+
|---|---|---|
|
|
665
|
+
| `arrow` | a filled arrowhead | `>` on the right, `<` on the left |
|
|
666
|
+
| `oarrow` | an outlined arrowhead | `\|>` on the right, `<\|` on the left |
|
|
667
|
+
| `dot` | a filled circle | `*` |
|
|
668
|
+
| `odot` | an outlined circle | `o` |
|
|
669
|
+
| `diamond` | a filled diamond | |
|
|
670
|
+
| `odiamond` | an outlined diamond | |
|
|
671
|
+
| `bar` | a stroke across the line | `\|` |
|
|
672
|
+
| `none` | nothing | |
|
|
672
673
|
|
|
673
|
-
|
|
674
|
+
The `o` prefix means outlined. `o-->`, `odot--arrow`, `(odot)--(arrow)` and `[odot] -- [arrow]` are one picture. A mark must touch the shaft or be bracketed, since `edge a -- dot b` reads like a line to a node named `dot`.
|
|
674
675
|
|
|
675
|
-
|
|
676
|
+
`from-mark:` and `to-mark:` say the same one end at a time, which is how a style carries marks. **An end with nothing written is open, not empty**: a style may fill it, and `none` says "nothing here, whatever the style says". **A mark written in the arrow is final**: the line's own `to-mark:` may repeat it but not contradict it.
|
|
676
677
|
|
|
677
678
|
```
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
679
|
+
style inherits to-mark: oarrow
|
|
680
|
+
node animal
|
|
681
|
+
node dog below-left of animal
|
|
682
|
+
node cat below-right of animal
|
|
683
|
+
edge dog -- animal style: inherits
|
|
684
|
+
edge cat -- animal style: inherits
|
|
681
685
|
```
|
|
682
686
|
|
|
683
|
-
|
|
687
|
+
**Writing order decides which end is which, never the arrow.** `a <- b` draws what `b -> a` draws, but `a` is the subject: `from:` is always the first name's end and `to:` the second's, and a text's fractions count from the first name.
|
|
684
688
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
689
|
+
**A line may be named** by a word before its ends: `edge req client -> api`. Other lines can then end on it, pass along it, or be drawn behind it.
|
|
690
|
+
|
|
691
|
+
**Each end is one name**: a box, a line, or a named point or region. `from:` and `to:` say where on it. The word before the ends, if there is one, is always the line's name, so `edge req end -> client` is a line named `req` from `end` to `client`.
|
|
692
|
+
|
|
693
|
+
```
|
|
694
|
+
node c
|
|
695
|
+
node d right of c (gap: wide)
|
|
696
|
+
point a 2 below c bottom-center
|
|
697
|
+
point b 2 above d top-center
|
|
698
|
+
region pair c top-left to d bottom-right
|
|
699
|
+
guide edge rail a -> b
|
|
700
|
+
edge c -> d via: rail
|
|
701
|
+
edge pair -> a
|
|
702
|
+
```
|
|
693
703
|
|
|
694
|
-
**
|
|
704
|
+
**An end at a named point is exactly on it.** A point has no sides, so `from:` or `to:` on that end is refused; the line heads out toward its far end, along the axis facing it, as a side would. Several lines at one point meet there, and the arrowhead or dot sits on the point, as on another line. **An end at a region is an end at a box** the size of the region: sides, spreading and every `from:` and `to:` work as on a node.
|
|
695
705
|
|
|
696
|
-
|
|
697
|
-
- `square` goes up, then across into B — one right angle, because leaving upward and arriving from the left fixes which way it turns. A square line naming no sides picks them: boxes sharing a column join top to bottom, boxes sharing a row side to side, and otherwise the line goes across first, then down. An end naming no side, beside one that does, takes whichever side needs the fewest turns.
|
|
698
|
-
- `straight` is one straight piece from A's top to B's left, ignoring which way each faces. Given `below c` or `between a and b`, it bends where that clause puts a point it has to pass, and nowhere else.
|
|
706
|
+
### Where a line ends
|
|
699
707
|
|
|
700
|
-
|
|
708
|
+
`from:` and `to:` name a side: `edge a -> b from: right to: top`. The line heads straight out of that side, or straight into it. Where a side is needed and none is named, it is the side facing the other box: top and bottom for boxes sharing a stretch across, left and right for boxes sharing a stretch up and down, and for boxes placed diagonally the side the line between their centers crosses. A box and one inside it face each other with no side, so a line between them must name one.
|
|
701
709
|
|
|
702
|
-
**
|
|
710
|
+
**An end may name a point instead of a side.** `from: bottom-center` leaves from that one point, any of the nine; several ends naming one point meet there. A point along a side is written side first, then how far: `to: left 3/4 down`, `to: left 1/4 up`, `to: bottom 1/4 across`, `to: bottom 1/4 across from right`.
|
|
703
711
|
|
|
704
|
-
|
|
712
|
+
A square or curved line heading out of a bare corner takes whichever way gives fewer bends. To get the other, name the corner as part of a side (`from: bottom 1/1 across`), which sets the heading. Where both ways bend equally the line is refused, quoting both forms.
|
|
705
713
|
|
|
706
|
-
|
|
714
|
+
`from: center` aims from the box's center at the far end and starts where that aim crosses the outline, so the start slides round the box as the far end moves.
|
|
707
715
|
|
|
708
|
-
|
|
716
|
+
**An end may be even with another thing.** `from: right, even with cat1` is on the right side, level with `cat1`'s center; on a top or bottom side it is at `cat1`'s place across. The line heads straight out of the side, as with a bare side. The thing is anything a placement's `even with` takes: a box, a part of one (`even with cat1 top`), a fraction (`even with 3/4 down cat1`), a named point, or several (`even with a and b`, the middle of the region round them). Where that height misses the side, the end is refused, never bent. It already says where along the side, so a fraction or `, right of z` written with it is refused as saying it twice. With `straight right` it says where the line leaves from (below).
|
|
709
717
|
|
|
710
718
|
```
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
719
|
+
node bin height: 12
|
|
720
|
+
node a left of bin top even with bin
|
|
721
|
+
node b below a (gap: tight)
|
|
722
|
+
node engine right of bin even with bin height: 12
|
|
723
|
+
edge a -> bin straight right
|
|
724
|
+
edge b -> bin straight right
|
|
725
|
+
edge bin -> engine from: right, even with a to: left, even with a
|
|
726
|
+
edge bin -> engine from: right, even with b to: left, even with b
|
|
715
727
|
```
|
|
716
728
|
|
|
717
|
-
|
|
729
|
+
**Several ends on one side spread evenly**, ordered by where each far box sits along the side: on a top side, the line from the leftmost box takes the leftmost slot. A line states its own place among the others with `to: top, right of z` or `from: top, right of z`, where `z` is a named line on that side; on a left or right side the words are `above` and `below`. Places stated against each other form one chain, whatever order they are written in, and a loop of them is refused. Or the box lists the whole order once, in reading order, top to bottom on a left or right side and left to right on a top or bottom one:
|
|
718
730
|
|
|
719
731
|
```
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
732
|
+
node a right-edge-order: ae, ad, ac
|
|
733
|
+
edge ae a -> e from: right
|
|
734
|
+
edge ad a -> d from: right
|
|
735
|
+
edge ac a -> c from: right
|
|
723
736
|
```
|
|
724
737
|
|
|
725
|
-
|
|
738
|
+
The list names every line spreading on that side, so a line left off, a name that isn't there, a line stating its own place as well, or an end pinned on that side is refused. The keys are `top-edge-order:`, `bottom-edge-order:`, `left-edge-order:` and `right-edge-order:`, written on the node itself. An end pinned to a point, or even with something, splits the side, so the others spread on either side of it.
|
|
726
739
|
|
|
727
|
-
**
|
|
740
|
+
**An end may be on another line.** `edge audit -> req` ends on the line `req`, at its middle, and `to: at 1/3` a third of the way along it. An end may also start where another line meets the same box: on a line out of `api`, `from: req end` leaves from the point where `req` ends on `api`; naming a box the line doesn't start at is refused. Lines ending on lines must be drawable in some order, so a loop of them is refused.
|
|
728
741
|
|
|
729
|
-
|
|
742
|
+
**A line may go from a box back to itself**, as a loop round one of its sides: `edge job -> job from: left to: right via: job top line: (path: square)` leaves the left side, runs over the top and comes back into the right side. A straight line can't loop, so a line to itself without a square or curved path is refused, quoting this form.
|
|
730
743
|
|
|
731
|
-
|
|
732
|
-
|---|---|
|
|
733
|
-
| `inside` | wholly within, against that part |
|
|
734
|
-
| `outside` | wholly beyond it |
|
|
735
|
-
| `on` | centered on it, so a node on a corner straddles it |
|
|
744
|
+
**A line may leave straight one way and stop at what it meets.** `edge d1 -- bus straight down` ends where the line straight down from `d1`'s center meets `bus`. A miss is refused, never bent. This is also how a line runs level: `straight right` leaves at its own height. **`from:` may name another spot on the side it leaves from**, and the line leaves from there instead of the middle: `edge bin -> engine from: right 1/4 down straight right` runs level a quarter of the way down `bin`. A `from:` on any other side is refused, since the line couldn't leave it that way, and so is a `to:`, since `straight` already says where the line ends. The longer form names any box or named point or region: `to: down from z3`, or `from: left from bin` to take the height from the far end.
|
|
736
745
|
|
|
737
746
|
```
|
|
738
|
-
node
|
|
739
|
-
node
|
|
747
|
+
node bus "bus" width: 40
|
|
748
|
+
node d1 above bus (gap: wide)
|
|
749
|
+
node d2 right of d1 even with d1
|
|
750
|
+
edge d1 -- bus straight down
|
|
751
|
+
edge d2 -- bus straight down
|
|
740
752
|
```
|
|
741
753
|
|
|
742
|
-
|
|
754
|
+
### A line is straight until told
|
|
743
755
|
|
|
744
|
-
|
|
756
|
+
`edge a -> c` with nothing else said is one straight segment between the two boxes, clipped at their borders, through whatever is in between. **Nothing is avoided**: a line through a box it doesn't connect is drawn over it and reported as `edge-node-overlap`. Its shape and its waypoints are how the file says otherwise, and each has one fixed meaning that never looks at the rest of the diagram.
|
|
745
757
|
|
|
746
|
-
|
|
758
|
+
`line: (path: straight)` is the default; `square` and `curved` are opt-in.
|
|
747
759
|
|
|
748
|
-
**
|
|
760
|
+
**A square line's route is read off its own two boxes and sides.** It has one free leg, which runs halfway between the boxes. Where both ends face the same way, it runs a step-out beyond the farther side. Where the ends face away from each other, each steps out and the line crosses halfway between the boxes the other way; if the boxes overlap that way there is no gap to cross, so the line runs through both and the finding names the fix, `via: a top` or `via: a bottom`. At right angles it is one corner where it can be, and otherwise goes round.
|
|
749
761
|
|
|
750
|
-
|
|
762
|
+
- `turn: 1/3` in the line's bracket moves the free leg a third of the way across, from the start's box. Without it, halfway.
|
|
763
|
+
- `step-out:` is the short first and last leg, `normal` by default: `line: (path: square, step-out: tight)`.
|
|
751
764
|
|
|
752
|
-
|
|
765
|
+
**A curved line follows what the file states exactly, and between two stated things it is one free sweep.** Its ends, waypoints and runs along sides are kept as written; from one to the next it is a single curve that leaves the way the line travels there and arrives the way it travels at the next. Where nothing is stated it takes the short way, over a box if one is in it, and that is reported. `curve: strong`, `normal` or `subtle` says how widely it swings. `turn:` on a curved line is a stated thing: the line passes the point where the square line's free leg would be, so the sweep becomes two.
|
|
753
766
|
|
|
754
|
-
A
|
|
767
|
+
A `turn:` that places nothing on the line it is written on is refused; from a style or `default edge` it is ignored where it can't apply.
|
|
755
768
|
|
|
756
769
|
```
|
|
757
|
-
node
|
|
758
|
-
node
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
node stamp "!" on server top-right
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
`server` widens so `server.mark` sits against its right edge, held in by the padding, on the database's row. A side word straight after `inside`, `outside` or `on <node>` is always the part, so `right level with` here is not read as the right-edge alignment. `stamp` is not part of `server`, so nothing moves for it: it lies over the corner, half in and half out.
|
|
765
|
-
|
|
766
|
-
The title band is not something a node has; it is what happens when things stack below the text. Children that say nothing about where they go stack below the text in written order, as they always have, and that is what makes the band. A node whose children all sit beside its text or against its frame has nothing below its text, so it has no band and draws as a leaf — its text centered, and whatever is placed against the text centered with it as one group:
|
|
767
|
-
|
|
768
|
-
```
|
|
769
|
-
node hub "Cloud sync"
|
|
770
|
-
node hub.star "★" right of hub text
|
|
770
|
+
node a
|
|
771
|
+
node b below-right of a (gap: wide)
|
|
772
|
+
edge a -> b from: right to: left line: (path: square)
|
|
773
|
+
edge a -> b from: bottom to: top line: (path: curved)
|
|
771
774
|
```
|
|
772
775
|
|
|
773
|
-
|
|
776
|
+
### Waypoints
|
|
774
777
|
|
|
775
|
-
|
|
778
|
+
`via:` lists the places a line passes, in order:
|
|
776
779
|
|
|
777
780
|
```
|
|
778
|
-
node
|
|
779
|
-
node
|
|
780
|
-
node
|
|
781
|
-
|
|
782
|
-
node q.d "south-east" inside q bottom-right
|
|
781
|
+
node a
|
|
782
|
+
node b right of a
|
|
783
|
+
node c right of b
|
|
784
|
+
edge a -> c from: top to: top via: b top
|
|
783
785
|
```
|
|
784
786
|
|
|
785
|
-
A
|
|
787
|
+
- **A bare part means just outside it**, a `tight` gap away. `via: b top` runs along `b`'s top from end to end, nearer end first. `via: b top (gap: wide)` sets the distance; `via: on b top` is on the border and `via: inside b top` just inside it. `via: outside b top` is refused: outside is already what `via:` means.
|
|
788
|
+
- **A point is one spot**: `via: b top-center`, `via: server right 3/4 down`.
|
|
789
|
+
- **A box's name goes through its center**: `via: proxy`.
|
|
790
|
+
- **Any point**: `between c and d at 1/3`, `down from a and left from b`, a named point, `req at 1/3`.
|
|
791
|
+
- **Through a region**: `via: through slot horizontal` runs from the region's left edge to its right. The axis is always written.
|
|
792
|
+
- **Alongside a named leg**: `via: above thru (gap: tight)` runs the whole length of `thru`, a tight gap above it. The side is required.
|
|
786
793
|
|
|
787
|
-
|
|
794
|
+
On a square line, the stretch between each pair of neighboring stops is shaped as a line between two boxes is, with one free leg; `turn:` sets all of them. A curved line sweeps from stop to stop.
|
|
788
795
|
|
|
789
|
-
**A
|
|
796
|
+
**A point and a gap are different stops.** `via: between b.1 and b.2` is a point: the line goes exactly there. To cross a gap like a doorway, run through the pair's region: `region slot between b.1 and b.2`, then `via: through slot horizontal`.
|
|
790
797
|
|
|
791
|
-
|
|
798
|
+
Lines through one point pinch there; they are never spread on their own. `at 1/3` and `at 2/3` part them, or a [bundle](#bundles) runs them side by side.
|
|
792
799
|
|
|
793
|
-
|
|
794
|
-
node hub "hub"
|
|
795
|
-
node a "one" right of hub
|
|
796
|
-
node b "two" right of hub
|
|
797
|
-
node c "three" right of hub
|
|
798
|
-
```
|
|
800
|
+
### Legs
|
|
799
801
|
|
|
800
|
-
|
|
802
|
+
Legs are named in the `via:` list: `via: leg climb, leg over_b b top, leg descent` names the three legs of a line from `a` over `b` to `c`. A `leg` entry with a place names the run along it; one without names the stretch between its neighbors. A leg's own settings go in its bracket after its name, `leg out (path: square, turn: 1/3)`, and a stop's after the stop. Legs are never counted, so adding a stop renames nothing. `leg` is required, since a bare word in `via:` is a box.
|
|
801
803
|
|
|
802
|
-
|
|
804
|
+
### Points on a line
|
|
803
805
|
|
|
804
|
-
|
|
806
|
+
A line named `req` has parts. `req start` and `req end` are where it was written to start and end. `req at 1/3` is a third of the way along it, bends included. `req b top` is `req` where it runs along `b`'s top. A named leg works anywhere a line does: `climb at 1/3`. A reference that matches two runs is refused, pointing to a `leg` name.
|
|
805
807
|
|
|
806
|
-
|
|
808
|
+
### Copies fan out
|
|
807
809
|
|
|
808
|
-
|
|
810
|
+
Copies are lines with the same two boxes on the same sides, in either direction, with nothing stated about their path. Texts and colors don't count, so a request and its response are copies. Copies are drawn as one shape, each shifted sideways from it by a fixed step like lanes on a road, so they never cross. Straight copies with no side named run parallel, a `tight` gap apart, each end landing where its lane meets the border. A line whose landing is stated, such as `to: top, right of z`, is no longer a copy, which is how to override the fan.
|
|
809
811
|
|
|
810
812
|
```
|
|
811
|
-
node
|
|
813
|
+
node client
|
|
814
|
+
node api right of client (gap: wide)
|
|
815
|
+
edge client -> api "request"
|
|
816
|
+
edge api -> client "response"
|
|
812
817
|
```
|
|
813
818
|
|
|
814
|
-
|
|
819
|
+
### Bundles
|
|
815
820
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
`shape: none` starts one step smaller than a node's text, because an aside at the same size reads as a statement. That is a default, not a ceiling: say `(size: …)` and it does what you said.
|
|
819
|
-
|
|
820
|
-
## Decks
|
|
821
|
+
A bundle is a path several lines share. `bundle trunk via: through slot horizontal` is built like a line with no ends, and a member joins with `via: trunk`, running its whole length.
|
|
821
822
|
|
|
822
823
|
```
|
|
823
|
-
node
|
|
824
|
+
node app1 "App 1"
|
|
825
|
+
node app2 "App 2" below app1 (gap: wide)
|
|
826
|
+
node web "Web" right of app1 (gap: 12)
|
|
827
|
+
node db "DB" below web (gap: wide)
|
|
828
|
+
guide region slot between web and db
|
|
829
|
+
node hub right of slot (gap: 12)
|
|
830
|
+
bundle trunk via: through slot horizontal
|
|
831
|
+
edge app1 -> hub via: trunk
|
|
832
|
+
edge app2 -> hub via: trunk
|
|
824
833
|
```
|
|
825
834
|
|
|
826
|
-
|
|
835
|
+
The two lines meet the gap between Web and DB, run through it side by side, and leave it together into the hub.
|
|
827
836
|
|
|
828
|
-
|
|
837
|
+
Its arrangement is `layout:`:
|
|
829
838
|
|
|
830
|
-
|
|
839
|
+
| layout | draws |
|
|
840
|
+
|---|---|
|
|
841
|
+
| `parallel` (the default) | members side by side a gap apart, `tight` unless the bracket says, so adding one widens the strip |
|
|
842
|
+
| `collapsed` | a bus: members merge onto the path at its start and split at its end, and the shared stretch is drawn once |
|
|
843
|
+
| `fan` | only on a bundle between two boxes: one curve each, widest apart at the middle |
|
|
831
844
|
|
|
832
|
-
|
|
845
|
+
**A parallel bundle holds one order**, so members never cross inside it. Either the bundle states it, `order: y, z, x`, listing every member by name, or members take written order and one places itself with `via: trunk (after: z)` or `(before: z)`. The two don't mix.
|
|
833
846
|
|
|
834
|
-
|
|
835
|
-
|---|---|---|---|---|---|
|
|
836
|
-
| `style` | ✓ | ✓ | ✓ | ✓ | the named bundles to take appearance from, one or a list |
|
|
837
|
-
| `gap` | ✓ | ✓ | ✓ | | the default distance to whatever it is placed against |
|
|
838
|
-
| `overlap` | ✓ | ✓ | ✓ | | `allow`, to opt out of non-overlap |
|
|
839
|
-
| `contents` | ✓ | | | | how the children are sized and where the block of them sits, in brackets |
|
|
840
|
-
| `badge` | ✓ | | | | the picture beside the text |
|
|
841
|
-
| `deck` | ✓ | | | | offset copies behind the box, one quoted text each |
|
|
842
|
-
| `shape` | ✓ | | ✓ | | the outline the node is drawn with, `none` included |
|
|
843
|
-
| `icon` | | ✓ | | | the picture the node is drawn as |
|
|
844
|
-
| `from` `to` | | | | ✓ | which side the line leaves and arrives on |
|
|
845
|
-
| `from-mark` `to-mark` | | | | ✓ | what is drawn at each end — see "What is drawn at each end" |
|
|
846
|
-
| `fill` | ✓ | | | | color — see "A color names the part it colors" |
|
|
847
|
-
| `border` | ✓ | | | | color |
|
|
848
|
-
| `text` | ✓ | ✓ | ✓ | ✓ | the text's properties, in brackets — a style's form of what a node or an edge writes after its own words |
|
|
849
|
-
| `line` | | | | ✓ | color, or everything about the line in brackets — see "How the line is drawn" |
|
|
850
|
-
| `url` | ✓ | ✓ | ✓ | ✓ | a destination to open when the thing is clicked |
|
|
851
|
-
|
|
852
|
-
The `diagram` statement has a vocabulary of its own — `theme`, `background` and `text` — which is checked the same way. Writing `background:` on a node is an error that points at `fill:`, and `theme:` on one points at `diagram theme:`. A `default` takes a narrower list for each kind; see "Defaults".
|
|
847
|
+
**A bundle may name two boxes instead of a path**: `bundle calls a -> b layout: fan` is the direct way between them, for copies of one line. Members must join those two boxes; `from:`, `to:` and `path:` on a member are refused, since the bundle says where its lines land.
|
|
853
848
|
|
|
854
|
-
**A
|
|
849
|
+
**A bundle between two boxes can say how it gets there, as a line does**, with `from:`, `to:` and `line: (path: …)`, and `turn:` and `step-out:` in the same bracket:
|
|
855
850
|
|
|
856
851
|
```
|
|
857
|
-
|
|
852
|
+
node web "Web tier"
|
|
853
|
+
node ops "Ops" below web (gap: 6) right of web (gap: 4)
|
|
854
|
+
bundle logs web -> ops from: bottom to: top line: (path: square)
|
|
855
|
+
edge web -> ops via: logs
|
|
856
|
+
edge web -> ops via: logs
|
|
857
|
+
edge web -> ops via: logs
|
|
858
858
|
```
|
|
859
859
|
|
|
860
|
-
|
|
860
|
+
The bundle's middle is routed as one line from Web's bottom to Ops's top would be. Each member runs its own lane beside it and lands where its lane meets the box, so the three leave Web side by side and arrive at Ops the same way. Where a side is too short to take the lanes at their gap, they draw closer all the way. `from:` and `to:` name a side or a point on it; `layout: fan` keeps to the direct way and is refused with any of these.
|
|
861
861
|
|
|
862
|
-
|
|
862
|
+
A parallel bundle's path is drawn only with guides; a collapsed one is drawn, styled with the line's own keys. A member joining or leaving partway is not built.
|
|
863
863
|
|
|
864
|
-
|
|
864
|
+
### A line from each child
|
|
865
865
|
|
|
866
|
-
|
|
866
|
+
`edge each child of a -> b` is one line from each direct child of `a` into `b`, and stays true as children are added; `a -> each child of b` likewise. Both ends is refused: pairing the children of two containers has no order to go by.
|
|
867
867
|
|
|
868
|
-
|
|
869
|
-
node docs "Documentation" url: "https://example.com/docs"
|
|
870
|
-
edge docs -> store "read first" url: "https://example.com/order"
|
|
871
|
-
```
|
|
868
|
+
### Lines to several ends
|
|
872
869
|
|
|
873
|
-
`
|
|
870
|
+
`edge a -> b, c, d` is one line from `a` to each of `b`, `c` and `d`; `b, c and d -> a` likewise into `a`. Everything after the ends applies to every line, so `from: right-center` sends all three out of one point, to fan from there:
|
|
874
871
|
|
|
875
|
-
|
|
872
|
+
```
|
|
873
|
+
edge a -> b, c, d from: right-center to: left
|
|
874
|
+
```
|
|
876
875
|
|
|
877
|
-
|
|
876
|
+
Lines one statement draws share their way on purpose, so a stretch they share isn't reported as `edge-overlap`; three separate statements naming the same point are. A text is drawn once, on the line to the first name, so `"fan" (at: start)` labels the group where its lines leave together. A list on both ends is refused, for the same reason as `each child of` on both, and so is a name, which belongs to one line.
|
|
878
877
|
|
|
879
|
-
|
|
878
|
+
### Crossings
|
|
880
879
|
|
|
881
|
-
|
|
880
|
+
Where two lines cross, the later-written one is drawn on top and jumps the earlier: `crossing: gap` (the default, a short break), `arc`, `square` or `none`, on the later line. A line never jumps within reach of its own ends. Lines are drawn over boxes. [`depth:`](#drawing-order) changes either.
|
|
882
881
|
|
|
883
|
-
|
|
882
|
+
### The line's bracket
|
|
884
883
|
|
|
885
|
-
|
|
884
|
+
Everything about the line goes in its bracket, on an edge, a style or `default edge`:
|
|
886
885
|
|
|
887
886
|
```
|
|
888
|
-
|
|
887
|
+
edge web -> api line: (color: #d2904e, path: square, corners: rounded, thickness: thick)
|
|
889
888
|
```
|
|
890
889
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
890
|
+
| property | takes |
|
|
891
|
+
|---|---|
|
|
892
|
+
| `color` | a color |
|
|
893
|
+
| `path` | `straight` (the default), `square`, `curved` |
|
|
894
|
+
| `corners` | `sharp` (the default), `rounded`; wherever a line has corners |
|
|
895
|
+
| `crossing` | `gap` (the default), `arc`, `square`, `none` |
|
|
896
|
+
| `pattern` | `solid` (the default), `dashed`, `dotted`, `dash-dot`; measured in thicknesses |
|
|
897
|
+
| `thickness` | `thin`, `normal` (the default), `thick`, a multiple of normal, or pixels (`3px`) |
|
|
898
|
+
| `curve` | `strong`, `normal` (the default), `subtle`; curved lines only |
|
|
899
|
+
| `turn` | a fraction; square and curved lines only |
|
|
900
|
+
| `step-out` | a distance; square and curved lines only |
|
|
897
901
|
|
|
898
|
-
|
|
902
|
+
`line: red` is short for `line: (color: red)`. `line: square` is refused with the bracket it meant. `corners: rounded` on a curved line is refused; from a style it lands only on lines with corners. A thick line's arrowhead grows with it, and that changes only its own drawing.
|
|
899
903
|
|
|
900
|
-
|
|
904
|
+
## A line's text
|
|
901
905
|
|
|
902
906
|
```
|
|
903
|
-
|
|
904
|
-
node server "Server" border: red style: backup
|
|
907
|
+
edge user -> order "1" (at: start) "places" "many" (at: end)
|
|
905
908
|
```
|
|
906
909
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
**A thing may take several styles**, listed the way a placement lists its targets — commas and `and` both separate:
|
|
910
|
+
A line may carry several texts, one after another, each with its own bracket. **With nothing said, a text sits at the middle of its line**, on it, with the line broken behind it. Several unplaced texts spread evenly in written order (one at the middle, three at a quarter, a half and three quarters), and placed ones cut the line into stretches: an unplaced text spreads within the stretch between the placed texts written either side of it. So write a line's texts in the order they run along it.
|
|
910
911
|
|
|
911
|
-
|
|
912
|
-
node pump "Pump 3" style: equipment, critical and alarm
|
|
913
|
-
```
|
|
912
|
+
**Along the line:**
|
|
914
913
|
|
|
915
|
-
|
|
914
|
+
- `(at: 1/4)`: a fraction along the whole line, bends included, from the first name written.
|
|
915
|
+
- `(on: rise, at: 1/3)`: on one named leg, a fraction along it.
|
|
916
|
+
- `(on: longest level)`: on the line's longest piece that runs left to right, at its middle. The way to move a text off a corner. Refused on a line with no level piece.
|
|
917
|
+
- `(at: start)`, `(at: end)`: near an end, clear of its mark, however long the line is.
|
|
916
918
|
|
|
917
|
-
|
|
919
|
+
**By a box:**
|
|
918
920
|
|
|
919
|
-
|
|
921
|
+
- `(straight right from c)`: where a line straight right from `c`'s center first meets this line.
|
|
922
|
+
- `(above s1)`: just above `s1` and centered on it, as a box placed `above s1` would be, off the line if need be. A distance goes in front, as a box writes it: `(2 above s1)`. `below`, `left of` and `right of` likewise.
|
|
923
|
+
- `(above s1, on the line)`: stays on the line, where it first reaches that height. `gap:` sets how far above.
|
|
920
924
|
|
|
921
|
-
|
|
922
|
-
|---|---|---|
|
|
923
|
-
| `fill` | the area inside the outline | a node |
|
|
924
|
-
| `border` | the outline | a node |
|
|
925
|
-
| `text: (color: …)` | the text | every node, and an edge |
|
|
926
|
-
| `line` | the drawn line and the marks at its ends | an edge |
|
|
925
|
+
**Beside the line:** `(right of edge)`, `(left of edge)`, `(above edge)`, `(below edge)` move the text out the stated way until it is clear of the part of the line it landed on.
|
|
927
926
|
|
|
928
|
-
|
|
927
|
+
**Lined up with a box on one axis:** `(left even with a right)` puts the left edge of the patch behind the text at `a`'s right side, and leaves its height where it would otherwise sit; `(x even with mid1)` centers the text across on `mid1`. Any `even with` a box takes works, one per axis, and the other axis comes from the line. On a level stretch it slides the text along the line; on an upright one, it moves the text off the line sideways. With a relation that already says the same axis, such as `right of edge`, it is refused. Separate it from the bracket's next item with a comma.
|
|
929
928
|
|
|
930
|
-
|
|
929
|
+
**Which way it reads:** `reads: up` and `reads: down` turn it a quarter turn; `reads: along` takes the line's angle where it sits, never upside down.
|
|
931
930
|
|
|
932
|
-
|
|
931
|
+
`gap:` is the distance from the box for `at: start`, `at: end` and the box relations; `edge-gap:` the distance off the line for a text beside it. Each defaults to half a unit, written in the text's own bracket.
|
|
933
932
|
|
|
934
933
|
```
|
|
935
|
-
|
|
934
|
+
node a
|
|
935
|
+
node b right of a (gap: 16)
|
|
936
|
+
edge a -> b "1" (at: start) "calls" (above edge) "n" (at: end)
|
|
936
937
|
```
|
|
937
938
|
|
|
938
|
-
The
|
|
939
|
+
**The line is broken behind its text** by a patch the color of whatever is drawn under the text's middle: the page, a container's fill, or a region's tint over it. The text's bracket can say otherwise, in a box's words: `fill:` is the patch's color, `none` for no patch, and `padding:` the room it leaves round the text, all round. By default it reaches a little past the words either side and not at all above or below.
|
|
939
940
|
|
|
940
|
-
|
|
941
|
+
```
|
|
942
|
+
node a
|
|
943
|
+
node b right of a (gap: 16)
|
|
944
|
+
edge a -> b "beside" (above edge, fill: none) "boxed" (at: 3/4, fill: theme-fill, padding: 0.5)
|
|
945
|
+
```
|
|
941
946
|
|
|
942
|
-
|
|
947
|
+
**A text never moves anything.** The line is drawn first and each text is measured on it. Texts that overlap are drawn and reported as `text-overlap`. A line's text takes the line's color unless its bracket says otherwise. `align:` in a line text's bracket is refused, pointing to the placement words.
|
|
943
948
|
|
|
944
|
-
|
|
949
|
+
## Guides
|
|
950
|
+
|
|
951
|
+
`guide` as the first word makes a `node`, `edge`, `point` or `region` reference-only:
|
|
945
952
|
|
|
946
953
|
```
|
|
947
|
-
|
|
948
|
-
node
|
|
954
|
+
node a
|
|
955
|
+
node b right of a (gap: wide)
|
|
956
|
+
guide point funnel between a and b
|
|
957
|
+
guide region slot a top-left to b bottom-right
|
|
958
|
+
guide node column "" below a width: 10 height: 20
|
|
949
959
|
```
|
|
950
960
|
|
|
951
|
-
A
|
|
961
|
+
**A guide does everything its kind does except draw.** It places things, holds children, is placed against, and shapes the lines through it. A `guide node` container's children are drawn; only its box and title aren't. That gives a reserved empty space, a column to align against, or a group with no outline.
|
|
952
962
|
|
|
953
|
-
|
|
963
|
+
Guides are shown by whoever renders the file, not by the file: `--guides` on the command line, the Guides box in the playground. A file that explains its own construction, such as a tutorial, may say `diagram guides: show`. Shown guides are dashed, in the theme's secondary color, and unfilled. Their look changes per kind with `default guide node`, `default guide edge`, `default guide point` and `default guide region`; a bare `default guide` is refused, listing the four.
|
|
954
964
|
|
|
955
|
-
|
|
965
|
+
A container styled with no border is different: the same picture with guides hidden, but showing guides never reveals it. A guide box draws nothing, so it is left out of the overlap and overflow findings.
|
|
956
966
|
|
|
957
|
-
|
|
967
|
+
## Drawing order
|
|
958
968
|
|
|
959
|
-
|
|
969
|
+
The default order: a container before its own children, boxes before lines, an earlier line before a later one. A drawn region goes in front of every box except the ones it names, which it goes behind with everything inside them. Points are drawn last.
|
|
960
970
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
```
|
|
964
|
-
style synced fill: #142814 border: #486544
|
|
965
|
-
style dim text: (color: theme-muted)
|
|
966
|
-
node pc.files "shared folder / [dim]synced[/dim]" style: synced
|
|
967
|
-
```
|
|
971
|
+
`depth: behind b` or `depth: in front of req` moves one thing to just behind or in front of another, and moves nothing else. A leg's name limits it to the crossings on that leg. A box moves with everything inside it. A contradiction needs a cycle, and the cycle is in the file, so it is refused naming both statements: `depth: behind a, in front of a.api`, or two things each behind the other. A style may not carry `depth:`.
|
|
968
972
|
|
|
969
|
-
|
|
973
|
+
## Appearance
|
|
970
974
|
|
|
971
|
-
|
|
975
|
+
### A color names the part it colors
|
|
972
976
|
|
|
973
|
-
|
|
977
|
+
| key | colors | on |
|
|
978
|
+
|---|---|---|
|
|
979
|
+
| `fill` | the inside of the outline | a box |
|
|
980
|
+
| `border` | the outline | a box |
|
|
981
|
+
| `(color: …)` after a text | the text | any node, an edge; `text: (color: …)` in a style or default |
|
|
982
|
+
| `line` | the line and its end marks | an edge |
|
|
974
983
|
|
|
975
|
-
|
|
984
|
+
A key means one thing everywhere, so it can be wrong: `border:` on a node with no outline is refused, and the error lists what that kind has. A color is written as the viewer receives it: a hex value, any CSS color, or a theme color. There is no list of color words: `green` works because it is a CSS color. A quoted color is refused. `none` means the part isn't painted: `fill: none`.
|
|
976
985
|
|
|
977
|
-
|
|
978
|
-
diagram <attributes>
|
|
979
|
-
```
|
|
986
|
+
**Changing a color never moves anything.** Size is different: a bigger text or a thicker line takes more room.
|
|
980
987
|
|
|
981
|
-
|
|
988
|
+
### Styles
|
|
982
989
|
|
|
983
990
|
```
|
|
984
|
-
|
|
991
|
+
style backup border: #d2904e line: #d2904e
|
|
992
|
+
node mirror "shared folder / mirror" style: backup
|
|
993
|
+
node nas "NAS" right of mirror
|
|
994
|
+
edge mirror -> nas style: backup
|
|
985
995
|
```
|
|
986
996
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
- `theme` names the theme that supplies every color the file does not state. See "Themes" below.
|
|
990
|
-
- `background` takes a color the same way `fill` does, and it colors the page behind everything, including the strip an edge text knocks out of whatever it crosses. Say nothing and the theme's own background stands.
|
|
991
|
-
- `text: (color: …)` sets the color of every text, on nodes and edges alike. It takes a color and nothing else; a text size is about one kind of text and belongs on a `default`.
|
|
997
|
+
A style is a named bundle of appearance, worn with `style:`. Color carries meaning through the style's name rather than being written per thing. A style takes `fill`, `border`, `line`, `text`, `badge`, `icon`, `shape`, `from-mark`, `to-mark`, `padding`, `corners` and a region's `opacity`, and a title's position inside `text: (…)`: `style zone text: (outside top, align: left)`. It never says where a thing goes, so it can't carry a placement, a `gap:`, a `depth:`, or a line's `from:` or `to:`, and it can't carry a `url:` or a deck's `cards:`.
|
|
992
998
|
|
|
993
|
-
|
|
999
|
+
- **A style may span kinds.** It gives each thing only the keys that thing has, so the style above gives nodes their border and lines their color.
|
|
1000
|
+
- **A style must give a thing at least one key it has.** A style that dresses a thing in nothing is on the wrong thing.
|
|
1001
|
+
- **What the statement says beats any style**, wherever `style:` sits on the line. Between styles, the later wins: `style: equipment, critical and alarm` applies in that order.
|
|
1002
|
+
- **A key written twice on one statement is refused**, quoting both values: two words on one line are equally explicit. So is a setting twice in one bracket, `style:` twice, one style twice in a list, and a style name declared twice.
|
|
994
1003
|
|
|
995
1004
|
### Themes
|
|
996
1005
|
|
|
997
|
-
|
|
998
|
-
diagram theme: solarized-dark
|
|
999
|
-
```
|
|
1006
|
+
`diagram theme: nord` names a theme, which supplies every color the file doesn't state.
|
|
1000
1007
|
|
|
1001
1008
|
| theme | |
|
|
1002
1009
|
|---|---|
|
|
1003
|
-
| `dark` | the default
|
|
1010
|
+
| `dark` | the default |
|
|
1004
1011
|
| `light` | the same roles on a white page |
|
|
1005
1012
|
| `solarized-dark`, `solarized-light` | [Solarized](https://ethanschoonover.com/solarized/) |
|
|
1006
1013
|
| `gruvbox-dark`, `gruvbox-light` | [Gruvbox](https://github.com/morhetz/gruvbox) |
|
|
@@ -1011,17 +1018,13 @@ diagram theme: solarized-dark
|
|
|
1011
1018
|
| `high-contrast-dark`, `high-contrast-light` | no fills to lean on, every line at full strength |
|
|
1012
1019
|
| `print` | a white page, black lines and no fills, for paper |
|
|
1013
1020
|
|
|
1014
|
-
|
|
1021
|
+
Each borrowed palette is its scheme read as a diagram (a page, a box, a border, text, a line), not a copy; their licenses are in `NOTICE`. An unknown name is refused with the list. `--theme light` on the command line overrides the file's theme, so one source renders a light and a dark image.
|
|
1015
1022
|
|
|
1016
|
-
A theme
|
|
1017
|
-
|
|
1018
|
-
An unknown name is an error that lists the themes.
|
|
1023
|
+
A theme draws a container quieter than a leaf, keyed on having children. A box whose only children are its badge, its heading or things joined to its text draws as a leaf.
|
|
1019
1024
|
|
|
1020
1025
|
### Theme colors
|
|
1021
1026
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
The theme's own color for each part — what a box or a line gets when the file says nothing:
|
|
1027
|
+
A color you write stays that color under every theme. To follow the theme, name a theme color. Every theme defines the same set, all beginning `theme-`:
|
|
1025
1028
|
|
|
1026
1029
|
| color | is |
|
|
1027
1030
|
|---|---|
|
|
@@ -1031,13 +1034,8 @@ The theme's own color for each part — what a box or a line gets when the file
|
|
|
1031
1034
|
| `theme-fill` | a box's fill |
|
|
1032
1035
|
| `theme-border` | a box's outline |
|
|
1033
1036
|
| `theme-line` | a line |
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
| color | is |
|
|
1038
|
-
|---|---|
|
|
1039
|
-
| `theme-primary` | the theme's signature color — Dracula's purple, Solarized's blue |
|
|
1040
|
-
| `theme-primary-subtle` | the same mixed toward the page: dark on a dark theme, pale on a light one |
|
|
1037
|
+
| `theme-primary` | the theme's signature color |
|
|
1038
|
+
| `theme-primary-subtle` | the same, mixed toward the page |
|
|
1041
1039
|
| `theme-on-primary` | text that reads on a solid `theme-primary` |
|
|
1042
1040
|
| `theme-secondary`, `theme-secondary-subtle`, `theme-on-secondary` | the same for its second color |
|
|
1043
1041
|
|
|
@@ -1047,11 +1045,7 @@ style live fill: theme-primary
|
|
|
1047
1045
|
style dim text: (color: theme-muted)
|
|
1048
1046
|
```
|
|
1049
1047
|
|
|
1050
|
-
A
|
|
1051
|
-
|
|
1052
|
-
A `theme-` name the theme does not define is refused with the list above.
|
|
1053
|
-
|
|
1054
|
-
The command line can render a file in another theme without editing it — `reladraw arch.reladraw --theme light` — and the flag wins over the file's `theme:`. That is how one source becomes a light and a dark image for a README that shows whichever matches the reader's settings. The file's own `background:` and `text:` still win over the flag's theme, as a hand-written color wins over any theme.
|
|
1048
|
+
A box with a theme fill and no text color of its own gets text that reads on that fill, so `style live` needs no `text:`. A hand-picked fill gets no such help. A `theme-` name no theme defines is refused with the list.
|
|
1055
1049
|
|
|
1056
1050
|
### Defaults
|
|
1057
1051
|
|
|
@@ -1062,83 +1056,236 @@ default container fill: #1a2620 border: #2a3a30
|
|
|
1062
1056
|
default edge line: #7a8a99 text: (color: #9aa5b1, size: small)
|
|
1063
1057
|
```
|
|
1064
1058
|
|
|
1065
|
-
A default is a style
|
|
1059
|
+
A default is a style every thing of one kind wears without naming it: `node`, `leaf` (no children but those of its label), `container` (some), `edge`, and the four `default guide` kinds. The more specific word wins, all the way down: the theme, `diagram`, `default node`, `default leaf` or `default container` or `default edge`, the thing's styles in order, and what its own line says.
|
|
1060
|
+
|
|
1061
|
+
A container inside another container is filled a shade further from the page than the one it sits in, so the two read as two backdrops. An invisible container (`shape: none`) doesn't count, and a stated `fill:` wins as always.
|
|
1062
|
+
|
|
1063
|
+
A default takes the words a style does and may wear a style of its own (`default edge style: quiet`), laid beneath its own words. It is strict about kind, since it names its kind: `default edge fill: red` is refused, pointing to `line:`. `icon:` is a leaf's alone. A default carries no `url:`. Each kind is written once, and `default leaf node` is refused, naming `default leaf`.
|
|
1066
1064
|
|
|
1067
|
-
The
|
|
1065
|
+
### The diagram
|
|
1068
1066
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
4. `default leaf` or `default container`, or `default edge`
|
|
1073
|
-
5. the thing's styles, a later one winning where two set the same key
|
|
1074
|
-
6. what the thing's own line says
|
|
1067
|
+
```
|
|
1068
|
+
diagram theme: nord background: #1e2229 text: (color: #e0e0e0)
|
|
1069
|
+
```
|
|
1075
1070
|
|
|
1076
|
-
|
|
1071
|
+
`diagram` holds what covers the whole drawing: `theme`, `background` (the page behind everything), `text: (color: …)` for every text, `guides: show`, and `checks: (…)` ([Findings](#errors-and-findings)). It has no name, since a file holds one diagram, and a second one is an error. `diagram text:` takes a color only; a text size belongs on a default.
|
|
1077
1072
|
|
|
1078
|
-
|
|
1073
|
+
### Destinations
|
|
1079
1074
|
|
|
1080
|
-
|
|
1075
|
+
```
|
|
1076
|
+
node docs "Documentation" url: "https://example.com/docs"
|
|
1077
|
+
node store "Store" right of docs (gap: 12)
|
|
1078
|
+
edge docs -> store "read first" url: "https://example.com/order"
|
|
1079
|
+
```
|
|
1081
1080
|
|
|
1082
|
-
|
|
1081
|
+
`url:` makes a thing clickable in a viewer that follows links. The whole thing is the target: a node's box and everything in it, a line's text. The value is quoted, since an unquoted `//` starts a comment. Nothing about a destination is visible. A container's destination reaches children that name none. A line with no text is refused one, since a line is a target nobody can hit. A style may not carry one.
|
|
1083
1082
|
|
|
1084
|
-
|
|
1085
|
-
- **Guessing an axis nobody constrained.** When two placements bind one axis and nothing binds the other, the tool refuses rather than picking a target to center on. Choosing there would decide which row a node shares, not how far it sits from something.
|
|
1086
|
-
- **Placements that run in a circle.** A loop where each placement demands more room than the last cannot be satisfied and is an error naming the placements involved. A target does *not* have to be positioned before the node naming it — the whole system is solved at once — so ordinary mutual references are fine.
|
|
1087
|
-
- **Edge waypoints.** A point a line must pass through is a coordinate wearing a hat. Saying a line goes between two named things is not one — it names things the diagram already contains, and it survives those things moving.
|
|
1088
|
-
- **Choosing where a line goes when you said.** The tool finds its own way round a box in a line's way, but only as the shortest way through the open space, so where a line goes follows from where the boxes are. When you want a particular way instead, `between` and `below <node>` say it, and the tool keeps to what they say.
|
|
1089
|
-
- **Set-level placement.** Four siblings around a hub are four statements today. Whether a durable group that reflows when a member is added is worth the same-axis conflict it introduces is undecided.
|
|
1083
|
+
## Errors and findings
|
|
1090
1084
|
|
|
1091
|
-
|
|
1085
|
+
An **error** means the file can't be drawn: an unknown key, two placements on one axis, a cycle. Nothing is drawn, and the message names what to write instead. A **finding** is about a picture that was drawn and may not read as meant. A render with findings succeeds.
|
|
1092
1086
|
|
|
1093
|
-
|
|
1087
|
+
| kind | reports | default |
|
|
1088
|
+
|---|---|---|
|
|
1089
|
+
| `text-overlap` | a text on another text, on a line it doesn't belong to, or on a node it doesn't belong to; a text running out past the border of the container it sits in; a node over its container's title | on |
|
|
1090
|
+
| `text-overflow` | a text running out of a box whose stated size is too small for it | on |
|
|
1091
|
+
| `edge-node-overlap` | a line across a node that isn't one of its ends, or through its own ends | on |
|
|
1092
|
+
| `edge-overlap` | two lines on one run for a stretch, however short; a collapsed bundle's bus, and lines from one statement such as `edge a -> b, c`, shared on purpose, are not reported | on |
|
|
1093
|
+
| `crowded-edge-ends` | several line ends bunched on a side too short to space them: two ends' marks would touch, or, where neither has a mark, the lines come within a third of a unit | on |
|
|
1094
|
+
| `node-overlap` | two nodes on one spot that no layout, `inside`, `on` or `overlap: allow` accounts for | on |
|
|
1095
|
+
| `edge-no-length` | a line between two boxes that touch, drawn as its marks at the seam | on |
|
|
1096
|
+
| `edge-crossings` | two lines crossing | off |
|
|
1094
1097
|
|
|
1095
|
-
|
|
1098
|
+
A finding is one line, in the form editors already read:
|
|
1096
1099
|
|
|
1097
|
-
|
|
1100
|
+
```
|
|
1101
|
+
diagram.reladraw:12: warning(text-overlap): text "statements" covers the top-left corner of node resolver; the overlap is 3 units wide and 2 units tall
|
|
1102
|
+
```
|
|
1098
1103
|
|
|
1099
|
-
|
|
1104
|
+
The file and line of the statement at fault, `warning` in a fixed spot, the kind, then what happened, saying where and how much in the file's unit, so the fix is plain without the picture. A finding never chooses a fix, though it may list the ways to write one.
|
|
1100
1105
|
|
|
1101
|
-
|
|
1106
|
+
Kinds are turned on or off by name, in the file or on the command line: `diagram checks: (edge-crossings: on, crowded-edge-ends: off)`, or `--checks "edge-crossings: on"`. A kind not mentioned keeps its default. A deliberate overlap is stated on the thing itself (`overlap: allow`), not turned off for the whole file.
|
|
1102
1107
|
|
|
1103
|
-
|
|
1108
|
+
In the playground, where you are looking at the picture, checks run only when you press Check. The findings are listed under the diagram, apart from errors, and clicking one selects its line.
|
|
1104
1109
|
|
|
1105
|
-
|
|
1110
|
+
## The command line
|
|
1106
1111
|
|
|
1107
|
-
|
|
1112
|
+
```
|
|
1113
|
+
reladraw render diagram.reladraw -o diagram.svg
|
|
1114
|
+
reladraw check diagram.reladraw
|
|
1115
|
+
```
|
|
1108
1116
|
|
|
1109
|
-
|
|
1117
|
+
`render` draws the SVG and prints any findings. `check` does the same layout and prints only the findings, writing nothing, so an agent iterating leaves a good SVG alone. The bare `reladraw diagram.reladraw` is refused, pointing to `reladraw render`, and a mistyped command is reported with the near match.
|
|
1110
1118
|
|
|
1111
|
-
|
|
1119
|
+
| option | |
|
|
1120
|
+
|---|---|
|
|
1121
|
+
| `-o`, `--out` | where `render` writes; defaults to the input with `.svg`; `-` for standard output |
|
|
1122
|
+
| `--theme <name>` | render in another theme, whatever the file says |
|
|
1123
|
+
| `--guides` | draw the guides |
|
|
1124
|
+
| `--checks "<kind>: on, …"` | turn kinds of finding on or off, over the file |
|
|
1125
|
+
| `--no-checks` | print no findings; errors still print |
|
|
1126
|
+
| `-v`, `--version` | print the version |
|
|
1112
1127
|
|
|
1113
|
-
|
|
1128
|
+
The output is a standalone SVG: every picture is drawn into it as path data, never from a font or a linked file. A web page can draw a diagram in place with `<reladraw-diagram>`; see "In a web page" in the README.
|
|
1114
1129
|
|
|
1115
|
-
|
|
1130
|
+
## Attributes
|
|
1116
1131
|
|
|
1117
|
-
|
|
1132
|
+
Every attribute, and what takes one. A node's kind is what its body is: a box (`shape:`), a picture (`icon:`) or bare text (`shape: none`).
|
|
1118
1133
|
|
|
1119
|
-
|
|
1134
|
+
| attribute | box | picture | bare | line | says |
|
|
1135
|
+
|---|---|---|---|---|---|
|
|
1136
|
+
| `style` | ✓ | ✓ | ✓ | ✓ | the styles to wear, one or a list |
|
|
1137
|
+
| `shape` | ✓ | | ✓ | | the outline |
|
|
1138
|
+
| `icon` | | ✓ | | | the picture the node is drawn as |
|
|
1139
|
+
| `badge` | ✓ | | | | a picture joined to the text |
|
|
1140
|
+
| `cards` | ✓ | | | | a deck's cards, when they are only texts, front first |
|
|
1141
|
+
| `fill`, `border` | ✓ | | | | colors |
|
|
1142
|
+
| `corners` | ✓ | | | | `sharp` or `rounded`; not on a circle. A line's go in `line: (…)` |
|
|
1143
|
+
| `text` | ✓ | ✓ | ✓ | ✓ | in a style only; on a statement, the bracket after the text |
|
|
1144
|
+
| `layout` | ✓ | | ✓ | | how the children are arranged |
|
|
1145
|
+
| `gather-children` | ✓ | | ✓ | | where the children sit in spare room |
|
|
1146
|
+
| `heading` | ✓ | | ✓ | | the child that is the title |
|
|
1147
|
+
| `join-with` | ✓ | ✓ | ✓ | | the thing this moves with |
|
|
1148
|
+
| `padding` | ✓ | | ✓ | | room inside the edge |
|
|
1149
|
+
| `padding-top`, `-right`, `-bottom`, `-left` | ✓ | | ✓ | | one side's room, over `padding` |
|
|
1150
|
+
| `width`, `height`, `min-…`, `max-…` | ✓ | | ✓ | | a stated size |
|
|
1151
|
+
| `overlap` | ✓ | ✓ | ✓ | | `allow`: an overlap is meant |
|
|
1152
|
+
| `depth` | ✓ | ✓ | ✓ | ✓ | drawn behind or in front of something |
|
|
1153
|
+
| `url` | ✓ | ✓ | ✓ | ✓ | a destination |
|
|
1154
|
+
| `from`, `to` | | | | ✓ | where the line leaves and arrives |
|
|
1155
|
+
| `via` | | | | ✓ | the places it passes |
|
|
1156
|
+
| `from-mark`, `to-mark` | | | | ✓ | the marks at its ends |
|
|
1157
|
+
| `line` | | | | ✓ | its color, or everything about it in a bracket |
|
|
1158
|
+
|
|
1159
|
+
A point takes `style`, `fill` and `depth`; a region those, `opacity`, `border` and `padding`; a bundle `via`, `layout`, `order`, `line`, `from-mark` and `to-mark`.
|
|
1160
|
+
|
|
1161
|
+
**A word the table doesn't give the kind is an error.** A word that is an attribute nowhere is a misspelling, and the error lists what the kind takes. A word that is an attribute somewhere else is usually written on the wrong thing, so the error says where it belongs: `background:` on a node points at `fill:`, and `theme:` on one points at `diagram theme:`.
|
|
1120
1162
|
|
|
1121
|
-
|
|
1163
|
+
## What the language refuses
|
|
1122
1164
|
|
|
1123
|
-
|
|
1165
|
+
Deliberate omissions. What they protect is that the tool never *chooses* an arrangement: it computes the one you described.
|
|
1124
1166
|
|
|
1125
|
-
|
|
1167
|
+
- **Coordinates**, in any form. Every position is said relative to things the diagram contains, so it survives those things moving.
|
|
1168
|
+
- **Guessing.** An axis nobody stated, an order nobody gave, a direction to separate two boxes, a way round a box. Each is refused or drawn as written and reported, never decided.
|
|
1169
|
+
- **Avoiding.** A line goes where it is told and is reported where it crosses something. A box stays where it is placed and is reported where it overlaps.
|
|
1170
|
+
- **Synonyms.** One spelling for each thing, and the others refused by name.
|
|
1171
|
+
- **Silence.** An unknown key, an unknown icon, a word on the wrong kind of thing, a removed spelling: each is an error naming what to write instead.
|
|
1126
1172
|
|
|
1127
|
-
|
|
1173
|
+
Not on this list: saying more about where something goes. A statement that lets you be more precise is not a step toward auto-layout.
|
|
1128
1174
|
|
|
1129
|
-
|
|
1175
|
+
## Not built yet
|
|
1130
1176
|
|
|
1131
|
-
|
|
1177
|
+
Designed and absent from the code.
|
|
1132
1178
|
|
|
1133
|
-
|
|
1179
|
+
- **A line joining or leaving a bundle partway.**
|
|
1180
|
+
- **Several marks at one end of a line**, such as a database's crow's feet.
|
|
1181
|
+
- **Attributes, templates and functions**: definitions of your own that add placements, nodes and lines.
|
|
1134
1182
|
|
|
1135
|
-
|
|
1183
|
+
## Undecided
|
|
1136
1184
|
|
|
1137
|
-
|
|
1185
|
+
- `widths: match` on a hand-placed container, so "as wide as the widest of them" doesn't go stale.
|
|
1186
|
+
- A text in a heading starts small, as bare text does, so a hand-built heading needs `(size: normal)` on its text. Whether it should start at a box's size is open.
|
|
1187
|
+
- How a file sets its own unit.
|
|
1188
|
+
- Spreading one side's line ends over the whole side.
|
|
1189
|
+
- More layouts: `grid`, `star`, `circle`.
|
|
1190
|
+
- Which side "faces" for two boxes placed diagonally. Today it is the side the line between their centers crosses; always across first is the other reading.
|
|
1138
1191
|
|
|
1139
1192
|
## Changelog
|
|
1140
1193
|
|
|
1141
|
-
Pre-1.0, so the minor number is where a breaking change goes. Every removal
|
|
1194
|
+
Pre-1.0, so the minor number is where a breaking change goes. Every removal is refused by name with the replacement quoted, rather than dropped in silence: an older file stops with an error saying what to write instead.
|
|
1195
|
+
|
|
1196
|
+
**0.17.1**
|
|
1197
|
+
|
|
1198
|
+
- **`reladraw --version`**, or `-v`, prints the version.
|
|
1199
|
+
- **The playground waits for a pause in typing** before it redraws a diagram that is slow to draw, so the keystrokes aren't held up behind it. A quick one still redraws on every keystroke. Suggested in #6.
|
|
1200
|
+
|
|
1201
|
+
**0.17.0**
|
|
1202
|
+
|
|
1203
|
+
The redesign. The tool no longer decides anything the file doesn't say: a gap is exact, nothing moves a box to make room, lines are straight unless told and go only where they are told, and anything that may not read as meant is drawn as written and reported as a finding. Almost every diagram written for 0.16.0 needs changes; the table below gives each old spelling and what to write instead.
|
|
1204
|
+
|
|
1205
|
+
Breaking, in how things are drawn:
|
|
1206
|
+
|
|
1207
|
+
- **Gaps are exact.** A gap used to be a minimum that other things could widen. Now it is the distance, and nothing widens it.
|
|
1208
|
+
- **The gap words changed size**, and a number is in the file's unit, not pixels. `tight`, `normal` and `wide` were 24, 56 and 110 pixels; they are now 2, 4 and 8 units of 12 pixels (24, 48 and 96). `gap: 12` was 12 pixels and is now 144; write `12px`, or `1`.
|
|
1209
|
+
- **Nothing pushes overlapping boxes apart.** Two boxes placed on one spot are drawn there and reported as `node-overlap`.
|
|
1210
|
+
- **Identical placements no longer make a list.** Three nodes `right of hub` used to stack into a column; now they sit on one spot, reported. Put them in a container with `layout: column`.
|
|
1211
|
+
- **A container's unplaced children no longer stack.** A container needs `layout: column` or `row`, or exactly one unplaced child with the rest placed against it.
|
|
1212
|
+
- **A child placed against its parent's side no longer grows the parent.** It is placed against the finished box.
|
|
1213
|
+
- **Opposite placements no longer push their targets apart.** `right of a left of b` centers the box in the space already there.
|
|
1214
|
+
- **A line's text no longer makes room for itself**, and no longer slides off other texts. It sits at the middle of its line unless placed, and overlaps are reported.
|
|
1215
|
+
- **The patch behind a line's text takes the color beneath it**, such as a container's fill, where it was always the page's color and showed as a dark box on a tint. `fill:` in the text's bracket sets it, `none` for none.
|
|
1216
|
+
- **A deck is a container, `layout: deck`, and its cards are its children**, the front one first, so each card has a name and the deck is the whole stack. `node drive "Drive 1" deck: "Drive 2" "Drive 3"` is written `node drive "" layout: deck cards: "Drive 1" "Drive 2" "Drive 3"`, and a front card that holds things is written out with every card as a child. `deck:` is refused, quoting the new form.
|
|
1217
|
+
- **Lines are straight by default**, `path: straight`. They were curved. `default edge line: (path: curved)` keeps the old look.
|
|
1218
|
+
- **Lines no longer find their way round boxes.** A line goes straight, or square or curved along a route read off its own two boxes, and through anything in between, which is reported. `via:` says where it goes. Lines no longer take lanes from each other; copies of one line still fan.
|
|
1219
|
+
- **A line with no side named meets the side facing the other box.** It used to aim at the other box's center; `from: center` does that.
|
|
1220
|
+
- **A line out of a side flush against another box, or between two touching boxes, is drawn and reported**, where it used to be refused.
|
|
1221
|
+
- **A container's title is centered along its top.** It was at the top left; `(inside top, align: left)` keeps that.
|
|
1222
|
+
- **A container inside a container is a shade lighter** (darker on a light theme) than the one it sits in. It used to take the same fill, so only a faint border told them apart. `fill:` sets it as before.
|
|
1223
|
+
- **A badge is part of the label.** The text and its picture are placed as one unit, so a badged box with nothing else in it draws as a leaf, and `badge:` is allowed on `default leaf` and `default node`.
|
|
1224
|
+
- **A text's `size:` number and a line's `thickness:` number are multiples of normal.** `size: 22` used to be 22 pixels, and is now 22 times normal, with no error; write `size: 22px`. `thickness: 3` likewise; write `3px`.
|
|
1225
|
+
- **The command takes a verb**: `reladraw render diagram.reladraw`. The bare form is refused.
|
|
1226
|
+
|
|
1227
|
+
Breaking, in spelling:
|
|
1228
|
+
|
|
1229
|
+
| 0.16.0 | now |
|
|
1230
|
+
|---|---|
|
|
1231
|
+
| `level with a`, `top level with a` | `even with a`, `top even with a` |
|
|
1232
|
+
| `gap: wide` on a node | in the placement's bracket: `right of a (gap: wide)`, or `8 right of a` |
|
|
1233
|
+
| `contents: (widths: match, align: center)` | `layout: column (widths: match)`; `gather-children: center` for where the group sits |
|
|
1234
|
+
| `align:` in a layout's bracket | `align-children:` in the bracket, or `gather-children:` on the box |
|
|
1235
|
+
| `below of a`, `left a` | `below a`, `left of a` |
|
|
1236
|
+
| `edge a -> b between c and d` | `via: between c and d` |
|
|
1237
|
+
| `edge a -> b between c and d vertically` | `via: between c and d`, or `via: through r horizontal` through a named region |
|
|
1238
|
+
| `edge a -> b below c` | `via: c bottom` |
|
|
1239
|
+
| `edge a -> b above c`, `left of c`, `right of c` | `via: c top`, `via: c left`, `via: c right` |
|
|
1240
|
+
| `"Title" (at: top-left)` on a node | `(inside top, align: left)` |
|
|
1241
|
+
| `(at: center)` on a container's text | `(center)` |
|
|
1242
|
+
| `(at: …)` on a leaf's text | nothing; a leaf's text is centered, or `(inside top)` and the other sides |
|
|
1243
|
+
| `reladraw diagram.reladraw` | `reladraw render diagram.reladraw` |
|
|
1244
|
+
| `size: 22` | `size: 22px` |
|
|
1245
|
+
| `thickness: 3` | `thickness: 3px` |
|
|
1246
|
+
| `gap: 12` | `gap: 12px`, or `1` |
|
|
1247
|
+
| `from:` or `to:` in a style, which did nothing | on each edge: `edge a -> b from: right to: left` |
|
|
1248
|
+
| `node drive "Drive 1" deck: "Drive 2" "Drive 3"` | `node drive "" layout: deck cards: "Drive 1" "Drive 2" "Drive 3"`; a front card holding things is written as a child, `node drive.1 "Drive 1"`, and so is every card |
|
|
1249
|
+
|
|
1250
|
+
New:
|
|
1251
|
+
|
|
1252
|
+
- **Points and regions.** `between a and b`, `down from a and left from b`, `up from c and even with d top`, `2 below c bottom`, named with `point` and `region`, usable anywhere a position is.
|
|
1253
|
+
- **Waypoints.** `via:` lists the places a line passes: a side, a point, a box, a region, a leg of another line. Legs can be named.
|
|
1254
|
+
- **Square and curved routes** read off a line's own two boxes, with `turn:`, `step-out:` and `curve:`.
|
|
1255
|
+
- **Line ends at points**: `from: bottom-center`, `to: left 3/4 down`, `from: center`, an end on another line, `straight down`, and a line's place among others on a side, `to: top, right of z`.
|
|
1256
|
+
- **A line's end even with another thing**: `from: right, even with cat1` leaves the right side level with `cat1`, and heads straight out. Lines out of a tall box can each run level with a box beside it without working out fractions of its height. A height that misses the side is refused.
|
|
1257
|
+
- **Named lines** and points on them: `req start`, `req end`, `req at 1/3`.
|
|
1258
|
+
- **A line between points and regions**: `edge a -> b` where `a` and `b` are named points, regions or boxes, in any mix, guide lines included. A point end is exactly on the point; a region end is like a box's.
|
|
1259
|
+
- **Bundles**, parallel, collapsed or fanned, with a stated `order:`; a bundle between two boxes routed as a line is, `bundle logs web -> ops from: bottom to: top line: (path: square)`, its lines side by side the whole way; `edge each child of a -> b`, and lines to several ends, `edge a -> b, c, d`.
|
|
1260
|
+
- **Texts on lines placed** along the line, on a leg, on its longest level piece, by a box, or beside the line, and turned with `reads:`; the patch behind one takes `fill:` and `padding:`.
|
|
1261
|
+
- **A line from a box back to itself**, as a loop round a side: `edge job -> job from: left to: right via: job top line: (path: square)`.
|
|
1262
|
+
- **Placing across containers**: a child may be placed against a box outside its container, `node host.bin top even with cat0`, and a container whose children are placed that way, with none unplaced, goes where they put it.
|
|
1263
|
+
- **A direction beside a pin**: `below trx top even with cat0 bottom even with nice` keeps `below` for lining up under `trx` and checking it holds, and takes how far down from the pins.
|
|
1264
|
+
- **The order of the lines on a side, listed on the box**: `node a right-edge-order: ae, ad, ac`. A line's own `below ae` works on `from:` as on `to:`, and several form one chain whatever order they are written in.
|
|
1265
|
+
- **`straight` from a spot on its side**: `from: right 1/4 down straight right` leaves from that spot rather than the side's middle.
|
|
1266
|
+
- **A curved line runs straight under its arrowhead**, so it goes into the head along its axis instead of bending out of its side.
|
|
1267
|
+
- **The dark theme's `theme-secondary-subtle` is quieter**, `#311b1b` where it was `#460000`, mixed toward the page as every other theme's is; the deep red glared across a venn's whole set.
|
|
1268
|
+
- **One side's padding**: `padding-right: 4`, and `padding-top:`, `padding-bottom:`, `padding-left:`, over `padding:` on that side, on a box or a region.
|
|
1269
|
+
- **A text running out of its container is reported**, as `text-overlap`, naming the side and how far: a text never moves a border, so the room is the writer's to make.
|
|
1270
|
+
- **A venn's sets lined up by their tops or bottoms**: `layout: venn (align-children: top)`, or `top even with` on either set, which draws the same.
|
|
1271
|
+
- **A venn's set staggered**: `top even with 6 below phases.design top` sits it 6 units lower than the other set; with `heights: equal` the two stay the same height.
|
|
1272
|
+
- **`heights: equal` gives a venn's sets the same top and bottom**, where before the shorter grew about its middle, so with `align-children: top` its top rose out of line.
|
|
1273
|
+
- **A line's text lined up with a box on one axis**: `"a > b" (left even with a right)`, its other axis left where the line put it.
|
|
1274
|
+
- **A line's text placed by a box as a box would be**: `"ack" (2 above service)` centers the text over `service`, two units up, off the line if need be; `(above service, on the line)` keeps it on the line, where the line passes above `service`. Before, `(above service)` meant the second; a file that relies on that adds `, on the line`.
|
|
1275
|
+
- **The axis named in front of `even with`**: `x even with a` shares `a`'s middle across, on a box or a line's text; `y even with a` is the bare `even with a` said outright.
|
|
1276
|
+
- **Exact placement**: a distance in front (`2 right of a`), part against part (`center 12 right of a center`), two distances (`3 below and 2 right of a`), a fraction along a side (`right of server 3/4 down`), a fraction of a box (`top even with 3/4 down a`), and a part of the target (`top even with a bottom`).
|
|
1277
|
+
- **Sizes**: `width:`, `height:` and the four limits, from numbers, measurements of other boxes, sums, spans and `larger of`.
|
|
1278
|
+
- **Layouts**: `layout: column` and `row`, with `gap:`, `widths:`, `align-children:` and `centers:`; `gather-children:` on any container.
|
|
1279
|
+
- **Titles placed** against any side, inside, on or outside the border, or against the box's own children, centered between two with opposite placements, and turned with `reads:`; `heading:`; `join-with:`, which a child placed only against a title its side words place takes without saying so.
|
|
1280
|
+
- **A point's and a region's text**: `point mid "halfway" (above-right)`, `region trust "trust boundary" (inside top)`.
|
|
1281
|
+
- **A region's fill is drawn at half opacity**, stated or not, so overlapping regions show both; `opacity:` from `0` to `1.0` says otherwise.
|
|
1282
|
+
- **Invisible containers**: `shape: none` with children.
|
|
1283
|
+
- **Square-cornered boxes**: `corners: sharp` on a node, a style or a default draws a box's corners square, a document's too, fold aside. Boxes are still rounded unless told, so no existing diagram changes. A circle refuses it, having no corners.
|
|
1284
|
+
- **`padding:`** on a box or region.
|
|
1285
|
+
- **Guides**: `guide` before any node, line, point or region, shown with `--guides`, the playground's Guides box, or `diagram guides: show`.
|
|
1286
|
+
- **Drawing order**: `depth: behind a`, `depth: in front of a`.
|
|
1287
|
+
- **Findings**, eight kinds, printed one per line, with `reladraw check`, `checks:`, `--checks` and `--no-checks`. In the playground, a Check button lists them under the diagram.
|
|
1288
|
+
- **Numbers**: `px` on any number, a number starting at its decimal point (`.5`), and `size:` and `thickness:` as multiples.
|
|
1142
1289
|
|
|
1143
1290
|
**0.16.0**
|
|
1144
1291
|
|
|
@@ -1191,7 +1338,7 @@ No syntax changes, and no file that worked is refused.
|
|
|
1191
1338
|
One breaking change: on an edge written with `<-`, `from:` and `to:` now name the sides of the first and second names written. They used to follow the arrow, so `disk <- writer from: bottom` meant Writer's bottom; it now means Disk's. Swap the two on any `<-` edge that names a side. No other file draws differently.
|
|
1192
1339
|
|
|
1193
1340
|
- A line can have no arrowhead: `edge a -- b`, or `edge a - b`.
|
|
1194
|
-
- Each end of a line can carry a mark: an arrowhead filled or outlined, a dot, a diamond or a bar, written in the arrow (`a o--> b`, `a diamond--arrow b`) or as `from-mark:` and `to-mark:`, which a style can carry. See
|
|
1341
|
+
- Each end of a line can carry a mark: an arrowhead filled or outlined, a dot, a diamond or a bar, written in the arrow (`a o--> b`, `a diamond--arrow b`) or as `from-mark:` and `to-mark:`, which a style can carry. See [The ends and their marks](#the-ends-and-their-marks).
|
|
1195
1342
|
|
|
1196
1343
|
**0.13.0**
|
|
1197
1344
|
|
|
@@ -1211,22 +1358,22 @@ No syntax changes, and no file that worked is refused. Lines move: every line th
|
|
|
1211
1358
|
|
|
1212
1359
|
**0.11.0**
|
|
1213
1360
|
|
|
1214
|
-
- A line never passes through a box. Every edge takes the shortest way between its ends that goes through none, and goes round whatever is in its way, including edges that name no side. This replaces the separate rules for lines going over a row, turning back and going round a node behind, which kept missing cases; a fan of three from one side into a column was the latest.
|
|
1361
|
+
- A line never passes through a box. Every edge takes the shortest way between its ends that goes through none, and goes round whatever is in its way, including edges that name no side. This replaces the separate rules for lines going over a row, turning back and going round a node behind, which kept missing cases; a fan of three from one side into a column was the latest.
|
|
1215
1362
|
- Of two ways round that are equally short, the line goes over the top; otherwise the shorter way wins. It used to go over the top always.
|
|
1216
1363
|
- A curve finishes straight at an arrowhead, so the head points square into its side. Most diagrams with a named side look slightly different.
|
|
1217
|
-
- Where two lines cross, the later one now breaks for a short gap, as though it passed underneath. It used to draw straight across; `crossing: none` keeps that.
|
|
1364
|
+
- Where two lines cross, the later one now breaks for a short gap, as though it passed underneath. It used to draw straight across; `crossing: none` keeps that.
|
|
1218
1365
|
- Lines that turn down the same gap, such as two into one side of a box, take a lane each in the order that keeps them from crossing, instead of curving across each other.
|
|
1219
1366
|
- A line's text no longer lands on another line's text: where two would overlap, the later one slides along its own line to the nearest clear spot.
|
|
1220
1367
|
- **Breaking:** a line whose named side is flush against another box, with no way out, is refused with the reason. It used to be drawn through the box.
|
|
1221
1368
|
|
|
1222
1369
|
**0.10.0**
|
|
1223
1370
|
|
|
1224
|
-
- A statement may continue onto the lines after it by indenting them.
|
|
1371
|
+
- A statement may continue onto the lines after it by indenting them. An error in such a statement names the line the mistake is on.
|
|
1225
1372
|
- **Breaking:** indentation used to be ignored, so an indented `node` line was a statement of its own. It now continues the statement above and is refused, with a message saying to remove the indentation.
|
|
1226
1373
|
|
|
1227
1374
|
**0.9.0**
|
|
1228
1375
|
|
|
1229
|
-
- Theme colors: `theme-page`, `theme-text`, `theme-muted`, `theme-fill`, `theme-border` and `theme-line` name the theme's own color for each part, and `theme-primary` and `theme-secondary`, with `-subtle` and `theme-on-` forms, name its two accents. Any attribute that takes a color takes them, and they follow the theme when it changes, so a diagram colored with them reads in light and dark themes alike.
|
|
1376
|
+
- Theme colors: `theme-page`, `theme-text`, `theme-muted`, `theme-fill`, `theme-border` and `theme-line` name the theme's own color for each part, and `theme-primary` and `theme-secondary`, with `-subtle` and `theme-on-` forms, name its two accents. Any attribute that takes a color takes them, and they follow the theme when it changes, so a diagram colored with them reads in light and dark themes alike.
|
|
1230
1377
|
- A box with a theme fill and no text color of its own gets text that reads on that fill.
|
|
1231
1378
|
- **Breaking:** `muted` is now `theme-muted`. `color: muted` is refused with the new name.
|
|
1232
1379
|
- The examples use theme colors where they used to hand-pick colors for a dark page, so they read in every theme.
|
|
@@ -1268,6 +1415,7 @@ No syntax changes, and no file that worked is refused. Lines move: every line th
|
|
|
1268
1415
|
- **Breaking:** `deck` is an attribute of the node, not a statement. `deck drive "Drive 2" "Drive 3"` is written `deck: "Drive 2" "Drive 3"` on `node drive`, and the old statement is an error that quotes that line back. It is refused on a picture and on a `shape: none` node, where the statement used to draw nothing.
|
|
1269
1416
|
- **Breaking:** a key written twice on one statement is an error that quotes both values — `fill: red fill: blue`, `style:` twice, or the same property twice inside one set of brackets. In 0.3.0 one of the two was dropped in silence. A node's own word overriding its style's is unaffected.
|
|
1270
1417
|
- `style:` takes a list, `style: equipment, critical and alarm`, applied in order with a later style winning where two set the same key.
|
|
1418
|
+
|
|
1271
1419
|
**0.3.0** — the vocabulary, reworked in one breaking version so there is one migration rather than five.
|
|
1272
1420
|
|
|
1273
1421
|
- `box` is `node` and `link` is `edge`. The string on either is its *text*; "label" is not a word the language has.
|
|
@@ -1284,15 +1432,3 @@ No syntax changes, and no file that worked is refused. Lines move: every line th
|
|
|
1284
1432
|
**0.2.0** — `stroke:` split into the part it colors (`border:`, `line:`, and the text's own color); `width:` became `wrap:`; every attribute is refused by name on a kind that has no use for it, where an unknown one used to be parsed and dropped.
|
|
1285
1433
|
|
|
1286
1434
|
**0.1.0** — first published version.
|
|
1287
|
-
|
|
1288
|
-
## Undecided
|
|
1289
|
-
|
|
1290
|
-
Open questions the benchmark raised, recorded so a later session does not rediscover them.
|
|
1291
|
-
|
|
1292
|
-
- ~~One edge passing some nodes above or below and others left or right — an L-shaped line, across under one node and then down past another — is refused today.~~ Answered in 0.6.0: such an edge turns between the two kinds as few times as it can, and where two orders both fit, a standing rule picks — a side named at an end says which way the line goes first, and with none named it goes across first. Since 0.13.0, such a line takes whichever way keeps its clauses with the fewest turns, and the across-first rule no longer applies. See "Passing on one side of a node" above.
|
|
1293
|
-
- Named gaps are the first step toward numbers, but making them minimums took most of the pressure off: they now set how much a diagram breathes, never whether something fits. Whether four names is the right number is still open.
|
|
1294
|
-
- Four machines each holding a `files` child with the same text means writing the same line four times. This is the strongest case for a set-level declaration, for terseness rather than for placement.
|
|
1295
|
-
- The 2×2 arrangement around a hub is four independent statements, so a fifth machine has no slot to reflow into. There are only eight directions.
|
|
1296
|
-
- ~~Two annotations anchored to the same side of one node will collide.~~ Answered by putting both in an invisible container and placing the container, so they stack instead of stacking on top of each other. Writing it the colliding way is now an error rather than a bad picture, since nothing in the file orders the two. Whether the container idiom is good enough or wants dedicated syntax is open.
|
|
1297
|
-
- Nothing yet expresses one node spanning several rows of a parallel column, which the OSI reference render needs.
|
|
1298
|
-
- ~~How contents sit inside a container that is wider than they are.~~ Answered by `contents: (widths: …, align: …)` — see "How the contents sit". Automatic centering stays ruled out: it would move every existing diagram whose container title is wider than its contents. Whether this is the same question as the bracketed node sitting against one side of its slack, under "Known to be wrong", is still open — they share the phrase and not the mechanism, since one distributes to a group at size time and the other is a single member in a constraint system.
|