@@ -698,7 +698,7 @@ export function createViewer(
698698 // bug. Ground-lock and pins have already fixed the root placement that
699699 // floor/landmark targets resolve against.
700700 applyReaches ( info . reaches ) ;
701- alignFloorPalms ( mannequin , info . reaches , info . pins ) ;
701+ alignFloorPalms ( mannequin , info . reaches , info . pins , info . groundLock ) ;
702702 // Plantigrade correction: keep planted soles flat to the floor so grounded
703703 // lower-body poses (squat, lunge, deadlift) don't balance on the toes.
704704 // Runs before the floor clamp so the leveled sole is what rests on y=0.
@@ -710,7 +710,7 @@ export function createViewer(
710710 mannequin ,
711711 gripSidesOf ( info . grips ) ,
712712 authoredFingers ,
713- floorHandSidesOf ( info . reaches , info . pins ) ,
713+ floorHandSidesOf ( info . reaches , info . pins , info . groundLock ) ,
714714 ) ;
715715 // L4.3 aliveness: turn the head toward the active contact (bar / floor reach).
716716 applyLookAt ( info ) ;
@@ -843,7 +843,7 @@ export function createViewer(
843843 mannequin ,
844844 gripSidesOf ( ir . phases [ 0 ] ?. grips ?? [ ] ) ,
845845 authoredFingers ,
846- floorHandSidesOf ( ir . phases [ 0 ] ?. reaches ?? [ ] , ir . phases [ 0 ] ?. pins ?? [ ] ) ,
846+ floorHandSidesOf ( ir . phases [ 0 ] ?. reaches ?? [ ] , ir . phases [ 0 ] ?. pins ?? [ ] , ir . phases [ 0 ] ?. groundLock ?? [ ] ) ,
847847 ) ;
848848 applyLookAt ( { grips : ir . phases [ 0 ] ?. grips ?? [ ] , reaches : ir . phases [ 0 ] ?. reaches ?? [ ] } ) ;
849849 captureGroundTargets ( ) ;
@@ -1080,13 +1080,17 @@ function gripSidesOf(grips: readonly { effector: string }[]): Set<"left" | "righ
10801080}
10811081
10821082/**
1083- * Hand sides pressed onto the floor this phase (a `reach`/`pin: hands floor`).
1084- * Their fingers rest flat instead of taking the idle inward hook, so a plank or
1085- * push-up hand lies on the ground rather than clawing into it.
1083+ * Hand sides pressed onto the floor this phase — via `reach`/`pin: hands floor`
1084+ * OR `ground-lock: hands` (a high plank / push-up / mountain-climber, where the
1085+ * hands bear weight flat on the ground). Their fingers rest flat instead of
1086+ * taking the idle inward hook, so the palm lies on the floor rather than
1087+ * clawing into it. Ground-locked hands never carry a `floor` reach/pin, so
1088+ * without the ground-lock check they were mis-read as free and hooked up.
10861089 */
10871090function floorHandSidesOf (
10881091 reaches : readonly { effector : string ; target : string } [ ] ,
10891092 pins : readonly { effector : string ; anchor : string } [ ] ,
1093+ groundLock : readonly string [ ] = [ ] ,
10901094) : Set < "left" | "right" > {
10911095 const sides = new Set < "left" | "right" > ( ) ;
10921096 const add = ( effector : string ) : void => {
@@ -1095,6 +1099,7 @@ function floorHandSidesOf(
10951099 } ;
10961100 for ( const r of reaches ) if ( r . target === "floor" ) add ( r . effector ) ;
10971101 for ( const p of pins ) if ( p . anchor === "floor" ) add ( p . effector ) ;
1102+ if ( groundLock . includes ( "hands" ) ) add ( "hands" ) ;
10981103 return sides ;
10991104}
11001105
0 commit comments