From 8d0d997fcafcecc66ca15074d6b7d224cb99b232 Mon Sep 17 00:00:00 2001 From: merge-test Date: Sat, 7 Nov 2026 13:38:39 -0500 Subject: [PATCH 1/2] Demo vs full game: Daily best time, 3 demo rides a day, no practice split (#641) - Daily Ride: the practice/ranked chooser is gone. Every ride counts and the day's best unaided time is kept. The full game is unlimited; the demo gets 3 rides a day (counted at start), opened by finishing the Tutorial and Grandma's. - The demo rides the real Daily on Adventurous; #400's Weekly Ride is removed. - Helping hand on every Daily ride. Any help (SAFETY/SPEED, silent tune, ASSIST, helping hand, shortcut) keeps a ride off the board. - Share strip: today's best plus "1st try". - Server POST /daily keeps the better time instead of 409ing a second ride (board still dark behind DAILY_BOARD_ENABLED). - Demo: Versus and 5 bike colours locked, 20 opt-in achievements, level scores still off the leaderboard (postScores). - Tests: unit + smoke:daily-best (replaces smoke:ranked), smoke:edition and the smokes that clicked the old chooser. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VDbZGpypLbzSQxBu62RC96 --- README.md | 2 +- docs/test-script.md | 8 +- index.html | 77 +---- js/achievement-defs.js | 67 ++-- js/auth.js | 4 +- js/crash-policy.js | 2 - js/daily-ride.js | 255 ++++++-------- js/daily-seed.js | 23 -- js/economy-mode.js | 2 +- js/economy.js | 4 +- js/edition.js | 89 +++-- js/game.js | 318 ++++++++---------- js/helping-hand-mode.js | 1 - js/hud.js | 13 +- js/lobby.js | 223 ++++++------ js/lobby/room-protocol.js | 2 +- js/records.js | 2 +- package.json | 2 +- scripts/probe-props.mjs | 6 +- scripts/shot-end-sheets.mjs | 13 +- scripts/smoke-daily-best.mjs | 170 ++++++++++ scripts/smoke-edition.mjs | 95 ++++-- scripts/smoke-grandma-finish.mjs | 4 +- scripts/smoke-helping-hand.mjs | 63 ++-- scripts/smoke-hud-layout.mjs | 3 +- scripts/smoke-props-3d.mjs | 4 +- scripts/smoke-ranked-run.mjs | 162 --------- scripts/smoke-tourist-coop.mjs | 112 +++--- scripts/smoke-tv-playtest.mjs | 54 +-- scripts/sync-steam-achievements.js | 6 +- test/unit/achievements.test.mjs | 52 ++- test/unit/crash-policy.test.mjs | 4 - test/unit/daily-board-upsert.test.mjs | 57 ++++ test/unit/daily-ride.test.mjs | 136 +++++--- ...d.test.mjs => daily-streak-strip.test.mjs} | 81 ++--- test/unit/economy.test.mjs | 20 +- test/unit/edition.test.mjs | 36 +- test/unit/look-no-thumbs.test.mjs | 4 +- test/unit/room-edition.test.mjs | 27 +- test/unit/weekly-road.test.mjs | 77 ----- worker/identity.js | 2 +- worker/leaderboard.js | 55 +-- 42 files changed, 1119 insertions(+), 1218 deletions(-) create mode 100644 scripts/smoke-daily-best.mjs delete mode 100644 scripts/smoke-ranked-run.mjs create mode 100644 test/unit/daily-board-upsert.test.mjs rename test/unit/{daily-ranked.test.mjs => daily-streak-strip.test.mjs} (73%) delete mode 100644 test/unit/weekly-road.test.mjs diff --git a/README.md b/README.md index 9838cd34..58b614ba 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ npm run smoke:records # personal bests reach the level card npm run smoke:seed # world reseeding is deterministic and leak-free npm run smoke:daily # the Daily Ride is the same road for everyone npm run smoke:ctas # end-screen wishlist / invite visibility rules -npm run smoke:ranked # one ranked run per day; the demo never asks +npm run smoke:daily-best # every Daily ride counts; the demo stops at 3 a day npm run smoke:lookahead # the stoker sees road the captain cannot npm run smoke:ping # sprint call, sync multiplier, emotes npm run smoke:disruptions # warned before it acts, released after diff --git a/docs/test-script.md b/docs/test-script.md index 3c2b04db..411d3a7a 100644 --- a/docs/test-script.md +++ b/docs/test-script.md @@ -113,7 +113,7 @@ CI: `pr-preview.yml` runs PF-01, PF-06 (UI) and the lobby smokes on every PR. | SR-09i | iPhone: SHARE in the clip preview offers FULL CLIP (20 s) and SHORT CLIP (10 s, FOR MESSAGES); the short one is cut from the same buffer on a keyframe; after the sheet closes a "Save Video, then send it from Photos" hint shows once; pad B steps back out of the choice; desktop unchanged (#408) | A | `smoke:clip-share` | | SR-10 | Victory buttons: NEXT LEVEL, PLAY AGAIN, END RIDE | A | `smoke:flows` | | SR-11 | Daily Ride: same road for two players on the same day; difficulty locked | A | `smoke:daily` | -| SR-12 | Daily Ride ranked: chooser on web, never in demo; share strip has no road spoilers | A | `smoke:ranked` | +| SR-12 | Daily Ride (#641): no chooser; every ride counts, best kept; help keeps a ride off the board; share strip has the first try and no road spoilers | A | `smoke:daily-best` | | SR-13 | Expired `?daily=` link lands on today | A | `smoke:daily` | | SR-14 | Slingshot: garage → buy upgrade → aim → launch → tally | A | `smoke:slingshot` | | SR-15 | Slingshot aim on phone (portrait and landscape, real touch) | A | `smoke:slingshot-aim` | @@ -301,9 +301,9 @@ Two devices on different networks for the M rows. | ID | Check | Tag | Covered by | |---|---|---|---| -| ED-01 | Demo shows Tutorial, Grandma's, Weekly Ride, Slingshot; no Tourist | A | `smoke:edition` | +| ED-01 | Demo shows Tutorial, Grandma's, Daily Ride, Slingshot; no Tourist; VERSUS and five bike colours shut (#641) | A | `smoke:edition` | | ED-02 | Demo-gated items show a wishlist hint, not a dead lock | A | `smoke:edition`, `smoke:ctas` | -| ED-03 | No ranked runs, streaks or share strip in the demo | A | `smoke:ranked` | +| ED-03 | Demo Daily Ride: shut until the Tutorial and Grandma's are done, then 3 rides a day, no 4th (#641) | A | `smoke:edition`, `smoke:daily-best` | | ED-04 | Wishlist and invite buttons fit at 390 px | A | `smoke:ctas` | | ED-05 | The real demo build on Steam matches ED-01 to ED-03 | M | — | @@ -341,7 +341,7 @@ Two devices on different networks for the M rows. |---|---|---|---| | DB-01 | Dashboard SQL valid against the schema | A | `check:dashboard-sql` | | DB-02 | A ride's analytics events (`ride_start`, `crash_recover`, `ride_takeover`, …) reach the dashboard | M | — | -| DB-03 | Daily Ride leaderboard records a ranked run | M | — | +| DB-03 | Daily Ride board keeps each player's best clean time of the day (needs DAILY_BOARD_ENABLED) | M | — | | DB-04 | Pad relay rate limit refuses a scripted room flood (30/min per IP; refused requests never reach a room) | A | `test/unit/pad-relay-ratelimit` | --- diff --git a/index.html b/index.html index 85a361fa..1efcbd5f 100644 --- a/index.html +++ b/index.html @@ -537,13 +537,12 @@ line-height: 1; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.6)); } - /* D-2 · the in-ride "this one counts" badge. */ /* HUD ZONES (review pass). Everything added in phases A-E was placed "top-centre" independently and ended up in a heap: eight overlapping elements on desktop, six on a phone. The screen is now divided: top strip 0 - 90px #hud-top (speed, sync row, ping row) - under strip 92px #ranked-badge (small, persistent, centred) + under strip 92px #help-badge (small, persistent, centred) left edge centred #lookahead (a vertical lane map belongs at a side) right edge 96px+ #ping-bubbles, then #split-delta centre 18% #disruption-banner (urgent, transient) @@ -552,25 +551,7 @@ above pedals #coach-card / #coop-coach (never both) Verified by scripts/smoke-hud-layout.mjs, which fails on any overlap. */ - #ranked-badge { - position: fixed; - top: 92px; - left: 50%; - transform: translateX(-50%); - display: none; - padding: 3px 10px; - border-radius: 999px; - background: rgba(255,210,63,0.9); - color: #201a00; - font-size: 11px; - font-weight: 800; - letter-spacing: 1px; - pointer-events: none; - z-index: 56; - } - #ranked-badge.show { display: block; } - /* #403 · the helping hand's badge (💨 / 🎩). Same slot as #ranked-badge: a - ranked run never gets help, so the two are never on screen together. */ + /* #403 · the helping hand's badge (💨 / 🎩). */ #help-badge { position: fixed; top: 92px; @@ -596,35 +577,6 @@ font-weight: 700; font-size: 17px; } - /* D-2 · practice / ranked chooser. */ - #daily-mode-overlay { - display: none; - position: fixed; - top: 0; left: 0; right: 0; bottom: 0; - background: rgba(8,10,14,0.88); - z-index: 120; - align-items: center; - justify-content: center; - padding: 20px; - } - #daily-mode-overlay.visible { display: flex; } - #daily-mode-box { - width: 100%; - max-width: 340px; - text-align: center; - } - #daily-mode-box h2 { margin: 0 0 4px; font-size: 20px; color: #fff; } - #daily-mode-sub { margin: 0 0 16px; font-size: 12px; color: rgba(255,255,255,0.6); } - #daily-mode-box uf-button { width: 100%; margin-top: 8px; } - #daily-mode-box uf-button[disabled] { opacity: 0.45; cursor: default; } - .daily-mode-hint { - display: block; - margin-top: 3px; - font-size: 10px; - font-weight: 500; - letter-spacing: 0; - color: rgba(255,255,255,0.5); - } /* D-3 · the shareable result strip. */ #daily-strip { margin: 10px auto 0; @@ -1906,7 +1858,7 @@ box-sizing: border-box; } .side-btn:active { filter: brightness(1.4); } - /* M4: SAFETY and SPEED are locked on a ranked run. */ + /* A side button that can't be used right now. */ .side-btn:disabled { opacity: 0.35; filter: grayscale(1); cursor: not-allowed; } #safety-btn { grid-area: safety; @@ -5333,27 +5285,8 @@ - -
RANKED RUN
- -
-
-

Daily Ride

-

- RANKED RUN - One per day. Crashes are fine; ending early is not. - - PRACTICE - Unlimited. Nothing recorded but your best. - - ← Back -
-
-
BOOST!
@@ -6463,7 +6396,6 @@

Tandemonium

- @@ -6472,7 +6404,6 @@

Tandemonium

RESTART - END RIDE TOGETHER @@ -6530,7 +6461,7 @@