4.0 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
npm run inst # Install deps (uses npm ci --ignore-scripts — do NOT use npm install)
npm run dev # Run client + server in dev mode with hot reload
npm run start:client # Client only
npm run start:server-dev # Server only
npm test # Run all tests (Vitest)
npm run test:coverage # Tests with coverage
npm run lint # ESLint
npm run lint:fix # ESLint with auto-fix
npm run format # Prettier
npm run build-prod # Production build
Run a single test file:
npx vitest tests/YourTest.test.ts --run
npx vitest NationAllianceBehavior --run # match by name pattern
Architecture
OpenFront.io is a real-time multiplayer territorial strategy game. There are four components:
src/core/— Deterministic game simulation. Pure TypeScript with no external dependencies. Must remain fully deterministic (seeded PRNG, no floating-point math). Runs in a Web Worker thread. Allsrc/corechanges must include tests.src/client/— Rendering (Pixi.js/WebGL), UI (Lit web components + Tailwind CSS 4), WebSocket communication.src/server/— Game coordination, intent relay, WebSocket management (Node.js/Express/ws).- API — Closed-source Cloudflare Worker handling auth, stats, cosmetics, monetization. Not in this repo.
Simulation Flow (Intent → Execution)
The game simulation runs on each client, not the server. The server only relays intents.
- Player action → client creates an Intent → sent to server
- Server bundles all intents for the tick into a Turn → relays to all clients
- Client forwards Turn to the Core worker
- Core creates an Execution for each intent
- Core calls
executeNextTick()— all executions run and mutate game state - Core sends GameUpdates back to client → client renders
Intents and all wire messages are Zod-validated schemas defined in src/core/Schemas.ts.
CDN / Static Assets
The game server only serves index.html and the WebSocket. All other assets (JS bundle, images, maps, worker) come from a CDN bucket. CDN_BASE is an empty string in dev (falls back to same-origin) and a full origin (e.g. https://cdn.example.com) in production. It is set as both a Vite build-time variable and a server runtime env var.
Key Files
| File | Purpose |
|---|---|
src/core/Schemas.ts |
All intent/message types (Zod schemas) |
src/core/GameRunner.ts |
Simulation orchestrator |
src/core/game/GameImpl.ts |
Game state implementation |
src/server/GameServer.ts |
Main WebSocket server, game loop |
src/server/Master.ts |
Lobby and game registry |
tests/util/Setup.ts |
Test helper — creates test games |
docs/Architecture.md |
Architecture overview |
docs/Auth.md |
JWT/auth flow |
docs/API.md |
Public API endpoints |
vite.config.ts |
Build config, CDN handling |
UI Text / i18n
All user-visible text must go through translateText() and have a corresponding entry added to resources/lang/en.json. Translations are managed via Crowdin. DO NOT modify any other translation files.
Testing Patterns
Tests use a setup() helper from tests/util/Setup.ts that creates a full game instance with map data from tests/testdata/maps/. Write tests that exercise the core simulation directly — not mocks.
Tech Stack
- Bundler: Vite + TypeScript 5.7
- Rendering: Pixi.js (WebGL)
- UI Components: Lit (LitElement) + Tailwind CSS 4
- Audio: Howler.js
- Schemas/Validation: Zod
- Testing: Vitest
- Server: Node.js, Express, ws (WebSocket)