Attributes
The parenthesised group every construct may carry: how values are written, and the types that parse them.
#The attribute group
Attributes live in a parenthesised group, written after the body and detail. On one line they separate with semicolons; across several, one per line with no separator. The two forms are equivalent, and a group may be empty — () — which is how a bare node head stops being prose. Which form to use where is a reading convention rather than a rule of the grammar; Source style states the one this manual follows.
point(x: 1; y: 2; colour: orange)
canvas.graph{
curve(expression: x^2)
}(
x-axis-label: t
y-axis-label: height
)The control-flow directives are the one exception to the group coming last — (audience: teacher){…} and (n: 0..4){…} put theirs first.
A semicolon separates attributes in both forms — one attribute per line included — so a value that needs one escapes it as \;: table(title: Yield at 300K\; 1 atm) is one title, and without the backslash it is an attribute called 1 atm. Every other backslash passes through untouched, which is what leaves $\pi$ intact in a rich-text value.
#Values as text, parsed by type
Every value is text until the attribute it lands in parses it, and a value the attribute's type cannot parse is a compile error — nothing is coerced or quietly defaulted. A type may be narrower than its name suggests — a number restricted to whole values, or to a range, or a list held to a fixed length — and a refused value's error names the restriction it broke rather than just the type. The type reference lists what each type accepts.
This is also why a dataset column needs no type of its own: a cell reaches an attribute as text and is parsed there, failing exactly as the same text typed by hand would.
#Shorthands & derived attributes
Two pages hang beneath this one. Attribute shorthands covers the four ways an attribute is written shorter than key: value — the implicit :value, bare booleans and ! negation, spaced names, and aliases. Derived attributes covers the attributes a construct computes while it renders — read-only, reached with #id.name or {{#id.name}}, never set.