Manifest changes:
- Version 0.1.0 -> 0.2.0
- New asset_aliases block: player + tiles + world all map to
lib-asset.prototype-subterrain
- deps bumped: lib-core.maps 0.1.1 -> 0.1.2, lib-core.puppet
0.1.0 -> 0.2.0
- New dep: lib-asset.prototype-subterrain 0.1.0
Rig, animations, tilemap, and init.lua updates land in follow-up
commits in this slice.
Two env-var-gated hooks (no-op in normal play):
- SPOREL_CI=1: emits 'vagrant: render_frame_ok' per frame from
render() and 'vagrant: frame_avg_ms=N' after 60 frames.
- SPOREL_VAGRANT_PHASE1_DRIVE=1: scripted move-right input on
frames 21-40, idle otherwise. Combined with SPOREL_CI=1 produces
observable idle -> walk -> idle state cycle.
State-transition trace 'vagrant: state=<walk|idle>' emits exactly
once per actual change in set_walk_or_idle, so the smoke greps
don't get noise from per-frame repeats.
Fix camera.set_target_provider (absent from camera API) to use
camera.set_target(x, y) called per frame from M.update instead.
Composer module: single-player character as puppet (humanoid 4-bone
rig: torso, head, leg_l, leg_r) at world (320, 240) on a 20x20
v0.1-format tilemap.
- WASD direct movement, normalized for diagonals, 120 px/s.
- Camera-chase via lib-core.camera target-provider (camera follows
puppet position frame-to-frame).
- Idle and walk keyframe animations: idle is a 2s torso-sway on the
upper track; walk is a 0.6s leg-cycle on the lower track.
- Animation-state transitions driven by movement input: walk while
WASD-active, idle when released.
- Headtrack: head bone (marked look_at: true in rig) rotates each
frame to face the mouse cursor's world position via
puppet.set_look_target.
- ESC -> launcher.
CI hooks (env-var-gated, no-op in normal play):
- SPOREL_CI=1: emits 'vagrant: frame_avg_ms=N' after 60 frames and
'vagrant: render_frame_ok' per frame from the render hook, then
engine.exit(0). Smoke stages consume these markers.