orbit/docs/PROJECT_NOTES.md

4.1 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, see lib/PHASER_LICENSE.md).
  • Must be served over http(s), not file:// (ES modules + fetch of 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.json lists which files to load. Add a config file = drop it in data/ + one line in the manifest. It is then available as a section named after the file (ship.jsonconfig.get('ship.thrust')).
  • Code reads config through the config singleton (js/config/Config.js):
    import { config } from '../config/Config.js';
    const thrust = config.get('ship.thrust', 900);
    const menu   = config.section('menu', {});
    
    Always supply a sensible fallback so code never depends on a missing key.
  • 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.json for 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 config
    • js/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, define preUpdate (the Phaser v4 hook — v4 does not auto-call update).
  • 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: infinite open space for now (ship flies unbounded; borders/sectors planned for later) — 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)