feat(vagrant): backpack as inventory container — end-to-end pickup/drop demo

- Add container={kind="list"} to the backpack template so inventory.add
  accepts it as a valid list-container
- Remove old backpack proximity-trigger (print-only callback, pre-B.5);
  the rock's register_pickup is now the sole interaction trigger
- Emit unconditional inventory inspection trace after every add/remove:
  backpack count + item reg-ids for user-facing demo feedback
- Add CI-gated tree-check traces: tree_check_after_pickup=ok and
  tree_check_after_drop=ok verify composition-tree child placement
- Bump version 0.7.3 -> 0.8.0 across init.lua header, manifest.module,
  and README
- README: rewrite Controls section into full demo walkthrough; add Demo
  Walkthrough section; update Demonstrates + Interactions sections;
  add v0.8.0 CHANGELOG entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Axel Meyer
2026-06-13 18:52:39 +02:00
parent f874813498
commit e38d396b87
3 changed files with 123 additions and 38 deletions

View File

@@ -5,11 +5,12 @@ 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.
cycle, and inheritance-decoupled foot sprites. End-to-end inventory pickup/drop
demo: pick up a rock into a backpack container, drop it back into the world.
**Version:** 0.7.3
**Version:** 0.8.0
**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
**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-core.composition >=0.2.0, lib-core.inventory-list >=0.1.0, lib-asset.prototype-subterrain >=0.1.0
**Tags:** test-chamber, puppet, walking-sim, interaction
## Topology
@@ -22,15 +23,37 @@ cycle, and inheritance-decoupled foot sprites.
- **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
- **E** — interact: if within range of the rock, picks it up into the backpack
- **Q** — drop: places the most-recently-added backpack item at player position (+30px right)
- **ESC** — return to launcher
> **Note:** The world now contains a rock (near the backpack, 80px to its left). Walk up
> and press E to pick it up into the backpack; press Q to drop it back at your feet.
> Picking up the rock currently throws a loud error because the backpack is not yet a
> container — this confirms the pickup wiring is alive. Full pickup-into-backpack works
> once the backpack becomes a container (next slice).
## Demo Walkthrough
The world contains three notable entities at startup:
1. **Player** — spawns at (320, 240), controlled via WASD + mouse.
2. **Backpack** — a visible sprite at (350, 400). Acts as a container (kind="list").
Not directly interactable; it receives items via inventory.add.
3. **Rock** — a standalone stone tile at (270, 400), 80px to the left of the backpack.
Tagged "renderable" + "item"; starts visible on the ground.
**Pickup flow:**
- Walk toward the rock (it sits to the left of the backpack).
- Press **E** within 40px of the rock.
- The rock moves into the backpack via `inventory.add`; its "renderable" tag is
removed so it no longer appears in the world.
- The console prints: `vagrant: backpack count=1 items=[<reg_id>]`
**Drop flow:**
- Press **Q** at any time when the backpack has items.
- The most-recently-added item is removed from the backpack (`inventory.remove`)
and placed at the player position +30px to the right. Its "renderable" tag
is restored so it reappears in the world.
- A new pickup trigger is registered at the drop position.
- The console prints: `vagrant: backpack count=0 items=[]`
**Multiple pickups:** Each E → Q → E cycle moves the same rock in and out.
Only one rock is spawned per session.
## Demonstrates
@@ -48,8 +71,10 @@ cycle, and inheritance-decoupled foot sprites.
- 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
- lib-core.interaction proximity trigger on the rock at (270, 400), range 40px,
"interact" action bound to E — fires inventory.add on dispatch
- lib-core.inventory-list: backpack is a container (kind="list"); rock is an
individual-stack item; add/remove toggle renderable tag
## Interactions
@@ -58,8 +83,10 @@ cycle, and inheritance-decoupled foot sprites.
- 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)`
- E pressed within 40px of the rock → fires `"interact"` action; rock moves into backpack;
console prints `vagrant: backpack count=N items=[...]`
- Q pressed with items in backpack → most-recent item drops at player position; pickup trigger
re-registered at drop location; console prints updated backpack state
## CI Hooks
@@ -82,15 +109,30 @@ cycle, and inheritance-decoupled foot sprites.
## CHANGELOG
### v0.8.0 — end-to-end inventory demo functional
- **Backpack container**: `composition.define_template{id="backpack"}` now includes
`container={kind="list"}`. The composition v0.2 validator accepts this; the backpack
can now receive items via `inventory.add`.
- **End-to-end pickup/drop**: E on the rock calls `inventory.add(state.backpack, rock)`;
inventory-list removes the "renderable" tag so the rock disappears from the world.
Q calls `inventory.remove`, restores "renderable", relocates item to player position
+30px right, and re-registers the pickup trigger. Full loop functional.
- **Inventory inspection trace**: after every add or remove, `engine.print` emits
`vagrant: backpack count=N items=[...]` (unconditional; user-facing demo feedback).
- **Tree-check traces (CI-gated)**: after pickup, `vagrant: tree_check_after_pickup=ok`
verifies item appears as `item.*` child of the backpack in the composition tree.
After drop, `vagrant: tree_check_after_drop=ok` verifies no `item.*` children remain.
- **Backpack interaction.register removed**: the old print-only proximity trigger on the
backpack sprite has been deleted. The rock's pickup trigger is the only interaction
trigger registered.
### v0.7.3
- **Rock entity**: `composition.define_template{id="rock"}` added (stack_mode=individual,
tags=renderable+item). One rock entity spawned at (270, 400) — 80px left of the backpack.
Uses `slot_00_isolated` UV from the `blob_rect_stone` atlas (lib-asset.prototype-blob-geom).
`register_pickup(state.rock)` wires an interaction trigger so pressing E near the rock
fires the pickup callback. The callback calls `inventory.add(state.backpack, …)` which
errors until the backpack becomes a container (next slice) — the error confirms the wiring
is alive. `render.draw_entities{tag="renderable"}` (existing Phase A render path) draws
the rock without any special-case render code.
fires the pickup callback. `render.draw_entities{tag="renderable"}` (existing Phase A
render path) draws the rock without any special-case render code.
### v0.4.4
- **Sprint** (Shift+WASD): doubles `WALK_SPEED` (120 → 240) and walk-anim