Files
Battle-for-Tismo/AGENTS.md
T

5.0 KiB

AGENTS.md

Battle for 'Tismo — HTML5 port of the strategy game. Pure JavaScript: shared game logic runs both in Node (authoritative server) and in the browser (client). There is no build step and no runtime dependency; the client vendors jQuery and everything else (transport included) is hand-written.

Commands

  • Install dev dependencies once: npm install (only c8 and jsdom, used by the test suite — nothing the game runs needs them).
  • Run the test suite: node tests/run_tests.js (alias npm test; prints a summary and exits non-zero on failure).
  • Coverage report: npm run coverage (c8, writes coverage/).
  • Start the game server and client locally: node server/server.js --port 27015 --bind 127.0.0.1. Then open http://127.0.0.1:27015/ (redirects to /client/index.html). The browser connects to ws(s)://<page-origin>/ws.
  • Install the versioned git hooks (runs the tests on every commit): ./scripts/install-git-hooks.sh; uninstall with git config --unset core.hooksPath.
  • Build the deployable packages: nix build .#server and nix build .#web.
  • If node is not on PATH, use the pinned one: nix-shell -p nodejs --run "node tests/run_tests.js".

There is no linter, formatter, or CI. Do not invent commands beyond these.

Gotchas

  • Keep the shared modules framework-free: they are imported unchanged by both server/ (Node, ESM) and client/js/ (browser). No Node built-ins and no DOM APIs in shared/ (server/websocket.js is the only place Node built-ins are expected).
  • Do not add JavaScript libraries. The only third-party code allowed is the vendored jQuery under client/vendor/; implement everything else by hand (see server/websocket.js, a dependency-free RFC 6455 server).
  • The game server also serves the app as static files from the repository root, so modules resolve as /client/... and /shared/.... Preserve the client/ + shared/ layout when packaging (nix/package.nix).
  • WebSocket state snapshots can be hundreds of KiB; the custom server handles fragmented and large frames (server/websocket.js). Do not lower the buffer limits without checking the snapshot path.
  • Indent .js files with 2 spaces. .editorconfig only enforces UTF-8.

Architecture

  • Game logic is server-authoritative. shared/game_state.js (GameState) is a framework-free model that owns the world, units, cities, territory, economy, training and visibility. server/game_server.js (GameServer) owns a GameState, validates orders and broadcasts snapshots over the transport in server/server.js. The browser client is a view: client/js/map_view.js rebuilds terrain from the shared seed, renders snapshots and sends orders.
  • Movement is continuous: server/server.js advances movement every tick and strikes an in-game hour every SECONDS_PER_HOUR real seconds. The client extrapolates each unit along its snapshot path and predicts move orders locally (map_view.js), mirroring GameState.find_path so a click feels instant. Any pathfinding or movement-cost change must be mirrored on both sides or prediction will fight the server.
  • shared/ holds the reusable algorithms so they stay testable without a server: hex.js (topology/geometry), map_generator.js, hex_pathfinder.js, terrain_stats.js, rules.js, economy figures in game_state.js, game_clock.js, rng.js, noise.js, text_format.js, login_manager.js. Data-driven content (civilisations, units, buildings, governments, technologies) lives in shared/data.js.
  • client/js/ splits the UI: app.js (screens and flow), net.js (transport wrapper), game_screen.js (HUD and panels), map_view.js (canvas/DOM map), modals.js (training, buildings, government/technology modals).
  • Tests live in tests/ as *_test.js files extending the TestCase base in tests/framework/; tests/run_tests.js discovers and runs them. Add a new tests/<topic>_test.js for each new pure behaviour.

Deployment

  • flake.nix exposes packages.<system>.server and .web, plus nixosModules.default. There is no compiler step: nix/package.nix copies the app and wraps node server/server.js; web is the static client/ and shared/ tree.
  • nix/module.nix runs the server as a services.battle-for-tismo systemd unit and serves the static client through nginx, redirecting / to /client/index.html and proxying /ws to the local Node server. The browser client connects to the page's own origin, so HTTPS gives it wss://.
  • Build locally with nix build .#server and nix build .#web.
  • Updating without a rebuild: set services.battle-for-tismo.appDirectory to a writable checkout (e.g. /opt/battle-for-tismo); the unit then runs node <dir>/server/server.js instead of the Nix-store copy. Serve nginx client/ and shared/ from that same checkout (e.g. alias locations), then git pull and systemctl restart battle-for-tismo. Keep the client and server trees on the same commit: the client mirrors the server's movement model, so a mismatched pair makes prediction fight the server.