[feat] 29-F: the waves template, and a knock fix it found - #234
Merged
Merged
Conversation
- src/lib/physics.js: `bodyVelocityOf` reports `held` for a `user` hold only (the grab it was documented for) and adds the raw `hold` kind. `held: !!entry.hold` folded the EXTERNAL hold — the engine yielding to another writer (a module walking a body every frame, a peer's move stream) — into "somebody is carrying it". - src/lib/knock.js: `evaluateProbe` still skips a carried body; on the initiator `fireKnock` treats a body that refused the impulse because it is DRIVEN (`hold === 'external'`) as a real hit — logged and sent like every other, the impulse alone refused (the next write would erase it) — which is the rule the receive side already keeps for a held crate (noteRemoteHit logs, applyHit refuses, independently). A body nobody drives that still refuses (gone, not dynamic) sends and spends nothing, as before. - Found by the waves template (29-F): its enemies are dynamic bodies the waves module walks each frame and its damage source is `hit`. On the one peer stepping the world every sweep read 0 hits with the body at `hold: 'external'` (a solo probe, eight sweeps), while a non-initiator (no body, `held: false`) hit them fine — the host could not damage a walking enemy. Counterfactual (game-waves against the staged scene): `held: !!entry.hold` restored -> 58/25, red from 4.1/4.2 (the initiator's slow knock reads 0 hits) and 4.3/4.4 (nothing for B to log) through the whole round (6.1-6.12); fix restored, physics.js identical. knock-physics 1.15 (a CARRIED body is never knocked) held in the same battery. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… suite - scripts/author-templates.cjs: `waves` joins MODULE_DEFS (modules/waves/waves.def.json, emitted by `npm run build:waves`; both modules in installModules, so the file's derived requirement list names health + waves). Built against the lane at 5215; byte-stable across two builds (compare-authored SAME). Staged for the scenes repo in cloud-lane-29-staging/games/waves/ (scene 11701 B + thumb 1690 B + index-row + README with the release order and the #230 ref note). - tests/e2e/game-waves.test.cjs (90 checks; two peers + a late joiner; skip-never-fail): the card is picked in the REAL Games tab (the feed's index.json + scene served through a route, since the row is not released) and loadRemoteScene replaces a non-empty world; the file's 10 objects, both modules, the sunset env, the play block (grab/grounded/simOnPlay) and the knock block; the modules derive 4 enemies on a 3-wave curve, a goal, three spawn pads, five health rows; B over the handshake; Start -> playing on both -> the HUD screen; the run is ON, the first enemy WALKS (+z) and B places it where A does; HUD Text reads the Waves Value nodes and the bar the player's health; kills are KNOCKS through core's feedProbe (a slow sweep = one pulse, a hard one = three), the hit in B's hit log and B's ledger agreeing, B's knock (a non-initiator) completing wave 1, the kills rows per peer, wave 2 healing the survivors one death's worth; the late joiner reads wave 2 and the same ledger from the triggers handshake; waves 2 and 3 fall one enemy at a time -> DONE on all three -> over (won) -> the over screen -> ONE run logged on every peer; Again -> a new round with every enemy back at full health. - .claude/skills/e2e-verify/SKILL.md: the suite in the GAMES-TAB line. The suite reads core's own SCENES_BASE fallback out of sceneTemplates.js, so the #230 ref move follows by construction. Counterfactuals: the def's env preset `dusk` (not a core preset; PR #8's def) -> 1.6 red (studio), fixed to `sunset` on modules feat/29f-waves-template (def-only, module.js and the zip unchanged); `waves` out of MODULE_DEFS -> the build refuses the slug and the suite SKIPs (no scene to test); the knock fix reverted -> the initiator's knocks 4.1/4.2/4.5/4.6 red (its own commit). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap 29 follow-up, lane
29f-waves-template: the one roadmap-29 deliverable that shipped without a way to play it. Baserelease/next(1.15.1).What
[feat]the waves template —wavesjoins author-templatesMODULE_DEFS(the def is the module'smodules/waves/waves.def.json), andgame-waves(90 checks, two peers + a late joiner) proves the card is picked in the REAL Games tab, the world arrives whole, Start begins a round, the enemies walk, kills are knocks, wave 2 heals the survivors, a late joiner reads the wave from the triggers handshake, the last wave falls, the shell goesover(won), the run is logged on every peer, and Again restarts. The scene is staged for the scenes repo (cloud-lane-29-staging/games/waves/, README with the release order — read core Scenes feed: jsDelivr treats scenes@v2 as a semver VERSION and never re-resolves a retag (Games tab stale) #230 before touching the ref).[fix]knock: a body under an external physics hold is hit, not carried — found by the template.bodyVelocityOfreportedheld: !!entry.hold, folding the EXTERNAL hold (the engine yielding to another writer: the waves module walking an enemy every frame, a peer's move stream) into the same flag as ausergrab, so on the one peer stepping the world a walking enemy could never be hit (solo probe: eight sweeps, 0 hits,hold:'external'every time) while every other peer hit it fine. Nowheldmeans a user hold only; a DRIVEN body refuses the impulse (the next write would erase it) but the hit is logged and sent — the rule the receive side already keeps for a held crate.Counterfactuals (in the commit bodies)
physics.jssha identical.duskpreset (not a core preset, modules PR Feature/save-load #8) → 1.6 red (studio); fixed tosunsetin the paired modules PR (def-only, zip unchanged).wavesout of MODULE_DEFS → the build refuses the slug and the suite SKIPs.Gates (this worktree)
npm run check336/47 with the error/warning LISTS identical to base · vitest 178/178 · build green (server down) · held: game-dungeon-realms 64/0 · game-untangle 46/0 · game-football 102/0 · game-stars-room 36/0 · knock-physics 77/0 (1.15 "a carried body is never knocked" green) · knock-node 50/0 · modules flights health 99/0 · waves 59/0.Pairs with
modules PR
feat/29f-waves-template(the def preset). Release order: modulesdev→main(zips on the CDN), scenes row onmain/the new ref, then"template": "games/waves"on the moduleswavesrow — with this core fix released before or with the row.🤖 Generated with Claude Code