- Bump time modes from 1/2 to 2/4 minutes across backend protocol, bot,
timer HUD, and net message types (more room to read a snippet before
guessing).
- Extract per-category token counts/weights into a shared
engine/categoryStats.ts, replacing three independently-drifting
copies of the same formula in ThemeGuessGame/botMatch/multiplayerMatch.
- Switch scoring.ts from a plain weighted average to a power-mean
combine so whiffing a high-weight category can't be masked by acing
the rest; retune colorUtils' similarity falloff divisor to match.
- Update solo config flow, opponent view, and renderer for the new time
options and scoring feedback.
Implements PROTOCOL.md's private-room flow: room:create/room:join
with a collision-checked numeric code, up to a 5-match repeating
series per room via game/session.js, random-theme selection that
excludes the previous match's theme, and room:closed for matchLimit
or quit (rooms never touch matchmaking's ban store). themeMode:
'chosen' gets a narrow resolveChosenTheme() stand-in pending #7's
real theme-voting flow.
Also adds a minimal opponentName lookup to registry.js
(registerSocket's new optional name arg + getPlayerName) since
room:joined needs it, mirroring the same addition landing on #5's
branch.
Registers queue:join/queue:leave handlers that FIFO-pair waiting players,
randomly assign timeMode (1 or 2, uniform) and theme via themeIds.js, and
hand off to game/session.js's createSession. Tracks a 2-minute
matchmaking-only quit ban (in-memory, resets on restart) via onEnd's
'quit' reason, scoped to sessions this module produced. Exports
isBanned() and registerMatchmakingHandlers(), wired into index.js at
boot.
Also extends ws/registry.js with a playerId -> display name store
(registerSocket's new optional third arg, getPlayerName()) so
match:found.opponentName (and future room:joined.opponentName) can be
populated; connectionHandler.js's identify handler now passes name
through.