reladraw 0.10.0 → 0.11.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 CHANGED
@@ -66,7 +66,7 @@ That gets you a copy of the skill at the time you run it, so you'll need to re-r
66
66
 
67
67
  ## Status
68
68
 
69
- Version 0.10.0. Early stage, but works. The parser, layout engine, and SVG renderer are written in TypeScript, with zero runtime dependencies. There is a command-line tool that turns a .reladraw text file into an SVG.
69
+ Version 0.11.1. Early stage, but works. The parser, layout engine, and SVG renderer are written in TypeScript, with zero runtime dependencies. There is a command-line tool that turns a .reladraw text file into an SVG.
70
70
 
71
71
  The language isn't stable yet, so expect the syntax to change.
72
72
 
package/SYNTAX.md CHANGED
@@ -1,4 +1,4 @@
1
- # Syntax reference — 0.10.0
1
+ # Syntax reference — 0.11.1
2
2
 
3
3
  What the language accepts. The parser, resolver and SVG renderer implement all of it; the sections at the end record what is defective, unchecked or undecided.
4
4
 
@@ -431,13 +431,15 @@ An edge with no text asks for nothing, since every gap is wide enough for an arr
431
431
  edge desktop1.files <-> hub from: right to: top
432
432
  ```
433
433
 
434
- That line leaves the right side of `desktop1.files` heading right, and arrives at the top of `hub` heading down. Naming a side is a statement about how the line should leave or arrive, so the edge is drawn as a curve that actually does. An edge naming neither side stays the straight center-to-center line it has always been. Either end may be named on its own; the unnamed one aims at wherever its partner ended up.
434
+ That line leaves the right side of `desktop1.files` heading right, and arrives at the top of `hub` heading down. Naming a side is a statement about how the line should leave or arrive, so the edge is drawn as a curve that actually does. An edge naming neither side is a straight line from center to center, unless a box is in the way (see "Going round boxes"). Either end may be named on its own; the unnamed one aims at wherever its partner ended up.
435
435
 
436
436
  You name a side and never a point on it. Alone on a side, an edge lands at its center. Sharing a side with other edges, the attachments space themselves apart, and which one goes where is derived from where the far ends actually sit — of two edges arriving at one top side, the one coming from further left arrives further left. Move a node and the order follows it. This is the same rule as nodes not overlapping: the tool separates things by default and reads the direction off the solved layout rather than asking you.
437
437
 
438
438
  The space it leaves is deliberately small, and shrinks further if the side is too short to hold the whole group. On a side short enough, it shrinks to nothing and the attachments coincide. Their texts still come apart, because the lines bow in the middle to make up what the side could not give them, but the arrowheads themselves land on one point and nothing warns you — so a small node with several edges arriving on one side is worth a look.
439
439
 
440
- #### Ends that face away from each other
440
+ #### Going round boxes
441
+
442
+ 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>` keeps to what you said instead.
441
443
 
442
444
  ```
443
445
  node parser "Parser"
@@ -446,17 +448,17 @@ node renderer "Renderer" right of resolver
446
448
  edge parser -> renderer "test edge" from: left to: right
447
449
  ```
448
450
 
449
- That line leaves Parser heading left and has to arrive at Renderer from the right, so it must turn back on itself somewhere. It turns back in the gap between its two nodes when there is one wide enough to hold the line and its text, and otherwise it goes over the top: out of its side, along the top of the row clear of the tallest node between its ends, and down into the far side. The text rides on that top stretch, so it never sits on a node. The same goes for `from: top to: bottom` in a column, which goes round the right, and for an edge from a node back to itself.
451
+ That line leaves Parser heading left and has to arrive at Renderer from the right, so it must turn back on itself somewhere. The shortest way is out of Parser's left, over the top of the row, and down into Renderer's right. Under the row would be exactly as long, and when two ways round tie, the line goes over the top, or round the right in a column. A node stepped down far enough leaves a gap between the two, and the line turns back through the gap, because that is shorter.
450
452
 
451
- Several such lines over the same row take a lane each, the shorter inside the longer, so they nest instead of drawing on top of one another.
453
+ 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.
452
454
 
453
- Sides at right angles can face away too. `from: left to: top` with the far node to the right leaves heading away from it, so the line steps out of the left, goes up past both nodes, runs along above them and comes straight down into the top. The side named at the far end says which way round: `to: bottom` takes it underneath instead.
455
+ Several lines along the same stretch take a lane each, side by side, instead of drawing on top of one another. 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.
454
456
 
455
- When the two nodes are stacked instead — `from: bottom to: left` into a node directly below — going out past both and coming straight in would pass through the lower node. There the line is one curve, bending round the corner into the side named. If even the curve would cross a node, the line goes round the node on the side it names, as `left of` that node would send it.
457
+ A curved line and a square one take the same way; the curved one sweeps its turns. At an arrowhead, the line always finishes straight, so the head points square into the side.
456
458
 
457
- Both ends can name the same side. `from: left to: left` with the far node to the right leaves heading away from it, and has to get round the node behind to reach the far side. It goes over the top, as the lines above do, and down into the gap; in a column, `from: bottom to: bottom` goes round the right.
459
+ When there is no way at all — the side you named is flush against another box — the file is refused with the reason: `edge a -> b: cannot leave a's right side, b is against it`.
458
460
 
459
- Over the top is the rule, not a guess the tool makes each time — it does not look for the shorter way round. To send the line underneath or round the left, say which side of a node it passes: `below resolver`. See "Passing on one side of a node".
461
+ To send a line round the other way, say which side of a node it passes: `below resolver`. See "Passing on one side of a node".
460
462
 
461
463
  #### Several edges between the same two sides
462
464
 
@@ -612,7 +614,7 @@ edge web -> api line: (color: #d2904e, thickness: thick, crossing: arc)
612
614
  | `color` | a color | as `line:` alone |
613
615
  | `path` | `curved` (the default), `square`, `straight` | how the line joins the points it has to meet |
614
616
  | `corners` | `sharp` (the default), `rounded` | how a square or straight line turns |
615
- | `crossing` | `none` (the default), `arc`, `gap`, `square` | how the line is drawn where it crosses an earlier one |
617
+ | `crossing` | `gap` (the default), `none`, `arc`, `square` | how the line is drawn where it crosses an earlier one |
616
618
  | `pattern` | `solid` (the default), `dashed`, `dotted`, `dash-dot` | |
617
619
  | `thickness` | `thin`, `normal` (the default), `thick`, or a number of pixels | |
618
620
 
@@ -624,7 +626,7 @@ edge web -> api line: (color: #d2904e, thickness: thick, crossing: arc)
624
626
 
625
627
  **Corners** apply wherever a line has them: every bend in a square line, and the bends a clause puts in a straight one. A curved line has none, so `corners: rounded` written on a curved edge is refused. From a style or a default it rounds the edges that have corners and leaves curved ones alone, as a style's `fill:` lands only on the things that have an inside.
626
628
 
627
- **A crossing is drawn on the later line**: the edge written further down the file jumps the one written above it. `arc` is a small half-circle hop, `square` a three-sided jump, and `gap` a short break in the later line, as though it passed underneath. A line never jumps within reach of its own ends, where two lines meeting at a box are not passing each other.
629
+ **A crossing is drawn on the later line**: the edge written further down the file jumps the one written above it. `gap`, the default, is a short break in the later line, as though it passed underneath; `arc` is a small half-circle hop, `square` a three-sided jump, and `none` draws the two lines straight across each other. A line never jumps within reach of its own ends, where two lines meeting at a box are not passing each other.
628
630
 
629
631
  **A pattern is measured in thicknesses**, so dashes keep their proportions on a thick line.
630
632
 
@@ -1009,7 +1011,7 @@ Deliberate omissions. What they protect is that the renderer never *chooses* an
1009
1011
  - **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.
1010
1012
  - **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.
1011
1013
  - **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.
1012
- - **Choosing a route.** The tool will not find its own way around an obstacle. A line that crosses something it should not is a line you have not yet said enough about, and `between` and `below <node>` are how you say it.
1014
+ - **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.
1013
1015
  - **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.
1014
1016
 
1015
1017
  Note what is *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, and the first version was short enough of them to render the benchmark wrong.
@@ -1060,12 +1062,26 @@ That one was found by testing the lexer, not by rendering — and it could not h
1060
1062
 
1061
1063
  ~~An edge text ignored the line break.~~ Fixed. ` / ` split a node's text and was never applied to an edge's, so the marker came out as a literal slash on an arrow and the benchmark's two-line captions had to be flattened to one. The measurer had always returned the split lines; the renderer was handing it the raw string and drawing that instead. The block now centers on the point the text already occupied, so a one-line text sits exactly where it did.
1062
1064
 
1063
- ~~An edge whose ends faced away from each other was drawn through its own nodes.~~ Fixed. `from: left to: right` with the far node further right was one curve bending out at both ends, and with the two nodes in a row it flattened into a straight line through both of them and anything between, its text landing on whatever was in the middle. It was not a matter of exact alignment: a node stepped down a little drew a tilted version of the same line. Such an edge now turns back in the gap between its nodes if there is room, and goes over the top of the row if not. See "Ends that face away from each other".
1065
+ ~~An edge whose ends faced away from each other was drawn through its own nodes.~~ Fixed. `from: left to: right` with the far node further right was one curve bending out at both ends, and with the two nodes in a row it flattened into a straight line through both of them and anything between, its text landing on whatever was in the middle. It was not a matter of exact alignment: a node stepped down a little drew a tilted version of the same line. Such an edge now turns back in the gap between its nodes if there is room, and goes over the top of the row if not. See "Going round boxes".
1064
1066
 
1065
1067
  ## Changelog
1066
1068
 
1067
1069
  Pre-1.0, so the minor number is where a breaking change goes. Every removal below 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.
1068
1070
 
1071
+ **0.11.1**
1072
+
1073
+ - Several diagrams inlined into one web page no longer lose their arrowheads. Every drawing used to name its arrowheads the same way, so a page took them all from the first drawing, and drew none when that drawing was hidden. The gaps where lines cross were named the same way, so a second drawing's lines were cut where the first drawing's crossed. Each drawing's names now carry a prefix of its own, taken from the drawing, so the same source still gives the same SVG.
1074
+
1075
+ **0.11.0**
1076
+
1077
+ - 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. See "Going round boxes".
1078
+ - 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.
1079
+ - A curve finishes straight at an arrowhead, so the head points square into its side. Most diagrams with a named side look slightly different.
1080
+ - 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. See "How the line is drawn".
1081
+ - 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.
1082
+ - 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.
1083
+ - **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.
1084
+
1069
1085
  **0.10.0**
1070
1086
 
1071
1087
  - A statement may continue onto the lines after it by indenting them. See "Shape of the file". An error in such a statement names the line the mistake is on.
@@ -1136,7 +1152,7 @@ Pre-1.0, so the minor number is where a breaking change goes. Every removal belo
1136
1152
 
1137
1153
  Open questions the benchmark raised, recorded so a later session does not rediscover them.
1138
1154
 
1139
- - 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. Often the picture leaves only one order for the two legs; where two orders both fit, the tool must not pick one, and whether it asks for another clause or follows a standing rule is not decided.
1155
+ - ~~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. See "Passing on one side of a node" above.
1140
1156
  - 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.
1141
1157
  - 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.
1142
1158
  - 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.
package/dist/ast.d.ts CHANGED
@@ -255,7 +255,7 @@ export declare const LINE_KEYS: readonly ["color", "path", "corners", "crossing"
255
255
  export declare const LINE_VALUES: {
256
256
  readonly path: readonly ["curved", "square", "straight"];
257
257
  readonly corners: readonly ["sharp", "rounded"];
258
- readonly crossing: readonly ["none", "arc", "gap", "square"];
258
+ readonly crossing: readonly ["gap", "none", "arc", "square"];
259
259
  readonly pattern: readonly ["solid", "dashed", "dotted", "dash-dot"];
260
260
  readonly thickness: readonly ["normal", "thin", "thick"];
261
261
  };
package/dist/ast.js CHANGED
@@ -236,7 +236,7 @@ export const LINE_KEYS = ['color', 'path', 'corners', 'crossing', 'pattern', 'th
236
236
  export const LINE_VALUES = {
237
237
  path: ['curved', 'square', 'straight'],
238
238
  corners: ['sharp', 'rounded'],
239
- crossing: ['none', 'arc', 'gap', 'square'],
239
+ crossing: ['gap', 'none', 'arc', 'square'],
240
240
  pattern: ['solid', 'dashed', 'dotted', 'dash-dot'],
241
241
  thickness: ['normal', 'thin', 'thick'],
242
242
  };