Expressions & parameters
Math expressions, free parameters, the parametised types, intervals, and live values in prose.
#Expressions
Wherever a graph wants a function, it takes a math expression in x: curve(expression: x^2 - 2x + 1), sin(a * x), 100 - 4.9x^2. Powers are written with ^, the usual functions are available by name, and multiplication may be implicit — 4.9x^2, 2(x + 1), and (m - px) / q with multi-letter parameter runs all parse. Surface expressions (contour, heatmap) are the one place y is legal alongside x.
#Parameters
A parameter declares a single-letter variable and hands the reader a slider: parameter(var: a; range: [-5, 5]; step: 0.1; default: 1). Every expression in the pane that mentions a re-evaluates as it moves. The current value is exposed as derived value — #speed.value for a parameter#speed — so prose and marks can cite what the reader chose.
#Parametised types
Attribute types with parametised- in their name accept expressions over parameters where a plain value would otherwise stand: a point's coordinates may be (a, 2a), a curve's domain [0, b], an integral's bound from: m - s. The type reference lists them all — parametised-number, parametised-interval, parametised-expression, parametised-coordinate-list, parametised-number-list, parametised-surface-expression.
canvas.graph{
parameter#m(var: m; range: [0, 5]; default: 2)
curve#f(expression: m * x)
point(x: 1; y: m; label: $m$)
}#Intervals
Ranges are written in interval notation with inclusive or exclusive bounds: [0, 10], (0, inf), [-inf, inf]. Domains, ranges and parameter spans all take them, and the parametised variant admits expressions in the bounds — [a, b].
#Live values in prose
Prose is text, so a live value needs a construct to carry it: !value renders the current value of whatever its reference points at — a derived attribute, a reader-set parameter — and keeps it current as the document runs.
The fitted slope is !value:#f.slope, to two places !value:#f.slope(digits: 2).The ! sigil is what makes it a construct — no bracket is needed when the implicit attachment has said everything, and the group appears when there is more to say (digits, format, maths). In attribute position no wrapper is needed at all: text(label: #f.slope) binds directly.
{{ }} for what is fixed at compile time, # bindings (and !value in prose) for what moves. The compiler enforces it — substituting a derived, animated or parameterised value is an error that names the binding to use instead.