Lodur/docs/first-slice.md
Nibu ef7386a35d First slice: PD-muscle humanoid ragdoll on Ymir's SoA world
Lodur.Core: engine-free PD law with per-muscle strength. Lodur.Body.Ymir: 13-body, 12-joint ragdoll
driven through the world's torque lanes from caller-owned strength and target arrays. Tests: stand, fall,
rest, per-muscle strength, torque conservation, no allocation, same seed gives the same state hash.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 04:07:37 +00:00

43 lines
3 KiB
Markdown

# First slice: a PD-muscle ragdoll on Ymir
Bad Day Simulator ladder rung 1: a body that stands, falls and rests deterministically, read through
Ymir's structure-of-arrays world. Nothing above layer 5 exists yet.
## What is built
- `Lodur.Core` (`netstandard2.1`, no references): `Quat`, `MuscleGains`, `PdMuscle.Torque`. A PD law on one
joint: the child's rotation relative to the parent and their relative angular velocity in, a torque out.
Strength is a multiplier on every gain; zero is limp and returns exactly zero. Swing (joint frame x, y) and
twist (z) have separate gains.
- `Lodur.Body.Ymir` (`net8.0`, references Ymir.Box3D): `HumanoidRagdoll` builds 13 bodies and 12 joints in a
caller-owned `Box3DSoaWorld`: capsule limbs, box pelvis, torso and feet, a sphere head, ball joints at
spine, neck, shoulders and hips, hinges at elbows, knees and ankles. `Drive(strengths, targets)` writes
each muscle's torque onto the world's torque lanes (equal and opposite on child and parent). The strength
array and the target array belong to the caller; nothing is copied or retained, and a tick allocates
nothing (tested).
- Tests (`tests/Lodur.Tests`): the PD law's behaviour; stand, fall, rest; per-muscle strength; torque
conservation; fractional strength scaling; no allocation; same seed, same state hash.
## Measured (Linux x64, Debug native build, one machine)
- At 120 Hz, with full strength and a random one-step shove from the seed (up to 30 N m per axis on pelvis and
torso), the ragdoll holds head height 1.73 m (initial 1.74) through 1.5 s for seeds 1, 2, 3 (tested) and
through about 2 s in the exploratory runs. It then topples: there is no balance controller, so a
pose-holding PD ragdoll is an inverted pendulum with soft ankles.
- With zero strength it falls (head under 0.6 m within 1 s) and its trunk comes to rest within 6 s for seeds
1, 2, 3 (trunk under 0.05 m/s and 0.2 rad/s). Extremities can keep rocking: a head resting on an arm
chattered at up to about 3.5 rad/s for 10 s in one seed. The test bounds it (under 0.6 m/s, 6 rad/s); it
does not claim every body is still.
- Same seed gives the same FNV-1a hash of every body and joint lane at 14 checkpoints, in one process. A
different seed, or one strength element changed, gives a different hash.
## Not measured, or limits found
- Cross-platform bit-identity: unclaimed. Windows build and Unity consumption: unrun. One machine, Debug
native build only; no Release run, no run in a second process.
- Explicit PD through torque lanes limits stiffness and damping: damping times the step must stay under the
inertia it acts on. Hips and spine went unstable at damping 15 and 20 and are set to 3 and 4; the gains
are tuned by running, not derived. Stiff ankles (what balance needs) need joint springs or motors inside
the solver, which Ymir's SoA world does not expose yet.
- A bare sphere rolls on forever, so the head takes a rolling resistance (0.1).
- Hands, a rig licence question, impairment, contact facts (pain input), body removal: not built.