[feat] Towers becomes a game: 12 levels, shapes, reach + jump (31-towers) - #252
Merged
Merged
Conversation
The Quest note on Towers: "you can't take object from specific distance and need to jump on
other objects". Both rules are core and opt-in, so any game can use them.
- playReach.js (pure leaf, vitest 12): reach is the distance from the aimed point to the
player's BODY (the segment feet..eye), not the eye - a crate at your feet is in reach, one
on a 3 m ledge is not until you stand on something or jump. carryLimit keeps a carry on
the reach boundary along any aim.
- scenePhysics `play.reach` (metres; OMITTED when absent, so older scenes are byte-identical)
+ playSettings `reach` (a publisher's userData.play.reach overrides, field by field).
- desktop Play (playInteract): a grabbable body out of reach reads 'toofar' (the crosshair:
"Too far - get closer"), a press on it carries nothing, and a carry is held inside the reach
whatever the wheel asks. The editor's Interact cursor carry (no body) is unaffected.
- VR Interact/Play (gripTargetOf): a grip on a piece out of reach holds nothing and buzzes
`fail`; the hand-inside path takes the same rule.
- VR jump: the Character Controller node's jumpHeight now jumps in VR on right A while it
declares walk mode and Interact walks (vrJumpHeight); A stays push-to-talk otherwise, and a
switch mid-hold cannot strand the mic open. vrWalkStep takes jumpHeight.
- Configure Scene > Physics > Play mode: "Limit grab reach" + a Reach (m) row.
Suite play-reach-jump (33): desktop reach + carry limit, desktop jump ONTO a 0.6 m crate (the
capsule stands on a dynamic piece and does not shove it), VR grip reach + the buzz through the
real per-frame path (fakeXR), VR jump on A through the real per-frame path, the Inspector row.
Each in-run counterfactual included (no reach -> the far crate is grabbable; jumpHeight 0 / no
controller -> no jump).
Counterfactuals (source reverted, suite re-run, restored):
- playInteract inReach -> always true: 7 red ("a crate 2.8 m away reads TOO FAR", "a press on
it carries nothing", ...).
- vrControls gripTargetOf reach -> null: "VR: a grip on the far crate takes nothing" and "the
squeeze holds nothing" red (it grabbed the far crate).
- vrControls vrJumpHeight -> 0: "VR: ... can jump" and "pressing A lifts the head" red
(peak 1.61).
svelte-check 333/47, the message list identical to the base.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-towers P2+P3)
The Quest note: "after finishing basic level nothing happens, just like hooray. I want to use
different levels and different shapes... logical things such as you can't take object from
specific distance and need to jump on other objects" (T1, T2).
- src/modules/towers: a CORE module (the pong precedent), dormant unless the scene holds the
`Towers game` marker. levels.js is the pure leaf (vitest 17): 12 levels - Stack, Planks,
Climb, Wedges, Barrels, Arches, Narrow base, Gusts, Balls, Wobble, Outline, Summit - each
with its own shape set dealt onto racks, a goal, par pieces + par time (1-3 stars), a time
limit and an allowance of lost pieces; the unlock chain (a star opens the next level); the
rack layout; the tower measure; the judge (win = the goal HELD 3 s with nothing held; lose =
time, a collapse, too many pieces lost outside the yard, the star lost); the gust schedule;
the outline cells.
- module.js: ONE authority (the physics initiator, else the lowest peer id) deals the pieces as
TRANSIENT duplicates of templates parked under the floor, judges ~10x/s, pushes gusts and
writes tw* game variables; every peer derives the HUD words (the `towersinfo` value node into
HUD Text's format), the moments (intro banner, gust warning, lost-piece poof, landing knocks,
win confetti/fanfare/buzz, fail sound) and saves stars with api.storage. HUD presses carry no
presser, so every peer watches the hudbutton stamps and only the authority acts. `towerswobble`
rocks the level-10 plate as a module EFFECT (a kinematic body). The game shell's
api.game.levels / setHelp / onRestart are feature-detected (feat/31-game-shell's shape).
- The Towers def: the arena (pad, pedestal, wobble plate, two racks, a high ledge above your
reach, a star perch, the goal/yard/ghost markers), ten piece templates (cube, plank, beam,
wedge, barrel, arch + L with compound colliders, ball, heavy base, star), the level-select
menu (12 buttons + stars), the in-game HUD, results (Next / Retry / Levels), a walk + 1 m
jump Character Controller and `play.reach: 1.3`. No module download any more.
- Author kit: a `block` object type (the app's Wedge/Arch/Corner/Stairs) and `thumb.dress`
(card-only objects: the card shows a round in progress).
Suites: towers-levels (NEW, 55/55 on the staged scene: level select + locked refusal, level 1
dealt + HUD + goal ring, a scripted WIN of level 1 (stars saved), the unlock PERSISTS across a
page reload, level 2 dealt + a scripted win, Next -> level 3 with its ledge pieces out of
reach, a LOSS by pieces lost outside the yard, Retry, P Restart/Levels, the empty arena on the
level select, gusts warned + pushing, the wobble plate rocking as a kinematic body, the outline
won, the summit won with the star on top). game-towers rewritten (21/21: the arena, the
templates, reach + spawn, the walk+jump body, the level select, the music, a readable frame).
Counterfactuals:
- the judge's hold removed (won on first contact): vitest "must HOLD for three seconds" and
"outline and deliver goals" red.
- the wobble effect reading `base.rotation` (the runtime hands `{rot: [...]}`): "in level 10 the
plate ROCKS" red (tilts 0.000 x6) - the bug this suite found.
- gusts at strength 1.1: "the gust PUSHED the top of the tower" red (3 cm).
- toMenu without clearPieces / a test writing progress behind api.storage: the level-select
sections red (the findings that added setProgress and the empty-arena clear).
The e2e counterfactual run for the unlock check and the lost-piece rule is scripted
(scratchpad cf-p2.py) and still OWED - the slot wait timed out before it ran.
svelte-check 333/47, message list identical to the base.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CLAUDE.md: the ROADMAP 31 Towers entry (playReach, VR jump, the core towers module, the module-effect base-is-arrays trap). MODULES.md: a walkthrough of the towers module as the pattern for a game's rules (a pure leaf, one authority, HUD presses without a presser, api.storage progress, the shell seams feature-detected). The docs-site pages (towers.md + a physics.md snippet) are staged for the integrator in cloud-lane-30-staging/31-towers/docs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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 31, items T1 (Towers: more than "hooray" after the basic level, with levels and different shapes) and T2 (limited grab reach, jumping onto pieces, logical rules). Lane
31-towers.What's in it
play.reachlimits Interact/Play grabs to a distance from the player's body. The new leaf isplayReach.js.fail.jumpHeightnow also jumps in VR on A while Interact is walking. Outside that, A stays push-to-talk.towersmodule with 12 levels, 10 piece shapes dealt onto racks, 1–3 stars, an unlock chain saved throughapi.storage, and a results screen with Next / Retry / Levels.blockobject type andthumb.dress(card-only objects).api.game.levels,setHelpandonRestartare feature-detected.Staged content, for the integrator
cloud-lane-30-staging/31-towers/containsgames/towers/{scene.tpscene, thumb.webp},index.jsonand a README. Itsdocs/folder hastowers.md(a new docs-site page) andphysics-reach-jump-snippet.md. The scene needs this core.Verification (final run, union of everything here, staged scene)
npm run build: green, run with the dev server stopped.Counterfactuals (code reverted, suite rerun, code restored)
inReachalways true): 7 checks red.reach = null): 2 checks red.vrJumpHeightreturns 0): 2 checks red.base.rotation; the runtime hands{rot: [...]}. "The plate ROCKS" was red until fixed — this suite found the bug.Perf (Play, GPU, unthrottled)
About 85–110 draw calls and ~14k triangles per level, with 3 lights (1 casting shadows). That is inside the Quest budget. The 4×-throttle protocol run is owed.
Owed on device (Quest 3)
Notes
🤖 Generated with Claude Code