One stop of a lab Flow: what is said, what the lab does, what the learner does. More...
| Import Statement: | import Clayground.Lab |
A step is either a demonstration (demo runs, the learner watches), a task (task waits for the learner) or narration only.
See also Flow.
demo : var |
Actions the lab performs on entering, as [[verb, args...], ...].
Verbs are resolved against the lab's flowActions() map. The form ["let", "name", verb, args...] binds the verb's return value to a flow-local name usable as an argument in later actions.
dwell : var |
Sim seconds to linger, or "auto" to estimate from reading time.
expect : var |
Optional predicate asserted after the step, for headless checks.
key : string |
mark : var |
Parts (or sub-parts) this step's line names, as a list of names.
The eye's half of a spoken sentence. A line that says "the battery, the switch, the LED and the resistor, one loop" asks the learner to find four things by ear; mark: ["battery", "switch", "led", "resistor"] rings all four on the model while the line lasts, and the marks go with the step.
The names are the lab's own - resolved exactly as a performance script's *point at NAME* target is, by whatever the presenter's guide was given as a resolver - so they are language-neutral authoring tokens, not display text. Nothing here draws them: a lab binds them to a MarkLayer.
A directed step (one with a performance script) ignores this field: its marks come from the script's own *mark ...* cues, which can raise a different set per line.
say : string |
Narration text, used when no dictionary entry exists for key.
task : var |
What the learner must do: {until, allow, hint, hintAfter, solve}.
until is a predicate receiving a name lookup function and returning true once the step is satisfied; solve is an action list that performs it (used by "show me" and by the headless verification run).
allow is what the task hands over: the parts the learner may touch while it runs, named the way until and solve name them ("allow": ["sw"]), everything else on the board being inert until the task is done. A step whose subject is whatever the preset it just applied put there names it with a function of the same name lookup instead ("allow": (n) => root.logicInputs). Leaving it out keeps the whole board live, which is what a flow written before Flow::control existed still gets.
view : var |
Where the camera should be for this step. Null leaves it alone.
A narrated step that talks about the far corner of the board while the camera is still on the near one teaches nothing, and moving it from a demo verb means every lab has to invent that verb. Three forms, all applied after the demo has run, so a step can frame what it just built:
{ viewpoint: "top" } - a name from OrbitCamera3D.viewpoints;{ focus: [points], pad: 1.3 } - frame these world points, or a single point to re-centre on it;{ pose: {yaw, pitch, distance, px, py, pz} } - a literal pose, as OrbitCamera3D.state() spells one.Add ms: to any of them to set the travel time. Applied only when the Flow has a camera; a flow without one ignores the property entirely, which is what keeps it non-breaking.
watch : var |
Wait for the simulation, as {until}.
The sibling of task for continuous labs: nothing is asked of the learner, the step simply ends when the world reaches a state ("the car enters the tunnel", "sigma passes 2 m"). Same predicate, different promise - so the narrator says "watching" rather than "your turn".