Star Wars – Wild Space
Exploitable ring only (outer Ø100, inner Ø60). Planet positions are deterministic from the server world seed; stats stay hidden until you click a tile. Reveals are persisted in PostgreSQL.
Desktop only — the galaxy map is not playable on phones or narrow screens (< 768 px wide).
Layout
The UI is split into two panes:
| Pane | Content |
|---|---|
| Left column | Title, team scores, player info, cooldown timer, world seed & period countdown, Refresh button, selection details |
| Right side | Galaxy map — a perfect square anchored to the right edge of the viewport |
Secrets & environment variables
Never commit secrets. All credentials live in .env (git-ignored).
Copy the template and fill in your values before the first run:
cp .env.example .env
# then edit .env
| Variable | Description |
|---|---|
JWT_SECRET |
Secret used to sign JWT tokens — use a long random string in production |
POSTGRES_USER |
Game-DB username (default game) |
POSTGRES_PASSWORD |
Game-DB password — change in production |
POSTGRES_DB |
Game-DB name (default star_wars_grid) |
POSTGRES_USERS_USER |
Users-DB username (default users) |
POSTGRES_USERS_PASSWORD |
Users-DB password — change in production |
POSTGRES_USERS_DB |
Users-DB name (default star_wars_users) |
PORT |
HTTP port exposed by the app (default 8080) |
Runtime config (file + volume)
Edit config/game.settings.json on the host (mounted into the container at /app/config/game.settings.json). The server reloads it when the file's mtime changes, on a schedule controlled by configReloadIntervalSeconds (minimum 5 s), so frequent polling is avoided when nothing changed.
| Field | Meaning |
|---|---|
clickCooldownSeconds |
Cooldown between new reveals (same as before). |
databaseWipeoutIntervalSeconds |
World period length in seconds (default 21600 = 6 h). The world seed is swg-<slot> with slot = floor(UTC unix seconds / this value). When the slot changes, grid_cells is truncated (full wipe). |
debugModeForTeams |
If true, the Blue / Red segmented control is shown; if false, it is hidden. |
configReloadIntervalSeconds |
How often the server checks the config file (mtime); also used by the client to poll /api/config. |
GET /api/config returns these values plus worldSeed, seedPeriodEndsAtUtc, seedPeriodStartsAtUtc.
Teams (blue / red)
- With
debugModeForTeams: use the Team control (top-left) to switch perspective. - Your discovered tiles use your team colour. Unclaimed ring tiles use the classic idle tint for both teams.
- Tiles discovered by the other team appear grey, show no planet, and are not clickable. First reveal owns the tile (
discovered_by).
Cooldown
After revealing a new tile, a cooldown runs (left column). During cooldown you cannot reveal additional unseen tiles, but you can still click tiles your team already discovered to view their stats.
Run with Docker Compose (Node + PostgreSQL)
Prerequisites
-
Copy the environment template and set your secrets:
cp star_wars_grid_game/.env.example star_wars_grid_game/.env # Edit .env — at minimum change JWT_SECRET, POSTGRES_PASSWORD, POSTGRES_USERS_PASSWORD -
From
star_wars_grid_game/:docker compose up --build -
Open
http://localhost:8080.
Ports
| Service | Port | Notes |
|---|---|---|
| App | 8080 |
configurable via PORT in .env |
| Game Postgres | 5432 |
user/pass from .env |
| Users Postgres | 5433 |
user/pass from .env |
Database persistence
PostgreSQL data is under ./data/postgres and ./data/postgres_users (bind mounts). The world wipe only clears grid_cells when the UTC period slot changes; it does not delete the Postgres data directory.
Local dev (without Docker)
Requires PostgreSQL, then:
cd star_wars_grid_game
cp .env.example .env # fill in DATABASE_URL etc.
npm install
# export vars or use a tool like dotenv-cli
$env:DATABASE_URL="postgres://game:game@localhost:5432/star_wars_grid"
$env:USERS_DATABASE_URL="postgres://users:users@localhost:5433/star_wars_users"
$env:JWT_SECRET="dev_secret"
npm start
Ensure config/game.settings.json exists (or copy from the repo).
Docker image notes
- Base image:
node:20-alpine - Runs as a non-root user (
appuser) for security NODE_ENV=productionis set inside the image- Built-in health check: polls
GET /api/configevery 15 s (wget) - Secrets (
JWT_SECRET, DB passwords) are never baked into the image — pass them via.env/ Compose environment
API
GET /api/config— cooldown, wipe interval, debug flag, poll interval,worldSeed, period timestamps.GET /api/grid/:seed— cells for that seed;410ifseedis not the current world seed.POST /api/cell/reveal— body{ seed, x, y, team: "blue" | "red" }— first reveal wins;409if the other team owns the tile;410if seed is stale.POST /api/auth/register—{ username, email, password, team }→{ token, user }.POST /api/auth/login—{ username, password }→{ token, user }.GET /api/auth/me— Bearer token required → refreshed{ token, user }.GET /api/scores—{ blue: N, red: N }tile counts for the current period.