- lightweight, dependency-free i18n: typed fr/en dictionaries (fr is the source
of truth, en must match its shape → compile error on drift), I18nProvider +
useI18n hook, browser detection + localStorage persistence
- FR/EN language switcher (home + room header)
- translated the whole player-facing flow: home, join, pseudo, room shell,
lobby (incl. settings, categories, bots, track submission, history),
quiz, blindtest, player-cards, round transitions, end screen (podium, awards,
tracks, rounds recap), and server-error messages (mapped by code)
- history dates localized to the active language
Content (questions/categories) intentionally left as-is. Back-office (admin)
not translated yet — internal, token-gated tool.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- results page: when there are no tracks (quiz-only game), the recap was sitting
in the left column of a 2-col grid; now a single section is centered (2 columns
only when both tracks and recap exist)
- add a shadcn Tooltip component (@workspace/ui, via radix-ui) and replace native
browser title= tooltips: connection dot, back-office active toggle, and the
locked blindtest tiles (now aria-disabled so the tooltip still triggers)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- room:leave event: removes the player from the room (not just disconnected),
reassigns host if the host leaves, deletes the room when empty
- store leaveRoom() emits it and clears the session (reset)
- room header gets a "Quitter" button (always available); end-screen "Quitter"
now also leaves cleanly
Verified e2e: leaver removed from snapshot, host reassigned to the next player.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- end screen: wider container (max-w-4xl), podium/awards stay centered, and the
two long sections (musiques + récap des manches) sit side-by-side on desktop
- back-office: 2-column layout (form | questions list) on desktop, wider
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mixed settings fix:
- RoundConfig carries a `pool` hint (quiz | image) per quiz round; lobby shows
a separate count for each selected sub-mode (Quiz, Images) and the blindtest
config — not just the quiz one
- server pool composes the queue per round's pool (quiz formats vs image_reveal),
in order; verified e2e (2 quiz + 2 images honored)
Awards:
- "⚡ Le plus rapide" — derived client-side from the speed bonus baked into
quiz/image points (points above the 100 base on correct answers)
Desktop restyle:
- room page gets an ambient halo background and a responsive container
(lobby max-w-3xl with a 2-column players|settings grid, game/end max-w-lg)
- game/end views widened to max-w-lg
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
image_reveal rounds (RoundType "quiz") now get their own "IMAGE" transition
(emerald/teal theme, 🖼️) instead of reusing the quiz one. The store derives a
roundKind (quiz | image | blindtest) from the round payload format; mode-change
detection and the custom-media folder use it (assets/transitions/image/).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- RoomPage animates between coarse phases (lobby ↔ game ↔ end) with a fade/
slide (AnimatePresence, mode wait). Keyed by phase, not status, so the
YouTube player survives in_round → reveal → scores.
- PlayerCards fires a small confetti burst when a player overtakes to take
the lead during the game.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restructure onboarding (option B):
- home is just Create / Join (code) — no name field
- name is chosen in the room: room:create/join no longer require a name;
new player:setName event. Nameless players are hidden from the snapshot
(players/scores/submissions) and excluded from eligible voters and the
3-player blindtest gate until they pick a pseudo.
- PseudoScreen with live DiceBear avatar preview gates RoomPage until set
- /join/:code auto-joins then redirects to the room (seamless invite links)
- RoomCode gains a "copier le lien" button (origin/join/CODE)
Verified e2e: nameless players excluded from the room until setName.
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>
- RoundTransition overlay: fullscreen colored wipe-in, spinning sunburst,
big bouncing "QUESTION N" + "PRÊT ?!", then wipe-out (Framer Motion)
- store: roundKey counter incremented on round:start
- rendered at RoomPage, keyed by roundKey so it plays once per round
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- voteAck now carries `voted` (playerIds who validated) — never their answer,
so no leak; the count/total stay for the progress text
- PlayerCards show a green "Prêt" check for players who answered and a
pulsing "en attente" dot for those who haven't, during in_round only
- score stays visible on the cards alongside the status
- engine test updated for the new voteAck shape
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- store: boomKey counter + boom() action
- Countdown fires boom() once when it reaches 0 (timer expiry only)
- Boom component (portal to body) plays a fullscreen white flash + giant 💥
- rendered at RoomPage level, keyed by boomKey so it plays fully (independent
of the countdown unmounting on reveal) and replays each round
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Countdown: under 10s it ramps into a "bomb" — white→red color and an
escalating scale/wiggle pulse (faster & wider as it nears 0) via Framer Motion
- RoomCode: click-to-copy the room code with visual feedback
- PlayerCards: always-on score HUD during the game (cards per player,
animated reorder, crown on the leader) so scores are tracked continuously
instead of only appearing at reveal
- quiz view: drop the reveal-only scoreboard (now covered by PlayerCards)
- add framer-motion dependency
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>