Game Mechanics
Band Game is a band name chain game where players take turns naming bands. Each band name must start with the last letter of the previous band's canonical name. Names are validated live against the Spotify catalog.
Core Concept
text
Player 1: "Radiohead" (ends in D)
Player 2: "Deep Purple" (starts with D, ends in E)
Player 1: "Eagles" (starts with E, ends in S)
Player 2: "Slayer" (starts with S, ends in R)
...A player loses when they submit an invalid band, run out of time, or abandon the match.
Game Modes
| Mode | gameMode value | Turn time | Notes |
|---|---|---|---|
| Default multiplayer | 'default' | 20 000 ms | Matchmaking queue or direct challenge |
| Lite | 'lite' | liteRoundLengthMs from config (default 20 000 ms) | Shorter rounds via admin config |
| Singleplayer | 'singleplayer' | 20 000 ms | Human vs bot (BOT_ID = 'bot'), timer skipped for bot turns |
Match Flow
- Match creation — via matchmaking queue, direct challenge, or singleplayer endpoint
- Turn 1 — challenger / first-queued player submits a band (always valid on letter-chain; other rules still apply)
- Band revealed — opponent sees the band was played (name hidden until they reveal it); revealing starts the turn timer
- Turn alternation — players alternate;
currentTurnadvances on each valid move - Invalid move — game ends immediately; the player who submitted the invalid move loses
- Timeout — game ends; the player who timed out loses
- Post-game — XP awarded, stats updated, rematch offered
Game State Structure
typescript
{
id: string;
status: 'waiting' | 'active' | 'completed' | 'abandoned';
gameMode: string;
players: { id: string; name: string; socketId: string }[];
currentTurn: string; // player ID
moves: GameMove[];
currentRound: number; // 1-based; increments when all players have played once
maxTurnTimeMs: number; // set at creation, default 20 000
lastBandName?: string;
currentTimer?: TurnTimer;
winner?: string; // player ID
createdAt: Date;
completedAt?: Date;
powerupsUsed?: Record<string, PowerupType[]>; // playerId → used types
activeScramblerLetter?: string; // set while Scrambler is pending
zappedBands?: string[]; // bands excluded from dupe check
}Win / Loss Conditions
| Event | Loser |
|---|---|
| Player submits invalid band (wrong letter, not on Spotify, duplicate, < 500 followers) | That player |
| Turn timer expires | Player whose turn it was |
Player sends abandonGame | That player |
Player sends clientTimeout (validated server-side) | That player |
Band Visibility (Reveal System)
Bands are not immediately visible to the opponent. This is intentional — the opponent must choose to reveal the band, which simultaneously starts their turn timer.
| Band | Visible to |
|---|---|
| Your own bands | Always visible to you |
| Opponent's valid band (not yet revealed) | Hidden — bandName returned as null |
Opponent's valid band (after revealBand) | Visible |
| Opponent's invalid band | Auto-revealed after you make a subsequent valid move |
Typing Indicator
- Client sends
playerTyping { gameId, playerId, isTyping }while composing - Server relays to opponent only via
opponentTyping - Cleared automatically on move submission or band reveal
- Not persisted anywhere
Rematch
- Available after
statusis'completed'or'abandoned' - Requester goes first in the new match
- Same
gameModeas original - New match ID generated; original match untouched
Sub-pages
- Band Name Validation — letter-chain rules, Spotify lookup, duplicate detection, follower threshold
- Timers & Abandonment — how the turn timer works, timeout handling, grace period
- XP & Ranks — XP formula, bonuses, rank progression
- Powerups — Add Time, Zapper, Mirror, Scrambler — rules, UI, and technical reference