- Main menu Galaxy Seed panel: displayed, editable, rerollable; the menu previews what the seed builds (galaxy name, scale, archetypes) before committing. Same seed always generates the same galaxy. - js/galaxy/Galaxy.js: seeded roster of 40k systems (disk + core + spiral arms, type weights, radial bands) with spatial hash for neighbor queries; contents generated lazily on arrival — identical to eager generateAll() because each system draws from Rng.derive(seed, 'system', id). - js/galaxy/SystemGenerator.js + data/systems.json: six themed archetypes whose attributes (star classes, planet count spread, class weights, moons, belts, habitability, hazard) steer content generation. - data/galaxy.json layout/distribution knobs, incl. distribution.rules[] hook for future proximity/clustering rules; data/naming.json name pools. - GameScene: current system name/identity HUD (lazy content generation on arrival); dev boot without a menu falls back to a dev galaxy. - dev/galaxy.test.mjs: determinism, distribution, bands, lazy==eager, neighbor brute-force checks (40k roster in ~70ms). - Docs: world model, determinism rules, roadmap update. |
||
|---|---|---|
| data | ||
| dev | ||
| docs | ||
| js | ||
| lib | ||
| README.md | ||
| index.html | ||
README.md
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.htmlviafile://won't work, because the game uses ES modules andfetches 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 indata/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.