- 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>
DB:
- quiz_question gains `lang` ('fr' default) and `active` (true default); migration 0002
- only active questions are served to games (pool filter)
History:
- engine writes a game_history row at game end (modes + ranked results), fire-and-forget
- public GET /api/history/:code lists a room's recent games
- lobby shows a "Parties précédentes" collapsible (date, modes, winner/scores)
Back-office:
- create form has a FR/EN language select; lang stored
- per-question active toggle (PATCH /questions/:id) — disable without deleting;
inactive rows dimmed and labelled
- seeds set lang (opentdb=en, manual/pokemon=fr)
Verified e2e: migration applied; game played → /api/history returns it.
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>
- image_reveal display: larger, object-contain (whole image up to 58vh), no crop
- image prompt optional in back-office (defaults to "Qui est-ce ?"), overridable
- mixed mode reworked: select "Mixte" then toggle sub-modes (Quiz/Images/
Blindtest). Blindtest sub-mode locked under 3 players; mixed itself no longer
needs 3. Server quiz pool formats derived from gameType + mixedModes.
shared: MixMode + RoomSettings.mixedModes (default quiz+image).
- DB: prompt uniqueness is now a partial index (excludes image_reveal) + unique
index on image_url; lets many images share the generic prompt, dedup by URL.
- seed: db:seed:images pulls Pokémon (PokéAPI) as image_reveal questions with
official artwork (remote URL) + FR/EN accepted answers; idempotent by image_url.
Verified: migration applied, Pokémon seed inserts FR+EN, image mode serves only
image_reveal, all checks green (23 tests).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- image_reveal becomes its own game mode: GameType gains "image"; the quiz
pool is filtered by allowed formats derived from gameType (image →
image_reveal only, quiz → mcq/truefalse/free, mixed → all). loadQuizPool
takes a formats list; pool fallback respects it.
- lobby settings reworked into a refined "Réglages" card: 4 mode tiles
(icon + label, locked <3 players for blindtest/mixed), question count as a
stepper, blindtest config grouped; dynamic label for image mode + hint.
- admin: real upload button (hidden input + styled Button with Upload icon)
instead of the bare file input.
- app title set to "NerdWare …" in index.html (+ lang fr, description).
Verified e2e: image mode serves only image_reveal questions (with imageUrl).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Server:
- quiz-round handles image_reveal like a text-answer format (tolerant match
on acceptedAnswers), exposing imageUrl in the round payload; degressive
scoring comes for free from the existing speed bonus (earlier = blurrier =
more points)
- repo includes image_reveal in the pool (requires imageUrl + acceptedAnswers)
- back-office: image upload (@fastify/multipart) saved to UPLOADS_DIR and
served statically on /uploads (@fastify/static); create supports image_reveal
- env: UPLOADS_DIR; gitignore uploads/
Client:
- admin form: "Image à deviner" — upload + preview + accepted answers
- in-game: ImageReveal shows the image with a time-cadenced decreasing blur
(synced via server timestamps) + text input; reveal shows the clear image
and the answer
shared: QuizQuestionPayload.imageUrl
Verified against real server+DB: upload (url), static serve (200), create
(201), validation (400).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>