No description
Find a file
Gabriel Franco 7a6df57ad0 fix(frontend,backend): online scoring bug, mutual reveal vote, theme preview timing
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.
2026-09-13 20:36:52 -03:00
backend fix(frontend,backend): online scoring bug, mutual reveal vote, theme preview timing 2026-09-13 20:36:52 -03:00
frontend fix(frontend,backend): online scoring bug, mutual reveal vote, theme preview timing 2026-09-13 20:36:52 -03:00
.gitignore refactor(frontend): move to frontend/, port to Vite + TypeScript 2026-09-10 10:37:44 -03:00
AGENTS.md docs: require agents to commit all changes before finishing a task 2026-09-13 17:36:52 -03:00
README.md feat(backend): scaffold matchmaking server project 2026-09-10 10:37:52 -03:00

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.