Repository navigation
v0.3.0
An additive release. Nothing on the wire changed meaning, and a caller that says nothing new behaves exactly as it did.
A line can name the hand its gesture uses
A one-handed gesture picks an arm afresh on every playback. The table authors one pose and mirrors it onto whichever hand is free — every entry was checked on both — and the draw is there because a character who waves with the same arm every time reads as a mechanism rather than a person.
side, L or R, pins it for a caller that has a reason to: the hand away from the document, or the same hand the line before used.
yarn ctl gesture peace --side L
yarn ctl say "こっちだよ" --gesture pointUp --side LIt is one optional field per line rather than one per sub-field, because a turn plays a single movement — gesture's, or the one perform names — and a hand written twice could only ever disagree with itself. On a two-handed gesture there is no hand to choose and it fixes which way the head turns instead.
It reaches say, perform and gesture on the control API, --side on the three matching ctl verbs, speak, react and revise in the MCP tools, and a side key on a script line. An inline cue deliberately does not carry it: [@gesture peace] mid-sentence draws its hand as before, and a line that needs a particular one names the movement on the line rather than inside it.
A motion loaded off disk states L or R itself and ignores the field, since a file that keyframed one arm keeps that arm.
A take holds its document layer between frames
The recorder composites the slide layer into a canvas of its own and copies it flat while nothing about it moves. A page held for thirty seconds was previously the same rescale of the largest rectangle in the frame eighteen hundred times, which is the difference between meeting the rate that was asked for and recording under the one the file claims.
The held layer is invalidated by the page, the crossfade opacity, the rectangle and the output size, so a page turn costs what it always did. The recording context opens desynchronized, and the held canvas is released when a take ends, since the next one may be a different size.
The guides
recording.md now explains why a take comes out variable-rate and what to do about it: a frame exists only when the compositing canvas is redrawn, so a 50 Hz display caps a 60 fps request at an average like 49.36. The file itself is in sync — packet spacing, frame spacing and both stream start times line up — and the drift only appears in a player reading a variable rate as a fixed one. The ffmpeg pass that settles it is written out, audio stream-copied.
shell.md is new, and is the first place the native shell is written down in full: the three processes yarn shell starts, the server it adopts rather than replaces and the one it refuses by name, the menu, the status lines, where the window state and the children's output are written, and which two URLs its windows are allowed to load.
The rest of the pass brought the guides back in step with the runtime — the renderer's URL parameters, the server flags and environment variables, the ctl verbs that are not commands, the limits on three MCP tools, and what each speech state means all have tables now — and settled the Japanese edition on one register and one vocabulary.