Real-time multiplayer space combat with no game server — peer discovery and matchmaking via Trystero (WebRTC + Nostr relays).
npm install
npm run dev- Open the app in a browser.
- Enter a callsign → Create Arena.
- Copy the room link (or code) and open it in a second browser/tab (or share with a friend).
- Dogfight in the nebula.
| Input | Action |
|---|---|
| WASD / arrows | Thrust |
| Mouse | Aim |
| Click / Space | Fire |
| Shift | Boost |
| Esc | Leave arena |
On phones/tablets: left stick move · right stick aim · FIRE / BOOST buttons.
- Vite + TypeScript — build tooling
- Trystero 0.25 —
joinRoomover Nostr,makeActionfor game events - Canvas 2D — ships, projectiles, particles, HUD
| Channel | Rate | Purpose |
|---|---|---|
hello |
on join | Callsign + color |
state |
~20 Hz | Position, velocity, aim, HP, score |
fire |
on shot | Bullet spawn |
hit |
on impact | Damage claim (shooter → victim) |
kill |
on destroy | Kill feed |
Each peer is authoritative for their own ship. Remote ships are interpolated between state snapshots. Hit detection is shooter-side; the victim applies damage when they receive a hit.
Static files only need a host that serves the SPA — game traffic never goes through your server after the page loads.
Peers on the same Wi‑Fi often connect with STUN alone. Mobile data and some NATs need a TURN relay. Without it you’ll see:
LINK ERROR: could not connect to peer … configure TURN servers
- Copy
.env.example→.envand fill in credentials from Metered Open Relay (free) or Cloudflare TURN. - Rebuild / redeploy so Vite embeds
VITE_TURN_*.
On Dokploy, add the same VITE_TURN_URLS, VITE_TURN_USERNAME, and VITE_TURN_CREDENTIAL as build environment variables.
| Command | Description |
|---|---|
npm run dev |
Local dev server |
npm run build |
Production build to dist/ |
npm run preview |
Preview production build |