Files
sporel-module-vagrant-skeleton/README.md
Axel Meyer f1e27d8183 feat(vagrant): pickup/drop glue + lib-core.inventory-list dep
- Add lib-core.inventory-list v0.1.0 to manifest deps; bump module
  version 0.7.1 -> 0.7.2
- Import inventory = require("lib-core.inventory-list") in init.lua
- Add Item-Template-Convention comment block after vagrant_player
  template: documents stack_mode/tags/sprite/position contract that
  B.4 (rock) and B.5 (backpack-as-container) will fulfill
- Add register_pickup(item) factory: reads item position, registers
  interaction trigger; callback calls inventory.add + unregisters
  trigger on pickup
- Bind "drop" action to Q; drop handler in M.update pops last item
  from backpack via inventory.remove (renderable tag restored by
  library), repositions item at player pos +30px, re-registers pickup
- Update README Controls section: document E (pickup) and Q (drop)
  with note that end-to-end use requires B.4 + B.5
2026-06-13 18:18:52 +02:00

132 lines
6.3 KiB
Markdown

# sporel-module-vagrant-skeleton
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.7.2
**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.4.4, lib-core.interaction >=0.1.0, lib-asset.prototype-subterrain >=0.1.0
**Tags:** test-chamber, puppet, walking-sim, interaction
## Topology
<!-- topology:start (auto-generated; do not edit) -->
<!-- topology:end -->
## Controls
- **W A S D** — direct movement (4-way, normalized for diagonals)
- **Shift + WASD** — sprint (2x player speed + 2x walk-anim cadence)
- **Mouse** — body + head look-at targets (same position, different smoothing)
- **E** — interact with nearest proximity-trigger in range (pickup nearby item into backpack)
- **Q** — drop most-recent item from backpack at player position + re-register pickup trigger
- **ESC** — return to launcher
> **Note:** Q (drop) and E (item pickup) are groundwork for B.4 (rock on ground) and
> B.5 (backpack-as-container) — not yet exercisable end-to-end until those slices land.
## Demonstrates
- 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)
- Shift+WASD sprint → `puppet.set_play_speed` doubles cadence to 0.9x mid-cycle
(no animation restart on toggle); player movement speed doubled (120 → 240)
- Idle state → idle + idle_lower animations
- Camera-chase via lib-core.camera target-provider
- Sprite-tilemap via lib-core.maps
- lib-core.interaction proximity trigger on the backpack sprite at (350, 400),
range 40px, "interact" action bound to E — fires log on dispatch
## Interactions
- WASD active → legs swing in walk direction; body slowly rotates to mouse; head snaps to mouse
- Shift held while moving → 2x player speed; walk cadence doubles (smooth mid-cycle transition)
- 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
- E pressed within 40px of the backpack sprite → fires `"interact"` action;
callback logs `vagrant: interact with backpack (distance=X.X)`
## CI Hooks
- `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)
- ADR-0038 (API-Doc-Convention)
## CHANGELOG
### v0.4.4
- **Sprint** (Shift+WASD): doubles `WALK_SPEED` (120 → 240) and walk-anim
`speed` (0.45 → 0.9). Mid-walk sprint toggle uses `puppet.set_play_speed`
(new v0.4.4 API) — no animation cycle restart.
- **Backpack interaction**: `lib-core.interaction.register(350, 400, 40,
"interact", callback)` registered at init. Pressing E within range
prints log message via `engine.print` with actor distance.
- New deps: lib-core.interaction ^0.1.0. lib-core.puppet bumped to >=0.4.4.
### 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; hardcoded furniture (bed, bench, backpack).