A multiplayer 2D top-down space combat/exploration game where you have three ways to control your ship (separately or all at once):
- manual keyboard/mouse input
- Python scripts you write (running sandboxed on the server)
- an LLM "ship's computer" connected via MCP.
See spaceship-scripting-game-spec.md for the full design.
# 1. Start the game server
scripts/start-server.sh
# 2. Start the web client (in another terminal)
scripts/start-client.sh
# 3. Open http://localhost:5173/ and register on the login screen
# ("New pilot") — credentials are remembered in the browser.
# Copy your token from the in-game Profile panel (key P) to
# connect MCP agents or API clients (docs/AUTH.md).Admins can still provision accounts from the shell: scripts/users.sh add alice prints a sign-in token.
Or everything at once:
scripts/start-all.sh| Component | What it is | Start with |
|---|---|---|
| Server | FastAPI + WebSocket simulation (physics 10 Hz, scripts 1 Hz) | scripts/start-server.sh |
| Client | Vite + TypeScript web client with Monaco script editor | scripts/start-client.sh |
| Sandbox | Node.js + Pyodide sidecar that runs player scripts (started automatically by the server) | auto |
| MCP | "Ship's computer" — LLM agent access via FastMCP | scripts/start-mcp.sh |
- AGENTS.md — for AI coding agents: architecture, invariants, and what to update when changing things
- docs/CONFIG.md — every configuration option
- docs/AUTH.md — users, tokens, multi-player setup
- docs/DOCKER.md — running the stack with Docker Compose
- docs/MCP_AGENT_GUIDE.md — connecting an LLM agent
- docs/SCRIPTING_API.md — writing ship scripts (API + events)
- skills/ship-operations/ — agent skill for operating the ship (MCP + scripting)
| Key | Action |
|---|---|
W / S |
Thrust forward / reverse |
A / D |
Turn left / right |
Space (hold) |
Fire plasma cannon (auto-fire at cooldown rate) |
Tab |
Sensor scan |
B |
Toggle mining beam (target a rock in the nav panel first) |
N |
Toggle nav panel (warp-jump planning + scans + waypoints) |
T |
Toggle trade panel (account, cargo, buy/sell) |
M |
Toggle missions panel (delivery job board + active missions) |
F |
Toggle workshop panel (fabrication recipes + shipyard components) |
J / K |
Engage / abort warp jump |
C |
Toggle comms chat panel |
P |
Toggle profile panel (ship name, token view/rotate, sign out) |
` (backtick) |
Toggle script editor panel |
- Accounts — register/sign in from the login screen; credentials live in
the browser (localStorage), not the URL. The Profile panel (
P) renames your ship and lets you view/copy/rotate your access token for MCP/API clients, or sign out. - Comms — chat with other ships in range (default 50,000 units) via the
chat panel (
C) — broadcast, or pick a specific ship from the recipient dropdown — via scripts (ship.comms.send), or your agent (comms_send). Incoming messages fire amessage_receivedscript event. - Ship naming — rename your ship via
game_control.ship.rename; the name shows in scans, comms, and other players' HUDs. - Celestial naming — scan a system, fly within 1,000 units of an unnamed
body, and name it (
exploration.name_body). Names are world-global and permanent — first-come-first-served exploration races. - Trade — ~70% of star systems host a commodity market. Dock within 500
units of a planet and trade (
trade.list/buy/sellvia your scripts, the REPL, or your agent). Prices are deterministic per system and per day — buy low in one system, sell high in another. You start with 1,000 credits and a 50-unit cargo hold; credits/cargo persist with your ship. - Delivery missions — every trade planet posts an hourly job board
(
missions.list_offers). Accept a job, haul the mission cargo (it shares your hold and can't be sold), and fly to the destination planet — the job auto-completes within 500 units and pays credits on arrival. Up to 3 concurrent missions, generous time limits, abandon anytime. - Mining — every
asteroid_fieldis a real place: a deterministic swarm of minable rocks (mining.surveybreaks a field down). Target a rock in the nav panel's survey list, then holdB(ormining.set_beamfrom a script or your agent — no auto-targeting, the beam refuses to engage without a target). The beam grinds that rock into cargo — rock→ore, ice→fuel, metal→alloys, rare→rare_earth— slowly, scaling inversely with value (ore ≈ a unit per second or two, rare_earth several seconds), and disarms itself when the hold fills or the target is lost. Beams are visible to other players. Jettison unwanted cargo from the trade panel (T→ Dump). Some empty sectors hide deep-space belts (they show up in cartography as unidentified mass signatures): no star, richer rocks, 2.5× the rare odds — the high-yield tier of the loop. Depletion is session state: restart the server and every belt is whole again. - Crafting & upgrades — the workshop panel (
F) has two tabs. Fabricate: turn commodities into repair kits (+40 hull) and shield cells (+50 shields) you can use anywhere mid-flight, refine ore into alloys (6 ore → 3 alloys at a port, → 4 at your outpost's refinery), nav beacons (your galaxy-wide address book — the nav panel lists them with bearing/distance, one click flies you back), and outpost kits. Shipyard: nine upgradeable components (engines, shields, weapons, sensors, reactor, hull, cargo, mining, jump drive; Mk 0–3, sequential) installed for credits plus commodity materials at shipyards — ~35% of market planets have one, and your outpost at L3 is a shipyard too. Stats recompute on install and persist with your profile. - Outposts — deploy an outpost kit (one per owner, needs 1,500+ units of clearance from bodies/stations) near a rich deep belt and upgrade it: L1 hull repairs, L2 refinery with the better refine ratio, L3 shipyard — the belt farm becomes the upgrade stop. Your outpost persists with your profile and enters the session universe when you connect; everyone sees it as a hexagon on the map.
cd server && python -m pytest tests -q # server tests
cd client && npx tsc # client typecheck

