diff --git a/README.md b/README.md index ae39007..3750428 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # sporel-module-vagrant-skeleton -F.vagrant Tier-1 test-chamber: single player as puppet, WASD direct -movement, camera-chase, headtrack to mouse-cursor. Phase 1 stage. +F.vagrant Tier-1 test-chamber: single player as a 13-bone humanoid puppet, +WASD movement, camera-chase, multi-target look-at (body lazy-tracks mouse via +slerp, head snaps to mouse with ±60° clamp). Demonstrates the Subterrain-style +puppet control model: leg orientation decoupled from body via procedural +callback, foot-body-orientation ("tactical twist"), scale-deformation walk +cycle, and inheritance-decoupled foot sprites. -**Version:** 0.2.0 +**Version:** 0.4.3 **Module-ID:** vagrant-skeleton -**Requires:** lib-core.input >=0.4.0, lib-core.camera >=0.3.0, lib-core.render >=0.1.0, lib-core.maps >=0.1.2, lib-core.puppet >=0.2.0, lib-asset.prototype-subterrain >=0.1.0 +**Requires:** lib-core.input >=0.4.0, lib-core.camera >=0.3.0, lib-core.render >=0.1.0, lib-core.maps >=0.1.2, lib-core.puppet >=0.4.3, lib-asset.prototype-subterrain >=0.1.0 **Tags:** test-chamber, puppet, walking-sim ## Topology @@ -16,32 +20,45 @@ movement, camera-chase, headtrack to mouse-cursor. Phase 1 stage. ## Controls - **W A S D** — direct movement (4-way, normalized for diagonals) -- **Mouse** — head/torso look-at target +- **Mouse** — body + head look-at targets (same position, different smoothing) - **ESC** — return to launcher ## Demonstrates -- lib-core.puppet integration (skeleton, keyframe animation, procedural-ready, look-at constraint) -- idle <-> walk animation-state transition driven by movement input +- lib-core.puppet v0.4.3 integration: + - Multi-look-target: body "soft" (slerp=6, lazy) + head "aim" (instant-snap, ±60° clamp) + - Scale-deformation walk cycle: leg.scl_y cycles +1/0/-1 via keyframe animation + - Procedural leg orientation: legs face walk direction independent of body rotation + - Foot-body-orientation ("tactical twist"): feet face body direction, not leg direction + - `inherit_scale: false` on feet: feet do not Y-flip when leg.scl_y goes negative + - Per-channel conflict guard: walk animation (scl) + procedural (rot) on same leg bones + - Camera in `camera.begin()/finish()` block for correct world-space rendering +- WASD movement → walk_fwd_lower + walk_upper animation pair (speed = 0.45x) +- Idle state → idle + idle_lower animations - Camera-chase via lib-core.camera target-provider -- Throwaway-content test-chamber stance: existing maps v0.1 format, - hand-painted humanoid rig + 2 keyframe animations. +- Sprite-tilemap via lib-core.maps ## Interactions -- WASD active -> walk animation on lower track -- WASD released -> idle animation on upper track (subtle torso sway) -- Mouse moved -> head-bone angle updates each frame to face cursor's - world-position (look-at constraint on bones marked `look_at: true`) +- WASD active → legs swing in walk direction; body slowly rotates to mouse; head snaps to mouse +- WASD released → idle_lower collapses legs (scl=0); upper body returns to idle sway +- Mouse moved → body lazy-rotates via slerp (look_at_slerp: 6); head snaps within ±60° of body +- Walking east while body faces north → legs perpendicular to body, hips body-relative, feet face north ## CI Hooks -- `SPOREL_CI=1` -> 60-frame perf canary. Emits `vagrant: frame_avg_ms=N` +- `SPOREL_CI=1` → 60-frame perf canary. Emits `vagrant: frame_avg_ms=N` and `vagrant: render_frame_ok` (per-frame, from render hook), then exits. Used by smoke stages P0-S25a + P0-S25b. +- `SPOREL_VAGRANT_PHASE1_DRIVE=1` → scripted synthetic WASD (frames 20-40 + move east). Used by P0-S25 puppet-test integration. ## References +- `superpowers/specs/2026-05-18-puppet-subterrain-model-design.md` (design basis) +- `docs/adrs/0040-puppet-subterrain-model-pivot.md` (architectural rationale) +- `architecture/puppet.md` (lib-core.puppet reference) +- `audit/2026-05-18-puppet-subterrain-model-manual-test.md` (manual verification checklist) - ADR-0028 (Launcher-Flow) - ADR-0036 (Lib-Override for multi-module reuse) - ADR-0037 (Tests-as-Libs) @@ -49,23 +66,44 @@ movement, camera-chase, headtrack to mouse-cursor. Phase 1 stage. ## CHANGELOG +### v0.4.3 +- `inherit_scale: false` on foot_l, foot_r: feet no longer Y-flip when leg.scl_y + inverts during walk cycle. foot.rest.scl reset to [1,1]. +- foot procedural callback writes foot.rot to cancel leg.rot → foot.world.rot = body.world.rot. + +### v0.4.2 +- Procedural orientation callback writes leg.rot + foot.rot (per-channel guard allows + this alongside walk_fwd_lower which writes only leg.scl). + +### v0.4.1 +- head look-at uses target_local normalization (-π, π]) to fix flick at body south-facing. + +### v0.4.0 +- Multi-look-target: body tracks "soft", head tracks "aim" (both currently raw mouse). +- body.look_at_slerp = 6 (lazy rotation); head instant-snap with rot_min/max ±60°. +- Legs re-parented from root to body (hip-static body-relative positioning). +- Procedural "leg_foot_orientation" callback: leg faces walk direction, + foot cancels leg rotation to stay body-aligned. +- walk_fwd_lower plays at speed = 0.45x for human-feel cadence. +- Rendering wrapped in camera.begin()/camera.finish() block. + +### v0.3.3 +- sprite_rot applied to leg bones to compensate for sprite natural orientation. + +### v0.3.2 +- Persistent look_at_state; fixes rate-limit reset each frame. + +### v0.3.1 +- look-at atan math corrected: atan(dx, -dy) for sprite-top convention. + +### v0.3.0 +- Sprite-mode rendering: 13-bone humanoid puppet with multi-channel animation. +- walk_fwd_lower (lower track): leg.scl_y cycle +1/0/-1 (substrate walk_fwd_lower). +- walk_upper (upper track): arm-swing animation. +- idle + idle_lower: upper body sway + leg collapse. +- Sprite-tilemap with 4 floor variants; hardcoded furniture. + ### v0.2.0 -- Sprite-mode rendering throughout: 13-bone humanoid puppet via - lib-core.puppet v0.2 with PROTOTYPE asset-pack textures; sprite-tilemap - via lib-core.maps v0.1.2 with 4 floor variants (floor_001-003 walkable, - floor_004 as wall); hardcoded furniture (bed, bench, backpack) via - engine.render.draw_sprite_transform. -- Asset-pack indirection: manifest.module asset_aliases maps the alias- - keys (player, tiles, world) to lib-asset.prototype-subterrain. Rig - and tilemap atlas-ids resolved at init via puppet.load_textures and - maps.load_textures. -- Tile rotations: vagrant_test.map.json includes a tile_rotations - parallel array exercising 90 and 180-degree rotations for visual - verification of the rotation pipeline. -- Animation refinements: walk on lower track now includes foot bones - (legs + feet alternate); idle on upper track with subtle body+head - sway. -- New smoke traces emitted under SPOREL_CI=1: - vagrant: render_frame_ok (per frame from render hook), - vagrant: sprite_mode=on (once after first sprite draw), - vagrant: assets_loaded=14 (once after init). +- Sprite-mode rendering throughout: 13-bone humanoid puppet via lib-core.puppet v0.2 + with PROTOTYPE asset-pack textures; sprite-tilemap via lib-core.maps v0.1.2 with + 4 floor variants; hardcoded furniture (bed, bench, backpack).