- This is a build-free JavaScript arcade plus one Node.js service. Browser pages load source files directly; do not introduce a bundler or framework without an explicit architectural decision.
- Modern games share accounts, results, achievements, appearance, navigation, and room UI through
arcade.js,arcade.css,theme-init.js, andscripts/. - Game-specific browser code lives in each game directory. Keep testable mechanics separate from DOM/rendering code when practical.
- The Node service in
server/serves static assets, REST APIs, SQLite persistence, and authoritative WebSocket rooms. - Classic games are intentionally preserved beside modern versions. Avoid broad rewrites of
classic/directories. - Coding-challenge directories such as
leetcode/,codeforces/, andcodewars/are independent scripts, not arcade runtime components.
Read docs/architecture.md before changing subsystem boundaries. Review the relevant record in docs/adr/ for themes, persistence, security, results, online rooms, Battle Tanks, or Tetris. Add an ADR when a change makes a durable architectural choice rather than quietly overriding an accepted decision.
- Use Node.js 22 or newer.
- Preserve the dependency-light, no-build browser architecture and existing plain JavaScript style.
- Match the formatting of the file being edited. Much of the CSS and browser markup is intentionally compact.
- Keep shared behavior in shared files and game-specific behavior in the game directory. Do not make game scripts branch on named experience themes.
- Experience themes (
playful,cabinet,calm) and color modes (system,light,dark) are independent. Theme palettes and layout contracts belong in CSS custom properties and shared theme selectors. - Maintain accessibility: semantic controls, useful labels, keyboard support, visible focus, live regions for status, and touch targets that remain usable at phone sizes.
- Treat narrow and short viewports as first-class. For mobile game changes, verify the board/canvas and controls together, account for
env(safe-area-inset-*), and test at least one phone-sized viewport such as 390 x 844. For layout changes, also check a laptop/desktop viewport and every experience theme affected. - Keep mechanics deterministic and independently testable. Rendering and client prediction must not become sources of authoritative online state.
- Never trust client-authored scores.
server/accounts.jsvalidates bounded result facts and derives scores server-side. - Online room managers own authoritative multiplayer state. Validate commands, preserve reconnect semantics, and serialize only viewer-safe state.
- Do not expose passcodes, session tokens, resume tokens, concealed opponent state, private implementation files, or database paths.
- Preserve origin checks, payload limits, rate limits, heartbeat handling, and secure cookie behavior when changing HTTP or WebSocket code.
- Add schema changes as the next ordered SQL file in
server/migrations/. Never edit a migration that may already have shipped.
Run from the repository root:
npm test
npm run checkUse focused tests while iterating, for example:
node --test tests/tetris.test.js
node --test tests/profile-page.test.jsBefore handing off a change:
- Add or update regression tests for the behavior.
- Run the focused tests, then the full test suite and syntax checks.
- Run
git diff --checkand review the final diff for unrelated changes. - For visual or interaction changes, start
node server/index.js, openhttp://localhost:8080/, and verify the rendered behavior at relevant desktop and mobile viewports. Reload after source changes because there is no build or hot-reload layer. - For online changes, test both local and online paths plus disconnect/resume and rematch behavior where applicable.
- Inspect
git statusbefore editing and preserve user-owned changes. - Never make requested changes directly on
master. Before editing, update localmasterfromorigin, then create a task-specific branch from the latestmasterunless the user specifies another base. - Keep commits focused and use concise imperative subjects consistent with the repository history.
- Treat each requested repository change as authorization to commit the completed work, push its branch, and open a pull request. Do not consider the work handed off until the pull request exists, unless the user explicitly asks not to commit, push, or create one.
- Never rewrite history unless the user explicitly asks.