Interaction
What a reader can move: parameters, a fit they drive, editable environments, and the state that follows them between scenes.
#Parameters
A is a named quantity with a slider in the environment footer. Its var is a single letter, and every expression in the environment that mentions that letter re-evaluates as the reader moves it.
canvas.graph{
parameter#a(var: a; name: steepness; range: [0, 4]; step: 0.25; default: 2)
curve(expression: a * x^2)
point(x: 1; y: a; label: $a$)
}name: is what the parameter is called in front of the reader — rich text, so Frequency $b$ sets its own maths — and without one the slider is labelled with its letter. hidden: true keeps it out of the footer — the expressions still use it, the reader cannot move it — and lock: true keeps it out of their reach on an editable environment. Its current position is derived as #a.value, readable in prose as {{#a.value}}.
#Giving fit a parameter for its degree
takes its degree as a number or as an expression of parameters. A parameter in that position hands the degree to the reader: the parameter's slider is the control, and the fit recomputes as it moves.
canvas.graph{
scatter(x: 1, 2, 3, 4, 5; y: 2.0, 2.4, 3.1, 4.8, 7.4)
parameter#d(var: d; name: fit degree; range: [1, 4]; step: 1; default: 1)
fit#f(model: polynomial; degree: d)
}#f.slope, #f.intercept and #f.r2 are derived from whatever the reader has chosen, so prose that reads them stays true at every degree.
#editable: environments and lock:
editable: true on a lets the reader add their own elements and pan or zoom the frame; on a it lets them edit the text, which still runs nothing. Any mark takes lock: true to stay out of their reach — and does nothing at all on an environment that is not editable.
#continue: and session state
A later environment written as continue: #projectile inherits what the reader did in the earlier one: where they left the sliders, the degree they chose, the view they zoomed to. Only that state carries — the content is the new environment's own.