Build browser JS and native physics together, then package static files and asset packs into ignored output/site. Save the existing Pages target in Wrangler configuration and document the deployment workflow and controls. Record completed UX, collision and camera verification: 230 tests passed, full type checks and build passed, and browser checks reported no errors.
- commit
- b20b16518311f9eb4d573b3653af0c904aba2647
- parent
- cfae4700bcf09cb8c7fd5928ce2cf8a37b5a5611
- author
- Dami <dami.etoile@gmail.com>
| M | README.md | 43 | +++++++++-- |
| M | deno.json | 1 | + |
| M | progress.md | 122 | ++++++++++++++++++++++++++++++- |
| A | tools/ | 37 | +++++++++ |
| A | wrangler.jsonc | 6 | + |
@@ -1,10 +1,10 @@
11 # marbles22 3-Seeded, emergent marble-track generator. A Deno webapp that assembles4-closed-circuit marble runs from Kenney's CC05-[Marble Kit](https://kenney.nl/assets/marble-kit), with the Nature Kit as a6-scenery layer. The URL fragment is the seed — every generated track is a7-browser-history entry you can share, revisit, and step back/forward through.3+Seeded, emergent marble-track generator. A Deno webapp that assembles an endless4+marble race from Kenney's CC0 [Marble Kit](https://kenney.nl/assets/marble-kit),5+with the Nature Kit as a scenery layer. The URL fragment is the seed — every6+generated track is a browser-history entry you can share, revisit, and step7+back/forward through.88 99 ## Quickstart1010 @@ -14,9 +14,18 @@ deno task dev # build (watch) + serve → http://localhost:8000
1414 1515 Open `http://localhost:8000/#your-seed-here` — any string is a valid seed.1616 17-- **new track** button (or editing the hash) generates a new seed and history17+- **New run** button (or editing the hash) generates a new seed and history1818 entry.19-- **follow cam** / `c` toggles orbit ↔ marble-chase camera.19+- **Follow cam / Orbit cam** or `C` toggles the camera. Drag to rotate and20+ scroll to zoom. Follow zoom persists; wide views use gentler camera movement.21+- **Pause / Resume** or `K` pauses the run while leaving orbit controls usable.22+- **Your marble / Race leader** or Space changes the camera subject when the run23+ has other racers. Solo runs omit this control.24+- **Full screen** or `F` toggles full screen; Esc exits.25+- **Share** copies the complete world URL, including seed and settings.26+- **Settings** returns to the launch screen with the current seed and options.27+- **Simulation options** contains Classic loop, Modern/Legacy steering, physical28+ simulation, diagnostics and Piece gallery.2029 - `?debug=1` overlays the loop centerline; `?gallery=1` lays out every imported2130 piece.2231 @@ -26,6 +35,8 @@ Open `http://localhost:8000/#your-seed-here` — any string is a valid seed.
2635 | ------------------------- | ------------------------------------------------------------ |2736 | `deno task dev` | bundle watch + dev server with live reload |2837 | `deno task build` | one-shot browser bundle → `static/dist/app.js` |38+| `deno task build:physics` | rebuild Box3D shim → `static/dist/box3d.mjs` + `.wasm` |39+| `deno task build:site` | rebuild JS and physics, package static files and assets |2940 | `deno task assets:import` | re-run the asset pipeline from the Kenney packs |3041 | `deno task test` | full test suite (RNG, registry, topology fuzz, golden seeds) |3142 | `deno task check` | type-check everything |@@ -34,6 +45,24 @@ Open `http://localhost:8000/#your-seed-here` — any string is a valid seed.
3445 needed when re-importing from the source packs (path configurable via3546 `--source-root`).3647 48+Physics shim changes require `build:physics` as well as the browser build. It49+uses Emscripten and CMake; include both native artifacts when distributing the50+site. See [the stall fix notes](docs/stall-fixes-2026-09-30.md) for the current51+collision behavior and verification.52+53+## Deployment54+55+The existing Cloudflare Pages project is `marbles`, at56+[marbles-3a0.pages.dev](https://marbles-3a0.pages.dev). Build the complete site,57+including the native physics module and asset packs, before deploying:58+59+```sh60+deno task build:site61+npx wrangler pages deploy --project-name marbles --branch main62+```63+64+The build output is `output/site/`; generated bundles stay out of Git.65+3766 ## How it works3867 3968 ```@@ -4,6 +4,7 @@
44 "serve": "deno run --allow-net --allow-read --allow-env=PORT src/server/main.ts",55 "build": "deno bundle --platform browser --sourcemap=linked -o static/dist/app.js src/client/main.ts",66 "build:physics": "bash tools/build_physics.sh",7+ "build:site": "deno task build:physics && deno task build && deno run --allow-read=static,assets --allow-write=output/site tools/package_site.ts",78 "build:watch": "deno bundle --platform browser --sourcemap=linked --watch -o static/dist/app.js src/client/main.ts",89 "assets:import": "deno run --allow-read --allow-write --allow-env --allow-ffi tools/import_assets.ts",910 "check": "deno check src/ tools/ tests/",@@ -25,7 +25,7 @@ Collision is MEASURED against the kit (audit round 2026-08-09:
2525 docs/collision-mesh-audit.md — shared proxy builder, open bores,2626 authored drop cups, additive wide shift, rim-height profile, 4-way2727 cross composite, quantitative metrics CI).28-214 tests green, `deno task check` clean.28+217 tests green, `deno task check` clean.2929 3030 ## Active 2026-08-26 bug hunt3131 @@ -45,6 +45,23 @@ cross composite, quantitative metrics CI).
4545 across teleports/leader changes. Boost is now a separate short orange-red4646 additive trail (in loop and endless modes) instead of a marble color filter;4747 it fades after flameout and remains constant-cost at pack scale.48+- Verified/fixed: slow rail/kinematic movement now accumulates distance from a49+ committed sampling anchor instead of its moving visual head. This prevents the50+ trail from freezing at one point and stretching until physics motion resumes.51+- Added `?debug=1` rail-flow provenance: distance-LOD handoffs are informational,52+ while fall/stall recoveries warn as `tileCandidate: true` with seed, racer,53+ segment, station, window, concrete piece id, family, zone, lane/part, repeat54+ count, and the reseat destination. Events are rate-limited at 1/2/4/8… and the55+ latest 12 are mirrored into `render_game_to_text().stream.railDebug` for CUA.56+- Rail recovery sample: 18 Chrome runs × 401 racers × 300 simulated seconds57+ produced 644 genuine fall/stall candidates. Two generated layouts account for58+ 87.73%: `rail-sample-008` segment 11's `ramp-long-b` →59+ `helix-large-quarter-right` transition, and `rail-sample-015` segment 14's60+ icy-alt/braid straight cluster. Full table and sensitivity analysis live in61+ `docs/rail-recovery-sample-2026-08-26.md`.62+- Fixed debug provenance after the sample exposed stale `placementIndex` values:63+ dropped jump/reorient meshes now remap surviving path windows to the final64+ placement array, so supports/decor can no longer be mislabeled as track tiles.4865 - Verified/fixed: the asset gallery and title menu fit 320–480px phone widths,4966 short-height Advanced options remain scrollable, focus rings are visible,5067 and keyboard input no longer starts the game or loses a text caret.@@ -167,3 +184,106 @@ cross composite, quantitative metrics CI).
167184 genVersion shifted once for the M19c batch (computed, not hand-bumped).168185 - `deno task check` is fully clean now — keep it that way; `deno task169186 test` remains the gate.187+188+## September 30, 2026 continuation — UX and recorded track stalls189+190+Current request: update and improve the site's UX and address tracks that stall;191+the user confirmed the previous agent's work had not been wrapped up. Preserved192+all pre-existing uncommitted trail, physics-provenance and generation changes.193+194+- Replaced the title menu with an opaque illustrated game launch screen: clear195+ Endless/Classic choices, racer presets/custom count, optional seed and a large196+ start button. Native form controls, focus states, mobile/short-height scrolling197+ and reduced-motion styling; the menu no longer loads game assets or a renderer.198+- Added a visible playback dock: orbit/follow, hero/leader, pause/resume, full199+ screen, share with feedback and controls help. Kept diagnostic stats behind200+ Backquote and audio hidden. Both run modes share playback state and CUA reports201+ it. New runs resume; keyboard shortcuts respect text editing and native Space202+ activation. Loading failures now offer a visible route back to Settings.203+- Replaced the pixel-frame toast/place chrome with the dock's quiet styling and204+ kept overlays clear of the phone controls. Loop overview now frames the circuit205+ rather than distant scenery and reframes when the viewport changes.206+- Fixed discontinuous braid collision ribbons, which silently connected separate207+ lanes with invisible walls. Packed independent strips without joining triangles208+ to stay within the native mesh-handle budget.209+- Reproduced the ramp/helix obstruction as segment 9 geometry overlapping segment210+ 11 after reorientation. Added native per-checkpoint static contact masks for211+ each racer (own + adjacent checkpoints), preserving marble contacts and ghost212+ behavior. Rebuilt the native module and added a build:physics task.213+- Verification: 222 tests passed; type check, build and changed-file lint passed.214+ Recorded ramp/helix and both braid lanes clear in native tests without recovery.215+ Two browser soaks × 401 racers × 300 simulated seconds: rail-sample-008 had zero216+ fall/stall recoveries; rail-sample-015 had two end-hole-rounded recoveries and217+ zero braid-cluster recoveries. Neither hero died; no browser errors.218+- Details and limitations: docs/stall-fixes-2026-09-30.md. Browser screenshots,219+ interaction checks and soak telemetry are in ignored output/.220+221+Remaining physics target: the two drop-cup stalls in the stress run. The recorded222+ramp/helix and icy-braid failures are resolved. World-space visual overlap and223+broader camera occlusion are still separate follow-up concerns. A distribution224+must include the rebuilt box3d.mjs/wasm, not just the browser JS bundle.225+226+Final UX verification: 32 browser interaction checks passed with no console or227+page errors, covering laptop CTA visibility, phone/short-height layout, exact228+Unicode/whitespace seeds, presets/custom counts, both modes, paused camera229+switching, sharing, fullscreen, native Space activation, focused-button letter230+shortcuts, Settings prefill and new-run playback reset. Inspected final menu,231+loop, endless, phone and controls screenshots. Built-in browser preview queued232+at http://localhost:8000/?menu=1; the local server remains running.233+234+## September 30 follow-up — persistent zoom and less menu copy235+236+- User preference: camera zoom must stay at the chosen distance. Removed the237+ follow camera's idle zoom decay and teleport zoom reset. Drag angles still238+ ease back toward the path; obstruction handling still restores the chosen239+ distance when clear. Zoom survives streaming, retargeting and mode switches.240+- Verification: 11 browser checks passed with no console/page errors, including241+ idle zoom in/out, teleport, retarget, stream bounds, mode round trip, resize242+ and zoom limits. Seven camera tests, full type check, build and lint passed.243+- User UI preference: omit subtitles unless they explain context that is not244+ already clear. Removed the title eyebrow/subtitle, top-right tagline, hero245+ graphic caption, footer copy, mode descriptions and racer/seed helper copy.246+ The menu top bar now contains only the logo, with the title in main content.247+ Preserved the seed's optional label. Cleaned up unused subtitle CSS.248+- Final menu browser check passed on desktop and phone: requested text absent,249+ logo-only top bar, visible start button, no horizontal overflow, mode/racer250+ selection and seed editing intact. Inspected both screenshots; no page errors.251+252+- Steering clarification: the former Automatic steering checkbox enabled the253+ newer autopilot when checked and the older track-assist law when unchecked.254+ Both automate steering. Replaced it with an explicit Steering choice:255+ Modern autopilot / Legacy track assist, preserving defaults, stored settings256+ and URL flags. Twelve menu browser checks passed for selection, mode gating,257+ submitted URLs, stored preferences and phone fit; no page errors. Build,258+ type check and lint passed; inspected desktop/phone option layouts.259+260+- Classic loop is a simulation/debug option, per user direction. Removed the261+ primary run-mode cards; Endless is the normal launch flow. Classic loop is262+ now a checkbox within Simulation options beside diagnostics and Piece gallery.263+ Active Classic settings reveal that section on return and disable the264+ endless-only controls; stored selections and shared URLs remain compatible.265+ Sixteen browser checks passed, including actual Classic and Endless launches,266+ field-size restoration, newer steering selection and phone layout. No browser267+ errors. Build, type check and lint passed; inspected final menu screenshots.268+269+- Solo runs now omit the hero/leader button and Space help, and reject leader270+ toggles. Decorative peers in legacy mode also omit the control. Real packs271+ retain both button and shortcut; regeneration keeps visibility correct.272+- Follow camera clearance now pairs entry/exit on the same mesh/instance, and273+ wide views tolerate foreground scenery while still avoiding a lens endpoint274+ inside geometry. Open shells no longer count as containing a distant lens.275+ Wide views ease more slowly through turns. Teleport detection compares actual276+ consecutive subject positions, so smoothing lag cannot trigger a false cut.277+- Verification: 230 tests passed, including eight new real-geometry camera278+ cases; full type check, build, format and changed-file lint passed. Fourteen279+ camera/control browser checks passed, including solo/new-run/pack/legacy280+ visibility and continuous fast motion at 30/60/120 fps. All eleven persistent281+ zoom checks still pass. No browser errors. On e0b75o4y7s at maximum wheel zoom,282+ an 80-second, 4800-frame comparison reduced moves over 2 units/frame from 21283+ to zero, largest move from 22.95 to 1.36, and frames below half the intended284+ boom from 630 to four. Inspected default and wide-view screenshots.285+- Added a repeatable complete-site build for the existing Cloudflare Pages286+ project: builds JS and native physics, then packages static files plus assets287+ into ignored output/site. The complete build passed, including the native288+ rebuild and packaging. After the missing Git remote was identified, the user289+ narrowed the request to local commits only; no push or deployment performed.@@ -0,0 +1,37 @@
1+/** Assemble the complete Pages upload after JS and native physics builds. */2+const destination = "output/site";3+for (4+ const path of [5+ "static/index.html",6+ "static/ui.css",7+ "static/dist/app.js",8+ "static/dist/box3d.mjs",9+ "static/dist/box3d.wasm",10+ "assets/marble-kit.glb",11+ ]12+) {13+ if (!(await Deno.stat(path)).isFile) {14+ throw new Error(`Missing build file: ${path}`);15+ }16+}17+18+try {19+ await Deno.remove(destination, { recursive: true });20+} catch (error) {21+ if (!(error instanceof Deno.errors.NotFound)) throw error;22+}23+24+async function copyTree(source: string, target: string): Promise<void> {25+ await Deno.mkdir(target, { recursive: true });26+ for await (const entry of Deno.readDir(source)) {27+ if (entry.name.startsWith(".")) continue;28+ const from = `${source}/${entry.name}`;29+ const to = `${target}/${entry.name}`;30+ if (entry.isDirectory) await copyTree(from, to);31+ else if (entry.isFile) await Deno.copyFile(from, to);32+ }33+}34+35+await copyTree("static", destination);36+await copyTree("assets", `${destination}/assets`);37+console.info(`Packaged site in ${destination}`);