- ?move=<ref> boot parameter (?policy= alias, ?session=&round= sugar)
- session:<id>[:<round>] refs fetch same-origin /api/play/* endpoints
- episodic manifests mount in the roll slot as a one-shot on R
- perpetual slot sitstand swaps the sit policy; walk unchanged
- script manifests load move_script.json and drive the 13-D command
vector on the walker (linear keyframes, loop), toggled by R
- HUD chip: PLAYING <prompt or name> by <author>
Co-authored-by: Cursor <cursoragent@cursor.com>
fix(build): configurable base prefix and relative mesh_dir for /play/ hosting
Resolve an org/repo Hub id (or a direct .onnx URL) into a validated
onnxruntime session and swap it into the walk slot only, keeping
recovery/sitstand/kicks/roulade on the official set:
- custom-policy.js: manifest schema-2 checks (reject only
present-and-wrong claims, walk-slot compatible kinds only), publish
smoke run mirror (1 input / 1 output, zeros + 2 noisy inferences,
[1,14] finite non-constant output), honors manifest action_scale
- game.js: name-agnostic inference (session inputNames/outputNames
instead of hardcoded obs/actions), per-session action scale,
Number.isFinite guard before writing ctrl, watchdog that auto-reverts
to the official walker on 3 abnormal endings (recovery entries +
solver explosions) in a rolling 20 s window or any non-finite action
- ?policy=<ref> URL param (parsed in App.jsx, loaded after boot, never
blocking it; failures surface in the HUD on the official walker)
- HUD: active-policy chip with unload X, LOADING POLICY OSD line,
toas…
feat: restyle the click-to-walk marker as a tron reticle
Replace the solid pulsing ring with hairline additive lines in the
wireframe-scan art direction: thin ring + rotating radial ticks + center
cross, a one-shot expanding ping on acquire, deterministic hologram
flicker while idle, and a collapse/fade-out on arrival or cancel.
Lives in fx/waypoint-marker.js, driven per-frame from frame(dt).
Co-authored-by: Cursor <cursoragent@cursor.com>
Peers broadcast their ball's free-joint pose in the state payload (new
optional b field, sent only while a ball is in play). Each ghost renders
it as the same translucent shell as its duck - geometry shared with the
local ball, material cloned - interpolated like the trunk and hidden the
moment the peer's ball despawns. debug() now reports peerId and ball.
Co-authored-by: Cursor <cursoragent@cursor.com>
fix: rate-limit ghost loco rebuilds against flag-flapping peers
Display keyboard tutorial labels for the active layout while keeping the existing physical bindings. Fall back to QWERTY/AZERTY labels when layout data is unavailable.
Tested with `npm test` and `npm run build`.
- Title menu: split layout with live 3D duck (vitrine-style materialize
shader), variant-tinted accents, unified boot spinner (assets + font +
game core), duck hidden on narrow touch screens
- Audio: new WebAudio sound system (sweeps synced to the tron shader,
per-prop pitch scaling) - shipped disabled via SOUND_DISABLED until the
sound design is finished; HUD mute toggle commented out accordingly
- Supply chain: MuJoCo, onnxruntime-web and trystero vendored from npm
instead of jsDelivr/esm.run CDNs (wasm assets bundled locally)
- Ghosts: explicit healthy Nostr relay list; the appId-seeded default
subset had rotted (dead/blocking/rate-limiting relays), silently
breaking peer discovery in prod
Co-authored-by: Cursor <cursoragent@cursor.com>
Receiver: per-ghost adaptive playback delay tracking the measured
snapshot arrival cadence (fast attack / slow release), floored at the
current 150 ms for healthy 15 Hz peers and slew-limited so rate changes
glide without popping; arrival stamps are de-jittered so bursty channel
delivery replays as motion. Sender: broadcast + stale sweep moved to an
inline Web Worker clock, exempt from the >=1 s hidden-tab timer clamp, so
backgrounded tabs keep sending at the nominal rate. Wire format unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
Pointer-down on the duck (or the live ball) grabs it: a three.js raycast
picks the body and a spring-damper force toward the cursor - projected on
a camera-facing plane, so lifting works - is written to xfrc_applied
every physics substep. Formula and gains mirror the native viewer's
mjv_applyPerturbForce (stiffness 100, damping sqrt(stiffness), scaled by
subtree mass). Orbit is disabled for the drag and restored on release;
grabbing detaches the chase cam; touch overlay untouched.
Co-authored-by: Cursor <cursoragent@cursor.com>
LT pressure now picks the wheee note on a major pentatonic octave anchored
below the sample's natural pitch (playbackRate glide, constant gain); the
ride plays the loop segment directly so pitch responds from the first
frame. Release cuts the ride like the robot runtime (no end-segment
retrigger). Both triggers open the beak analogically (visual only). Also
fixes LT/RT trigger cross-talk on pads that mirror a combined trigger
channel, and prefers standard-mapping gamepads.
Co-authored-by: Cursor <cursoragent@cursor.com>
fix: bust stale edge-cached bundle URL with new content hash
- HUD chrome reworked as comic panels: cream keyline frames with 1px ink
inset, caption cartouches (NAV / SHOP / COLOR / MODE), inner glass
padding and square gapped colour swatches
- drop the T relief toggle and B ball-respawn keyboard bindings; gamepad
Y becomes HEAD mode, A ground pick, LT rides the looping wheee
- decor props row + CRT distortion pass, per-duck wheee voice sets,
ground-pick and stand policies, updated robot meshes, title menu
refresh; README controls updated
Co-authored-by: Cursor <cursoragent@cursor.com>
Cabinets at their real-world 1.73 m height tower over the 0.25 m duck.
The materialization fx now scales with its target: band widths and
stripe wavelength grow linearly with the object's height, the timeline
by sqrt of it (capped), so big props scan as the same effect instead of
a fast flash with hairline bands. Duck and ball sizes are unaffected.
Co-authored-by: Cursor <cursoragent@cursor.com>
feat: relief as gentle slopes baked into the level itself
Replace the plateau boxes with a MuJoCo heightfield over the arena and
vertex displacement of the grid floor shader, both driven by the same
analytic cosine-bump function so physics and visuals are the same
surface. Raising/sinking ramps one scalar (hfield z-size + uTopoScale
uniform). Trigger still uncommitted: T key or rl.setRelief().
Co-authored-by: Cursor <cursoragent@cursor.com>
feat: arcade row moved to the front wall + toggleable relief terraces (prototype)
The three cabinets now face the player from the +X wall. New prototype:
four grid cells (two mirrored terraces) rise into plateaus on demand -
kinematically driven slide joints, contacts with the world excluded so
the buried boxes don't fight the floor, animated rise/sink at 0.25 m/s.
Trigger is deliberately uncommitted for now: T key or rl.setRelief().
Co-authored-by: Cursor <cursoragent@cursor.com>
feat: replace jukebox with a row of 3 arcade cabinets
New arcade.glb (from the user's FBX, texture downscaled to 1024, plus a
500-tri wire stand-in for the hologram pass). Three clones line up
against the back wall facing the arena, staggered in the ceremony, with
one static collision box covering the row.
Co-authored-by: Cursor <cursoragent@cursor.com>