1. Mental Model
A Lini file is the body of an implicit root container: a stylesheet of setup first, then the drawn canvas instances and links in source order — and every statement is exactly one of the three:
| Part | Holds | Drawn? |
|---|---|---|
| stylesheet | one { } block: scene config (incl. link & routing defaults), rules, classes, defines | no — it styles |
| canvas | instances — boxes (|type#id|) and text ("…") | yes |
| links | a -> b connections | yes |
One character tells a statement’s kind — a leading | opens identity (a
node — or, when a link operator follows the closed capsule, a capsule-headed
link, SPEC 9), a " text, a bare name a link, and inside the
stylesheet a ./#/|…| opens a rule. The capsule is self-delimiting, so
one token after it still decides; no prescan, no ambiguity.
Two brackets, one capsule, three sigils — one meaning each (the table in
At a glance, SPEC 2): |…| is identity, the only place a
type lives; { … } is style, the only place declarations live; [ … ] is
content, in source order. A drawn node is
|type#id| "label" .class { style } [ children ], only the bars required; a link
is the same tail on a different head: a -> b "label" .class { style } [ labels ].
A name goes bare only when referenced, and the one thing you reference is an
id; types and classes are never linked, so they are always sigil-marked.
Boxes and text, like HTML. A box has identity, classes, a style block, and
children. A string is text content — a leaf with no identity or children, though
it may wear classes and carry a style block ("x" .quiet { color: red },
SPEC 3). A
string in a box’s [ ] (or trailing the head as its label) is that box’s text; on
its own it is a free-standing text node. To give text children, a border, padding,
a pin, or a wirable id, wrap it in a box (|block| is the minimal one) — exactly
like wrapping a web page’s text in an element.
The file is the root container. The stylesheet { } is the root’s own setup
block; the canvas instances are its children (written bare — the file is its
[ ]); the links are its internal links. Scene properties (layout, gap,
padding, fill, font-size, clearance, routing, …) sit in that block, alongside
rules like |-| { stroke: … } for link look; inheritable ones (font-*, color,
clearance, routing) cascade to every node and link.
Render order is source order; the cascade is whole-file. Instances draw in the
order written (later on top, pinned children above the flow; layer: overrides),
and every rule applies to every instance. Links need no declaration: naming an id
declared nowhere auto-creates it (SPEC 3).
Two kinds of variable. Visual values that don’t affect layout — colours and
the font family — stay live CSS variables (--lini-fill, --lini-accent, …), so a
host page can re-theme them; each colour carries a built-in dark variant following
the viewer’s OS or a data-theme toggle (SPEC 10).
Layout values — sizes, gaps, paddings, widths, and font size — bake into the
SVG as literals: text is measured at compile time, so its size can never be a
runtime var(), and a standalone SVG always looks right.