- Replace the sparse disk (radius, flatten, spiral arms, per-type radiusBand)
with a seeded square domain placed by Bridson Poisson-disk sampling for
even, organic star spacing (no clumps/voids).
- Add a home→far difficulty axis: each record now carries `d` (0 at the home
corner, 1 at the opposite corner) and a named zone; type distribution is
mixed per zone via `distribution.zoneMix` instead of radial bands.
- Move the starting system to the star nearest the configured corner
(`startingSystem.policy: "corner"`, default SE / lower right), with
`center` and `random` policies still supported.
- Increase default system count from 60 to 90 and retune settlement density
gradient, landing video slots, and test expectations to the new layout.
- Introduce StationFrames.js galaxy-wide pass that spreads spacestations.png
variant frames across the galaxy, avoiding collisions among neighbor stars
- Stamp settlement.stationFrame in SystemGenerator so content carries the
assigned variant (lazy === eager)
- Render deep-space stations from the spritesheet when available; keep
procedural fallback for waypoints and missing textures
- Extend comms target with isStation/frame and allow REQUEST LANDING on
deep-space stations, passing station flag into SurfaceScene
- Add landing.stationVideos entries and music.stationFrames slots keyed by
variant frame; surface/shop clips degrade gracefully until authored
- Add dev tooling: station-shot page/runner for world/panel/land/deck states
and a Node test asserting variant spread beats naive random assignment
- Sort gate candidates by destination-side before tier, so an on-ray point behind the center loses to any destination-side aimed/scan point
- Add a new soft "facing from the center" check in tests: when some anchor's tether circle reaches the destination side (maxProj + tether > 0), the gate must lie there; a single far planet may still take the best aimed point
- Prefer a destination-side aimed candidate in the clearance fallback
- Shrink the roster from 200 to 60 systems and drop spiral arms / core bulge for a uniform-in-area sparse disk (data/galaxy.json)
- Turn the jump network into a pure spanning tree (shortcuts off): exactly one route between any two systems, barren systems become single-gate dead-end leaves
- Remove the rendered Star entity; non-home system centers are now empty space with the star kept only as invisible dossier flavor
- Gate anchors restricted to planets (stations no longer anchor) and every non-barren system guaranteed ≥1 planet so a buildable world always exists
- Give barren dead ends 1–2 asteroid clusters drifting inside their gate's level-1 tether as the stop's only payload
- Bump save format to 2 and reject legacy format-1 saves with a clear toast message
- Update tests, docs, and README to reflect the maze layout, leaf dead ends, empty centers, and new barren cluster rules
- Introduce Star entity (procedural texture per spectral class) drawn at the origin of every non-home system; only the starting system's central body is the home world
- Freeze `homeSystemId` at roster build so lazily generated content for newly arrived systems no longer misreads as home and deals a second home world
- Anchor tether-l1 builds on newly discovered worlds (effects.tether in data/builds.json) and re-materialize installed tethers after jump cuts / scene rebuilds
- Discovery now reports the central body in every system ("Home World" vs. spectral-class star label); stars are solid but not comms targets
- Add dev tools: nav-reach-probe (soft-lock analysis), star unit tests, tether-newworld browser test; fix landing video references and Phaser stubs
- Galaxy shrunk to 200 systems (data/galaxy.json) — always fully known,
generation ~15 ms; roster/content two-level design unchanged.
- Object composition replaces planetCount (data/systems.json → objectCount):
10% barren (jump-gate-only), else 2/3/4/5 objects (planets + free-space
stations) at 15/30/30/15. One unified roll (rollSystemComposition) shared
by the content generator and the frame pass.
- Barren systems: no planets, no stations, no asteroid clusters; their
single gate sits on the star→destination ray at barrenDistance (8192 px).
Strong connectivity keeps them reachable.
- Jump gates are DORMANT by default: every gate record carries
active:false, the entity renders dim with a still field. Activation is
the seam for the tether mechanic (an activated gate anchors a level-1
tether). data/gates.json gains barrenDistance.
- Frame diversity (js/galaxy/PlanetFrames.js): one galaxy-wide pass spreads
(class, frame) across the galaxy — fixed spatial order, least-used face
among already-assigned nearest stars, seeded tie-breaks. Stamps
planet.frame + content.homeFrame, read by GameScene.
- Tests: dev/frames.test.mjs added; jumps/galaxy/discovery/jumpgate/asteroids
suites updated to the new rules (composition buckets, barren gates,
active flags, frame determinism/spread, 5-object max, index clamps).
- Docs (README, PROJECT_NOTES) and stale 40k references updated.
- Introduce data/gates.json + js/galaxy/JumpNetwork.js: a strongly-connected, degree-limited spanning tree over the nearest-star graph (plus local shortcuts) so every system holds 1–3 gates, all jumps are local, and no system is closed or trapped
- Place each gate on the tether circle of an anchor (planet / space station / home world), facing its destination star; enforce radius band, clearance from anchors, and gap between gates in SystemGenerator.layoutGates
- Add the JumpGate entity (procedural twin-pylon portal) with the same solid contract as Planet/Station, discoverable in cyan, listed in the HUD dossier; wire into GameScene solids + discovery
- Guarantee every system holds at least one gate anchor (barren systems get a deep-space station); cap the home system at 3 objects so it fits the tighter band
- Rework solar-system layout to a full pairwise band [minSpacing, maxSpacing] with rotation tuned toward gate bearings; update tests and docs accordingly
- Planet count is now a single global rule (20% barren, else 2–4 planets)
instead of per-type spreads; the starting system always holds a gas giant
plus a rocky world beside the home world.
- Every planet hosts one settlement by class (habitable rocky → colony, other
rocky/ice/lava → mining station, gas → cloud base); free-space stations and
beacons still roll per archetype with the core→rim gradient.
- Old probabilistic planet-settlement path kept behind allPlanetsSettled flag.
- Layout max drops to 6 objects (4 planets + 2 stations); the 11-object
two-orbit case remains as a defensive fallback.
- Update tests, docs, and add rocky-land video asset.
- Change radiusGrowth from 1.25 to 2.0 so level N doubles the previous
level (L2 = 10240, L3 = 20480, L4 = 40960 px)
- Update all data descriptions, docs, and test defaults to match
- Add refreshHudTetherLevel() in SurfaceScene so the HUD line re-decodes
when a tether build completes while on-surface
- Rename rocky-planet-02 asset (typo fix), add 03-a/03-b variants,
point rocky frames at indices 6–8 in planets.json
- Add dev/tether-flow harness to exercise the full L2 build flow end-to-end
- Introduce Reputation module (js/reputation/Reputation.js) tracking player standing on planets and space stations on a −20…+20 scale, with the home world pinned at +20
- Add data/reputation.json config for scale bounds, neutral default, and home-world standing
- Assign stable seed-deterministic ids to planets (<systemId>-p<ordinal>) and settlements (<systemId>-s<n>) in SystemGenerator so saved standing lines up with regenerated galaxies
- Wire reputation into the save system (captureState/prepareLoad/resetRunState) with backward-compatible loading of pre-reputation saves as all-neutral
- Add faction-check placeholder: standingFor() resolves home → stored → owner/faction → neutral, with factionStanding() stubbed for the upcoming factions layer
- Register a single Reputation instance in GameScene via the shared registry (same pattern as Discovery)
- Add dev/reputation.test.mjs covering scale clamping, home pinning, serialization round-trips, legacy/corrupt record handling, save integration, and place-id stability
- Replace the old per-rock placement retry loop with a deterministic pairwise relaxation pass (relaxRockGaps) that enforces a gapFactor x (r1+r2) separation between every pair, so rocks keep a subtle visible gap instead of interpenetrating
- Add cluster.gapFactor (default 1.12) and asteroids.compassColor (#c8d2e0) config keys, with updated comments in data/asteroids.json and SystemGenerator.js
- Tint the DiscoveryCompass arrow per target: bake the arrow texture white and tint it to the target's color (worlds keep theme neon cyan, clusters use their light gray)
- Extend dev/asteroids.test.mjs to assert every rock pair respects the gapFactor separation
- Generate 4–8 rock groups per system with seeded placement, spacing, and slow tumble/drift motion driven by data/asteroids.json
- Add AsteroidCluster entity (Phaser container) with halo, dust motes, per-rock spins, and ship keep-out collision reusing Planet.resolve
- Integrate clusters into GameScene: load spritesheet, constrain ship post-physics, include in click-to-fly/autopilot/discovery/compass
- Synthesise unique cluster names via NameGenerator.asteroid (syllables + field suffix)
- Add dev test suite and ?seed= param for deterministic galaxy generation
- Replace the annular-band scatter (minOrbit/maxOrbit/minEdgeGap) with a ring-based placement: objects sit on one or two orbits around the home world, governed by center-to-center `minSpacing` and `maxNeighbor`
- Free-space stations (deep-space stations, waypoints) are now layout objects alongside planets; planet-bound settlements stay features of their planet
- Handle the N=11 case (9 planets + 2 stations) with an inner 3-ring + outer 8-ring; chain outward defensively for any larger N
- Update tests to verify the new spacing invariants, the two-orbit case, and determinism including station positions
- Refresh PROJECT_NOTES and the data-file comment to describe the orbit model
Two small naming/labeling fixes:
1. The home planet was always the generic "Terra". It now takes the first
name off the STARTING system's planet-name deck (SystemGenerator), so it
reads as a real place and can never clash with one of that system's
planets. Stored as content.homeName (only the starting system has one);
the old planets.homeName stays as a fallback. Used for the compass
home chip and the tether anchor label.
2. Confirmed/sharpened the compass name tag: each discovered off-screen
object's arrow chip already renders TYPE + NAME — now the home world
shows its bank name too (e.g. "HOME WORLD · ESHKAELURA").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Planets and space stations were previously made by stitching a root word to
a kind noun ("Kest Skyspire", "New Natick IV"), which read like labels, not
names. They now draw from deep, hand-picked name BANKS in data/naming.json:
- banks.planet — colonial "New Denver"/"Port Tucson" worlds mixed with
alien "Klaxoria"/"Vexithunhal" worlds (269 names).
- banks.station — official designations ("Deep Space SC-145", "Nav Relay
V-77") mixed with smuggler hangouts ("Hell's Hideout",
"The Rusty Anchor") (165 names).
Assignment is a seeded shuffle of the whole bank (NameGenerator.planetDeck /
stationDeck), dealt out per-system in order, so a system never repeats a
name until the pool is exhausted (impossible at these sizes). The decks come
from dedicated Rng.derive(...) streams, keeping generation order-independent
(lazy === eager). Stars and the galaxy still synthesize from syllable pools
(unbounded), and the home world keeps its configured name.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Discovery rule: ship within `discovery.distance` (540 px) of a world's edge discovers it once per system; state is pure, save-ready (`Discovery.toJSON/fromJSON`)
- Off-screen compass (`DiscoveryCompass`): themed screen-edge arrows with type/name chips point back at discovered worlds; geometry helpers (`edgeAnchor`, `circleInView`, `lerpAngle`) exported for Node tests
- Solar-system layout: `layoutSystemPlanets` places generated worlds in a deterministic annular band around the home world, enforcing edge-to-edge separation and per-class scale/tint from `data/planets.json`
- All system planets are solid to the ship (collision + click-clamp), not just home
- Rim ping + HUD toast on discovery (`celebrateDiscovery`)
- New planet class pools (rocky/gas/ice/lava) with frames, `classScale`, `classTint`, and `typeLabels`
- Smoke-game dev hooks: `?ship=x,y` and `?near=px` for screenshotting discovery/compass states
- Node test suite (`dev/discovery.test.mjs`) covering rule boundaries, per-system state, JSON round-trip, layout bounds/determinism, compass geometry, and class pools
The galaxy was settled long before the player arrives. Systems now
host colonies on habitable worlds, mining stations over resource
worlds, cloud bases riding gas giants, stations adrift in open
space, and beacons — or report "charted · unclaimed" when empty.
- data/settlements.json: the shared kind vocabulary (label, theme,
population range, anchor type); add a kind = JSON + naming pool.
- Per-archetype rates in data/systems.json (chance + required
planet class) and a core→rim density gradient in data/galaxy.json
(falloff/floor), keyed off each record's new rNorm.
- Draws stay in a stable order on the system's own Rng stream, so
lazy and eager generation still produce identical content.
- Every settlement keeps owner: null, a reserved seam for the
factions/pirates that will claim them later.
- NameGenerator.station() names from anchor + kind ("Kest Skyspire").
- SystemReport.js is a pure, testable formatter (dossier lines,
"charted · unclaimed" for empty); GameScene's HUD renders it and
Node tests cover structure, mix, gradient, naming, lazy === eager.
- 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.