Playtest feedback round 2:
- blindtest DJ can now be anyone incl. the track's contributor (pickDj only
excludes bots) — no more "immunity" for whoever isn't picked
- blindtest rounds last 90s (longer listen + typing)
- per-player volume slider (persisted), YT player setVolume + origin/enablejsapi
- theme switcher (light/dark/system) on home + room header
- clock sync: clients estimate the server-clock offset (time:sync) so the
countdown is identical across devices (was off by each device's clock skew);
also used for blindtest media sync
Note on duplicates: anti-repeat is per room code (quiz_played) — it works when
you replay in the SAME room, but a new room starts fresh. Verified e2e: two
chained games in one room share 0 questions.
Verified: typecheck 4/4, lint 4/4, 24 server tests, web build; e2e dedup (0
overlap) and clock/DJ behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revert the DJ change: the DJ is again a neutral player (never the track's
contributor), broadcast to all and counted as an eligible voter (votes blind).
The contributor is a normal voter whose vote never scores on their own track;
they only earn the who_added/mixed misdirection bonus (+50 per wrong guess).
- engine: restore single round:start broadcast + DJ-included eligible voters
- blindtest-round: restore neutral pickDj; contributor may vote (ignored in
scoring) so the round can still end on "all voted"
- client: DJ controls + everyone (DJ included) votes; reveal message simplified
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- DJ is now the track's contributor (controls their own song); their identity
is sent only to them so "who added" stays non-trivial. The contributor
doesn't vote and is excluded from the eligible-voters count.
- Scoring: the contributor earns nothing except in who_added/mixed, where they
get a misdirection bonus (50) per player who guesses the wrong adder.
- Blindtest (and mixed) require >= 3 connected players: lobby disables the
options with a hint, and game:start rejects with NEED_THREE.
- Player card is now 16:9 and full width — the video banner shows at reveal;
DJ gets a seek bar (current/duration) to jump anywhere, plus play/pause/restart.
- Mixed game order is shuffled (no predictable quiz/blindtest alternation).
Verified e2e (3 players): guard rejects at 2, DJ id hidden from others,
misdirection scoring correct. 23 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mixed mode (default):
- gameType is now mixed | quiz | blindtest, default "mixed"; the lobby
interleaves quiz + blindtest rounds so modes alternate
- lobby reworked: 3-way game-type switch, quiz count and/or blindtest config
+ track submission shown per selected type
Free-text quiz questions:
- quiz supports the `free` format (e.g. maths) alongside mcq/truefalse:
payload without choices, {text} vote, tolerant matching on acceptedAnswers
- shared QuizQuestionPayload.choices optional; reveal truth carries answer
- match util moved to game/match.ts (shared by quiz + blindtest)
- repo/seed include free + acceptedAnswers; in-code bank gains free questions
- client quiz view renders a text input for free questions
Mode-aware transitions:
- RoundTransition themed per mode (colors/label/emoji); announces the mode
on change (quiz <-> blindtest), lighter teaser within the same mode
- custom media buckets per mode: assets/transitions/{quiz,blindtest}/ + shared
- store tracks roundModeChanged
Verified e2e: mixed game alternates quiz/blindtest to completion; free-text
scoring covered by tests (22 pass).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>