Gameplay Workflow
Phase state machineβ
waiting
β host:start
βΌ
question_open βββββ host:resume
β β²
β host:pause β
βΌ β
question_paused ββββββββββ
β
β host:reveal (or timer alarm)
βΌ
question_revealed
β
β host:next
βΌ
question_leaderboard (after every question)
β
β host:next
βΌ
question_open (next question in same round) OR
round_leaderboard (after last question in a round)
β
β host:next
βΌ
question_open (next round) OR
ended (after final round)
Session creationβ
The host fills in SessionForm:
- Title β optional display name for the tasting (shown in session list). If left blank, the first wine's name is used.
- Wines β one or more wines; each wine gets 5 questions (one per category, fixed order:
color,region,grape_variety,vintage_year,wine_name) - Correct answer β always blank; host fills in
- Distractors β 3 per question; pre-filled for most categories (grape_variety is empty)
- Timer β range slider 15β120 s (default 60 s); applies to all questions
Session edition (edit before game starts)β
While the session is in the waiting phase (lobby), the host can click βοΈ Edit Wines to return to the form pre-filled. Submitting the form sends update_session to the backend, which replaces ctx.wines, saves state, and responds with host:session_updated. The host is returned to the lobby. Edition is blocked once the game has started (phase !== 'waiting').
Scoringβ
| Outcome | Points |
|---|---|
| Correct answer | 100 |
| Wrong answer | 0 |
| No answer (timer expires) | 0 |
Points are awarded at host:reveal. There is no speed bonus.
Answer changingβ
Participants can change their selected option at any time until the host clicks Reveal. The backend overwrites the answer on each submit_answer message. answeredCount (shown to host) increments only on a participant's first answer per question.
Timer behaviourβ
- Timer starts when the question is broadcast (not when
host:startfires) - Host can Pause and Resume any time during
question_open - Timer expiry (
alarm()) automatically triggers reveal (same ashost:reveal) game:timer_tickis emitted every second to all connected clients
Round leaderboardβ
After the last question of each wine (5th question), the server emits game:round_leaderboard instead of proceeding to the next question. After the final wine's last question, it emits game:final_leaderboard and transitions to ended.
Host disconnect / reconnectβ
If the host disconnects (browser close, network loss), the game enters a 1-hour grace period. Participants remain connected and see a waiting state. If the host reconnects within the grace period, the game resumes from where it left off. If the grace period expires without the host returning, the session ends automatically and participants are notified.
Session endβ
Host clicks End Session at any time OR the game completes all questions. On end:
- Final rankings are saved to Durable Object state (
finalRankingsin the session snapshot). Note: KV writes are disabled β session history islocalStorage-only. - All clients receive
session:ended - Phase transitions to
ended