Links
You place the nodes; Lini routes the wires. A link is two ids and an operator, and the operator is the whole look.
The operator is the look
{
direction: column; gap: 14;
|row| { gap: 150; }
|box| { width: 60; padding: 6; font-size: 13; }
|-| { font-size: 12; }
}
|row| [ |box#a1| "a"; |box#b1| "b"; a1 -> b1 "->" ]
|row| [ |box#a2| "a"; |box#b2| "b"; a2 <-> b2 "<->" ]
|row| [ |box#a3| "a"; |box#b3| "b"; a3 --> b3 "-->" ]
|row| [ |box#a4| "a"; |box#b4| "b"; a4 ---> b4 "--->" ]
|row| [ |box#a5| "a"; |box#b5| "b"; a5 ~> b5 "~>" ]
|row| [ |box#a6| "a"; |box#b6| "b"; a6 *-* b6 "*-*" ]
|row| [ |box#a7| "a"; |box#b7| "b"; a7 -<> b7 "-<>" ]
|row| [ |box#a8| "a"; |box#b8| "b"; a8 - b8 "-" ]
An operator is [start marker][line][end marker], glued together with no
spaces. That is the whole grammar:
| Line | Marker | ||
|---|---|---|---|
- | solid | > | an arrow |
-- | dashed | * | a dot |
--- | dotted | <> | a diamond |
~ | wavy |
So --> is a dashed arrow, and *-* a solid line with a dot at each end. A
bare line op leaves both ends plain.
The ER cardinality markers ride the same scheme — Tables & entities shows them.
Labels ride the route
{
gap: 120;
|box| { fill: --purple-wash; stroke: --purple-deep; color: --purple-ink; }
}
|box#client| "Client"
|box#server| "Server"
|box#store| "Store"
client -> server "request"
server -> store { along: 0.25, 0.75; } [ "read" "write" ]
store --> client [ "rows" { color: --teal-ink; font-weight: bold; } ]
One label follows the head, and slides along the route to keep clear of nodes.
Several labels, or a styled one, ride the link’s own [ ] — and along: fixes
each as a fraction of the route, so 0.25, 0.75 puts them at the quarter and
three-quarter marks.
A label cuts its wire where it sits, so it reads over any background.
Chains and fans
{
gap: 60;
|box| { fill: --sky-wash; stroke: --sky-deep; color: --sky-ink; }
|cyl| { fill: --teal-wash; stroke: --teal-deep; color: --teal-ink; }
}
|box#lb| "LB" { fill: --rose-wash; stroke: --rose-deep; color: --rose-ink; }
|column#apps| { gap: 20; } [
|box#a| "app-1"
|box#b| "app-2"
|box#c| "app-3"
]
|cyl#db| "DB"
lb -> apps.a & apps.b & apps.c
apps.a & apps.b & apps.c -> db
a -> b -> c is a chain: two links, every hop marked.
& groups endpoints, and which side you group decides the shape:
lb -> a & b & cfans out.a & b & c -> dbfans in.- Both sides grouped is a cartesian product — every left to every right.
A fan shares its trunk wherever the geometry allows, which is what makes the two bundles above read as buses rather than as six separate wires.
Steering: sides, clearance and dotted paths
{ gap: 70; clearance: 20; }
|box#a| "a"
|box#b| "b"
|box#c| "c"
a -> b -> c
a:top -> c:top "skip"
c:bottom -> a:bottom "retry"
Without a side the router picks the edges by geometry. a:top forces one.
clearance is the gap a wire keeps from every node and every other wire. Set
it on a container and it cascades to the links written inside.
It shapes the drawing as well as spacing it: corners round to fit the clearance, and a parallel run steps aside so two wires never share a track.
Three routing strategies
{
gap: 40;
|group| { layout: grid; columns: repeat(2); gap: 44 60; padding: 24; }
|box| { fill: --amber-wash; stroke: --amber-deep; color: --amber-ink; }
}
|group#o| "orthogonal" [
|box#o1| "a"; |box#o2| "b"
|box#o3| "c"; |box#o4| "d"
o1 -> o4
o2 -> o3
]
|group#n| "natural" { routing: natural; } [
|box#n1| "a"; |box#n2| "b"
|box#n3| "c"; |box#n4| "d"
n1 -> n4
n2 -> n3
]
|group#s| "straight" { routing: straight; } [
|box#s1| "a"; |box#s2| "b"
|box#s3| "c"; |box#s4| "d"
s1 -> s4
s2 -> s3
]
routing: is scene config, like clearance:
orthogonal(the default) — horizontal and vertical legs through the free space between nodes.natural— smooth curves that bend around what they would hit, and are free to cross.straight— one segment between the bodies, avoiding nothing.
A group can route its internals one way while the root routes another, which is what the figure above is doing.
Styling a link
{
gap: 70;
|-| { stroke: --gray-deep; stroke-width: 1.5; font-size: 12; }
.hot { stroke: --red-deep; stroke-width: 2.5; color: --red-ink; }
}
|box#a| "a"
|box#b| "b"
|box#c| "c"
a -> b "cold"
b -> c "hot" .hot
A link is styled exactly like a node. stroke, stroke-width and
stroke-style dress the wire; color and the font-* family dress its labels.
The cascade is the same one too: |-| { } is the rule for every link, a class
applies to whichever nodes or links wear it, and a link’s own { } wins.
There is no separate link-* vocabulary to learn.
Go deeper
Links in the reference covers endpoints, scope and capsule endpoints; the full routing contract — priority, crossings, self-loops — is ROUTING.md.