This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Multiplayer LeetCode is a real-time collaborative coding game where multiple players on a team solve programming puzzles simultaneously using multiple physical keyboards connected to a single computer.
The system captures raw keyboard input via Linux evdev and streams keystrokes through WebSockets to a shared code editor. The system enforces rules such as which keyboard must be used to type the next character, which may be indicated by e.g. keyboard LEDs.
Other players can send "penalties" by completing online puzzles, which temporarily mess with the typing experience even more (e.g. swapping keys, randomizing rules, visual effects).
The game server executes player code submissions in isolated Docker containers to validate correctness.
The project consists of three components:
- Backend (
backend/) - Python WebSocket game server
- Manages player sessions, editor state, submissions, penalties and online puzzles
- Executes Python code submissions in isolated Docker containers
- Stores player/submission data in SQLite (
state.db) - (Re)loads puzzles defined in
puzzles.yaml - Runs on port 6979
- evdev-ws (
evdev-ws/) - Python keyboard input daemon (Linux only)
- Captures raw keyboard events via Linux evdev, identifies keyboards by USB port path
- Broadcasts keystrokes to WebSocket clients
- Controls keyboard LEDs (NumLock, CapsLock, ScrollLock) via WebSocket messages
- Runs on port 6969
- Frontend (
frontend/) - React/Vite web client
- Text editing
- Player penalties (visual effects, keyboard usage rules, key remapping)
- Connects to both game server and keyboard server via WebSockets (
connection.ts) - Admin frontend for control and spectation
- Player frontend:
- Custom text editor implementation (
Editor.tsx) - not using any editor library - Keyboard layout handling (Finnish layout default, US layout available;
keyboards.ts) - All game logic goes through
PlayerController.ts, which stores mutable state and publishes a Zustand store for React - Support for numerous debuffs that make the coding experience more difficult and funny (defined in
debuffs.ts, implemented all over)
- Custom text editor implementation (
cd frontend
npm install
npm run dev # Start dev server
npm run build # Build for production (runs tsc first)
npm run lint # Run ESLintcd backend
uv sync # Install dependencies
ADMIN_PASSWORD=xxx uv run main.py # Start server (requires Docker)
DEBUG=1 ADMIN_PASSWORD=xxx uv run main.py # With debug logging
uvx black . # Run Black formatter
uvx isort . # Run isortcd evdev-ws
uv sync
sudo uv run main.py # Requires root for evdev access
uvx black . # Run Black formatter
uvx isort . # Run isortKeyboards are identified by their USB port path (not device name), allowing consistent identification when reconnected to the same port.
User code is wrapped using the puzzle's wrapper template and executed in Docker with strict sandboxing:
- No network, 256MB memory, 0.5 CPU, 2s timeout
- Read-only filesystem, seccomp profile
- Output compared against
expected_outputfor validation
Puzzles in puzzles.yaml use | to mark initial cursor position in the template.
- Client sends:
login,edit,submit - Server sends:
welcome,editor,puzzle,output,state,error
- Server broadcasts:
[keyboardId, state, key](state: "down"|"up"|"hold") - Client sends:
[keyboardId, numLock, capsLock, scrollLock]for LED control