Scoring bug (priority fix): MultiplayerMatch/BotMatch add a `hidden` class to the solo result panel (#solo-score-meter-wrap, #score-verdict, #score-breakdown, #compare-toggle) once a networked/bot round's real two-column scoreboard takes over, but no CSS rule ever paired `.hidden` with those selectors (every other hideable element in this codebase has its own scoped rule) -- the class was inert, so the solo panel stayed visible forever, stacked above the mp-scoreboard, making both look like they showed the same/wrong numbers. Added the missing scoped rules. Reveal button (online play): clicking Reveal Match used to run ThemeGuessGame's own instant local reveal() even in a live multiplayer round -- unrelated to the server, and the direct trigger of the above scoring bug. Added a revealOverride hook on ThemeGuessGame; while a multiplayer round is live, MultiplayerMatch routes the click through a new round:revealVote message instead. The round now only ends early once *both* players vote (server tracks votes per session and reveals immediately on a mutual vote); a single vote relays round:revealVoteUpdate to the opponent, and the voter sees "Waiting for opponent to vote for reveal..." below the button. Theme preview timing: matchmaking and private-room rounds never ran the 10s theme-preview flash solo/bot rounds already have, so a round's real colors never appeared before painting started. Added it to both flows (ui/matchmakingFlow.ts, ui/privateRoomFlow.ts, including every match in a private room's up-to-5-match series, not just the first). The backend's round:start.endsAt now bakes in a matching 10s PREVIEW_MS head start (session.js) so the preview never eats into actual painting time. Private room results view: a private room's next match used to start within milliseconds of the previous one's reveal, cutting the result modal off almost instantly. room.js now delays round:nextMatch (and the series-ending room:closed) by RESULT_VIEW_MS (10s) after round:reveal so both players actually get to look at a match's result. Theme grid / vote UI: the theme-vote modal's grid was missing the theme-grid class that actually applies the 2-column CSS grid (dead CSS already anticipated the combination), so vote theme cards rendered in whatever the browser's default block flow was. Added the class, and added a distinct (pink, dashed outline) opponent-pick highlight to ui/themeGrid.ts so the opponent's live vote pick is visually distinct from the local player's own selection, keeping the existing 'Opponent chose <theme>' text. PROTOCOL.md updated for all wire-visible changes: endsAt formula, round:revealVote/round:revealVoteUpdate, and the round:nextMatch/ room:closed timing. |
||
|---|---|---|
| backend | ||
| frontend | ||
| .gitignore | ||
| AGENTS.md | ||
| README.md | ||
Theme Guess
A browser game about syntax-highlighting themes. A snippet of code is rendered with every token type (keywords, strings, functions, variables, comments, ...) in a neutral color. You click a token, every token of that same kind lights up together, and you pick a color for it — repeat until the whole file is themed. Reveal shows how close your from-scratch palette landed to a real theme (Gruvbox, Tokyo Night, VS Code Dark+, GitHub Dark, Dracula, Catppuccin), token kind by token kind.
The project is moving from a single-player-only page toward supporting multiplayer matchmaking (race another player to the closest match on the same theme/snippet). This repo is split into a frontend game client and a backend matchmaking/realtime server so that work can land independently.
Layout
frontend/ Canvas game client: Vite + TypeScript, no UI framework.
backend/ Matchmaking + realtime session server: Node, HTTP + WebSocket.
Each package has its own package.json, dependencies, and scripts — see
frontend/README.md-equivalent notes below and backend/src/*/README.md
for what's reserved but not implemented yet.
Running the frontend
cd frontend
npm install
npm run dev # Vite dev server with HMR
npm run build # type-check + production bundle to dist/
npm run typecheck # tsc --noEmit only
Running the backend
cd backend
npm install
npm start # node src/index.js
npm run dev # same, with --watch
Boots a plain HTTP server (with a /health check) and attaches a
WebSocket server to it. Matchmaking and room/session logic are not
implemented yet — see backend/src/matchmaking/README.md and
backend/src/rooms/README.md.
Status
Single-player game: playable. Multiplayer: backend is a bare HTTP+WS
scaffold with no matchmaking logic yet; frontend has no multiplayer UI
yet. See AGENTS.md for architecture notes and contribution conventions.