- Robot arm (category Industry): picks goods off the end of the nearest conveyor within its reach
and puts them on the start of another conveyor within reach, or on a pallet a quarter turn on
(pick / put: auto or a side). One move per item coming in (cycle 0) or a set cycle; waits while
the line before it stands. The belt it feeds carries its goods at its pace and starts its loop
when they land (feeds carry a time offset `ph`), so arm and belts stay in step.
- Drawn as a 16-pose flipbook: two-link inverse kinematics per pose, each pose shown for a
sixteenth of the cycle by a stepped CSS animation (iso-flip; pose 0 alone when unanimated).
Poses pointing away from the viewer are drawn before the base, the others after it.
- New sprite method beam(a, b, n, w, mat): a square bar between two 3D points, six faces culled
and shaded like face(). Native, so the factory demo renders in 4.7 ms instead of 18.8 ms.
- Factory demo: a palletiser at the end of the carton line, a loading robot passing drums from the
incline onto the loading belt into the truck. MCP instructions on robot arms.
Checks: 70 Rust tests (arms and belts in step, waiting arm, beam faces from every side),
Studio 109/109, web 90/90.
- Producer (category Industry): a press making cartons, crates, drums, sacks or parts at a set
rate per minute; its ram goes down once per item, a green / red light shows running / stopped.
- Conveyor: drawn the way it runs (new prefab meta `directed`: the Studio turns the piece from
where the drag starts), belt width, height, rise (inclines), speed, goods and spacing; legs,
rails and a drive motor. Corners join without overlap (the receiving belt runs through, the
feeding one stops at its side).
- A conveyor starting on a producer's output side carries its goods at its rate; one starting at
another's end carries on with what that one carries. The gap is speed / rate. A stopped press or
belt stops the goods after it. Tooltips show speed, rate and source.
- The goods ride a group moving one gap per loop (no reordering), first fading in, last out.
- Script API: world_of(o, u, v), info_row(key, value); objects_on falls back to half of p.d.
- Theme: industry colours, LED colours (the marker's LED had none).
- examples/factory + Factory demo in the web Studio; MCP instructions on production lines.
Checks: 68 Rust tests (conveyor joints, feed and spacing, every view of the factory demo),
Studio 108/108 (draw direction, feed from a producer, rate change), web 89/89.
Measured with the new tools/bench_web.py on the web Studio's house demo, CPU slowed 6x:
- Idle: running CSS animations repainted the whole drawing every frame (99% of the main
thread in a window). Animations now step on about ten times a second by default
("light", 5% idle); the new toolbar button switches light / smooth / off and the browser
remembers it; [build] animation sets the default for built pages; view.animation().
Pan and zoom gestures pause them. Status LEDs pause off-screen and with the rest now.
- Pan 28 -> 10 ms, zoom 69 -> 11 ms per step: gestures move the drawing as one compositor
layer (transform) and set the viewBox once they end; --iso-k is set on the tags group
only and only when it changes; the stage box is read once per frame.
- Hover 22 -> 15 ms per move: the tooltip is placed once per frame on its own layer and
measured only when its text changes; the Studio's x/y readout updates ten times a second
in a contained box; hover work in the Studio runs once per frame.
- Long object lists skip layout of rows out of sight (content-visibility).
- WASM built with opt-level 3: engine render 11.7 -> 9.4 ms for 10% more download.
Checks: Studio 102/102 (animation modes, pan as a layer, contained readout), web 87/87.
Selection: S.sel stays the object picked last; S.selIds holds everything
selected.
- In the object list, Ctrl+click adds or removes an object and
Shift+click selects a range.
- On the map, Ctrl/Shift+click toggles an object and Shift+drag draws a
box that selects what lies wholly inside it (locked and hidden objects
are left out).
- Ctrl+A selects everything that is not locked; Esc selects nothing.
- Clicking a wall or fence a second time selects every piece of the same
type joined to it; another click goes back to that one piece.
- Dragging one selected object moves them all, together with the windows
and doors on them, as one undo step. Arrow keys, R (turns the group
about its middle), Ctrl+D, Delete, Lock and Hide all work on the whole
selection.
- When all selected objects share a type, the property form edits them
all; fields where they differ show "mixed".
- The agent's system prompt lists the selected objects.
The viewer outlines several objects with selectObj([ids]) and passes the
click event to onPick. A batch op now answers `ids`, one per operation,
so the copies from a group duplicate get selected.
Pond (Nature): natural, round or square, with a stone or grass edge,
fish, lily pads, spreading ripples and reed clumps. The fish come from a
new Swim primitive (script: s.swim). One matrix maps the object's frame
to the screen. Each fish turns round its ellipse with a CSS rotation,
so off-screen pausing and reduced motion apply as for the other
animations. The house demo gets a koi pond in the back garden.
Tests: ponds in every shape and rotation have the right number of fish,
no NaN and no depth-sort cycles, and stay inside their rectangle.
check_studio covers list and map multi-select, a group drag undone in
one step, joined-fence selection, a mixed-value form applied to all, box
select, delete and undo, Ctrl+A, Esc, and a new pond's fish.