Files
joshuaandClaude Opus 5.5 825eb14f2e Phase 13: questions, sounds and videos on the scoreboard
A game can now carry a list of items the host puts on the scoreboard one at
a time: a question (shown above the standings, with an optional picture and
an answer to reveal), a sound (played through the scoreboard's speakers) or
a video such as a karaoke track (takes over the screen).

- Media is a YouTube link, an https link to a file, or an upload to the
  private game-media bucket. The scoreboard API signs a URL only for the
  item that is on screen.
- What is on screen is state on the event, like the timer, so the ping
  still carries no data. An unrevealed answer and a sound's or video's name
  never reach the scoreboard payload.
- Control room: click an item to show it, or "Random" to have one picked
  (prefers items not played yet). Show/hide answer, pause, take off screen;
  shortcuts Q / A / X.
- Duplicating a game or event copies its items and files; deleting removes
  the files.

Needs supabase/migrations/0006_screen_items.sql applied before deploying.
database.types.ts was edited by hand to match; re-run gen:types after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 10:54:08 +02:00

13 KiB
Raw Permalink Blame History

PRD — Game Night Live

1. Goal

Run a youth game night (e.g. "Worship Game Night") from one admin tab while a projector tab shows a live scoreboard, and judges score from their phones via links. Versatile enough for any game format.

2. Roles

Role Access How they get in
Admin Everything in the events they own or co-host Logs in (magic link). Email must be in ADMIN_EMAILS.
Scoreboard viewer Read-only scoreboard for ONE event Public link /s/{scoreboardToken}
Judge Score ONE game Personal link /j/{judgeToken} OR open game link /jo/{openToken} (enters name first)
Team Buzz in for ONE team Team buzzer link /b/{buzzerToken}, one per team for the whole night

3. Core concepts

  • Event — one game night. Has teams, games, one scoreboard link, visibility state.
  • Team — name + colour. Belongs to an event.
  • Game — one activity. Ordered. Has a scoring mode:
    • judged — judges submit scores via links; admin can see progress & override.
    • direct — admin enters scores directly.
  • Criterion ("block") — one thing being scored in a game. A game has 1..N criteria.
    • e.g. Karaoke: Pitch, Energy, Lyrics accuracy, Stage presence, Crowd reaction (each 1–5).
    • e.g. Guess the Lyric: one criterion "Correct answers" (number input, 0–20).
    • Input type: blocks (tap a number in a row of buttons) or number (free numeric input / +/- stepper).
    • Has min, max, step, weight, and a description (shown to whoever scores it).
  • Points mode per game (how a game's result becomes leaderboard points):
    • raw — game points = criteria total × multiplier.
    • placement — teams ranked by criteria total, then awarded placement points (default 10/7/5/3).
  • Adjustment — bonus or penalty points with a reason, optionally tied to a game.
  • Notes — admin_notes (only admin sees) and judge_notes (judges see) per game.

4. Features

4.1 Admin — Setup (/admin/events/[id])

  • Create/edit/delete events; duplicate an event (copies teams, games, criteria — not scores).
  • Teams: add, rename, recolour, reorder, delete.
  • Games builder: add, reorder (drag or up/down), duplicate, delete.
    • Title, description, scoring mode, points mode, multiplier, placement points.
    • Criteria list: add/remove/reorder; label, description, input type, min/max/step, weight.
    • Quick presets: "Karaoke (5 × 1–5)", "Single score (0–10)", "Points (number)", "Win/Lose (0–1)".
    • Admin notes + judge notes (multiline).
    • "Teams buzz in" checkbox: this game uses the team buzzers (see 4.7).
    • Questions, sounds and videos to put on the scoreboard during the game (see 4.8).
  • Judges (judged games only):
    • Nominate judges by name → each gets a personal link (copy button + QR code).
    • Toggle the open link on/off; anyone opening it types their name and becomes a judge.
    • Revoke a judge (link stops working, their scores excluded).
  • Share panel: scoreboard link + QR, all judge links per game, and one buzzer link + QR per team (shown once any game uses buzzers).
  • Co-hosts: the admin who created an event (its owner) shares it with other admins by email.
    • The email must already be in ADMIN_EMAILS; it can be added before that admin's first login.
    • A co-host sees the event in their list ("Shared with you") and can do everything in it — setup, control room, scores — except delete it or change who it is shared with.
    • The owner can remove a co-host at any time. Duplicating a shared event gives the co-host their own copy, which they own.

4.2 Admin — Control room (/admin/events/[id]/live)

This is the screen used during the night. Must be fast and hard to mess up.

  • Game switcher: Prev / Next buttons + list of all games with status (upcoming / live / done). Setting a game as current marks it live and shows it on the scoreboard.
  • Current game panel:
    • Scoring grid: rows = teams, columns = criteria, using the same block/number inputs.
      • Direct mode: admin types/taps here. Autosaves.
      • Judged mode: shows per-team average per criterion, a judge-progress matrix (✓ per judge per team), and per-judge breakdown on expand. Admin can override a cell (override wins over judge average; clearly marked; can be cleared).
    • Spotlight: pick "now performing" team — judges see it highlighted.
    • Lock judging toggle (judges become read-only).
    • Mark game done.
    • Admin notes visible.
  • Bonus/penalty: per team quick buttons (+1, +5, +10, −5) and custom amount + reason. Recent adjustments list with undo.
  • Scoreboard visibility: Visible / Frozen / Hidden (see 4.3). Big obvious toggle.
  • "Open scoreboard" button (new tab) + "Reveal mode" button (see 4.3).
  • Buzzers (buzzer games only): who buzzed, in order, with each team's gap behind the first; "Got it" / "Wrong" for the team answering, "Undo" on a marked team, and "Next question".
  • On the scoreboard (games with questions, sounds or videos): the game's list, a button per item to show or play it, "Random" per kind, show/hide answer, pause/resume, take off screen (see 4.8).
  • Keyboard shortcuts: N next game, P prev game, H cycle visibility, T start/pause timer, G got it, W wrong, B next question (clears the buzzers), Q show the next question, A show/hide the answer, X take it off screen, ? help.

4.3 Scoreboard (/s/[token])

  • Projector-first, 16:9, readable from the back of a hall.
  • Shows: event name, current game title, team standings (rank, name, colour, total points). v1 shows totals only; per-game points columns are a later option.
  • Updates live (< 1s) when admin changes anything. Rank changes animate.
  • Visible — live totals.
  • Frozen — shows totals as they were the moment it was frozen, with a subtle "scores frozen" note. Server stores the snapshot; live scores are not sent. The current game title still updates live.
  • Hidden — no scores sent at all. Shows team names (no order implied — alphabetical) and the current game, with a "scores are hidden" state.
  • Reveal mode (admin-triggered): scoreboard reveals final standings last place → first, one team per admin click ("Reveal next") — tied teams too, each showing the shared rank — then sets visibility to Visible.
  • Auto-reconnects; also polls every 10s as a fallback. Shows a small offline dot if disconnected.
  • Fullscreen button; hides cursor after inactivity.

4.4 Judge (/j/[token])

  • Mobile-first. Shows game title, judge notes, and their own name.
  • One card per team (spotlighted team pinned on top + highlighted).
  • Each card: one block row per criterion (e.g. 1 2 3 4 5 big tap targets) with the criterion label + description; number criteria get a stepper.
  • Autosaves on every tap; shows saved ✓ / saving / error per card.
  • Judges see only their own scores — never other judges' or totals.
  • If judging locked or game done: read-only with a message. If revoked: "This link is no longer active."
  • Open link (/jo/[token]): enter name → creates judge → redirects to personal link and stores it in localStorage so a refresh keeps them in.

4.5 Timer

One countdown timer per event, run from the control room; not tied to a game.

  • Set a time (minutes + seconds, or presets 30s / 1 min / 2 min / 5 min). Setting a time resets the timer.
  • Start, pause, resume, reset. Show or hide it on the scoreboard; starting it also shows it.
  • The scoreboard shows it large above the standings. It is not a score, so it shows whether scores are visible, frozen or hidden.
  • The last 10 seconds are highlighted; at zero it shows "Time's up" until reset.
  • The server's clock decides when it ends, so every screen agrees even if a device clock is wrong.
  • Keyboard shortcut in the control room: T start/pause.

4.6 Sound effects (scoreboard only)

Played by the scoreboard page, so they come out of the projector PC's speakers.

  • Reveal: a drum-roll, then a crash as each team appears; a fanfare for first place.
  • Game transition: a chime when the current game changes.
  • Timer: a tick for each of the last 10 seconds (sharper for the last 3) and a buzzer at zero.
  • Browsers only allow sound after a click on the page, so the scoreboard has a "Turn sound on" button. The choice is remembered, but after a reload one click anywhere is needed again.
  • Buzzer: a two-note ding when a team starts answering, a rising arpeggio for "got it" and two falling notes for "wrong".
  • Sounds are synthesised in the browser (no audio files). With reduced motion the drum-roll is skipped.

4.7 Buzzers (/b/[token])

For "first to answer" games. A game opts in with the "Teams buzz in" checkbox.

  • Every team has one buzzer link for the whole night. Someone on the team opens it on a phone: team name, the current game, and one big "Buzz" button.
  • The button works only while the current game uses buzzers and isn't done. Otherwise the page says there's no buzzer for this game, and wakes up by itself when one starts.
  • The server decides the order, using the database's clock — never the phones' clocks.
  • A team buzzes once per question; pressing again does nothing. Later teams can still buzz and queue up behind the team answering.
  • The team answering is the earliest buzz the host hasn't marked. The host marks it:
    • Got it (G) — the question is decided and the buzzers close. In a direct game the team gets +1 in the game's first criterion (so the point follows the game's multiplier and placement rules like any other score). In a judged game nothing is added: the judges score.
    • Wrong (W) — that team is out for this question and the turn passes to the next team in the buzz order. With nobody waiting, the buzzers stay open for the other teams.
    • Undo on a marked team removes the mark, and takes the point back if it was "got it".
    • Next question (B) clears everything and opens the buzzers again.
  • If the point can't be added (the score is at the criterion's maximum, or +1 doesn't fit its step), the answer stays unmarked and the host sees why.
  • The phone's screen turns the team's colour while it is that team's turn ("You buzzed first! Answer now." / "Your turn! Answer now.") and when it got it. Otherwise it shows the team's place and who is answering, "Not this time" after a wrong answer, or who got it.
  • The control room lists the order with the gap behind the first buzz ("+0.42s") and each mark.
  • The scoreboard shows "{Team} buzzed!" in the team's colour with the waiting teams after it, "{Team} to answer" when the turn passes, and "{Team} got it!". It is not a score, so it shows whether scores are visible, frozen or hidden (the point itself follows the usual visibility rules).
  • The phone asks the browser to keep the screen on while the page is open.

4.8 Questions, sounds and videos on the scoreboard

A game can carry a list of things the host puts on the scoreboard, one at a time.

  • Three kinds:
    • Question — text, an optional picture and an optional answer. Shows above the standings.
    • Sound — plays through the scoreboard's speakers; the screen only says "Listen…". Optional answer (e.g. the song's name).
    • Video — a karaoke track or a clip. Takes over the whole screen until taken off.
  • Media is a link or an upload:
    • a YouTube link (for a sound, only the audio is used), or an https:// link to a file;
    • or a file uploaded from the setup page: image for a question, audio for a sound, video for a video, up to 50 MB each.
  • Setup: per game, add / edit / reorder / delete items. Duplicating a game or an event copies them, uploaded files included.
  • Control room: the current game's list. Click an item to put it on screen; clicking the one already showing starts it again. Only one item is on screen at a time, and switching game clears it.
    • Random (per kind, when there are at least two): picks one for the host — e.g. the next karaoke song. It prefers items that haven't been shown yet and never repeats the one on screen. Shown items get a ✓; "Clear the ✓ ticks" starts over.
    • Show answer (A) reveals the answer under the question or sound; again to hide it.
    • Pause / Resume for a sound or video. Take off screen (X) returns to the scoreboard.
    • Q shows the next question in list order.
  • Nothing here is a score, so it shows whether scores are visible, frozen or hidden.
  • Secrets stay on the server: an answer is not sent to the scoreboard until it is revealed, and a sound's or video's name is never sent (it is often the answer).
  • Sound needs the same "Turn sound on" click as the sound effects (4.6). Until then a video plays muted and the screen says the sound is off.

5. Non-functional

  • Live latency target < 1s on normal Wi-Fi.
  • Works with ~10 teams, ~20 games, ~10 judges per game without lag.
  • No data loss on refresh; all state server-side.
  • Accessible: visible focus, sufficient contrast, tap targets ≥ 44px.

6. Out of scope (v1)

  • Individual contestants within teams (stretch: participants per team).
  • Transferring an event to another owner, and read-only co-hosts.
  • Per-game timers (stretch). The event countdown timer is in 4.5; team buzzers are in 4.7.
  • Buzzers for individual contestants, a configurable points value per correct answer, and penalties for a wrong answer (use the bonus/penalty panel).
  • Multiple-choice questions, questions on the judges' or teams' phones, importing a list of questions from a file, and seeking within a video from the control room.