Lane D R17 (v3.2): the drummer's pelvic-lean (ledger #1)
The R16 seated drummer sat bolt-upright (the sit clip can't carry a pelvic tilt
— Hips.quaternion is unusable on these rigs). Fix: a small constant forward torso
lean applied POST-MIX. spawnRig({seated}) caches the mid-spine bone (seatBone);
seatedLean(spine) rotates it forward ~0.34 rad each frame after the mixer resets
it (constant offset, not accumulation); band.js calls it for m.seated members.
The drummer leans into the kit — head 0.28m forward of the hips, reads as a real
drummer from the side.
Byte-identical (my signature): standing rigs get no seatBone (found only in the
seated block) and seatedLean runs for seated figs only. Verified with the lean
live — walkers 188/188 face travel, keeper standing rig (stature 1.718,
hasSeatBone:false, innerRotY pi). No existing consumer moves.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6fffd19043
commit
6671cf08f4
@ -6,6 +6,25 @@ _rotOnly/head-bone normalize/upgradeStreetPeople). Measurements on the M3 Ultra
|
||||
|
||||
---
|
||||
|
||||
## ROUND 17 — v3.2 THE TAIL: the drummer's pelvic-lean (ledger #1)
|
||||
|
||||
*PROCITY-D, 2026-07-16. The R16 honest limit — the upright bent-leg sit read stiff — is fixed. Files
|
||||
`rigs.js`, `band.js`. Byte-identical proof holds (my signature discipline).*
|
||||
|
||||
The sit clip can't carry a pelvic tilt (`Hips.quaternion` is unusable on these rigs — R16), so the R16
|
||||
drummer sat bolt-upright. **Fix: a small constant forward torso lean applied POST-MIX.** `rigs.js`
|
||||
`spawnRig({seated})` now caches the mid-spine bone (`seatBone`), and `seatedLean(spine)` rotates it forward
|
||||
~0.34 rad each frame AFTER the mixer resets it (so it's a constant offset, never an accumulation). `band.js`
|
||||
calls it for `m.seated` members only. The drummer now leans into the kit — verified **head 0.28 m forward
|
||||
of the hips**, reads as a real drummer from the side (the R16 stiffness is gone).
|
||||
|
||||
**Byte-identical proof**: standing rigs get **no `seatBone`** (found only in `spawnRig`'s seated block) and
|
||||
`seatedLean` is only called for seated figs. Verified with the lean live: streamed walkers **188/188** face
|
||||
travel, keeper is a standing rig (stature **1.718**, `hasSeatBone:false`, `innerRotY:π`). No existing
|
||||
consumer moves. Seated-only, parallel path — same discipline as R16.
|
||||
|
||||
---
|
||||
|
||||
## ROUND 16 — v3.1 THE FLIP: the drummer finally sits + backline unification
|
||||
|
||||
*PROCITY-D, 2026-07-16. Ledger #2 (sit-clip wiring) + #5 (amp at C's `backline[]`). Files `rigs.js`,
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
import * as THREE from 'three';
|
||||
import { rng, shuffle } from '../core/prng.js';
|
||||
import { pickRig, spawnRig } from './rigs.js';
|
||||
import { pickRig, spawnRig, seatedLean } from './rigs.js';
|
||||
import { makePlaceholder } from './placeholder.js';
|
||||
import { loadGLB } from '../core/loaders.js';
|
||||
|
||||
@ -271,6 +271,7 @@ export class GigCrew {
|
||||
for (const m of this.members) {
|
||||
if (m.actor.mixer) m.actor.mixer.update(dt); // rig idle
|
||||
else m.actor.tick && m.actor.tick(dt, false); // placeholder idle
|
||||
if (m.seated) seatedLean(m.actor.seatBone); // R17: tilt the drummer forward into the kit (post-mix)
|
||||
const f = m.actor.fig, b = m.base, ph = m.phase;
|
||||
if (m.part === 'band') {
|
||||
if (m.seated) { // drummer: seated bob + a little shoulder work, planted
|
||||
|
||||
@ -189,6 +189,7 @@ export function spawnRig(rig, { ry = 0, clip = null, height = 1.75, phase = 0, s
|
||||
const mixer = new THREE.AnimationMixer(inner);
|
||||
const chosen = clip || rig.anims.find(c => /idle/i.test(c.name)) || rig.anims[1] || rig.anims[0];
|
||||
const act = _action(mixer, inner, chosen);
|
||||
let seatBone = null;
|
||||
if (act) {
|
||||
act.time = phase * (act.getClip().duration || 0); act.play();
|
||||
// R16 SEATED re-plant (OPT-IN — standing spawns skip this, so keepers/browsers/band are byte-identical).
|
||||
@ -202,10 +203,22 @@ export function spawnRig(rig, { ry = 0, clip = null, height = 1.75, phase = 0, s
|
||||
let m = Infinity;
|
||||
inner.traverse(o => { if (o.isBone) { o.getWorldPosition(_wp); m = Math.min(m, _wp.y); } });
|
||||
if (isFinite(m)) inner.position.y -= m;
|
||||
// R17 pelvic-lean: cache the mid-spine bone so seatedLean() can tilt the torso forward each frame (the
|
||||
// sit clip can't — Hips.quaternion is unusable on these rigs). Seated-only; standing rigs get no seatBone.
|
||||
inner.traverse(o => { if (!seatBone && o.isBone && /Spine1$/i.test(o.name)) seatBone = o; });
|
||||
}
|
||||
}
|
||||
function dispose() { mixer.stopAllAction(); mixer.uncacheRoot(inner); _disposeInner(inner); }
|
||||
return { fig, inner, mixer, height, head, dispose };
|
||||
return { fig, inner, mixer, height, head, seatBone, dispose };
|
||||
}
|
||||
|
||||
// R17 pelvic-lean: tilt a seated fig's torso forward, applied AFTER the mixer each frame. The mixer resets
|
||||
// the bone's quaternion from the clip every frame, so this is a CONSTANT offset (not an accumulation). Only
|
||||
// seated figs (drummer, bench-sit loiterers) call it; standing rigs have no seatBone → never leaned.
|
||||
const _LEAN_AXIS = new THREE.Vector3(1, 0, 0);
|
||||
const _LEAN_Q = new THREE.Quaternion();
|
||||
export function seatedLean(spine, angle = 0.34) {
|
||||
if (spine) spine.quaternion.multiply(_LEAN_Q.setFromAxisAngle(_LEAN_AXIS, angle));
|
||||
}
|
||||
|
||||
// ---- makeActor: near-tier pedestrian with walk↔idle crossfade (built at nominal height; the sim
|
||||
|
||||
Loading…
Reference in New Issue
Block a user