Problem Statement
The arcade room is the campus's designated fun zone, but it doesn't retain players. Snake is unpleasant to play (one speed that is too fast, no levels, no settings) and both cabinet games render as bare procedural shapes with no feedback — no particles, no sounds tied to actions, no celebration on success — so they feel like prototypes, not games. Board tables are flat CSS grids with text-glyph pieces and borrowed sounds. There is nothing to come back for tomorrow: high scores are a static all-time top-10 that early players permanently dominate, there are no daily goals or streaks, and there is no way to directly compete with a friend standing next to you. The result: players try the arcade once and don't return.
Solution
Rebuild the arcade into the most polished, replayable corner of the campus, in four increments:
- Juice + Snake rework — every existing game gets satisfying feedback (particles, screen shake, score pop-ups, per-event sounds, animations); Snake gets selectable speed, designed levels with obstacles, and real pixel art; board tables get piece animations and their own sound identity. Flappy keeps its mechanics, juiced.
- Merge-drop flagship — a new physics puzzle cabinet with an original space theme: drop celestial bodies into a well; two same-tier bodies merge into the next tier (pebble → asteroid → moon → … → sun). Wobbly physics, glow effects, the best-looking game in the app.
- Race mode — 1–N players play the same game with the same layout simultaneously; first to the finish line (e.g. "20 apples", "build a planet") wins the moment they cross it. Solo racing is the same mode against the clock and your best time. Losers were still playing when it ended — no dead waiting, near-miss finishes, instant rematch.
- Leaderboard meta-layer — weekly-reset leaderboards alongside all-time bests, a daily challenge (same seed for everyone that day), play streaks, personal-best celebrations, and server-side plausibility validation so the boards stay meaningful.
User Stories
- As a player, I want to choose Snake's speed (chill / normal / fast), so that I can play at a pace that is fun rather than frustrating.
- As a player, I want Snake levels with walls and obstacles, so that the game stays fresh and lets me progress.
- As a player, I want Snake drawn with real pixel-art sprites matching the campus style, so that the game inside the cabinet looks as good as the cabinet itself.
- As a player, I want particles, score pop-ups, a brief screen shake, and a distinct sound on every meaningful event (eat, score, die, win), so that every action feels satisfying.
- As a player, I want death to lead to an instant one-key restart with a "so close" framing, so that losing makes me retry instead of quit.
- As a player, I want Flappy to keep its current mechanics but gain the same feedback polish, so that both classic cabinets feel finished.
- As a motion-sensitive player, I want a settings toggle that disables screen shake, so that juice never makes games uncomfortable.
- As a board-table player, I want Connect-4 pieces to visibly fall and tic-tac-toe marks to draw in, so that matches feel physical.
- As a board-table player, I want a win-line animation and distinct board sounds (place, win), so that victories feel celebrated.
- As a player, I want a new merge-drop cabinet with an original space theme, so that the arcade has a flagship game worth showing friends.
- As a merge-drop player, I want to see the next body I will drop and the full evolution ladder, so that I can plan my moves.
- As a merge-drop player, I want a visible danger line and an overflow warning, so that I always understand how close I am to losing.
- As a merge-drop player, I want merges to feel physical and celebratory (wobble, glow, particle burst, rising pitch per tier), so that chaining merges is deeply satisfying.
- As a player, I want to start a race from a cabinet with nearby friends, so that we can compete without leaving the world.
- As a race participant, I want everyone to get the identical layout and item sequence, so that the race is pure skill, not luck.
- As a race participant, I want to see opponents' live progress bars while I play, so that the race stays tense to the last second.
- As a race participant, I want the match to end the instant someone reaches the goal (or everyone dies — most progress wins), so that no one ever sits waiting for a better player to finish.
- As a race loser, I want a one-click rematch, so that "one more round" is frictionless.
- As a solo player, I want race-the-clock mode with my best time recorded, so that racing is fun even when I'm alone.
- As a player, I want a weekly-reset leaderboard next to the all-time board, so that newcomers can realistically top a board.
- As a player, I want a daily challenge where everyone plays the same seed, so that each day has a fair, fresh competition.
- As a player, I want a visible play streak that grows each day I play, so that I have a reason to come back tomorrow.
- As a player, I want a celebration when I beat my personal best, so that improvement is always rewarded even off the podium.
- As a player, I want my scores saved and ranked per game, so that every cabinet has its own competition.
- As an operator, I want the server to reject implausible score submissions (impossible totals, impossible pace), so that leaderboards stay credible without heavyweight anti-cheat.
- As an operator, I want all arcade features to add negligible load to the single production box, so that voice/video and movement stay smooth.
- As a player in the arcade room, I want all of this reachable from the existing cabinets and HUD, so that nothing about navigating the world changes.
Implementation Decisions
- Game rules stay pure, deterministic, seeded. Snake rework, merge-drop physics, and race progress/winner logic are pure reducer modules (plain values in/out, seeded PRNG threaded through state, no engine/net/DOM imports), each landing with exhaustive vitest coverage in the same commit — the repo's established game-logic convention. Renderers stay thin canvas/React surfaces over reducer output.
- Snake rework: speed becomes a player-selectable tier (3 tiers) mapped to tick cadence; levels are data-defined obstacle/wall layouts consumed by the reducer; level select lives in the cabinet overlay; art moves from procedural shapes to sprite-sheet rendering generated through the existing project-original sprite pipeline with attribution rows.
- Merge-drop: fixed-timestep circle physics (gravity, circle-circle collision/settling) implemented in the pure module — no external physics engine; determinism guaranteed by fixed timestep + seeded spawn queue + avoiding non-deterministic math. Ten-tier space progression (pebble → … → sun) as data. Registered as a new arcade game id in the shared registry; cabinet placed via the campus generator; overlay/renderer lazy-loaded like existing games so the entry bundle budget is untouched.
- Race mode: new socket wire shapes (join/leave/ready/start/progress/finish) defined once in the shared contract package with strict zod schemas. A backend race manager modeled on the existing board-manager pattern: per-space serialized dispatch, Redis-mirrored match snapshots with TTL, space-scoped broadcasts. The server is lobby + relay + arbiter: it distributes the shared seed, throttles/relays ~1 progress event per second per racer, and declares the winner (first to goal, or most progress when all runs end). Clients each run their own deterministic sim — the server never simulates gameplay. Race entry happens at the cabinet (solo vs race choice on interact); readiness + countdown before start; forfeit on disconnect past a grace window, mirroring board-table semantics.
- Meta-layer: leaderboards become period-aware (all-time + ISO-week periods) in Postgres; daily challenge seed is derived server-side from the date and served to clients; streaks are per-user daily-play records. All request/response shapes live in the shared contract package. Plausibility validation on submission: per-game score ceilings, minimum-duration-versus-score pace checks, and monotonic progress sanity — rejects casual cheating; full replay verification is explicitly out of scope.
- Sound + settings: every new sound routes through the central event→clip table; board tables get their own clips instead of borrowed ones; new clips come from the existing audio generation pipeline with attribution rows. Screen-shake toggle joins the existing persisted settings.
- Testing seams (all existing, one new): pure game-module layer, shared zod contract layer, manager-shell pattern for socket lifecycles, REST resource layer for scores, event-bus seam for scene↔React, settings store. The single new seam is the race manager + its wire events, deliberately shaped like the board-table seam so tests and reviews follow a known pattern.
- Process: implemented phase-by-phase by Opus 5 coder agents (UI and backend both — a deliberate capability benchmark tracked in the repo's benchmark doc by the orchestrator), reviewed per the active review protocol; cabinets/fixtures only ever placed via the campus generator; no wire shape ever declared outside the shared package.
Testing Decisions
- Test external behavior only: reducer transition tables (including illegal inputs), determinism properties (same seed + same input script ⇒ identical state sequence — this also underpins race fairness), and win/lose/finish-line edges. Prior art: the existing snake/flappy reducer tests and the board-rules transition matrices.
- Race lifecycle gets an exhaustive pure transition-machine test (lobby → countdown → running → finished; joins/leaves/disconnects at every phase), mirroring the meeting and board-match machine tests. The manager shell is exercised through the socket app boot seam, service-free where possible, following existing backend test conventions.
- Meta-layer REST (weekly boards, daily seed, streaks, plausibility rejection) tests follow the existing arcade-scores REST test patterns, including rate-limit and validation-rejection cases.
- Overlay/HUD changes are tested with React Testing Library + jsdom, stubbing canvas and heavy children — asserting rendered state and bus events, never canvas pixels.
- One Playwright E2E addition at most (solo race happy path through the bus hook + DOM), honoring the no-sleeps and serial-worker rules; CI remains the sole gate — no full local suites.
Out of Scope
- Server-side replay verification of scores (plausibility checks only in this spec).
- Race finish line for Flappy (joins later), and any new board-table games (Battleship, Reversi, etc.).
- Drawing/guessing party games (stroke streaming needs its own design).
- Spectator UI for arcade races, tournaments/brackets, and cross-space races.
- Mobile/touch controls, map re-layout beyond generator-placed cabinets, and any change to voice/video systems.
- Retiring or redesigning Flappy's core mechanics (it stays, juiced).
Further Notes
- The merge-drop game must be an original theme and name — mechanics of merge-on-collision are safe, but no fruit/watermelon theming or naming. A Tetris-like was considered and rejected on IP risk grounds.
- Server-load analysis: every element here is orders of magnitude below the box's Socket.IO capacity (~1 msg/sec per racer at peak; turn/REST traffic negligible). No capacity work needed.
- This effort doubles as the Opus 5 implementer benchmark; findings are logged per dispatch/review round in the repo's benchmark doc by the orchestrator (coders never edit docs).
Problem Statement
The arcade room is the campus's designated fun zone, but it doesn't retain players. Snake is unpleasant to play (one speed that is too fast, no levels, no settings) and both cabinet games render as bare procedural shapes with no feedback — no particles, no sounds tied to actions, no celebration on success — so they feel like prototypes, not games. Board tables are flat CSS grids with text-glyph pieces and borrowed sounds. There is nothing to come back for tomorrow: high scores are a static all-time top-10 that early players permanently dominate, there are no daily goals or streaks, and there is no way to directly compete with a friend standing next to you. The result: players try the arcade once and don't return.
Solution
Rebuild the arcade into the most polished, replayable corner of the campus, in four increments:
User Stories
Implementation Decisions
Testing Decisions
Out of Scope
Further Notes