Search Results

Lab Plugin

The experiment kernel for Clayground Labs: turns any sandbox into an interactive, deterministic, agent-verifiable experimentation space.

Components

  • Lab (singleton) — registry connecting everything; agents read/write parameters via Lab.p(name) / Lab.set(name, value) and fetch Lab.labInfo() through the inspector’s eval action.
  • Parameter — named, ranged tunable; bind your system to value.
  • Probe — named observable sampled on a fixed sim-time grid.
  • SimClock — seeded deterministic clock; with a world attached, sim time advances with the physics steps (exact under the inspector’s time/step action); seeded random()/randomRange() are the only randomness a lab may use.
  • ParamPanel — auto-generated slider panel for all parameters. Rows are Tab-reachable and arrow-operable, with a visible focus ring.
  • Plot2D — live autoscaled strip chart of probes. Pass probes for a fixed set, or series: [{probe, label, color, style, sigmaProbe}] when the plotted set is built at runtime: the lab then owns naming and colouring, an empty array draws placeholder instead of every probe, and legend entries become clickable (seriesClicked) so the user can drop a curve where it is named. style: "scatter" leaves discrete measurements unjoined, sigmaProbe fills a translucent ±σ band behind a curve, and hovering the chart reads every visible series back at the nearest sample.
  • DataRecorder — probes to a run record (record.js): lab, scenario, seed, every parameter, the per-probe series with their summaries and the command that regenerates it, no wall clock anywhere - so two runs of one seed are byte-identical and a paper can cite the file by id. A .csv destination still writes the flat table, but a CSV carries no provenance and so cannot be cited. Always set an explicit destination (a relative default once littered the repo root).
  • LabTheme / ThemeSwitch / ScaleSwitch — every colour, shape, type and spacing token, in a light and a dark palette that swap at runtime, all multiplied by one uiScale factor. The two palettes are counterparts rather than inversions, and the rules that make them so live (and are tested) in palette.js — most importantly LabTheme.inkOn(fill), which every chip and badge must use instead of naming an ink, and LabTheme.step(c, amount), which moves a colour away from the ground in whichever direction the palette has room. The measurement half is tokens.js: seven type roles (fontMicro … fontTitle), six spacing steps (spaceXs … spaceXxl) and LabTheme.px(n) for one-off geometry. node palette.test.js and node tokens.test.js check the relationships, not the values. Two roles are easy to miss: the board has its own (board for the sky, table, sheet, inkSolid for a rim or wall - ink as a lit surface cannot simply invert or it becomes a light source), because a recessed 2D paperDeep well still sinks in the dark while the board’s ordering inverts; and data tokens keep their identity across themes - the paper says “the rose track is GPS” and the legend has to agree in both, so a colour is measured on the dark ground and lifted along its own hue only if it fails to read there. The scale exists because a lab shown on a large external screen had HUD controls nobody could read and nothing to turn: every size in the chrome was a bare pixel literal.
  • LabPrefs — the three settings that belong to the person rather than to the run: ui.theme, ui.scale, ui.lang. Backed by Clayground.Storage when it is present and by memory when it is not, so a lab that never links the storage plugin still runs — it just forgets on exit.
  • LabLang / LangSwitch — runtime language switch for a published lab. Whoever owns a vocabulary registers it (LabLang.register(dict) with {lang: {key: text}}), strings are ordinary bindings on LabLang.t(key) / tf(key, ...), and LabLang.num(v, digits) prints numbers in the language’s notation (German gets a decimal comma; Plot2D, BudgetBar and ParamPanel already use it). LabLang.qty(v, unit, digits) adds the quantity layer on top — SI prefixes with the mA↔A, ms↔s and k/M crossovers every lab used to hand-roll (format.js, node format.test.js). Not qsTr: retranslating a live engine is a C++ call on the QQmlEngine, which a lab hosted by the dojo or exported to WASM does not own. Drop LangSwitch in a corner and it offers exactly the registered languages.
  • Scenario / ScenarioSet — named, scripted situations wiring the scenarios()/applyScenario() inspector convention; applying resets the clock so runs are reproducible.
  • Flow / FlowStep / Narrator / FlowChip — the guided, narrated walkthrough: verbs-as-data driven through the lab’s own flowActions(), demo/task/watch steps, hint→solve escalation, checkpoint scrubbing. FlowChip is the on-screen offer to be taught, so the lesson is not hidden behind a key nobody knows.
  • CameraDirector — which shot when, for a lab with a presenter in it: journey (start, destination and subject in one frame, the presenter followed until it lands), twoShot (presenter and the thing pointed at), portrait (level with the face, for explanation), cutaway (one thing alone for a beat, then back), wide. Science-TV grammar written once, composed through OrbitCamera3D.fit() with a safe area for the chrome, so no lab hand-rolls arrival/address hooks and no finger points at something outside the picture. The professor kit’s FlowGuide takes one as director:.

Focus mode

Tab clears the HUD: LabView.focus goes true and the instruments, panels, plot, compass, clock and switches step out of the way, leaving the scene and - while a flow runs - the Narrator. It is for studying a scene when nothing is being changed or measured. Most of it is automatic: anything built on LabPanel fades on its own, as do the kernel’s own pieces. A lab only wires what it built itself (a scrim, a button declared beside a panel rather than inside it) with visible: !LabView.focus, and a panel that must survive focus mode sets hideOnFocus: false. LabPanel uses opacity and enabled rather than visible, because labs bind visible on their own panels constantly and a component assigning it would be silently overwritten by exactly the labs that use it most. The alarm banner deliberately does not hide - a short circuit outranks whatever you were looking at.

The board — what a build lab is made of

A lab that places typed parts on a grid, wires their pads and solves the result owns none of that mechanism any more. The domain kit hands over a part spec (spec[type] = { terminals, half, actuator, fields, rows, watch }, see board.js), a solver and a part visual; the kernel does the rest. board.js is pure JS (node board.test.js), tests/tst_board.qml drives the store and the gesture with no GPU.

  • Board — the store: parts, wires, rev, hit test, keep-out, the mutations, batching, state()/load(), an optional router; changed is where the domain re-solves.
  • BoardInput — the mouse: wire pads, select and drag, tap a wire, the two-step actuator (operate), eraser, the right-click cancel chain; the camera and the instrument belt are asked first, always. A part’s state belongs on its selection card (a resistor’s ohms, a gate’s function, a switch’s on/off), which is also the only channel that survives having no pointer on a touch screen; operating a part in the scene is a shortcut gated on selection - the part you picked is the part that responds - so a click during building flips nothing and no mode has to be remembered. An actuator region comes first in the hit test (actuatorHalf(type)), has its own gesture (no selection, no drag, fires on release) and three signals that agree on one predicate: a pointing-hand cursor, the lever lightening (never recolouring what already carries state), and a hint-bar line naming what the click will do. electronics-101’s switch was the cautionary tale: its pads reached inward and left a few pixels in the middle as the only place a click flipped it, which read as a bug in wiring rather than in the switch.
  • BoardWires3D — every wire as one flat batch plus the dangling preview; the lab’s lineOf styles them.
  • PartPlacer — the palette’s parts as one handheld: take, ghost, place.
  • BoardPalette — presets, parts and tools in foldable sections.
  • PartCard — the selection card with the domain’s rows between the kernel’s title/reading and plot/tag rows; a keyboard target via keys.
  • BoardOverlay — value labels, wire readings, watch marks, pinned tags.

Chrome — what makes two labs look like one product

Everything below was hand-rolled in two labs before it moved here.

  • LabPanel — the titled paper panel every HUD is made of; children stack, or set a size and anchor to its body.
  • LabKeys / LabHelp — the canonical key map (1..9 presets, T flow, f jump labels / ⇧F frame (plain F in a jump-less lab), 0 reset, H takes the next instrument, P keeps its reading, Shift+R record, ? help, arrows and WASD travel, Shift+arrows turn) plus the lab’s own keys as data. The arrows used to turn, which a drag already did well; crossing the scene had no key at all, so turning moved onto Shift and watching moved off W to Q. f/⇧F are the map’s first Shift-differentiated pair - f acquires a target, ⇧F frames it. While a flow runs →/← and Space are the flow’s, so the arrows are the camera’s only when nothing narrates.
  • HintJump — keyboard selection: f labels every target the lab names (1–2 home-row letters), typing one selects it in place; off-screen targets become a grouped badge strip and do fly on pick. The lab supplies targets() (id, world pos, name, group) and wires jump: on LabKeys; the letters are physical, the capture follows the pin-prompt guard, and a focus loss puts the labels away. Declaring a key is what documents it: LabHelp renders the map from the same list, so the two can never drift. The six travel letters are reserved and dispatched after the lab’s own keys, so claiming one silently costs a pan direction.
  • HintBar — bottom-centre line that steps aside while a flow narrates and stays width-capped against its neighbours.
  • ScenarioBar — clickable preset chips, each with the one-line reason it exists (scenario.note.<name>).
  • WatchMonitor — watch a thing, get a probe, a colour and a curve; owns probe lifecycle, stable names and the one-quantity-per-axis rule — which, since traces became (id, quantity) pairs (traceIn), means one strip per traced quantity, stacked on a shared time axis and cursor (maxStrips, default 3). A part keeps one colour across strips, so its WatchMark matches every curve it owns. WatchChip is the per-object toggle that feeds it (watch / watched / plot full, the limit read off the monitor), WatchMark the dot the object then wears in the world, in its curve’s colour.
  • WorldLabel — 2D paper chip pinned to a 3D point.
  • MarkLayer — rings on the world points something is naming right now, optionally captioned. Fed by a FlowStep.mark list or a performance script’s *mark ...* cue; keepOut keeps a ring off a presenter standing in front of the part it marks.
  • SelectionFrame3D — the shared hover/select language on the work surface (thin outline hovering, full frame plus facing mark selected). Used by the circuit kit; note that its lift is measured from the object, so a part sunk into its board needs a matching height.
  • Compass — which way the work surface faces while you circle it.
  • GridMode — snap/free placement with grafli’s contract (# cycles, Alt inverts for one gesture). It holds the mode and draws nothing; LabStage3D is what shows it.
  • LabStage3D — the ground every 3D lab stands on, plus the light rig and the SceneEnvironment that go with it. One quad, no texture: the raster is computed in the fragment shader from world coordinates, so it is millimeter paper on the light palette and blueprint on the dark one, one line weight at any zoom, and it dissolves into the sky rather than ending at a board edge. It shows GridMode’s mode as crosses or dots at the intersections, answers worldAt(view, mx, my) for mouse editing, and publishes the height/depthBias budget flat overlays have to stay inside. Three labs built a table, a sheet, a rim, a light rig and 585 peg Models between them before this existed. Three things to know: GridMode draws nothing - hand it over with gridMode: and set cueSize: 0 in a lab that places nothing, because a snap cue on a surface nobody snaps to is a lie; worldAt(view, mx, my) is the pick, the plane being the only pickable thing the stage adds (a raster not centred on the origin says so with rasterOrigin); and flat markings sit between overlayMinY and overlayMaxY (overlayY(layer) stacks them) with a depthBias in overlayMinBias..overlayMaxBias - depthBias only settles sort order, so the lift is what actually does the work.

Instruments — the shelf

Promoted from the labs, which had proved each of them (some three times over):

  • InstrumentScale — what a reading means, with nothing that draws it: value or probe, unit, fixed limits or a self-ranging set of ranges, linear or log positioning, severity bands, nice-number gradations, and the lag and peak-hold of a real movement. One of these feeds as many faces as the page shows, so they cannot disagree; adaptability lives in the model x face matrix, so a music VU meter is a BarFace on a log scale with peak-hold, not a new component. Bands (okUntil/warnUntil, or zones) are the scale’s, not the face’s: declared once they colour the needle, the fill, the digits and the tint behind them from LabTheme’s severity tokens, and a reading past the end of the scale takes the band at that end
    • a pinned needle on a red-topped dial must not read back “ok”. settleTime is a swing for a value that changes on an action; damping is the lag of a real movement, for a continuously noisy one. Never both. Which face: Gauge for what is this relative to what the instrument can take, BarFace for how far along, ColumnFace for how much read off the scale, DigitFace for what is the number - paired with a needle or a column, because alone it says nothing about what the number is worth. demo/Instruments.qml is the reference page: one scale under four faces.
  • Gauge — the needle face. Given ranges it selects its own, and prints the one it settled on. Laid out in fractions of its own size, so the same component serves a HUD dial and a Texture baked onto a 3D part.
  • BarFace — the level face, horizontal or vertical, optionally as the LED ladder of a level meter, with the held peak marked. A music VU meter is this on a log scale, not a component of its own.
  • ColumnFace — the thermometer face: every major gradation labelled, for a quantity read off the scale rather than as a proportion.
  • DigitFace — the numeric face, in mono digits through LabLang.qty().
  • InstrumentDock / DockedInstrument — the HUD column, where each instrument can be put away by the reader and taken back out of a tray at its foot. The visible set rides in the lab’s viewState().
  • ReadoutPanel / ReadoutRow — swatch · name · live value rows, built from data, with an optional share bar per row.
  • MiniMap — the abstract view: fit-to-content projection plus the repaint plumbing, driven by a draw(ctx, map) callback the lab supplies.
  • LabBanner — the centred status pill, severity in the fill and the ink from inkOn(), blinking only for a live fault.
  • TransportChip — sim time, pause and speed, driving SimClock.timeScale from outside.
  • RecIndicator — the recording dot, so a growing CSV is never a secret.

Instruments you hold

The shelf above is mounted: the lab author bound what each one measures when the lab was written, and it reads for the whole run. These are the other half — the viewer binds the subject at runtime by pointing, and the reading dies with the gesture.

  • HandheldInstrument — the contract. An instrument declares what a click contributes (pickKind: a "point" on the ground, an "object" in the scene, or a "moment" in sim time), how many it takes (maxPicks, 0 for an endless chain), and what the reading means (value / valueText). It handles no input and knows nothing about the camera. That is the acceptance test: a new instrument is one file saying what it picks and what that means, with no gesture code in it.
  • InstrumentBelt — what the viewer can pick up, and the owner of the hand’s click. One line inside the View3D (pointer: nav, unit: the lab’s unit) and the lab has a TapeMeasure and a Stopwatch; a kit’s own instrument is declared inside the belt and joins the same row. A ruler you have to install first is a ruler nobody reaches for.
  • TapeMeasure — the screen-space tape. Its arithmetic is measure.js, checked by node, so lengths and angles are not geometry that only exists inside a paint call.
  • Stopwatch — the same contract against the sim clock rather than the ground.
  • CameraAnchorMark — the dotted ring showing what the view is orbiting and zooming about. A screen-space overlay, because as world content it clipped into geometry at close range.

pin() is the one transition out: it names the reading, registers it as a Probe, and from then on it is sampled on the clock grid like any other — so it lands in the run record and a paper can cite it. It asks for the name because that name is what gets cited. A measurement itself is never in viewState(): it is a question being asked now, not scene state.

The mouse

One rule, and the rest follows from it: the left button is never the camera’s. A mode used to exist only because the camera wanted LMB — panning sat there, so a lab that needed LMB had to be able to take it back, and the thing that took it back was the mode. OrbitInput3D declines the left button instead, so nothing has to.

  • RMB drag turns the view about the point under the cursor; a right click cancels — the “put it down” gesture.
  • Middle drag pans, wheel zooms towards the cursor, double-click focuses. Always live, never taken away.
  • LMB is the lab’s: its own tool, or a click handed to whatever instrument is in the hand. Holding Space lends it to the camera for as long as the key is down.
  • A lab with nothing to build may spend LMB on the view deliberately (panButtons: Qt.LeftButton | Qt.MiddleButton) — one decision, made once, not a mode.

The determinism contract

Every lab must (a) derive all randomness from SimClock (seeded), (b) run correctly under the inspector’s time pause/step actions, (c) expose labInfo() — typically just return Lab.labInfo(). Same seed + same stepped frames ⇒ identical probe series.

Minimal lab skeleton

Do not write one — generate it:

tools/lab-new/lab-new <slug> --kind build|continuous|draw --purpose learning|teaching|research

The generated Sandbox.qml answers the whole conventions contract (scenarios(), applyScenario(), labInfo(), viewState(), flowActions(), …), comes with a bilingual strings.js, the records and figures drivers and the paper/board skeletons, and its template is itself a lab that ctest -R lab_new boots. tools/lab-new/README.md explains the tokens and how a kind is added.

See demo/Sandbox.qml — a damped oscillator with a noisy measurement, used as an excuse to put every instrument on one page, and the fastest way to see whether a change to the palette or the scale has broken anything. Render it at two scales in two themes:

clayrender plugins/clay_lab/demo/Sandbox.qml --out shot.png --size 1400x900 \
    --eval 'LabTheme.mode = "dark"' --eval 'LabTheme.uiScale = 1.6' --frames 300

labs/electronics-101/ and labs/hydraulics-101/ are full build labs on the board layer.

API Reference

BarFace A level bar on an InstrumentScale - horizontal or vertical, with peak-hold

Properties

NameTypeDescription
frameRadiusrealCorner radius of the frame - 0 when baked into a Texture
horizontal readonlyboolTrue while the bar runs left to right
labelstringCaption above the bar; empty hides the row
orientationintQt.Horizontal (default) or Qt.Vertical
scaleInstrumentScaleMeasurement model this face draws
segmentsintSplit the fill into this many cells - 0 (default) is a continuous bar
showFrameboolDraw the panel background and border behind the face
showPeakboolMark the held peak. Follows scale.peakHold by default
showTicksboolDraw the scale's gradations along the bar
showValueboolPrint the reading beside the label
showZonesboolTint the severity bands into the track
thicknessrealAcross-the-bar size of the track
Board Store behind a build-type lab: typed parts on a grid, wires between their pads

Properties

NameTypeDescription
cellreal
cell \brief World units per cell.real
colsint
cols \brief Cells across.int
cursorHeightreal
cursorHeight \brief The y \l cursorW is reported at.real
cursorWvar
cursorW \brief The cursor on the board, in world units.var
eraserbool
eraser \brief The eraser tool is on.bool
hoverHitvar
hoverHit \brief What is under the cursor, as \l hitAt reports it.var
lanereal
lane \brief The raster a router turns on; half a cell by default.real
nextIdint
nextId \brief The next id handed out, shared by parts and wires.int
padYrealA pad in world space, turned with its part; y is padY
partsvar[{ id, type, col, row, rot, ...fields }] - col/row are fractional cells
revintBumped by every mutation and every move; the dependency in-place edits need
routervarOptional: { all(links, obstacles, lane), one(a, b, lane) } choosing wire paths
routes readonlyvarEvery wire's drawn path, { wireId: [{x, z}, ...] }, from the router
rowsint
rows \brief Cells deep.int
selectedIdint
selectedId \brief The selected part, -1 for none.int
specvarDomain's part types: { type: { terminals, half, actuator, keepOut, fields, rows, watch } }
wiresvar
wires \brief \c {[{ id, a: [partId, ti], b: [partId, ti] }]}.var
wiringFromvar
wiringFrom \brief \c while a wire is dangling.var

Methods

MethodReturnsDescription
actuatorHalf(string type)var
addJunction(real col, real row)int
addPart(string type, real col, real row)int
addRotated(string type, real col, real row, int quarters)int
addWire(var a, var b)void
beginBatch()void
bodyHalf(string type)var
bounds(var which, real pad)var
cellFree(real col, real row, int ignoreId, string type)bool
cellX(real col)real
cellZ(real row)real
clear()void
closestOnPath(var path, real x, real z)var
colOf(real x)real
endBatch()void
hitAt(real wx, real wz)var
jumpTargets(var labelOf, var groupOf, real y)var
keepOut(string type)int
keys(var grid, var overlay)var
load(var s)void
movePart(int id, real col, real row, bool snap)void
nearestFreeCell(real col, real row, string type)var
partAt(int id)var
previewPath(var from, var to)var
removePart(int id)void
removeWire(int id)void
rotatePart(int id)void
rowOf(real z)real
selectionKeys(var monitor, var grid)var
setField(int id, string key, var value)bool
specOf(string type)var
splitWireAt(int wireId, real wx, real wz)int
state()var
terminalCount(string type)int
terminalDir(int id, int ti)var
terminalLocal(string type, int ti)var
wireMid(var wire)var
wirePath(var wire)var

Signals

SignalDescription
changed(string kind)
cleared()
removed(int id)
BoardInput Mouse on a Board: wire pads, select and drag parts, operate, erase, tap a wire

Properties

NameTypeDescription
boardBoard
dragSloprealWorld units a press must travel before it is a drag
flowvarLab's Flow. While one runs, it decides what the board answers to
gated readonlyboolA flow is running, so it - not the learner - says what is live
gridvar
grid \brief A \l GridMode; Alt inverts it for one drag. Optional.var
handsvar
hands \brief The \l InstrumentBelt; asked second. Optional.var
hint readonlystringHint-bar line for the current state, translated
hintKeysvarLabLang keys the hint line is built from; a lab overrides the wording by key
hoverActuator readonlyboolCursor is over the SELECTED part's actuator - the next click operates it
hoverActuatorIdle readonlyboolOver an operable part that is not the one being worked on - the next click selects it
navvar
nav \brief The \c OrbitInput3D; asked first about every press.var
stagevar
stage \brief The \l LabStage3D, for \c worldAt.var
viewvar
view \brief The View3D the stage projects through.var

Methods

MethodReturnsDescription
cancelAll()void
clickAt(real x, real y, int mods)void
dragFrom(real x1, real y1, real x2, real y2, int mods)void
granted(var hit)bool
moveAt(real mx, real my, int mods, bool isDown)void
pressAt(real mx, real my, int button, int mods)void
releaseAt()void
worldAt(real mx, real my)var

Signals

SignalDescription
interacted()
operate(int id)
BoardOverlay 2D readings over a Board: value labels, wire readings, watch marks and pinned tags

Properties

NameTypeDescription
attributes readonlyvar
attributes \readonly \brief The monitor's quantity keys. readonlyvar
boardBoard
cameravar
hiddenbool
hidden \brief Wire readings, marks and tags step aside (a teacher on the board).bool
keepOutvarA screen rectangle ({x, y, width, height}) nothing is drawn into, or null
labelOfvar
labelOf \brief \c {(id) -> string}, the short name a watch mark carries.var
labelYreal
labelY \brief World height the value labels and marks anchor at.real
monitorvar
monitor \brief The \l WatchMonitor: quantities, colours, the watched set.var
readingOfvar
readingOf \brief \c {(id, attr) -> string}, one reading, any attribute.var
severityOfvar
severityOf \brief \c {(id, attr) -> "ok" | "warn"}.var
showValuesboolLabels on. Turning it on lights the first attribute; setting any attribute sets it
solvedvarBind the domain's solve result here so every reading re-reads when it changes
tagYreal
tagsvar
tags \brief \c - the pinned tags.var
valueAttrstringAttribute the value labels show; "" is off. Twin of showValues
viewvar
view \brief The View3D to project through.var
wireAttrstring
wireAttr \brief The one attribute a wire reading rides on; the first quantity.string
wireReadingOfvar
wireReadingOf \brief \c {(wire) -> string | null}; null draws nothing.var
wireYreal

Methods

MethodReturnsDescription
cycleValueAttr()void
load(var s)void
setTag(int id, string attr)void
state()var
BoardPalette Build lab's top-left panel: presets, the parts to take, the tools - in foldable sections

Properties

NameTypeDescription
boardBoard
catalogvar[{ type, color }] - the parts on offer, in this order, each with its board colour
columnWidth readonlyreal
columnWidth \brief The content width. readonlyreal
compactboolTwo-across layout without hints; measured from the window height by default
flowvar
flow \brief The flow the \l FlowChip offers.var
gridvar
grid \brief The \l GridMode the grid button toggles.var
handsvar
hands \brief The \l InstrumentBelt the placer lives on.var
iconComponentDrawn beside each part; gets type and ink set on it. Optional
labvar
lab \brief The sandbox root, for the \l ScenarioBar.var
overlayvar
overlay \brief The \l BoardOverlay the values button cycles.var
placervar
placer \brief The \l PartPlacer.var
sectionsOpenvarWhich sections are unfolded, { presets, parts, tools }; put it in viewState()
toolsvarWhich of the standard tools to show, in order: "eraser", "values", "grid", "clear"

Methods

MethodReturnsDescription
sectionOpen(string key)bool
toggleSection(string key)void
BoardWires3D Every wire on a Board as one flat instanced line batch, plus the dangling preview

Properties

NameTypeDescription
boardBoard
clockvar
clock \brief The \l SimClock the flow animation runs on - deterministic, never a wall clock.var
flowSteps readonlyint
flowSteps \brief How many chevron speeds there are. readonlyint
lineOfvar(wire, points, hovered) -> { color, width, styleId, flow }
lines readonlyvarWhat the batch draws; rebuilt on every board change, hover, eraser flip and solved
previewColorcolor
previewColor \brief The dangling wire's ink.color
previewWidthreal
solvedvarBind the domain's solve result here; the lines are rebuilt whenever it changes
yreal
y \brief Height above the board the wires are drawn at (the stage's overlay budget).real

Methods

MethodReturnsDescription
flowStyle(real rel)int
midOf(var wire)vector3d
pathOf(var wire)var
BudgetBar Shows how one total splits into its parts

Properties

NameTypeDescription
decimalsintDigits shown per value. Defaults to 2
segmentsvarShares, as [{label, value, color}]
totalrealWhole the shares are measured against
unitstringUnit appended to every value in the legend
CameraAnchorMark Shows where the camera turns and zooms: a dotted ring on the anchor

Properties

NameTypeDescription
pointervarOrbitInput3D to watch
radiusPxrealRing radius in pixels
tonecolorRing and dot colour
CameraDirector Which shot when, for a lab with a presenter in it

Properties

NameTypeDescription
cutMsintHow long a change of shot glides. -1 takes the rig's travelMs
followSlackrealHanded to the rig's follow while a journey runs
girthrealHalf-width of the presenter's frame box, as a factor of standHeight. Arms out, a hoverboard, a bit of ground
headroomrealHow much taller than the presenter its frame box is, as a factor of standHeight. Room for a speech bubble
padrealAir around a wide shot and a two-shot, as a factor on the fitted distance. 1 is edge to edge
portraitLimitsvarRig limits a portrait is allowed to relax: {minPitch, minHeight}
portraitPitchrealAngle a portrait is taken from: level with the face
presentervarWho is in the picture. Duck-typed: stand (a vector3d on the ground), standHeight, travelling and present
rigvarOrbitCamera3D to direct. Null does nothing at all
safevarWhat is NOT picture: {top, bottom, left, right}, fractions of the frame. The flow bar, the hint strip, the cards
shot readonlystringIn force: "wide", "journey", "two", "portrait", "cutaway" or "" before the first one
shotPoints readonlyvarWorld points the current shot was composed around. What a check reads back through rig.covers()
title readonlystringScene title an establish is showing; "" otherwise
widePitchrealAngle a wide shot and a two-shot are taken from

Methods

MethodReturnsDescription
cutaway(var points, int holdMs)bool
establish(var points, string title, int holdMs)bool
journey(var to, var subject)bool
portrait()bool
presenterPoints(var at)var
release()void
twoShot(var subject)bool
wide(var points, real pad)bool

Signals

SignalDescription
cut(string shot)
CardFocusRing Ring a card's control wears while the keyboard is on it

Properties

NameTypeDescription
hostItemWhere the ring actually lives - the first non-positioner ancestor unless a lab names one
onboolThis row is the one j/\c k landed on
trackItemRow to frame; defaults to where the ring was declared
ColumnFace A thermometer column on an InstrumentScale - every gradation labelled

Properties

NameTypeDescription
frameRadiusrealCorner radius of the frame - 0 when baked into a Texture
labelstringCaption above the column; empty hides the row
scaleInstrumentScaleMeasurement model this face draws
showBulbboolDraw the reservoir at the foot
showFrameboolDraw the panel background and border behind the face
showPeakboolMark the held peak. Follows scale.peakHold by default
showValueboolPrint the reading above the column
showZonesboolTint the severity bands into the column
thicknessrealWidth of the column
Compass Which way the work surface faces while you circle it

Properties

NameTypeDescription
aspectrealWidth/height of the surface shown
frontColorcolorMarker on the surface's front edge
yawrealCamera yaw in degrees (the rig's)
DataRecorder Records a run as a citable run record (or as plain CSV)

Properties

NameTypeDescription
commandstringThat regenerates this record, written into it
destinationstringOutput path. A .csv suffix selects the flat CSV table; anything else (by convention .labrec) writes a run record
error readonlystringWhy the last write failed ("" if it did not)
formatstring"auto" (from the suffix), "record" or "csv"
labstringLab id written into the record; defaults to the destination's parent-of-records directory when it can be read off the path
lastFile readonlystringPath of the most recently written file ("" if none)
maxBytesintSize above which the sample table is thinned instead of written in full (the record stays committable; summaries stay over all samples)
probesvarProbe names to record (empty = all registered probes)
recordIdstringId a paper cites this record by; defaults to the file's base name
recordingboolToggle to start/stop; stopping writes the file
rows readonlyintSample ticks recorded in the current/last run
stepSizerealSim seconds per step, for the record's provenance
stepsintFixed steps the run advanced, for the record's provenance (0 = unknown, e.g. a live dojo recording)

Methods

MethodReturnsDescription
record()var

Signals

SignalDescription
written(string path, int rows)
DigitFace Reading as mono digits - the numeric face of an InstrumentScale

Properties

NameTypeDescription
alignmentintQt.AlignLeft (default), Qt.AlignHCenter or Qt.AlignRight
digitSizerealPixel size of the number
frameRadiusrealCorner radius of the frame - 0 when baked into a Texture
labelstringCaption above the digits; empty hides the row
scaleInstrumentScaleMeasurement model this face draws
showFrameboolDraw the panel background and border behind the face
showRangeboolPrint the scale in force under the digits
showUnitboolPrint the unit beside the number
DockedInstrument One instrument in an InstrumentDock - a titled panel the reader can put away

Properties

NameTypeDescription
accentcolorTitle colour
body readonlyItemPanel's content area - bind a face's width to body.width
contentItemStacked children (the default property)
dismissableboolOffer the dismiss affordance. Turn it off for an instrument the lab considers essential
dock readonlyInstrumentDockThis belongs to
keystringStable name the dock and the lab's viewState() use
labelstringPanel title, already translated
Flow A narrated walkthrough that drives the lab through its own mutation API

Properties

NameTypeDescription
cameravarLab's camera rig, for steps that carry a FlowStep::view
control readonlystringWho has the board right now: "learner", "flow" or "task"
dwellTarget readonlyrealSim seconds this step is estimated to need (0 while waiting)
flowIdstringStable id; prefixes narration keys and identifies the flow
hintShown readonlybool
indexintActive step, -1 while the flow is not running
labvarSandbox root: source of flowActions() and of the checkpoints
marks readonlyvarActive step's FlowStep::mark names; empty when idle
narration readonlystringActive step's text in the current language
pacingstringHow a step ends: "ready" (default), "auto" or "manual"
pending readonlyboolWaiting on the learner or on the sim
readyProgress readonlyreal0..1 progress through the estimate; 1 means "read it, go on"
readySince readonlyreal0..1 progress through the estimate; 1 means "read it, go on"
refusalstringLabLang key of why the last touch did nothing; "" again after a moment
ripe readonlyboolEstimate has elapsed: Next is the obvious thing to do now
running readonlybool
step readonlyFlowStep
stepslist<FlowStep>(default property)
title readonlystring
titleKeystringDictionary key of the flow's title
unresolvedVerbs readonlyvarVerb names a demo or a solve asked for and the lab does not have
waiting readonlyboolIn a task: the learner must act

Methods

MethodReturnsDescription
applyView(var v)void
check()bool
goTo(int i)void
grants(var id)bool
next()void
prev()void
refuse()void
replayStep()void
run(var actions)void
sayOf(QtObject step)string
solve()void
start()void
stop()void

Signals

SignalDescription
finished()
narrated(string text, string lang, string key)
FlowChip Offer to be taught: starts a Flow, and says that it exists

Properties

NameTypeDescription
flowvarFlow to offer
labelstringText; defaults to the flow's title
FlowStep One stop of a lab Flow: what is said, what the lab does, what the learner does

Properties

NameTypeDescription
demovarActions the lab performs on entering, as [[verb, args...], ...]
dwellvarSim seconds to linger, or "auto" to estimate from reading time
expectvarOptional predicate asserted after the step, for headless checks
keystringStable step name; also the narration key suffix
markvarParts (or sub-parts) this step's line names, as a list of names
saystringNarration text, used when no dictionary entry exists for key
taskvarWhat the learner must do: {until, allow, hint, hintAfter, solve}
viewvarWhere the camera should be for this step. Null leaves it alone
watchvarWait for the simulation, as {until}
Gauge A needle dial that picks its own range - the instrument, not a number

Properties

NameTypeDescription
accentcolorRing/symbol colour - use it to say what this is
facecolorDial face
frameRadiusrealCorner radius of the face
fullScale readonlyrealSelected range - the smallest one the reading fits in
majorEveryintEvery n-th tick is a long one
needleColorcolorNeedle, while the scale has no severity bands
rangeText readonlystringSelected range as a quantity, e.g. "10 mA"
rangesvarFull-scale values on offer, ascending
scaleInstrumentScaleMeasurement this face draws
settleTimeintMilliseconds the needle takes to swing to a new reading
showFrameboolDraw the panel background and border
showValueboolPrint the reading under the dial as well
sweeprealAngular travel of the needle, in degrees
symbolstringLarge glyph in the corner - what this instrument measures
ticksintTick marks across the sweep
unitstringSI unit of value, e.g. "A"
valuerealReading. Its magnitude drives the needle
valueText readonlystringReading as a quantity
GridMode Snap-or-free placement, with grafli's grid contract

Properties

NameTypeDescription
snapboolSnapping to the raster
steprealRaster spacing in world units

Methods

MethodReturnsDescription
quantize(real v, int modifiers)real
snapping(int modifiers)bool
toggle()void
HandheldInstrument An instrument the viewer picks up, applies to the scene, and puts down

Properties

NameTypeDescription
clearOnPutAwayboolPutting the instrument away ends the measurement. Off
count readonlyintHow many picks the subject has
empty readonlyboolNothing picked yet
full readonlyboolMaxPicks reached
glyphstringOne character for the belt chip
heldboolBelt has this one in hand. Set by the belt, read by the visuals
hintstringOne line describing what a click does with this in hand
hoveringvarWhere the cursor is right now, in the same shape as a pick
labelstringBelt caption, already translated
maxPicksintHow many picks make a subject; 0 is unbounded
namestringId-like name, language-neutral - what a pinned probe is named after
pickKindstring"point", "object" or "moment"
picks readonlyvarSubject so far - points, objects or moments, per pickKind
pinnable readonlyboolThere is a reading worth keeping
pinnedReadings readonlyvarWhat has been pinned from this instrument: [{name, at, text}]
tonecolorInstrument's ink
unitstringUnit of value, e.g. "m", "V", "s"
valuerealReading. Bind it
valueTextstringReading as text; defaults to value in unit
viewvarView3D the picks came from - what the visuals project through

Methods

MethodReturnsDescription
add(var pick)void
clear()void
info()var
pin(string probeName)bool
sampler(var snapshot)var
suggestedName()string
undo()void

Signals

SignalDescription
pinned(string probeName)
HintBar Bottom-centre line that says what you can do right now

Properties

NameTypeDescription
flowvarHidden while this Flow runs
leftGuardItemPanel on the left the bar may not grow into
marginintGap kept to the guards
rightGuardItemPanel on the right the bar may not grow into (usually the monitor)
textstringLine to show; empty hides the bar

Methods

MethodReturnsDescription
flash(string message)void
HintJump Keyboard selection: label every target, type the label

Properties

NameTypeDescription
active readonlyboolLabels are up and the keyboard is this component's
cameravarThe View3D renders with (projection dependency)
maxBadgesintOff-screen entries shown before the strip says "+N"
rigvarAn OrbitCamera3D; only focusOn is used, and only for off-screen targets (select-and-fly)
targetsvar() => [{id, pos, name, group}] - what can be jumped to
viewvarView3D to project through

Methods

MethodReturnsDescription
begin()bool
cancel()void
handleKey(var event)bool

Signals

SignalDescription
selected(var target)
InstrumentBelt What the viewer can pick up: the kernel's instruments in every lab, plus whatever the kit brought

Properties

NameTypeDescription
clickSloprealPixels a press may travel and still count as a click
defaultsboolCarry the kernel's own instruments. On, and rarely off
empty readonlyboolHand is empty
held readonlyvarInstrument in hand, or null
heldIndexintWhich instrument is in hand; -1 for none
instruments readonlyvarEverything on the belt: the kernel's, then the kit's, in order
keystringThat cycles the belt, for hints
pinKeystringKey that keeps a reading
pinning readonlyboolName prompt is open
pointervarOrbitInput3D whose picks feed the hand
rowMarginrealHow far above the bottom of the view the belt sits
unitstringThis lab's world is in: "m", "mm", "u" ..
viewvarView3D; defaults to the pointer's

Methods

MethodReturnsDescription
beginPin()bool
cancelPin()void
commitPin()bool
cycle()void
info()var
move(real x, real y)bool
press(real x, real y)void
putAway()void
release()bool
take(int i)void
takeNamed(string n)void
InstrumentDock A column of HUD instruments the reader can put away one at a time

Properties

NameTypeDescription
contentItemDocked instruments (the default property)
hiddenvarKeys currently put away, in the order they were dismissed
isInstrumentDock readonlyboolMarker a DockedInstrument finds its dock by
itemWidthrealWidth every docked instrument takes
revision readonlyintBumps whenever an instrument registers
showTrayboolOffer the put-away instruments back
spacingintGap between stacked instruments

Methods

MethodReturnsDescription
applyViewState(var s)void
hide(string key)void
isShown(string key)bool
keys()var
labelOf(string key)string
show(string key)void
showAll()void
toggle(string key)void
viewState()var

Signals

SignalDescription
changed()
InstrumentScale What a reading means - the measurement model every instrument face draws

Properties

NameTypeDescription
accentcolorColour while the instrument has no opinion
autoRange readonlyboolTrue while ranges drives the limits
dampingrealMovement time constant in seconds - the lag of a real meter
digitsintDecimals in the printed reading, or -1 for three significant figures
displayValue readonlyrealWhere the face actually points - the reading after lag and settling
fraction readonlyrealWhere the face points, 0 at lo and 1 at hi
fullScale readonlyrealAlias of hi, in the language a bench meter uses
graded readonlyboolTrue while the instrument has bands to judge by
hi readonlyrealTop of the scale in force - the selected range, when self-ranging
lo readonlyrealBottom of the scale in force
logScaleboolPosition the reading by its logarithm - equal ratios, equal space
maxrealTop of a fixed scale
minrealBottom of a fixed scale
okUntilrealTop of the good band. Leave unset for an instrument with no opinion
peakFallrealHow fast it then falls, in scale fractions per second
peakFraction readonlyrealWhere the peak marker sits, 0..1
peakHoldboolRemember the highest reading and mark it
peakHoldTimerealSeconds the marker sits before falling
probestringName of a Probe to read instead of value
rangeText readonlystringScale in force, e.g. "0 - 10 mA"
rangesvarFull-scale values on offer, for a self-ranging meter
reading readonlyrealValue as it is read against the scale
settleTimeintMilliseconds a face takes to travel to a new reading
severity readonlystring"ok", "warn" or "alarm"
severityColor readonlycolorColour the reading has earned - accent while the instrument is ungraded
source readonlyrealRaw reading, from probe or value
symbolstringWhat this instrument measures, as a glyph. Defaults to the unit
tickCountintLabelled divisions a face should aim for
ticks readonlyvarGradations, [{value, fraction, major, text}]
unitstringSI unit of the reading, e.g. "V"
valuerealReading. Ignored while probe names one
valueText readonlystringReading as a quantity, e.g. "50.0 mA"
warnUntilrealTop of the warned band
zoneList readonlyvarBands in force, [{from, to, severity}]
zonesvarExplicit bands, [{from, to, severity}], overriding okUntil / warnUntil

Methods

MethodReturnsDescription
colorAt(real v)color
colorFor(string severity)color
fractionOf(real v)real
reset()void
valueAt(real f)real
Lab Global registry connecting parameters, probes and the sim clock

Properties

NameTypeDescription
clockQtObjectActive SimClock (set automatically by SimClock)
flowIds readonlyvarIds of all registered flows (registration order)
headlessboolNo one is watching: skip audio and character travel
paramNames readonlyvarNames of all registered parameters (registration order)
probeNames readonlyvarNames of all registered probes (registration order)
scenariostringName of the currently applied scenario ("" if none)

Methods

MethodReturnsDescription
applyViewState(var s)void
clearProbes()void
labInfo()var
p(string name)real
parameter(string name)Parameter
probe(string name)Probe
probeSummary()var
runFlow(string flowId, var opts)var
set(string name, real value)bool
viewState()var

Signals

SignalDescription
sampled(real t)
LabBanner Centred status pill: something is wrong, or something just happened

Properties

NameTypeDescription
activeboolShow it
alarmboolFault colouring rather than a warning's gold
blinkboolPulse - reserve it for a live fault
fillcolorOverride the severity colour outright
guardItemA panel on either side the banner may not grow into
maxWidthrealHard cap, whatever the guard allows
textstringMessage (already translated)
topMarginrealDistance from the top edge
LabHelp Key map, on screen, generated from a LabKeys

Properties

NameTypeDescription
keymapvarLabKeys to describe
LabKeys Canonical lab key map, and the help text that describes it

Properties

NameTypeDescription
cameravarAn OrbitCamera3D (or anything with orbitBy/zoomBy)
entries readonlyvarComplete map as [{key, label}] - reserved keys included
flowvarLab's Flow, if it has one
frameAllvarCalled on 0; defaults to the lab's frameAll()
frameSelectionvarCalled on F; defaults to the lab's frameSelection()
handKeystringLetter that walks the belt
handKeys readonlyboolThere is a belt to take instruments from
handsvarAn InstrumentBelt - the keys that take, edit and keep a reading
helpVisibleboolToggled by ?, rendered by LabHelp
hintsvarA HintBar for refusals - a key that cannot act says why
jumpvarA HintJump - keyboard selection on f
keysvarLab's own keys: [{key, label, action, hidden}]
labvarSandbox root - supplies scenarios(), applyScenario() and the framing functions
measureKeys readonlyboolA measurement is being taken right now, so its editing keys are live
navKeys readonlyboolThere is a pointer, so Space can lend it to the camera
orbitSteprealDegrees of yaw per Shift+Left / Shift+Right
panSteprealOne arrow-key pan, as a fraction of the camera's distance
pinKeystringLetter that keeps a reading
pointervarAn OrbitInput3D, for the one key that touches the mouse
recordervarA DataRecorder toggled by Shift+R
scaleKeysboolHandle Ctrl+Plus / Ctrl+Minus / Ctrl+0 for LabTheme::uiScale
scenarioNamesvarNames bound to 1..9; defaults to the lab's own scenario list
selectionvarSelected part's card as a keyboard target
selectionKeys readonlyboolA card is selected, so its keys are live
viewKeysboolHandle the arrow/zoom/frame keys

Methods

MethodReturnsDescription
handle(var event)bool
handleRelease(var event)bool
helpText()string
releaseSprings()void

Signals

SignalDescription
refused(string reason)
LabLang Runtime language switch for labs: dictionaries, lookup and number format

Properties

NameTypeDescription
decimalPoint readonlystringDecimal separator of the active language
langstringActive language code, e.g. "en" or "de"
languagesvarLanguage codes offered by the registered dictionaries

Methods

MethodReturnsDescription
langName(string code)string
num(real v, int digits)string
qty(real v, string unit, int digits)string
qtyParts(real v, string unit, int digits)var
register(var dict)void
t(string key)string
tf(string key, ...)string
LabPanel A titled paper panel - the surface every lab HUD is made of

Properties

NameTypeDescription
accentcolorTitle colour
body readonlyItemContent area below the header - anchor to it for fixed-size panels
contentItemStacked children (the default property)
hideOnFocusboolWhether this panel steps out of the way in focus mode. True for everything but a flow's own overlay
paddingintInset around the content
spacingintGap between stacked children
tagstringKey hint shown in the top-right corner, e.g. "M"
titlestringHeading text (already translated)
LabPrefs Handful of settings that must outlive a reload, and where they go

Properties

NameTypeDescription
persistent readonlyboolTrue when a backing store was found; false means memory only
storeNamestringDatabase name. One store for all labs, so the settings are the person's rather than the lab's

Methods

MethodReturnsDescription
forget(string key)void
get(string key, var fallback)string
set(string key, var value)void
LabStage3D Ground every 3D lab stands on: an endless sheet of squared paper, plus the light rig and the environment that go with it

Properties

NameTypeDescription
cellSizerealSpacing of the fine rules and of the snap cue, in world units
cueColorcolorSnap cue: the peg role, one step further from the paper
cueSizerealArm length of a snap cross / diameter of a free dot, in pixels
cueWidthrealStroke weight of the snap cue, in pixels
edgeColorcolorWork-area boundary
edgeWidthrealWork-area boundary weight, in pixels; 0 hides it
environmentSceneEnvironmentThe lab assigns to its View3D
gridModevarGridMode whose mode the surface shows, or a plain bool
ground readonlyModelPick plane itself, for a lab that has to compare hits
horizonFarrealDistance at which it has become the sky exactly
horizonNearrealDistance from the origin at which the surface starts dissolving
keyBrightnessrealStrength of the shadow-casting key light
lightsEnabledboolSet false for a lab that brings its own lighting
majorColorcolorHeavy rules
majorEveryrealHow many cells make one heavy rule. Defaults to 5, as paper does
majorWidthrealHeavy rule weight, in pixels
minorColorcolorFine rules
minorWidthrealFine rule weight, in pixels
overlayMaxBias readonlyintHighest one worth using
overlayMaxY readonlyrealHighest it may sit and still read as a marking ON the ground
overlayMinBias readonlyintLowest sensible depthBias for a marking
overlayMinY readonlyrealLowest a flat overlay may sit and still clear the plane
overlayStep readonlyrealVertical gap between two overlays that must not fight each other
rasterOriginvector2dA world point that an intersection of the raster sits on
shadowMapFarrealHow far the shadow volume reaches, measured from the camera
sheetColorcolorWorking surface
skyColorcolorWhat the surface dissolves into - the environment's clear colour
snapping readonlyboolMode the surface is showing
tableColorcolorOutside the work area
toneScalerealWhat the light rig gives back on a flat, upward-facing surface
workExtentvector2dFull width and depth of the area the lab actually works in
workRadius readonlyrealHalf the work area's diagonal

Methods

MethodReturnsDescription
overlayY(int layer)real
worldAt(var view, real mx, real my)var
LabTheme Shared paper-and-ink design tokens for lab UIs, in light and dark

Properties

NameTypeDescription
ambient3d readonlycolorAmbient fill for a scene lit by a single key light
dark readonlyboolTrue while the dark palette is active
fontAction readonlyintFlow controls - things clicked by name
fontBody readonlyintChips, readouts, buttons
fontLabel readonlyintHand-font labels, notes, help rows
fontLead readonlyintHint bar and a task's hint
fontMicro readonlyintAxis ticks, budget legend
fontSmall readonlyintMono structure: panel titles, row labels, key caps
fontTitle readonlyintNarration, sized for the back row
modestringActive palette: "light" (default) or "dark"
modes readonlyvarPalette names on offer
scaleLabel readonlystringScale as a percentage, e.g. "130%"
shadowFactor readonlyintHow hard a cast shadow lands, as DirectionalLight expects it
spaceL readonlyintPanel padding, canvas insets
spaceM readonlyintBetween chips in a row
spaceS readonlyintBetween stacked rows
spaceXl readonlyintPanel-to-edge margin
spaceXs readonlyintHairline gap
spaceXxl readonlyintPanel-to-panel margin
uiScalerealMultiplies every type size, spacing step and panel measurement

Methods

MethodReturnsDescription
contrast(color a, color b)real
inkOn(color fill)color
px(real v)real
resetScale()void
step(color c, real amount)color
stepScale(int dir)void
toggle()void
LabView Session-wide view state - currently, whether the HUD is out of the way

Properties

NameTypeDescription
focusboolWhether the lab is showing the scene and nothing else

Methods

MethodReturnsDescription
toggleFocus()void
LangSwitch A row of language chips driving LabLang::lang

Properties

NameTypeDescription
languagesvarLanguage codes to offer (defaults to every registered one)
MarkLayer Rings on the world points something is naming right now

Properties

NameTypeDescription
cameravar
camera \brief The camera the \l view renders with.var
count readonlyint
count \readonly \brief How many marks are up. readonlyint
keepOutvarA screen rectangle ({x, y, width, height}) no mark is drawn into, or null
marksvarWhat to ring: world points, each a vector3d or {at, label}
pulseMsintPeriod of the halo that expands out of each ring; 0 draws none
ringSizereal
ringSize \brief Ring diameter at rest, in px.real
tonecolor
tone \brief The ring colour.color
viewvarView3D to project through

Methods

MethodReturnsDescription
clear(real sx, real sy)bool
screenOf(int i)var
MiniMap Abstract view: a fitted 2D projection of the scene, drawn by the lab

Properties

NameTypeDescription
boundsvarWhat to fit, as {x0, y0, x1, y1} - or {empty: true}
contentPaddingrealInset kept around the fitted content
drawvar(ctx, map) -> void: the lab's paint code
emptyTextstringDrawn centred when bounds is empty
map readonlyvarLive projection: {s, sx, sy, ox, oy, px(), py(), width, height, empty}
revisionintBump to repaint. The counter every in-place model needs
uniformScaleboolKeep the aspect ratio, so the shape stays the shape you built

Methods

MethodReturnsDescription
repaint()void
Narrator Learner-facing surface of a Flow: what is being said and where we are

Properties

NameTypeDescription
flowvarFlow to present
showTextboolWhether the panel carries the narration itself
ParamPanel Auto-generated slider panel for all registered parameters

Properties

NameTypeDescription
expandedboolWhether the slider rows are shown
Parameter A named, ranged lab parameter, auto-registered with Lab

Properties

NameTypeDescription
descriptionstringOne-line explanation shown as tooltip/annotation
fromrealLower bound of the value range
namestringUnique name used by Lab, ParamPanel and agents
stepSizerealSlider step (0 = continuous)
torealUpper bound of the value range
unitstringDisplay unit, e.g. "m/s²"
valuerealCurrent value; bind your system to this
PartCard Selection card: what is selected, what it reads, what you can do to it

Properties

NameTypeDescription
adjustvar(part, row, d) -> bool - h/\c l on a domain row; false refuses
anchorDzreal
anchorDz \brief How far below the part's centre the card hangs, in world units.real
anchorYreal
attributes readonlyvar
attributes \readonly \brief What a tag may show: the monitor's quantity keys. readonlyvar
boardBoard
cameravar
camera \brief The camera the View3D renders with (projection dependency).var
flowvarLab's Flow. While one runs, it says whether this card is live
focusRowint
focusRow \brief Which row \c j/\c k landed on.int
focusedRow readonlystring
focusedRow \readonly readonlystring
hintOfvar
hintOf \brief \c {(part) -> string}, the last line.var
keys readonlyQtObjectAdapter for LabKeys::selection
live readonlyboolCard's controls act right now
minWidthOfvar
minWidthOf \brief \c {(part) -> real}, a floor for the card's width.var
monitorvar
monitor \brief The \l WatchMonitor the watch row toggles.var
operatevar(part) -> bool - Enter on the card; false refuses
overlayvar
overlay \brief The \l BoardOverlay the tag row pins into.var
part readonlyvarSelected part, live; null when nothing is selected
readingOfvar
readingOf \brief \c {(part) -> string}, the second line; "" hides it.var
rowsalias
rows \brief The domain's rows, stacked between the reading and the watch row.list<Item>
titleOfvar
titleOf \brief \c {(part) -> string}, the first line.var
viewvar
view \brief The View3D to project through.var
watchable readonlybool
watchable \readonly \brief The part takes a plot and a tag (spec \c watch). readonlybool

Methods

MethodReturnsDescription
rowsOf(var part)var
PartPlacer Palette's parts as ONE handheld tool that carries which part it is about to place

Properties

NameTypeDescription
boardBoard
free readonlyboolSpot is free - the one refusal a placement can meet, and the ghost says so first
partTypestring
partType \brief What the next click places.string
spot readonlyvarWhere the part would land, as board cells {col, row} - null off-board

Signals

SignalDescription
placed(int id)
Plot2D Live time-series plot of probe samples: lines, scatter, uncertainty bands

Properties

NameTypeDescription
cursorReadoutboolRead every series back at the hovered sample
placeholderstringText drawn centred while there is nothing to plot
probesvarProbe names to draw (empty = all registered probes)
seriesvarExplicit series as [{probe, label, color, style, sigmaProbe}], overriding probes
seriesColorsvarColors cycled through per series (LabTheme paper set)
stripBandHeight readonlyrealHeight of one strip's legend band (its title and latest values)
stripMinChartrealSmallest chart a stacked strip is allowed to shrink to
stripsvarStacked charts as [{label, series}], overriding series
windowSecondsrealWidth of the sliding sim-time window

Methods

MethodReturnsDescription
heightForStrips(int n)real

Signals

SignalDescription
seriesClicked(string probe)
Probe A named observable sampled by the SimClock, auto-registered with Lab

Properties

NameTypeDescription
capacityintMaximum retained samples (ring buffer)
exprvarFunction returning the current numeric value
namestringUnique name used by Lab, Plot2D and DataRecorder
samples readonlyvarRetained samples as [{t, v}, ...]
unitstringDisplay unit, e.g. "J"
value readonlyrealMost recent sampled value

Methods

MethodReturnsDescription
clear()void
summary()var
ReadoutPanel A titled panel of live readout rows, built from data

Properties

NameTypeDescription
revisionintBump to re-read rows after mutating state in place
rowsvarReadings, as [{swatch, label, value, valueColor, dim, bar, showSwatch}]
ReadoutRow One line of a readout: swatch, name, live value

Properties

NameTypeDescription
barreal0..1 - draws a share bar under the row, or a negative to omit it
dimreal0..1 - fades the swatch for a stale or inactive source
labelstringWhat it is (already translated)
showSwatchboolDraw the swatch (off for a plain stat line)
swatchcolorColour this thing wears elsewhere
valuestringWhat it reads right now
valueColorcolorValue colour; use alarm to raise it
RecIndicator Recording dot: this run is being written to a file

Properties

NameTypeDescription
recordervarDataRecorder to watch
showRowsboolAppend the row count
tonecolorDot and text colour
ScaleSwitch Makes the whole lab larger or smaller: A-, the current percentage, A+

Properties

NameTypeDescription
showValueboolShow the percentage chip between the buttons
Scenario A named, scripted lab situation, used inside a ScenarioSet

Properties

NameTypeDescription
descriptionstringOne-line explanation of the situation
namestringName used with applyScenario()/the inspector reload action
scriptvarFunction that sets up the situation imperatively
ScenarioBar Clickable preset chips, each carrying what it is worth noticing

Properties

NameTypeDescription
labvarSandbox root (scenarios/applyScenario)
namePrefixstringDictionary prefix for chip labels
namesvarPresets to offer; defaults to the lab's
notePrefixstringDictionary prefix for the active note
showNoteboolShow the active preset's one-liner
ScenarioSet Declarative collection of scenarios wiring the scenarios()/applyScenario() convention

Properties

NameTypeDescription
scenarioslist<Scenario>(default property)

Methods

MethodReturnsDescription
apply(string name)bool
names()var
SceneTitle A title card over the whole picture: fades in, holds, fades out

Properties

NameTypeDescription
atrealWhere the title sits, as a fraction of the height from the top
fadeMsint
fadeMs \brief Fade in and out, in ms.int
textstring
text \brief The title; "" hides the card.string
washrealHow much the picture is calmed under the type, 0..1
SelectionFrame3D Shared hover/select language: a flat frame on the work surface

Properties

NameTypeDescription
halfDepthrealHalf extent along z
halfWidthrealHalf extent along x
heightrealHeight above the surface
hoveredboolThin, quiet outline
noseColorcolorColour of the facing mark
selectedboolFull frame plus nose mark
showNoseboolDraw the facing mark when selected
thicknessrealBar thickness when selected
tonecolorFrame colour (the interactive blue)
SimClock Seeded simulation clock driving deterministic probe sampling

Properties

NameTypeDescription
fixedSteprealLength of a fixed simulation step; 0 disables stepped
maxStepsPerAdvanceintFixed steps allowed per advance, so a hitch cannot become a freeze
sampleIntervalrealSim-time seconds between probe samples
seedintSeed for the deterministic random generator; changing it resets the clock
time readonlyrealSimulated seconds since the last reset
timeScalerealSlow-motion/fast-forward factor for live (frame-driven) mode
worldvarOptional ClayWorld2d; when set, time advances with physics steps

Methods

MethodReturnsDescription
random()real
randomGaussian()real
randomRange(real from, real to)real
reset()void

Signals

SignalDescription
stepped(real dt)
wasReset()
Stopwatch How long something took, in simulated seconds: click to start, click to stop

Properties

NameTypeDescription
running readonlyboolStarted and not yet stopped
stopped readonlyboolA completed timing is on the face
TapeMeasure Clicked points chained into a run, with the length of every leg, the angle at every corner and the total on screen

Properties

NameTypeDescription
angles readonlyvarAngle at each interior corner, in degrees
arcPxrealRadius of the angle arc, in pixels
dotPxrealRadius of a vertex dot, in pixels
lengths readonlyvarLength of each leg
plan readonlyvarRun projected into view pixels - what the overlay draws
readout readonlyvarWhole measurement as data: segments, vertices and total
total readonlyrealTotal length of the run
ThemeSwitch A button that swaps the lab between the light and dark palette
TransportChip Sim time, pause and speed - the clock, on screen

Properties

NameTypeDescription
clockvarSimClock; the active one by default
digitsintDecimals on the time readout
paused readonlyboolClock is standing still
showSpeedboolOffer the speed cycle
speedsvarSpeed rungs the button cycles

Methods

MethodReturnsDescription
cycleSpeed()void
toggle()void
WatchChip Put this thing on the plot - the watch toggle, in three states

Properties

NameTypeDescription
full readonlyboolNo series left to give
labelsvarDictionary keys for the three states
monitorvarWatchMonitor that owns the watch set
targetvarId to watch
watched readonlyboolTarget is on the plot
WatchMark Dot a watched object wears in the world, in its curve's colour

Properties

NameTypeDescription
labelstringText beside the dot; empty draws the dot alone
monitorvarWatchMonitor supplying the colour
onlyWhenWatchedboolHide unless the target is actually on the plot (the default)
targetvarWatched id
tone readonlycolorTarget's series colour
WatchMonitor Watch a thing, get a probe, a colour and a curve

Properties

NameTypeDescription
canWatchvar(id) -> bool: veto (a solder dot has no reading)
idPrefixstringProbe-name prefix; probes are <idPrefix><id>
labelOfvar(id) -> string: the legend/board label
maxSeriesintBeyond this the colours would repeat
maxStripsintHow many quantities may be stacked at once
placeholderstringShown while nothing is watched
plotHeightrealChart height - the budget the strips divide
plotWidthrealChart width
quantitiesvar[{key, label, unit}]
quantitystringActive quantity key: what setWatched traces in, and what the chip row shows as chosen
revisionintBump when labels change (ordinals, renames)
stripModel readonlyvarWhat the plot is drawing: one entry per traced quantity, in quantities order, as [{key, label, series}]
tracedQuantities readonlyvarQuantity keys that currently have a strip, in quantities order
unitText readonlystringUnit of the active quantity
valueOfvar(id, quantity) -> real: the current reading
watched readonlyvarIds, in plot order - which is also colour order
windowSecondsrealPlot window

Methods

MethodReturnsDescription
clear()void
colorOf(var id)color
isFull()bool
isTracedIn(string quantity, var id)bool
isWatched(var id)bool
probeName(var id, string quantity)string
prune(var stillExists)void
setWatched(var id, bool on)void
toggle(var id)void
traceIn(string quantity, var id, bool on)bool
traceOnly(var list)void
traces()var
unitOf(string quantity)string
watchOnly(var ids)void

Signals

SignalDescription
changed()
WorldLabel A 2D chip pinned to a point in a 3D scene

Properties

NameTypeDescription
accentcolorBorder colour - use it to carry meaning
activeboolSet false to hide without unloading
cameravarThat View3D renders with
contentItem readonlyvarItem children are parented to
gaprealPixels between the point and the chip
keepInViewboolKeeps the chip inside its parent instead of letting it leave
marginrealClosest the chip may come to the window edge
offsetpointExtra pixel nudge, applied after placement
onScreen readonlyboolWhether the anchor point is in front of the camera
placementintSee Placement
textstringConvenience one-line content
viewvarView3D to project through
worldPositionvector3dScene point to pin to