← Back to Docs
  • index.html
  • Clayground
  • Clayground.Lab
  • HandheldInstrument
  • Clayground 2026.7
  • HandheldInstrument QML Type

    An instrument the viewer picks up, applies to the scene, and puts down. More...

    Import Statement: import Clayground.Lab
    Inherited By:

    PartPlacer, Stopwatch, and TapeMeasure

    Properties

    Signals

    Methods

    Detailed Description

    The other kind of instrument. A Gauge or a DockedInstrument is mounted: the lab author bound what it measures when the lab was written, and it reads for the whole run. This is the half that was missing - the user binds the subject at runtime, by pointing, and the reading dies with the gesture. A tape measure, a voltmeter held across two terminals, a stopwatch.

    The contract

    A handheld declares three things and inherits everything else:

    It handles no input and knows nothing about the camera: the InstrumentBelt forwards OrbitInput3D::picked to whichever instrument is held. That is the acceptance test for this contract - a new instrument is one file that says what it picks and what that means, with no gesture code in it.

    Pinning

    pin() is the one transition out: it snapshots the subject, registers a Probe under the given name, and from that moment the reading is sampled on the sim clock's grid like any other - so it lands in the run record and a paper can cite it. Pinning asks for the name because that name is what gets cited; a column called measure_1 is a bad citation forever.

    A subclass says how a pinned reading keeps reading by overriding sampler(): the default freezes the value it had, which is right for a tape measure between two fixed points and wrong for a voltmeter, which overrides it with a closure that keeps asking the circuit.

    HandheldInstrument {
        name: "tape"; label: LabLang.t("hand.tape"); glyph: "\u{1F4CF}"
        pickKind: "point"
        value: Measure.total(picks)
    }

    See also InstrumentBelt, TapeMeasure, Stopwatch, and Probe.

    Property Documentation

    clearOnPutAway : bool

    Putting the instrument away ends the measurement. Off.

    It was true while a measurement could only be taken in a mode of its own: leaving that mode was leaving the question, so the run went with it. There is no such mode now, and the case that matters runs the other way - measure the gap, then pick up the road tool and build to it. A reading that vanished the moment you reached for something else would make that impossible.

    So a measurement ends when you say so: Esc, or the instrument's own clear. Set this true for an instrument whose subject genuinely cannot outlive the holding.


    count : int [read-only]

    How many picks the subject has.


    empty : bool [read-only]

    Nothing picked yet.


    full : bool [read-only]

    maxPicks reached.


    glyph : string

    One character for the belt chip.


    held : bool

    The belt has this one in hand. Set by the belt, read by the visuals.


    hint : string

    One line describing what a click does with this in hand.

    A LabLang key, for the lab's hint bar. It lives on the instrument because only the instrument knows: "click measures" is a lie while a stopwatch is out.


    hovering : var

    Where the cursor is right now, in the same shape as a pick.

    {point, object, x, y}, or null when the cursor is off the scene. Fed by the InstrumentBelt from the pointer, for the same reason view is: an instrument does not reach for the camera.

    This is what a preview is drawn from - the ghost of the part that would be placed, the rubber band to the next measured point, the highlight on the thing under the cursor. Showing what a click would do before it does it is the difference between a tool you learn by trying and a tool you learn by undoing.


    label : string

    Belt caption, already translated.


    maxPicks : int

    How many picks make a subject; 0 is unbounded.


    name : string

    Id-like name, language-neutral - what a pinned probe is named after.


    pickKind : string

    "point", "object" or "moment".


    picks : var [read-only]

    The subject so far - points, objects or moments, per pickKind.


    pinnable : bool [read-only]

    There is a reading worth keeping.


    pinnedReadings : var [read-only]

    What has been pinned from this instrument: [{name, at, text}].


    tone : color

    The instrument's ink.


    unit : string

    Unit of value, e.g. "m", "V", "s".


    value : real

    The reading. Bind it.


    valueText : string

    The reading as text; defaults to value in unit.


    view : var

    The View3D the picks came from - what the visuals project through.


    Signal Documentation

    pinned(string probeName)

    A reading was kept.

    Note: The corresponding handler is onPinned.


    Method Documentation

    void add(var pick)

    Contributes one pick, per pickKind. What the belt calls.

    A pick that does not carry what this instrument needs - no ground point under a "point" instrument, nothing hit under an "object" one - is ignored rather than stored as a hole.


    void clear()

    Ends the measurement.


    var info()

    The reading as plain values, for an agent or a test.


    bool pin(string probeName)

    Keeps this reading: registers a Probe that goes on sampling it.

    The one way a handheld reading becomes mounted, and therefore the one way it reaches a run record. Returns false when there is nothing to pin. The measurement itself is ended by pinning - what was a question is now an instrument, and leaving both on screen says the same thing twice.


    var sampler(var snapshot)

    Returns the function a pinned probe samples. Override to keep reading.

    snapshot is a copy of picks taken at the moment of pinning. The default returns the value frozen at that moment, which is correct for anything whose subject cannot change; an instrument bound to something live overrides it and closes over snapshot instead.


    string suggestedName()

    The name pin() offers - name plus a counter.


    void undo()

    Takes the last pick back.