3. Statements & the Label

A file is a stylesheet, then drawn statements in source order (SPEC 1), and a container’s body nests the same idea: a { } style block, then a [ ] of children and internal links.

The stylesheet

One { } block at the very top of the file — optional, omitted when there is nothing to set up. Unlike an ordinary style block (declarations only), it is the root’s setup block, so it additionally holds the file-global definitions:

ItemFormMeans
Scene configlayout: grid; routing: orthogonal;a declaration on the root — clearance / routing cascade to every link (SPEC 9)
Variable--brand: #f60;a themeable visual variable (colour / font)
Bindingmy_r = 5; scale(n) = (…)a compile-time value / function, bound with = — read in any expression (SPEC 10)
Rule|box| { … }style every box (an element selector)
Link rule|-| { stroke: #666; }style every link — the |-| selector (SPEC 9)
Descendant rule|table| |box| { … }style every box inside a table
Class.hot { … }define class hot
Id rule#hero { … }style the one node with id hero
Define|treat::box| { … }a new type treat, base box, with its defaults
{
  gap: 16;  fill: --bg;
  --brand: #ff6600;
  scale(n) = (100 * 1.2^n);
  |box| { radius: 6; }
  |-| { stroke: #666; }
  .hot { stroke-width: 2; }
  |treat::box| { radius: 5; }
}

|treat::box| reads “treat is a box”; the :: sets a define apart from a plain reference (|box|) at a glance. Defines chain (|panel::treat|) and may carry intrinsic children (SPEC 9). Max inheritance depth 16; cycles are an error.

Node declaration

|type#id| [ "label" ] [ .class] [ { style } ] [ [ children ] ]

Only the bars are required — and at least a type or an #id must sit inside them. SPEC 1 names the parts; classes follow the bars (|box| .hot, |box| .hot.loud), never sit inside them.

|cyl#db| "Postgres" .primary { fill: #eef } [
  |badge| "v16"
]
FormEffect
|box#cat| ""same as |box#cat|"" is just an empty string.
|box| "Load balancer"anonymous labelled box (can’t be linked to).
|#cat|a default |box|, id cat.

The label

A node has no label unless you give it one — a bare |box#cat| is an empty box (the #cat is a handle, like HTML’s id=, not text):

LabelMeans
no string at allnothing — an empty box
"X"the label “X”
""an empty string — nothing in flow, an empty cell in a grid (SPEC 12)

A link to an undeclared name still draws a labelled box (Implicit nodes). A multi-word label needs no [ ] (|box#lb| "Load balancer").

The label is smart — each type places it, and every layout extends the same rule (a chart’s label is its title, a series’ its legend entry — SPEC 14), so no type needs a hand-written caption or symbol. Give no label and a type places nothing:

"X" onbecomes
|box| and the shapes (|oval|, |hex|, |cyl|, |diamond|, …)its centred text
|group| / |table|its caption (SPEC 8)
|icon| / |sign|its symbol|icon| "heart" is |icon| { symbol: heart }
a linka label along the route (SPEC 9)
a |chart| / series / |axis| / participant / frameits title / legend / axis title / header / guard (SPEC 13, SPEC 14)

The label takes no style of its own. The { } and classes after the head are the node’s, so a styled, classed, or nudged label rides the [ ] content form instead, where each string is a leaf in its own right (Text content):

|box#api| "API" .hot { fill: red }        // label + class + the node's own style
|box#api| [ "API" { translate: 0 -6 } ]   // a styled label, via content

The label and [ ] coexist — one inline label only (two or more strings go in the [ ]). The label is the node’s one inline item, lowered by its type — a text or caption child prepended to the [ ], or (for |icon|/|sign|) the symbol — and the [ ] holds the rest:

|group#kitchen| "Kitchen" [ |box#bowl| "Bowl" ]   // caption + a child
|icon| "bell" [ "3" ]                              // symbol + a text badge
Bowl Kitchen 3

Text content

A string is a text node — always a <text> leaf, never wrapped:

  • In a box’s [ ] (or as the box’s label) it is that box’s text — centred when it is the only in-flow child, else a flow child laid out by the box’s layout.
  • On its own (on the canvas, or in a [ ]) it is a free-standing flow / canvas text node.
  • Several strings are several text nodes — "a" "b" "c" is three (a string is self-delimiting, so no ; is needed between them).
  • An empty "" is suppressed (adds no text) — except as a grid cell, where it holds its track (SPEC 12).
  • Multi-line text uses \n (or wraps at max-widthSPEC 5); the box sizes to the widest line, with a font-size × 1.2 leading between lines (plus any line-spacing), lines aligned by the container’s packing knob (SPEC 6).

A string carries no children — text is a leaf, not a box — but where it is content (free-standing, or a child in a [ ]) it takes the node tail: it may wear classes and carry a style block of text properties — "Starter" .card-title, "X" { color: red; font-weight: bold; translate: 0 -6; rotate: 12 }. In its own block only text-valid properties apply (color / fill, every font-*, opacity, letter-spacing, line-spacing, text-transform, text-decoration, text-shadow, translate, rotate, layer); any other — pin, padding, width, a border, children, even href / hint — needs a real box, so wrap the text in a |block|. A worn class is looser, per the class law (SPEC 4): its text-valid declarations land, the rest are inert on the text wearer. Set on the string the style applies to it directly; set on a containing box it cascades down (SPEC 6).

Implicit nodes

A link endpoint that is a single bare id not present in the link’s scope auto-creates the node |box#cat| "cat" in that scope — a box named cat, labelled “cat” — so cat -> dog -> bird is a complete three-box diagram. The same holds inside a container body: a body link auto-creates its missing endpoints among that body’s own children. Declaring the id in the scope — before or after the link — uses it instead of creating one. A path endpoint (kitchen.bowl) is never auto-created: it must resolve to an existing node, or it is an error. If a same-named node exists elsewhere in the tree, the box is still created here and a warning names the other match.

An auto-created id that is a near-miss of a name already known in its scope — a small typo (edit distance ≤ 2, and shorter than the id itself), or equal ignoring case, against the declared and the previously auto-created names — warns toward the likely target: cta -> bird warns did you mean 'cat'? even in an all-implicit file. Distinct names stay silent — short ids (a -> b) and numbered siblings (server -> server2) are families, not typos — so legitimate mixed use draws no noise (SPEC 21). Auto-create is box-only; the typed declare-at-first-use is the capsule endpoint (cat -> |cyl#db|SPEC 9).

Declarations

A declaration key: value; lives only in a { } style block — the stylesheet (configuring the root) or a node’s own block — and ends with ;, so a value may span lines (SPEC 2); the ; is optional only immediately before }. A bare key: value outside a { } is an error. Every property, its value shape, and where it applies is in the Property Ledger.