4.0 KiB
4.0 KiB
Orbit — Project Notes
Working agreements and conventions for building this game. Read this before adding new systems — these are the rules that keep the project scalable.
What we're building
A procedurally generated space RPG in the spirit of Privateer, but in top-down 2D: stars/sectors you can jump between, ships to fly, crew, trading/economy, stations, quests — to be scoped as we go.
Hard technical constraints:
- Plain ES6 modules, no transpilation, no build step.
- No package managers required to run — the game must work from any static HTTP server (the browser fetches everything).
- Third-party libraries are vendored into
lib/(right now:lib/phaser.min.js, Phaser 4.2.1 UMD build, seelib/PHASER_LICENSE.md). - Must be served over http(s), not
file://(ES modules +fetchof JSON).
Config lives in JSON (important)
- Tunable data lives in
data/*.json: dimensions, colors, text, physics, balance, spawn tables, and anything a non-programmer might want to tweak. data/manifest.jsonlists which files to load. Add a config file = drop it indata/+ one line in the manifest. It is then available as a section named after the file (ship.json→config.get('ship.thrust')).- Code reads config through the
configsingleton (js/config/Config.js):
Always supply a sensible fallback so code never depends on a missing key.import { config } from '../config/Config.js'; const thrust = config.get('ship.thrust', 900); const menu = config.section('menu', {}); - Rule of thumb: if a value might ever change (balance, layout, copy, colors), it belongs in JSON, not code. Code owns behavior, JSON owns parameters.
- Split config by concern as the game grows:
data/sectors.jsonfor world generation,data/economy.json,data/ships.json,data/crew.json, etc. One file per system beats one giant file.
Code is modular & class-based (important)
- One class per file, ES module exports, no globals (except the deliberate
singletons:
config). - Layering:
js/scenes/— Phaser scenes: state + orchestration only (thin classes)js/entities/— in-world objects that own their behavior (Ship, NPC, …)js/ui/— reusable UI components (MenuButton, panels, HUD)js/visuals/— decorative, non-interactive visuals (Starfield, …)js/utils/— small pure helpers (Color, math, rng)js/config/— config loading + Phaser game configjs/vendor/— shims to pinned third-party libraries
- Scenes stay thin: they compose entities/UI and wire input. They don't hold balance numbers or game rules.
- Every class should be standalone-constructible: it takes what it needs
(
scene, config values) in its constructor rather than reaching for globals — that keeps things testable and reusable. - Entities drive themselves from their own
update(time, delta)method, called by the owning scene (e.g.GameScene.update). If an entity ever needs the engine's auto-update instead, definepreUpdate(the Phaser v4 hook — v4 does not auto-callupdate). - Import Phaser only through
js/vendor/phaser.js— the single place that changes if we swap framework versions.
Phaser version
- Pinned: Phaser 4.2.1 ("Giedi"), vendored in
lib/phaser.min.js. - App code is v4-specific where v4 changed things (e.g.
Phaser.Math.Angle.RotateTo,banner: false,Clamp(value, min, max)). - To upgrade: replace the vendored file + note the version here.
Roadmap (working list, intentionally rough)
- v0.1 foundation — menu → New Game → click-to-fly ship
- Decide the world model: bounded sectors vs. infinite space (affects camera, starfield, and world gen)
- Procedural star map / sector generation (driven by
data/sectors.json) - Ship input beyond click-to-fly (throttle/brake keys, manual rotation)
- HUD (speed, sector name, later: fuel/crew)
- Save/load (the
config+ entity split should make this tractable) - Economy/trading loop (the Privateer heart)