orbit/README.md

4.1 KiB

Orbit

A procedurally generated space RPG in the spirit of Privateer, in top-down 2D. Built with Phaser 4 as plain ES6 modules — no build step, no package managers required to run.

Run it

Any static file server works (Python, Node, Caddy, nginx, …):

cd orbit
python3 -m http.server 8080
# → http://localhost:8080

Must be served over http(s) — opening index.html via file:// won't work, because the game uses ES modules and fetches its JSON config.

Current state — v0.2: a seedable galaxy

  • Main menu with New Game and a Galaxy Seed panel: the seed is displayed, editable (click it and type), and rerollable — and the menu shows what that seed builds (the galaxy's name, system count, archetype count) before you commit. Same seed ⇒ same galaxy.
  • Procedural galaxy: 40,000 star systems in a seeded disk + core + spiral arms (data/galaxy.json), typed into six themed archetypes (data/systems.json) with per-type distribution weights and radial bands — the first "how does the galaxy lay itself out" rules.
  • Two-level generation: the whole galaxy roster is generated at New Game (~70 ms); each system's planets/moons/belts are generated lazily on arrival, deterministically (seed + system id), so lazy and eager give identical results. The current system's name/identity shows top-left in the game scene.
  • Game screen with a basic top-down ship: click anywhere to fly there in infinite, unbounded space (system boundaries/jumps come next)
  • Camera gently trails the ship; the parallax starfield streams past while it flies and the view slowly recenters (≈1.5 s) once the ship comes to rest
  • Config-driven setup: every tunable value lives in data/*.json

Project layout

orbit/
├── index.html              # boots the game
├── data/                   # ← ALL tunable config (edit these freely)
│   ├── manifest.json       #   which config files exist
│   ├── game.json           #   dimensions, colors, starfield, …
│   ├── menu.json           #   menu text, colors, button layout, seed panel
│   ├── ship.json           #   ship feel: thrust, drag, maxSpeed, …
│   ├── galaxy.json         #   galaxy scale & shape (count, radius, spiral…)
│   ├── systems.json        #   system archetypes: theme, attributes, distribution
│   └── naming.json         #   syllable pools for names
├── lib/                    # vendored third-party libs (Phaser 4.2.1)
├── js/
│   ├── main.js             # entry point: load config → boot Phaser
│   ├── config/             # Config singleton, ConfigLoader, game config
│   ├── scenes/             # MenuScene, GameScene (thin, orchestration)
│   ├── entities/           # Ship (own behavior)
│   ├── galaxy/             # Galaxy (seeded world model), SystemGenerator
│   ├── ui/                 # MenuButton (reusable)
│   ├── visuals/            # Starfield (decorative)
│   ├── utils/              # small pure helpers (Color, Rng, NameGenerator)
│   └── vendor/             # shim to the vendored Phaser
└── docs/PROJECT_NOTES.md   # ← project conventions: read this

Conventions (short version)

  • Config in JSON. If a value might change, it goes in data/, not code. Add a file = one line in data/manifest.json.
  • One class per file, ES modules, scenes stay thin, entities own their behavior. Details in docs/PROJECT_NOTES.md.
  • Phaser is imported only via js/vendor/phaser.js (one-file version swap).

Dev tools

node dev/ship-behavior.test.mjs   # runs the real Ship.update() loop in Node
node dev/starfield.test.mjs       # runs the real Starfield.create() in Node
node dev/galaxy.test.mjs          # galaxy determinism, distribution, lazy vs eager

dev/test-game.html boots straight into the GameScene (no menu click), handy for manual testing of the flight feel.

Phaser

Phaser 4.2.1 is vendored at lib/phaser.min.js (UMD build, MIT license — see lib/PHASER_LICENSE.md). No internet or npm needed at runtime.