Repository navigation
Holding things: grasp, place, release, handover, swap (an#502) - #535
Merged
Merged
Conversation
Core action kinds that move an item between holders (a body's point, a
socket of another prop, the ground, a flight) inside the solve pass, so a
pick-up, a put-down, a hand-over or a swap looks handled rather than
teleported:
- the hand reaches its goal on a minimum-jerk path (a pull row whose goal
is a per-frame track, kept inside the ring the chain can reach) and
retracts; the item changes holder at the contact frame keeping its world
pose (no slide, no jump);
- when the goal is out of reach, the chain's root turns about its pivot by
the least angle that brings it in (closed form, `lean`, 60 degrees by
default), and the parts riding on it turn with it;
- a carried item follows its holder (mirror and squash included) and turns
to the hand's frame over the retract (`align`); a place aligns it with a
socket's frame or lays it on the ground at its rest angle, its lowest
painted pixel (the texture's alpha hull) on the floor; a release is a
parabola under gravity, or a toss to `ground@x` on an `arc`;
- `solve: {ground: y}` is the floor line; `overrides: {held_by: ...}` says
what holds an item when the shot opens;
- checks: hold_conflict and unreachable_hold (errors, the latter with which
way to move the carrier), floating_item (warning);
- `EntityKind.landmarks` (genre API level 8): named points a rig has no
bone for (the cut-out genre's hands, `stu@hand_r`).
Two solve fixes the hold layer exposed: a part that draws a speck (a
one-pixel "empty" swap key) is a body of the default extent at its pivot
(it drifted off its joint), and in pose mode a passenger part (nothing
acts on it or below it) keeps its document angle (heads and idle arms
swung about their joints as a figure walked).
- passengers are parts no joint or verb ever names: a pin's end no longer snaps the part back (P2 behaviour kept for driven parts); - a release orders before a catch at one instant; one frame's events keep the schedule's order; - the reach swings in an arc about the shoulder (no flip through it); - a gesture reaching after the shot's end is refused; - reach rows are not reported as rejoins; - the second plan uses where the grasp really put the item; a ground place is measured by the item against the floor; - the speck rule only for drawings under 2 px both ways; - a moving part holds one item, whatever point of it is named; opposite leans at once are said; an item that holds another is refused by name; - contract package 1.10.0 (the five vocabulary entries).
This was referenced Oct 25, 2026
Merged
Closed
This was referenced Oct 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Picking up, putting down, handing over and swapping a held object, as declarative actions that look handled rather than teleported. The body-frame half of #502 (its owner comment: "a frame can be a node of a rig ...
reframewith a duration ... the floor is one of the frames ... mirroring"); the world-frame half (P4b, a bottle leaving a car) stays open there.What a scene says
Grammar and defaults:
.claude/skills/an/references/holding-things.md.How it works (
an/stage/hold.py, inside thesolvepass)pullof the hand's point whose goal is a per-frametrack(an arc about the leaning shoulder from where the shot has the hand to the goal and back, angle and distance minimum-jerk blended, the distance kept in the ring the chain can reach so it is never refused), and frees the chain's authored channels for its span._solve_lean), capped bylean(60 degrees), a fixed point among gestures that bend one root; what rides on it (head, other arm) turns with it viaPuppet.leantargets; legs stay planted.HOLD_PLAN_PASSES = 2).align, as a socket would); a place blends it to the socket's frame or to its rest angle on the ground; contact with the floor is the lowest point of the texture's alpha hull (a carved part's transparent margin does not float); a release is a parabola under the shot's or pack's gravity (else 980), or a toss solved to land atground@x.__solve__clip;meta.extensions.solve.holdsreports each gesture (contact, gap, lean), each item's holders, floating items.hold_conflict(error; the compile raisesHoldErrortoo),unreachable_hold(error, with which way and how far to move the carrier),floating_item(warning).EntityKind.landmarks(genre API level 8): named points a rig has no bone for. cutan registers a character'shand_l/hand_r(companion PR in reeleehq/cutan).Two changes to the existing solve pass (behaviour fixes, found by this work)
_local_box: a drawing smaller thanDFLT_BODY_EXTENTon both sides (a one-pixel "empty" swap key, the transparent-part workaround) is a body of the default extent at its pivot. As a speck many widths from its pivot, the solver could not hold it: the carved Stu's face slot drifted up to 365 px off its joint during a walk.pin_upper_tip,pull_torso,join_upper_world_then_unjoin, in each nesting mode). Corpus byte-identity (scenes with no joint or verb) holds; P2's own tests pass unchanged.Both are guarded by tests that go red when the fix is deleted (mutation-checked locally):
test_a_passenger_part_does_not_swing_when_its_body_moves,test_a_part_that_draws_a_speck_stays_on_its_joint, andtest_a_part_a_joint_let_go_of_stays_where_it_was_left(tests/test_solve.py).Seams (v1)
EntityKind.landmarkssolve: {ground}, else the carrier's lowest root partNot seams: the reach path shape, the flight, no bounce, the report layout.
Verified where
Compiled-document tests (
tests/test_holds.py, 32 tests on a fixture figure that bends at the hip): exact contact (gap under 0.5 px), no frame-to-frame jump of the grip beyond the hand's own step, riders bend with the root, socket alignment, ink-hull floor contact, toss landing at x on the floor, drop, mirror carry, swap, handover at meet 0.5, conflicts by name, unreachable with direction, floating warning, landmarks hook, determinism. Rendered on a developer machine (not CI): the carved Stu picking a musket and a falcata off the floor, placing the musket in Napoleon's figurine hand (drawn over the figurine's own swap-slot musket at half opacity, the two coincide), swapping it for the sword, tossing the musket back onto the floor; and cutan's factory-character demo. A render can change pixels for shots that declare joints or verbs (the two solve fixes): labelrun-browser-tests.Not built (follow-ups)
A draw order that changes with the holder (the item draws where it is staged), placing onto a prop's surface other than the floor (
support_top), a crouch (legs that bend), bounce or friction on landing, holds across cuts.Independent adversarial review (done; findings fixed in this PR)
hold_conflict).jointhe scene never wrote: reach rows are left out of the rejoin snaps.unreachable_holdnow says so; a part that moves holds one item whatever point of it is named.Contract package: 1.10.0 (the five new vocabulary entries,
python contract/build.py bump --level minor).Closes nothing yet: the body-frame half of #502; the world-frame reframe (P4b) stays open there. Companion: reeleehq/cutan grasp-hands.