Skip to content

[feat] Towers becomes a game: 12 levels, shapes, reach + jump (31-towers) - #252

Merged
AlexZ005 merged 3 commits into
feat/1.18from
feat/31-towers
Oct 1, 2026
Merged

AlexZ005 merged 3 commits into
feat/1.18from
feat/31-towers

Conversation

@AlexZ005

@AlexZ005 AlexZ005 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

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

  • P1, core and reusable (d420300):
    • play.reach limits Interact/Play grabs to a distance from the player's body. The new leaf is playReach.js.
    • Desktop Play's crosshair shows "Too far — get closer" and a carried piece stays inside the reach. A VR grip on a piece out of reach holds nothing and buzzes fail.
    • The Character Controller node's jumpHeight now also jumps in VR on A while Interact is walking. Outside that, A stays push-to-talk.
    • New Inspector row: Configure Scene ▸ Physics ▸ Play mode ▸ Limit grab reach.
  • P2+P3 (3a3475b):
    • A core towers module with 12 levels, 10 piece shapes dealt onto racks, 1–3 stars, an unlock chain saved through api.storage, and a results screen with Next / Retry / Levels.
    • The rules: the tower must hold for 3 s; a level fails on time, a collapse, or too many pieces lost outside the yard. Some levels add gusts, a rocking plate, an outline to fill, or a star to deliver.
    • The template def is rewritten as the arena, the piece templates, the HUD and a small graph. It needs no module download.
    • The author kit gains a block object type and thumb.dress (card-only objects).
    • The game shell's api.game.levels, setHelp and onRestart are feature-detected.
  • P5 (e5461d3): a CLAUDE.md entry and a MODULES.md walkthrough.

Staged content, for the integrator

cloud-lane-30-staging/31-towers/ contains games/towers/{scene.tpscene, thumb.webp}, index.json and a README. Its docs/ folder has towers.md (a new docs-site page) and physics-reach-jump-snippet.md. The scene needs this core.

Verification (final run, union of everything here, staged scene)

suite result
towers-levels (NEW) 56/56
game-towers (rewritten) 21/21
play-reach-jump (NEW) 33/33
author-kit 59/59
templates-modal 45/45
vr-game-panel (section 13 loads Towers) 35/35
  • vitest: 304/304 (+29 new).
  • svelte-check: 333/47, with a message list identical to the base.
  • npm run build: green, run with the dev server stopped.
  • check:storage: clean.

Counterfactuals (code reverted, suite rerun, code restored)

  • Desktop reach (inReach always true): 7 checks red.
  • VR grip reach (reach = null): 2 checks red.
  • VR jump (vrJumpHeight returns 0): 2 checks red.
  • Unlock check bypassed: "pressing locked level 2 starts nothing" red.
  • Lost-piece rule off: "a cube resting outside the yard is LOST", "Out of pieces" and its results red.
  • Judge hold removed: 2 vitest checks red.
  • The wobble effect read 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)

  • VR jump on A.
  • How a 1.3 m reach feels with real arms.
  • Climbing onto pieces.
  • Each level's difficulty, and the gust strength.
  • The board and wrist card legibility.

Notes

  • In co-op, unlocks follow the authority's progress (the physics initiator). Every peer saves the stars it earns on its own device.
  • A is jump (not push-to-talk) while a game's walk controller can jump. This belongs in the changelog.
  • Once the 31-game-shell pause menu is on every game, Towers' own P screen can go.

🤖 Generated with Claude Code

AlexZ005 and others added 3 commits October 1, 2026 01:11
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>
@AlexZ005
AlexZ005 merged commit 99a1c40 into feat/1.18 Oct 1, 2026
4 checks passed
@AlexZ005
AlexZ005 deleted the feat/31-towers branch October 1, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant