Skip to content

Motion: the animation system of #853 end to end, and every open motion issue - #891

Merged
paul-hammant merged 26 commits into
mainfrom
feat/anim-pipeline
Nov 1, 2026
Merged

paul-hammant merged 26 commits into
mainfrom
feat/anim-pipeline

Conversation

@nicolas-maman

@nicolas-maman nicolas-maman commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Every open motion and animation issue in one pull request: the animation system of #853 built end to end (M0 to M8), and each motion defect closed by a fix and the test that measures it, or shown fixed with its evidence. Work is in dependency order. A box is ticked only when its issue's own acceptance list is met on this branch, and this PR merges only when every box is ticked.

The animation system (#853), in order

Where it stands

Done: #856 (the graph, the mover, starts, stops, turns on the spot, motion matching) and most of #855 (rig, clips, retargeting, root motion, 100STYLE captures; left: lifting the 96-bone cap to 256).

#857, IK and constraints, built in ae3d.ikrig and held by tests/test_ik_constraints.ae (16 checks, all passing):

measured held to
walk, jog, crouch and idle, feet locked: the most a knee and an elbow bend; a knee behind straight 133°, 150°; 0 mm 150°; 1 mm
a hand turned 90° about its forearm: off its grip; what the wrist took (the forearm the rest) 0.00003 mm; 44° 5 mm; 40 to 50°
a FABRIK spine bowing the head 10 cm on: off the point; bone lengths 0.51 mm; 2e-13 mm 1 mm; 0.01 mm
a hand 15 cm past its arm's length, whole-body reach: the hand; the feet held 1e-6 mm; 2e-13 mm 5 mm; 1 mm
a rifle held bladed in both hands, aimed 40° right and 15° up at 10 m: the barrel; the hands off their grips; the forearm off the trunk 0.10°; 0.002 mm; 24 cm 1°; 5 mm; 12 cm
walking on flat ground: a sole into the floor, the clip alone and with ikrig 29 mm and 0.008 mm 5 mm
five 0.2 m stairs, a stride deep, up and down: a foot down's sole off the ground; into it 0.07 mm; 0.05 mm 1 cm; 5 mm
five 0.2 m stairs 0.3 m deep, a tread a step (stride warping to 0.40): the same; the knees 0.94 mm; 0.94 mm; 138° 1 cm; 5 mm; 150°
a 20° ramp up and down at 0.7 of the stride: a foot down's sole off it; into it; a flat foot against the clip's 4.5 mm; 0.008 mm; 4.4 mm 1 cm; 5 mm; 5 mm

Left in #857: one foot system (ae3d.feet, motion's feet and ae3d.lookat retired onto ikrig, with #860), and #700's reach across the trunk (an elbow swung clear of the trunk got the palm from 22 to 19 cm but turned the arm at 26 rad/s against its 14; not kept). On the ramp at the walk's own stride the trailing toe stands 16 mm off the slope at push-off; the test walks it at 0.7 of the stride, as people step short up a steep slope.

tests/test_anim_pipeline.ae: 81 checks, all passing: a planted toe's slide now 0.03 to 1.4 mm with toes bent at the ball, against 5 mm; a look checks where the head points, within 2°; and turning half round on the spot (#898), no foot crosses the hips' middle (was 16.7 cm past it: a planted foot's heading was held in the turning figure's frame), each step lifts its foot 60 mm (steps slid along the floor), and no ankle passes 3 m/s (a stepping foot jumped 16 cm between frames).

tools/anim_showcase.ae (off CI) has seven figures: a runner and a female through starts, stops and sprints; a mannequin on a block taking hits; 100STYLE's captured walker; the figure on a stick (graph, mover, matching); a climber on stairs and a ramp with a bowl (AE3D_WATCH=6); a rifleman aiming with both hands (AE3D_WATCH=7).

Also in this PR: the dependency move to Aether 0.860.0 (worker.wait's tuple, file.close) and aephysics 7985511, on which all 290 programs and the editor compile; and the README, rewritten to say what ae3d is and does, with the animation pipeline in it.

CI: GitHub's ubuntu-latest moved to 26.04 during this PR, and its GCC flagged a memset in aephysics's update_mesh_contact (a byte count in 32-bit wrapping int); aephysics ad0cae2 fixed it and main is back on ubuntu-latest (#901), both merged in here. From this PR: actions/cache saved only after a passing job, so a shard cut off cold never saved and stayed cold (the first Linux suites shard hit 40 minutes twice); the compile cache is now saved whatever became of the run, with Run CI stopped six minutes inside the job's limit, and ci.sh type-checks the modules in its pool (the first Linux suites shard's type-check went from 19 to 25 minutes one module at a time down to 10; the shard from cut off at its limit to 23.5 minutes).

docs/animation-pipeline.md has the reference.

- worker.wait answers (ran, why): the image preload takes the count.
- std.file's long names are gone: file.close for file_close in
  test_scene_io and generate_shaders.
- wait_for_idle now panics inside an actor or on a scheduler core; ae3d
  does not call it.
- aephysics 7985511, its main on 0.839's @keep rules, builds on it.

All 290 programs and the editor compile on 0.860 without an error.
…, on real people (#853)

One pose a frame, one writer: a figure's animator evaluates its pose and
writes it to the figure's joints once, in the pose phase. Games set
parameters and never write bones. The layers, beside the old modules,
which stay frozen until #860 retires them:

- ae3d.pose (L0): a rig read once from a skin, its joints mapped onto the
  UE5 mannequin's 53 humanoid slots from UE5, Rigify or Mixamo naming;
  poses as flat arrays; blends, masks, additive differences, model space.
- ae3d.retarget (L0): a take carried from one humanoid to another, rest
  poses aligned bone by bone, the pelvis and root scaled by the two
  pelvises' heights.
- ae3d.clips (L1): an animation resampled for a rig at the file's key
  rate, with root motion taken out and, read at import, foot contacts,
  planted frames, speed over the ground, heading and footfall sync
  markers.
- ae3d.animator (L2): states and 1D blend spaces, inertialized
  transitions (Bollo, GDC 2018), gaits blended on their footfalls and
  played at the speed the figure moves, hand-overs in step, masked and
  additive layers, root motion onto the figure's object.
- ae3d.ikrig (L3): feet on the ground under each foot with the pelvis
  dropped for the lower one, the foot locked on its heel then its toe's
  tip where the clip plants it, the heel peeled up when the leg cannot
  reach, two-bone legs with soft reach, the head turned to a point.

The test figures are real people for the first time: the Quaternius
mannequins (UE5 skeleton, male and female) and a Rigify-named one, with
89 authored clips, CC0, in tests/fixtures/people (#854).

tests/test_anim_pipeline.ae holds the layers to:
- a planted toe's slide with feet locked, 1 to 8 m/s: under 1e-12 mm;
- the blend's speed against the speed asked: within 1%;
- idle to sprint and back, inertialized: no joint faster than the
  takes' own;
- retargeted segments against the source's: 0.00005 degrees;
- root motion carried exactly;
- a foot onto a 10 cm block within 5 mm, at most 4.4 degrees a step.

tools/anim_showcase.ae shows three figures on the layers, and
docs/animation-pipeline.md describes them.
The README opens on what the engine is and why it is built the way it is
(measured, driven by programs, one language, two renderers at parity),
then lists what is inside by area, each with its doc. The animation
pipeline is in it with the numbers it is held to and a real frame from
tools/anim_showcase.ae, now under a late afternoon sky on a dark ground.
Links point at aether-lang-dev/ae3d, the roadmap names only open work,
and the layout follows the modules as they are.
@nicolas-maman nicolas-maman changed the title The animation pipeline: rigs, takes, retargeting, the animator and IK, on real people (#853); Aether 0.860 Motion: the animation system of #853 end to end, and every open motion issue Oct 30, 2026
…eet (#855)

- pose.mirror: each joint's turn from rest reflected onto its other side's
  joint (names with left and right swapped), places reflected. The
  mannequins' rest poses are their own mirrors to 0.02 degrees; a walk
  mirrored twice is itself to 2e-6 degrees; a mirrored walk leads with the
  other foot at the same speed. clips.mirror does a whole take.
- Clip events: named moments of a take, footfalls found at import, fired by
  the animator as its clock passes them (a blend's from its heaviest take).
- ae3d.bvh reads motion capture (Xsens naming mapped as a fifth scheme,
  End Sites as joints, units found from the height); tools/bvh_cut.ae cuts
  stretches of a take unedited. Nine cuts of 100STYLE's Neutral takes
  (CC BY 4.0, Ian Mason) are the fixtures: walks and runs forward, back and
  sideways, turns, a stop and a start.
- Planted feet must also move with the ground: a capture's shuffle at a
  turn was low and flat and went 137 mm through its "stance". A take whose
  pelvis travels in its frames is on still ground, at its pelvis's speed.
- The retargeter aligns the figures' facings (from the thighs), aligns
  hands and toes to a child where a slot is missing, and keeps the feet on
  their contacts: a planted ball held on the source's ground
  (clips.ground_carry), the pelvis lowered where a leg cannot reach, legs
  solved by two-bone IK, the source's contacts kept. 100STYLE's walk and
  run onto the UE5 mannequin: a planted toe holds to 4.5 and 4.0 mm a
  stance, against 46.8 and 19.4 mm turned bone by bone and the capture's
  own 6.9 and 5.6 mm.

test_anim_pipeline: 44 checks, all passing.
…st (#855)

- A figure with a character controller is moved by its capsule: the root's
  travel is the step's velocity, so a wall stops it. The roll goes its
  root's 4.99 m on open ground and stops at 1.705 m against a wall whose
  face is at 2.0 (the capsule 0.3 wide).
- Loops are sealed at import, as Unity's Loop Pose seals them: the gap
  between a loop's last frame and its first spread over the take, root
  travel and pelvis placement left alone. UAL's idle, jog and sprint ended
  0.5 to 0.8 degrees off their starts; every loop now closes to 2e-6.
- Measured: sampling a 53-joint take costs 0.32 microseconds a character.

test_anim_pipeline: 50 checks, all passing.
…ng (#855)

- Retargeting a capture (no root bone) onto a rig with one makes the root
  under the hips: its place and heading averaged over 0.4 s either side,
  narrowed at the ends so it starts and ends under the hips. Its root
  motion is the hips' travel exactly (1.786 of 1.786 m on the walk).
- The root lock holds the root over its rest place, facing as at rest:
  a capture's figure was drawn 8 m from its object (where the actor stood)
  and 100STYLE's backward walk carried it 45 degrees off its back. The
  root's turn is read as its twist about up (the UE5 root's forward axis
  points up, and read off it the turn was always 0).
- clips.straighten: no turn, the travel on its line, or on the nearest of
  forward, back, left and right; the captured walker in the showcase goes
  out and back on its line to 1e-13 m.
- The retargeter holds a planted foot by its toe's tip, as ikrig locks it
  (ikrig.toe_local, shared): the backward walk's toe went 5.1 mm held by
  the ball, and now 1e-12 mm; the walk and run likewise.
- A planted foot must also be still only over a still ground (a capture
  read whole): filtered on an in-place sprint, the runner's lock let go
  mid-stance at 8.5 m/s and its toe went 327 mm.
- 100STYLE cuts are whole strides, left footfall to left footfall, where
  travel and hips both keep their direction (README lists frames and sums).
- animator.current_take; the showcase's fourth figure walks the captured
  forward and backward walks on a capsule by root motion.

test_anim_pipeline: 64 checks, all passing.
…rgeting with IK goals (#855)

The layer table gains ae3d.bvh and what each layer now does; a section on
motion capture (read, retarget, root made under the hips, root lock,
straighten) and one on events, sealed loops and mirrors; the techniques
gain IK goals in retargeting and planted-means-still; the numbers table
gains each new measurement from test_anim_pipeline.
- animator.add_blend2 / blend_add2 / set_velocity: a blend space over the
  ground's two directions, each take at its velocity relative to the
  figure's facing, weighted by polar gradient band interpolation
  (Johansen 2009, Unity's freeform directional), its takes in step by their
  footfalls and paced so their blended velocity (a vector sum) carries the
  ground at the speed asked. blend_weight reads a take's weight.
- Blends carry root motion: their takes' root deltas, weighted.
- clips.loop_cut: a capture's best loop, the two frames at least 0.6 s
  apart whose key joints' places and motion match best, cropped (crop) and
  sealed. Cut between footfalls, 100STYLE's strides ended 16 to 41 degrees
  off their starts at a foot, too far to seal, and wrapping jumped the foot.
- seal_loop seals the pelvis's place too when the take's root carries its
  travel; only a joint that travels is left alone.
- Over a still ground a dragged foot is neither planted nor down: the side
  step drags its trailing foot for most of a stride, and the lock held it
  and let go a third of a metre behind.
- clips.mirror keeps the take's contacts, left for right.

100STYLE's walks and runs forward, back and to either side on the UE5
mannequin, moved at 8 directions by 0.6, 1.0 and 1.4 m/s with feet locked:
a planted toe slides 1.8e-12 mm at worst, the speed matched exactly.
test_anim_pipeline: 66 checks, all passing.
…, held poses, aim offsets (#856)

- Named parameters (set_float, set_bool, trigger) a game drives the graph
  by; blend spaces bound to them (bind, bind2).
- Transitions the graph takes by itself when all their conditions hold:
  a parameter ABOVE or BELOW a value, a switch IS or IS_NOT on, a trigger
  TRIGGERED (spent when taken), the state's take ENDED; from a state or
  ANY; inertialized, or cross-faded with both states playing.
- snapshot: a state holding the pose drawn now, to blend out of (what a
  get-up starts from).
- Aim offsets: aim poses at their yaw and pitch, blended by gradient bands
  and added over a mask as their difference from the level one.

On the Rigify mannequin: a graph of idle, gaits and a roll driven by its
parameters alone goes idle, gaits, idle, roll, idle, its fastest joint
turn 32.6 rad/s under the takes' own 38.7; halfway through a cross-fade the
pose is 42 and 43 degrees from states 83 apart; a held pose stays within
2e-6 degrees; the pistol's aim offset holds the hand at 0.90, 1.40 and
1.80 m aimed down, level and up, and aimed level leaves the idle as it is.
test_anim_pipeline: 71 checks, all passing.
…#855)

macOS's leak check found the two controllers capsule_root_motion made: a
controller a program makes with physics.character_controller is its own to
free (physics frees only those it made), as test_character frees its own.
- ae3d.mover: the controller a game drives with a velocity and, for
  strafing, a facing. Holden's springs move the figure's object and feed
  the graph its parameters (vx, vz, speed, moving, go, turning, travelled,
  rest); the gait is the graph's choice from the real velocity. It brakes
  at a constant deceleration when set (set_braking), from a stop take's own
  (clips.braking), so the stop enters where its feet are in the stride.
- Distance matching (Paragon, GDC 2016): animator.clock_by plays a take by
  a parameter's distance, from its start or left to its end, from the frame
  it is entered; clips.travel_length, time_at_distance(_left), moving_at,
  still_at (the first stand after its fastest).
- Transitions entered in step (transition_synced: a start hands over to
  the gaits at its stride's phase) and choosing among targets by the feet
  (transition_or: a stop or its mirror, whichever's feet match).
- clips.straighten re-integrates the path in the root's own frame (a
  turn's step as the root took it) and turns poses and path together onto
  the nearest axis: zeroing a stop's 29 degrees of turn and dropping its
  path's side slid its planted ball 362 mm over its own ground. Loops cut
  for the blend are straightened onto their axes too.
- Fixture: 100STYLE's straightest forward stop of every style's
  transitions (LookUp; the Neutral style has none).

On the UE5 mannequin, a mover and a graph of idle, a start, the 2D blend
and a stop: stand, walk 4 s at 0.8 m/s, let go: idle, start, gaits, stop,
idle, no planted toe sliding 9e-13 mm with the feet locked. The 2D blend
matches the speed asked exactly at 8 directions within its samples.
test_anim_pipeline: 73 checks, all passing.
…856)

- ikrig.feet_set_steps: while a figure stands, a planted foot the clip has
  turned or moved off where it is held steps there: lifted 6 cm at its
  middle over 0.28 s (quicker for a foot far behind), set down and locked
  again; one foot at a time, the next lifting as the first is 70% down;
  begun on the twist the foot will have half a step on (stepped on the
  twist alone, a fast turn left a foot 58 degrees behind the body).
- A locked foot keeps its heading over the ground as the body turns above
  it, its toe no longer swept round its ankle.

The UE5 mannequin on its captured idle, turned half round on the spot by a
mover (its facing on a 0.6 s half-life): 10 steps of 18 degrees, a planted
toe still to 4e-13 mm, the hips 5 mm off their spot, no planted foot more
than 38 degrees further off the body than it stood.
test_anim_pipeline: 75 checks, all passing.
…rough toe-off (#856)

- animator.add_matcher / matcher_add / matcher_build: a state that plays
  whichever frame of its takes best fits the pose drawn and the way ahead
  asked (Clavet, GDC 2016; Holden; Unreal's pose search): features of each
  foot's place and velocity about the root, the hips' velocity, and the
  root's place and facing a third, two thirds and a whole second on, each
  scaled by its spread. Searches every 0.1 s; changes, inertialized, only
  for a clear gain over playing on, and only to frames that keep each
  planted foot planted within 15 cm (changing into a frame with a planted
  foot elsewhere dragged it a third of a metre off its lock). Looping takes
  play on round.
- mover.set_follow: the figure moved by its clips' own root motion, the
  springs a simulation it is eased toward (at most 0.2 m/s over its own
  motion: each metre eased is a metre a planted foot's lock drifts) and
  kept within 15 cm of; set_matcher asks the matcher for the simulation's
  way ahead, from where the figure stands.
- ikrig: a foot's heading is its twist about up from rest (read heel to
  toe over the ground it swung 50 degrees in two frames as the foot rose
  onto its toe); the heading held through a stance is eased out with the
  place when the lock lets go, and a lock that slips eases out too (both
  snapped before, a foot swinging 105 degrees in a frame). A turn on the
  spot now takes 7 steps of 26 degrees, no planted foot more than 0.7
  degrees further off the body than it stood.

On the UE5 mannequin over 100STYLE's walks, runs, side steps, turns, a
start, a stop and a stand: the matcher plays a frame going ahead at 0.69
m/s while walking, left at 0.48 m/s while stepping left, still at rest,
no planted toe sliding over 1.4e-12 mm. Its fastest joint turn, 25.6 rad/s
against the takes' own 14.8, is printed and not yet held: a database of
the style's whole takes is the next step.
test_anim_pipeline: 76 checks, all passing.
…a stick (#855, #856)

- The retargeter aligns a bone that one rig has nothing beyond (the UE5
  head has no child) by the bone coming into it on both rigs: left
  unaligned, the mannequin's head, pitched 11 degrees at rest where the
  capture's stands upright, bowed that much further than the capture's.
  The capture test now holds the head's own orientation, not only the
  neck's line: within 1.2e-6 degrees on the walk, run and backward walk.
- tools/anim_showcase.ae's fifth figure (AE3D_WATCH=5): the UE5 mannequin
  on a mover and a graph of the captured stand, start, 2D blend of walks,
  runs and side steps, and stop (and its mirror), its feet stepping as it
  turns on the spot, the runner's pistol aims retargeted as an aim offset,
  its eyes ahead: through 24 s it stands, walks, steps left and right
  facing ahead, runs, stops, turns round on the spot, walks back aiming,
  stops and turns round again. The showcase's own circling figures'
  struct is a Circler now (the mover's is a Mover).

test_anim_pipeline: 79 checks, all passing.
…n the spot, motion matching (#856)

The layer table gains the graph's states and transitions and ae3d.mover; a
section shows a figure on a stick (a 2D blend, a start and a stop played by
distance, transitions in step and by the feet) and what each technique is
and where it comes from; the numbers table gains each new measurement.
…rs and slopes (#857)

Limbs: two-bone limbs with hinge limits (no knee or elbow past 150
degrees, no knee bent back) and the hand's extra twist shared into the
forearm; one triangle (ae3d.ik.triangle) under the pose rig's limbs and the
physical figure's. FABRIK chains within cones. Whole-body reach with
effector weights: the spine and the hips lean to what the arms cannot
reach, the feet held. Aim over the spine with hands held on a joint, so a
rifle aimed with the chest carries both hands in the same solve.

Feet on any ground: soles traced heel, pad and toe where the foot goes;
one surface laid on with the ankle stood off along its normal, a stair's
edge rested on by its corner (found by halving); a swinging foot looks a
foot's length ahead for an edge; after the leg solve the foot is rested on
the ground by its lowest point and its toes bent at the ball out of it
(the walk clip alone sinks a toe 29 mm); the pelvis down by what the lower
foot and each leg's reach need; a capsule's step up leaves feet and pelvis
where they were in the world; stride warping for stairs.

tests/test_ik_constraints.ae (16 checks) holds it on the Rigify mannequin;
the showcase gains a climber on stairs and a ramp and a rifleman.
…#857)

Found watching the showcase, measured on it with its new AE3D_METRICS mode
(per figure: legs through each other, a knee out off the hips, the chest
off the hips, a forearm over-rolled, and when):

- A retarget carried points through the world, so a source figure kept
  out of sight 50 m below put the showcase's female 50 m underground; the
  new sole clamp then reached for the ground 50 m up and her planted toes
  slid 0.9 m a cycle. Points are carried over each figure's own ground.
- ikrig's figure forward ran heel to ball, 30 degrees down: every look
  pointed the head 30 degrees over its target. Levelled; the pipeline's
  look test now checks where the head points (1e-6 degrees off).
- A knee bent in the clip's plane taken against the line to a foot held
  off the clip's place swung out up to 90 degrees and crossed the legs
  (the climber's legs came 2 cm apart). A knee keeps the clip's plane
  within 20 degrees of its hinge's, and is held there past it.
- The pelvis drop for reach no longer squats to reach a foot left behind
  by a lock: only by how far the ground fell away under it.
- geometry's growth doubled an int without a bound, so a memset could be
  sized by a negative number; GCC's fortified memset warned on Linux
  (test_falls). The growth is bounded and sized in 64 bits.

The showcase's rifleman turns his whole body to his target (55 degrees of
chest off the hips down to 19), its climber walks the ramp at the slope
stride, and AE3D_WATCH_FRONT=1 watches a figure from in front.
…, #898)

Watching the showcase from in front (AE3D_WATCH_FRONT=1) and measuring
knees caving in and feet crossing (AE3D_METRICS=1), with the feet IK on
and off: the IK caved the runner's knee in 33 degrees (5 with it off).
A knee was bent the way the clip bends it measured off the line to its
target; with the foot held off the clip's place, that line leans and the
knee turned in. Held to the hinge from the thigh's twist instead, it swung
out 90 (authored clips do not twist their thighs as their knees bend). It
now takes the clip's bend off the clip's own hip-to-foot line, turned onto
the line to its target by the least turn between the two: knees in 5 to 7
degrees, out as the clip has them; the block step's fastest turn back to
4.4 degrees a step.

test_falls failed to build on Linux (GCC's fortified memset warned)
once motion imported ae3d.ik for the shared triangle; motion keeps its own
copy until it moves onto the pipeline (#860), and the geometry change made
for it is backed out (it recompiled every suite, and the linux leg ran out
of time on a cold cache); the growth overflow it fixed is #899.
- README: the animation block names what the pipeline now does (BVH
  capture with its feet kept, the state graph, motion matching, the
  mover, IK to joint limits, FABRIK, whole-body reach, a rifle in both
  hands, soles on stairs and slopes) and its numbers as the tests measure
  them today: a planted toe under 1.5 mm from 1 to 8 m/s, no sole 1 mm
  into 0.2 m stairs or a 20 degree ramp. The showcase is seven people.
- CI: GitHub's ubuntu-latest moved to 26.04, whose GCC misses every
  object cached on 24.04, and actions/cache saves only after a job that
  passed: the suites' first Linux shard was cut off cold at 40 minutes on
  two runs, saving nothing, and the third passed at 39.5. The compile
  cache is now restored and saved as two steps, the save whatever became
  of the run, and Run CI stops six minutes inside the job's limit so a
  cut-off run still saves.
- ci.sh prints the six lines GCC puts over a build warning (the
  function, what it was inlined from), so the memset 26.04's GCC flags
  in test_falls is named on the next run.
…#898)

Found on the showcase's figure on a stick (a knee 51 degrees out, a foot
10 cm over the hips' middle as it turned round), reproduced without a
window in test_anim_pipeline's turn on the spot, which now measures what
a player sees there too:

- A planted foot's heading was read in the figure's own frame, which a
  mover turns: the clip's foot never turned in it (4.2 degrees through a
  60 degree turn), so the lock held nothing and the foot swung round
  with the body on its toe, its heel 14 cm across the other leg. It is
  read over the ground now; the figure takes 10 steps of 18 degrees for
  half a turn where it took 7 of 26 dragged round.
- A step kept its foot's lock until it landed, and the heel's peel about
  the locked toe and the toe's return over its lock both still pulled
  the foot back to where it stood: the stepping ankle jumped 16 cm
  between frames. Neither holds a foot that is stepping.
- A stepping foot was held down on the ground as the clip has it (a
  stand has both feet down), so a step slid along the floor, its ankle
  never 13 mm up. It is lifted through its step now, 60 mm at its middle,
  and laid on the slope at its ends only.

Turning half round: no foot past the hips' middle (4.9 cm short of it,
was 16.7 cm past), each step lifts its foot 60 mm, the fastest ankle
0.89 m/s; a planted toe slides 0.0007 mm. test_anim_pipeline 81 checks,
test_ik_constraints 16, test_matching 16, all passing.
GitHub's ubuntu-latest 26.04 GCC flagged a memset in aephysics's
update_mesh_contact as sized by a negative int: aephysics declared
memset's size as a 32-bit int, so `old_count * 4` was worked out in
wrapping int arithmetic. aephysics 9ea02c3 (branch
fix/mesh-contact-memset) takes the size as a long and computes every
byte count in 64 bits from its count. test_falls builds without a
warning and passes its 21 checks.
main pinned the Linux jobs to ubuntu-24.04 (266f2c9, #901), where the
memset warning does not show, so this PR need not hang on an aephysics
branch with no pull request yet. The fix (aephysics 9ea02c3, branch
fix/mesh-contact-memset: memset sizes in 64 bits) returns with the move
back to ubuntu-latest under #901.
The type-check ran aetherc on some 150 modules one after another, and
on the first Linux suites shard it took 19 minutes on a warm runner and
24.6 on the 26.04 image (run 41249856048): with the suites, the Vulkan
validation pass and the benchmarks after it, that shard was cut off at
its limit with its tests all passed. Each module's check now runs in
ci.sh's pool (in_pool, as the builds do), its log and status kept, and
the results are said in the same order after.
@paul-hammant
paul-hammant merged commit 6fda12b into main Nov 1, 2026
10 checks passed
@nicolas-maman
nicolas-maman deleted the feat/anim-pipeline branch November 1, 2026 16:23
nicolas-maman added a commit that referenced this pull request Nov 1, 2026
After #891, a merge that touched most of the engine, main's first Linux
run on the 26.04 image built cold and its linux and linux-2 legs were cut
off at 34 minutes in Run CI (run 41279330619), each leaving a rerun to
finish what it had started. A cut-off run and its rerun cost more than
one run let finish, and a warm shard (24 minutes) never comes near the
limit. Run CI stops at 54, six inside it, so a cut-off run still saves
its compile cache.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants