Precision dispense

How a student closes the last few millilitres of a volumetric transfer with a Pasteur pipette — one drop at a time, under a hard-prevent overshoot guard. Second step of a two-stage pattern: the coarse pour was already animated in the prior step; this step is where the student does the precision work. Same operation as drip, two extra fields, no new authoring vocabulary.

Filling a graduated cylinder to exactly 20 mL is not a one-shot pour. Real labs split the transfer in two: pour close to target with the source vessel, then top up the shortfall with a pipette. The first stage is coarse and bulk; the second is fine and metered. This page is about the second stage.

The mechanism is discrete drops. Each tap on the pipette's bulb dispenses one drop of a known volume. The student counts drops — or watches the meniscus rise — until the target is reached. If the next drop would overshoot, the pipette refuses it: the drop hangs at the tip and reabsorbs. Hard prevent, no exceptions.

Two lesson-script fields control the behaviour: target_volume_ml (where to stop) and drop_size_ml (how big each drop is). Drop count itself isn't authored — it's just shortfall ÷ drop_size, computed live from whatever the prior pour deposited. The SME tunes drop_size so the math lands cleanly on the target.

  1. 1

    The pipette lies on the desk.

    At step entry, the camera focuses on the action zone. The pipette rests on the desk between a source beaker (holding the working liquid) and the destination cylinder. The cylinder already holds liquid from the prior coarse-pour step. A contents chip on the cylinder body shows the running volume — the substance label, extended with a live quantity readout for the duration of this step.

  2. 2

    The student picks up the pipette and drags it to the source.

    Same gesture as moving any object on the desk: click the pipette, drag, release. The pipette lifts off the desk and follows the cursor. The student drags the tip into the source beaker — the vessel holding the working liquid. Snap-on-proximity highlights the source's opening as a valid drop-into target.

  3. 3

    The student taps the bulb to aspirate.

    One tap fills the pipette to its working capacity — 4 mL or so, comfortably more than any plausible shortfall. The bulb compresses, the liquid column rises into the central reservoir, the bulb releases. No fine control here: aspiration is mechanical, not the lesson. Filling stops automatically.

    The lab object's pour_from / pour_to anchor purposes are reused for the dip-into-source target selection — the same anchors drip already consumes today. No new authoring.

    Production view: pipette tip inside the source beaker, step bar reads 'Tap the pipette to aspirate the water'.
  4. 4

    The student moves over the cylinder and dispenses, one tap per drop.

    The student drags the pipette over the cylinder's opening, then taps the bulb. Each tap is one squeeze, one drop. A drop emerges from the tip, falls into the cylinder, the meniscus rises one tick. A floating “+X.X mL” indicator (the drop volume) rises from the impact point at a slight outward angle and fades within ~1.1 s. The substance label on the cylinder updates per drop.

    Drop count is emergent — shortfall ÷ drop_size_ml. The runtime never stores the count; it just checks, before each drop, whether the next one would overshoot the target.

    Production view: pipette positioned at the cylinder rim mid-dispense, '+0.2 ml' floaters rising from the meniscus area, substance label reads 'Water 248 ml', step bar reads 'Tap the pipette until you reach 250 ml'.
  5. 5

    Target reached. The bulb locks; Continue appears.

    When the meniscus lands on the target volume exactly, the bulb locks — further taps are no-ops, with a denied-audio cue. A Continue button reveals via the existing StepBarHandler arming path (analogous to simulation_complete). The student presses Continue, the step ends, and any liquid still in the pipette stays in the pipette — no discard step in v1.

What if the student keeps tapping?

The bulb still squeezes visually — the gesture is acknowledged. A drop forms at the tip, but if it would push the cylinder past the target volume, the drop hangs there and reabsorbs into the pipette. No volume changes, no floater spawns, no label updates. The student sees, drop after drop, that further dispensing is refused. Same hard-prevent posture as everywhere else in the lab.

A one-shot <lab-volume-floater> spawns at the meniscus impact point on each accepted drop, rises at a slight outward angle, and fades within ~1.1 s before removing itself from the DOM. IBM Plex Sans Bold 15 px, white fill, 1 px stroke at rgba(0, 0, 0, 0.30) painted outside the fill via paint-order: stroke fill. Legible against the coloured liquid column inside the destination cylinder; the tiles below put the floater on a faux water backdrop so the white reads in isolation.

The floater is volume feedback, not identity: it is not a label, it carries no name, and hide_label does not suppress it. The chip states it fires alongside — including the live {substance} — {quantity} mL readout — are contents-chip vocabulary and live on Object labels § H.

+ 0.4 mL
+ 0.4 mL · canonical scene drop
+ 0.2 mL
+ 0.2 mL · finer increment
+ 0.05 mL
+ 0.05 mL · trace drop
+ 0.2 mL + 0.2 mL
rapid-tap stack · trail at 0.5 opacity