Repository navigation
Muscles: a 0.8 m/s push from the side fells a standing POWERED figure that the servo holds by stepping #821
Description
The case. Siltreach (a private game on ae3d) tried the opt-in muscles (#815, motion.set_muscles) on its people. Its hit station pushes five POWERED figures at the chest the way ae3d's own balance tests do; on muscles, a side push that the servo stands through by stepping fells the figure.
Setup (ae3d d62ddbc, aephysics f0bd6d621, Aether 0.831.0; game build 3c47057, SILTREACH_STATION=hits SILTREACH_SEED=1, 60 Hz fixed step):
- The figure: the game's own person (an MPFB 2 human built in Blender on a game-engine skeleton: pelvis, spine_01..03, neck_01, thigh/calf/foot, upperarm/lowerarm under Root; 57 bones, the feet hanging from the calves), 1.75 m, dressed with
physics.ragdoll_dress_namedon aphysics.ragdoll,motion.active_ragdoll; POWERED, standing in its clip's idle (softer knees than ae3d's straight-legged test rig). Ragdoll mass 78.4 kg. - Muscles on:
physics.physics_set_ankles(physics.of(e), true)before the ragdoll is made (14 bones),motion.set_muscles(m, true)right afteractive_ragdoll. - The push at 2.0 s:
motion.hit(m, BONE_SPINE_03, chest, impulse, true, cost)with impulse 62.7 N·s along +x (0.8 m/s times the mass), the figure facing +z: square from the side.
Numbers, the same station and seed:
| servo (muscles off) | muscles on | |
|---|---|---|
| dummy 3, 0.8 m/s from the side | stands, steps: worst lean 0.53 rad, pelvis lowest 0.82 m | falls: worst lean 1.64-1.89 rad, pelvis lowest 0.14 m, gets up |
| dummy 1, 0.5 m/s from behind | lean 0.05 | lean 0.02 |
| dummy 2, 1.0 m/s from behind | lean 0.18 | lean 0.22 |
| dummy 4, 0.5 m/s from in front | lean 0.16 | lean 0.20 |
| dummy 5, 5 m/s from behind | falls, gets up | falls, gets up |
tests/test_balance.ae's envelope has the figure out of 1.0 m/s from the side by stepping; on muscles this one goes over at 0.8. In the frames it staggers, stands about a second, then goes over sideways about 1.3 s after the push and lands face down.
Log lines (game journal):
servo: {"kind":"push","dummy":3,"speed":0.8,"impulse":62.719,"from":[1,0]}
{"kind":"dummy","dummy":3,"fell":false,"got_up":false,"lowest":0.822239,"worst_lean":0.526091,"hips_gap":0.0151329,"standing_end":true,"mode":"powered"}
muscles: {"kind":"push","dummy":3,"speed":0.8,"impulse":62.719,"from":[1,0]}
{"kind":"dummy","dummy":3,"fell":true,"got_up":true,"lowest":0.140084,"worst_lean":1.63781,"hips_gap":0.015133,"standing_end":true,"mode":"powered"}
Frames (on the dev machine): contact sheets D:\Git\siltreach\build\scratch\mu_cap\push_m0.png (servo) and push_m1.png (muscles), frames 122, 130, 140, 150, 165, 180, 200, 240, 300, 420 at 60 Hz (the push lands on frame 122), left to right then the second row; dummy 3 is the middle figure, seen from in front. Every frame from 122 to 420 is beside them in push_m0\ and push_m1\ (p_NNNN.png). Journals: D:\Git\siltreach\build\scratch\mu2_hits_on\log.jsonl, mu2_hits_off\log.jsonl.
On the game's side, to rule it out: the game's body driver caps each bone's muscle by the injury model through motion.set_part_strength per part (twelve bones mapped to parts); an ankled figure's two feet are never capped, so they keep their full strength, which may matter here. Its per-bone loops (hit events, the collision filter by mode, a shape's bone) now cover all fourteen; that changed nothing in these numbers (lean 1.89 before, 1.64 after).
Activity
nicolas-maman commentedon Oct 19, 2026
Not reproduced from ae3d alone. The probe: Siltreach's drifter.glb at 1.75 m, dressed by name as
body_newdoes (physics.ragdoll(e, name, at, 8, 8, 1),ragdoll_dress_namedwith the twelve game-engine names),active_ragdoll+motion.attach, ankled, on a flat box ground at friction 0.8. It stands in the glb's ownIdleclip, either POWERED from the start or ANIMATED then POWERED at the push. Thenmotion.hit(m, BONE_SPINE_03, chest, side * v * mass), square from its side, ae3d 1b8ebf7:So the muscled figure leans more than the servo, but nowhere near a fall. The game's servo leans 0.53 at 0.8 m/s against 0.10 here, so the game's setup upsets its figure about five times as much. What the probe doesn't have: the game's animator and its captured idles (softer knees, the moods), the sand terrain under the feet,
apply_caps/set_part_strength, and the body driver's own step order (motion_stepafter the world's).Could Siltreach add a standalone repro under
repro/, likegetup_topple.ae? One dummy standing in the idle it uses, on its ground, pushed 0.8 m/s from the side, withSILTREACH_MUSCLES0/1. Then this can be bisected over those differences from the ae3d side.(#822, the backward roll on the knock, reproduced on the drifter and is fixed on PR #824: the fall keeps its brake until the figure lands.)
nicolas-maman commentedon Oct 20, 2026
A repro on Siltreach's own stack, and what it narrows down (siltreach 9011f55:
repro/side_push.ae, on this machine atD:\Git\siltreach\repro\side_push.ae; buildae build repro/side_push.ae -o build/side_pushin D:\Git\siltreach with Aether 0.831, ext/ae3d at d62ddbc).It makes one hit dummy as the hits station does: the drifter (build/assets/people/drifter.glb) at the game's scale for 1.75 m, facing +z, POWERED; siltreach.animator writing its idle before the world steps (
REPRO_ANIMATOR=0:figure.play(Idle)), siltreach.body building and stepping the body (motion_step after the world's step, then its per-bone caps), siltreach.limbs setting the caps each step (REPRO_LIMBS=0: none); pushed at 2.0 s throughbody_hit(motion.hit) at the chest, 0.8 m/s times the mass along +x.SILTREACH_MUSCLES=1as before (ankles on).Worst lean after the push (rad), nothing falls in any of these:
REPRO_FRICTION=0.9)REPRO_LAND=1): siltreach.ground's static mesh collider, friction 0.9, level there (normal 0.999997 up)The hits station's dummy 3: servo 0.53, muscles falls (1.64).
So:
nicolas-maman commentedon Oct 22, 2026
Moved under the animation epic #853, milestone #858 (the physics asset and physical animation layer).