- Nebula gas layer: soft coloured cloud sprites at depth 3, tinted with a
per-system palette color assigned deterministically at galaxy generation
(SystemGenerator stamps content.atmosphere.color). Only nebula-type
systems render it; all other types are untouched.
- Ripple effect: a full-screen WebGL composite on the world camera that
displaces the starfield and world objects while the HUD stays crisp via
a new UI/world camera split (UiCameras.js). Data-driven per archetype in
data/systems.json (nebula = ripple, all others = none). Canvas fallback
degrades to no effect.
- Demo mode: ?fx=<type> URL param retargets the run to the richest system
of that archetype, fully charted with all gates active, for judging the
effect in isolation.
- New ice and lava planet art (slots 9–14 in planets.png) replacing the
placeholder terran/rocky/gas reuse.
- Node test suites for the nebula palette/determinism/cloud texture and
the ripple math/data contract/shader/facade (50+ checks, bare Node).
- Replace the square star field with a wide (width × height) field whose
aspect matches the map plate, so the fully-zoomed-out galaxy fills the
plate instead of letterboxing; recompute zone edges for equal-area thirds
under the new diagonal CDF.
- Add fitPadded() in SystemChart.js and use it in GalaxyView.js to frame
the galaxy as a true rectangle fit with a plate-pixel margin, replacing
the old world-unit padding that left stars on the plate edge.
- Rework the JumpNetwork spanning-tree heuristic to "save the stranded
first" (attach the candidate with the fewest unvisited non-barren
neighbors) and strengthen the repair pass: never attach to barren nodes,
guard swaps against cycles via inSubtree(), and add a last-resort
fallback that preserves strong connectivity.
- Update tests (galaxy.test.mjs, system-chart.test.mjs) for the field
bounds and the new fitPadded behavior; refresh README, PROJECT_NOTES,
and data comments to document the 2:1 field and platePadding knob.
- 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.
- SystemReport now returns a tight {title, subtitle, faction, population, status} shape instead of per-settlement/gate line lists; the HUD shows only the name, "<Type> system · star <class>", and "Faction: Neutral · Pop ~X" (or "Unclaimed").
- Drop the settlements/gates/summary/seed lines from the GameScene HUD render and update the decode/collapse docs to the new two-line layout.
- Fix planet kindLabel lookup to key on rec.class instead of rec.name so the comms/surface panels don't repeat the proper name.
- Update asteroid, galaxy, and system-hud tests plus PROJECT_NOTES to match the compact report shape.
- Draw the active SET DESTINATION path in orange on galaxy lanes and circle the destination star with a breathing ring
- On the current-system chart, circle the destination object when it is in this system, or show the route exit gate plus a dashed ship-to-gate line when the destination is elsewhere
- Carry `route` edge keys and `destinationId` through `buildGalaxySnapshot`, `mapChartSnapshot`, and `systemChartSnapshotFor` so views can render the course
- Add dev screenshot harnesses (route-shot, exit-gate-shot) and extend galaxy-map tests to cover route/destination flags
- Document the new visualization in PROJECT_NOTES.md and add a takeoff video asset
- In the destination system, the orange compass arrow now points at the
destination OBJECT (not just the next gate), so the "where to fly next"
marker persists across the last hop into the system.
- Add `_checkDestinationReached` per-frame check: clears the destination and
fires REACHED only when the ship is within the object's keep-out rim,
replacing the old jump-time clear for destinations with a specific object.
- Route compass entries (`route:`/`dest:` ids) are now resolvable by
`autopilotTo`, fixing the ship aiming at the star instead of the gate.
- New `alwaysFull` flag on compass targets keeps route waypoints at full
readout (arrow + type + name) regardless of distance; add tests.
- Add `route.destTypeLabel` config key and update docs/PROJECT_NOTES.md.
- New `js/galaxy/Route.js` derives the unique path between systems over the spanning-tree jump network (Dijkstra), exposing `planRoute` / `nextSystem`; pure and Node-tested in `dev/route.test.mjs`.
- Persist only the destination (`systemId`, `objectId`) in save data; the route itself is recomputed from the current system, so following it shortens automatically and a detour re-plots.
- Compass marks the route's next gate in orange (shown even while undiscovered) and suppresses that gate's ordinary cyan entry.
- On jump, resolve arrival / on-course / detour before `captureState` and queue REACHED / RE-PLOTTED notices to surface after the destination scene spawns.
- Map console SYSTEM tab now charts a charted star's system; confirming an object sets the destination and closes the map.
- Fix galaxy stars bleeding through the system chart: plate culling respects overall visibility, fog skips when no tethers anchor it, and the boot reveal finalizes to full alpha on tab switch.
- Add `assets/videos/ss-land-03.mp4` and document the route feature in PROJECT_NOTES.
- New `GalaxyView` renders glowing stars per archetype (pulsing heartbeat),
the jump-lane web (traveled/frontier/unexplored), the charted region's
convex hull, HOME/SHIP markers, hover readouts, and CONFIRM JUMP on a
live lane (reuses the existing gate transport).
- `GalaxyChart.js` provides the pure model + geometry: edgeKey, snapshot
builder, convex hull / padded polygon, star pulse/color, and plate
clipping (Liang-Barsky + Sutherland-Hodgman) — all Node-testable.
- Run's footprint (`visitedSystems`, `usedGates`) is captured/restored/
reset in SaveData; legacy saves default to "current system charted,
nothing traveled".
- MapWindow gains tab switching between the system chart and the galaxy
view, with shared stats/legend/status chrome per mode.
- Two dev tests cover the galaxy model, save round-trip, hull geometry,
plate clipping, and a regression for the star-label blink bug.
- 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
- New `data/research/mining.json` tree (Improved/Advanced Mining Arm, Improved Storage) as blueprints that unlock matching builds
- Three new ship-scoped builds in the console's Mining tab: mining arm rate 1.5/2.0 minerals/s and hold cap 350; MAX-guarded effects applied to `ship.stats`
- Tether Level 3 promoted from research-direct effect to a build (tether-l3) gated on L2 tether, consistent with L2 blueprint pattern
- `BuildState.isBuiltAnywhere` + `isShipScoped` so ship upgrades count as built wherever the ship lands (no re-buy), records still key the planet
- `GameScene._restoreMiningUpgrades` re-derives ship mining stats from build records on load; `_applyMiningUpgrade` handles rate/capacity with toasts and HUD refresh
- New procedural icons: tether3, mining, mining2, storage
- Updated tests (builds, research-builds), diagnostics (BuildDiag v4), docs, README, manifest
- Replace direct-click-to-jump with a shared comms panel variant that shows LINK ACTIVE/DORMANT status, REQUEST JUMP (disabled while dormant), and CANCEL
- Render gates from the new 256x256 spritesheet (frame 0 body, frame 1 active swirl) with procedural fallback when the texture is missing
- Active gate swirl spins clockwise and breathes alpha between configurable bounds; dormant gates keep the body at full alpha with the swirl hidden
- Wire CommsPanel to a dynamic primary-button action id so the same panel serves world and gate variants
- Add dev probe page (dev/gate-comms.html/.mjs) and update jumpgate/jump-travel tests for the new sprite path, fallback renderer, and comm-window flow
- 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
- Play a cover-scaled video between systems on jump, with an opaque backdrop so the source doesn't show through
- Double-click skips the remaining clip; single press is swallowed while it plays
- Fall back to the short jumpDelayMs cut when no video is configured or missing
- Guard against stalled/overlong playback with a grace and duration cap before restarting
- Add assets/videos/jump.mp4 and document the new behavior in gates.json and PROJECT_NOTES.md
- `_applyResearchEffects` now receives the node id explicitly instead of
reading `node.id`, which is undefined (the id is the key in the tree's
`nodes` map, not a field on the object) — this was silently skipping
`activateGates` so researched jumpgates stayed dark
- Add `systemIdOfGatesNode()` as the pure inverse of `systemNodeId()` for
the gates node, with round-trip tests
- Reconcile gate activation in `_onEnterSystem()`: if the gates tech is
already unlocked, re-run `_activateSystemJumpgates` (idempotent) so a
missed activation self-heals on the next entry/jump/reload
- Make `_activateSystemJumpgates` idempotent by tracking fresh keys and
early-returning when everything is already online
- Add `navPoints()` and `navChart()` to SystemCategory.js as pure,
testable cores for the jumpgate unlock condition (discovered/missing
split over all NAV points)
- Add `js/dev/NavDiag.js` with `orbitNav()` / `orbitNavBrief()` console
commands that print the live NAV chart and which objects are still
undiscovered, installed by `main.js` on every page load
- Update `data/landing.json` to reference the correct gasgiant surface/shop
videos for slot 03
- Add tests for `navPoints`, `navChart`, and `systemIdOfGatesNode`
- Document the activation wiring bug, the `orbitNav()` diagnostic, and the
new pure functions in PROJECT_NOTES.md
- Add JumpTravel.js with pure arrival geometry (return-gate lookup, spawn point past keepout) and wire it into GameScene.jumpThroughGate to re-stage the run via the save pipeline and scene restart
- Add gate hit-test (gateAt) so active gates trigger the jump on click while dormant ones show a console nudge and fall through to fly-here
- Add jump config block to gates.json (feature switch, arrival gap, delay, toast templates) and update landing.json gasgiant shop clips
- Add dev/jump-travel.test.mjs covering config, geometry, real-galaxy coverage, and determinism; refresh PROJECT_NOTES for the new mechanic
- Introduce a dynamic "system" research category built at runtime with two techs: `{System} Map` (granted on entry) and `Unlock {System} Jumpgates` (researchable once every NAV point is discovered).
- Wire gate activation through the research effects seam so completing the jumpgate tech activates the system's gates plus linked return gates, anchors level-1 tethers at each activated gate, and saves/restores via a new `activatedGates` set.
- Extend ResearchModel with optional tree hooks (`available`, `lockNote`) so dynamic categories can gate research on live world state without adding static requires.
- Add map and gate procedural icons, update tests for the new category contract and icon roster, and document the system category in project notes.
- Reduce maxLevel from 12 to 3 in data/tether.json
- Remove the tether_l4 entry from exploration.json; tether_l3 now has empty unlocks
- Update research-builds and tether tests to reflect the shorter chain (3 layout rows, level checks for 1–3 only)
- Revise PROJECT_NOTES.md to describe the 3-level progression
- Clicking a planet or station now opens the comms panel without moving the ship; world clicks are no longer fly-here targets, keeping mining beams live during panel interaction
- Add double-click (350 ms) skip for landing and takeoff clips in SurfaceScene so players can cut to the deck or flight world immediately
- Push restored mineral hold through the upper-right HUD on load so the readout matches the saved value instead of staying at zero
- Replace removed Phaser v4 Container.removeChildren() with removeAll(true) in JumpGate and Station destroy paths
- Update landing.json shop entries for terran frames 2–3 and document the new skip behavior
- Add dev harnesses for surface-skip, hold-restore, scene-restart, container-probe, and import probes; extend comms-click and saves-ui tests to cover the new interactions
- 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 the BUILD deck slot on planet surfaces: full-screen BuildWindow
(looping feed video, category tabs, build list, dossier + cost + BUILD
button) backed by pure BuildModel/BuildState rules
- Move tether level 2 from a research effect to a one-off planet build
(200 minerals, 20 s, requires L1 tether on the world); home world starts
with tether-l1 pre-installed as a rule re-asserted after load
- Add `node dev/server.mjs` static server sending Cache-Control: no-store to
stop browsers heuristically caching ES modules (the "new data + old JS" bug)
- Fix world-name casing leak: CommsPanel keeps canonical spelling in the
landing payload; GameScene.startLanding normalizes via WorldNames.canonicalPlanetName
so name-keyed build/tether lookups match
- Add in-game diagnostics (orbitDiag/orbitDiagBrief), dev/build-check.html
self-check page, and Node tests for builds, world names, and save staging
- Persist builds (built records + in-flight remaining time) in the save bank;
tick on the game-loop clock so a build survives takeoff mid-build
- Define the two-sided unlock contract: research nodes declare `unlocks.builds`/`unlocks.research`, builds declare `requires` as "category/node id" (authoritative gate); ResearchModel exposes `unlocksOf`, `buildDefs`, `unlockIssues`, `buildIssues`
- Add `tether-l2` build entry (planet/station targets, credits+minerals cost, level-2 tether effect) and link it from `exploration/tether_l2`
- Show an UNLOCKS line in the research dossier so the console surfaces what a tech opens
- Extend dev/research-builds.test.mjs to validate both sides of the gate and the new model helpers
- Update data/builds.json, research.json, exploration.json `_comment`s and PROJECT_NOTES to document the contract
- Full-screen RESEARCH window: looping archive feed, category tabs, branching
DAG tech tree (top-down layout), per-tech dossier + RESEARCH button, deck
progress bar
- Pure rules layer (ResearchModel / ResearchState) is Node-testable; the
window is a passive view and GameScene owns effects, toasts, and saves
- First category **Exploration** (Tether Level 1–4, Tether Anchoring, Signal
Amplification) lives in data/research/exploration.json; adding a category
= one JSON file + one registry line + one manifest line
- Effects seam: `tether.level` grows the home tether via TetherField.setLevel;
`capability` flags land on scene.researchCapabilities for future systems
- Save/restore round-trips an in-flight project (remainingMs captured at save,
startedAt rebuilt on load); old saves without research still load
- Dev tooling: dev/cdp-shot.mjs (CDP screenshot with readiness wait),
dev/research-shot.html/.mjs (boots the console + starts a run for a shot)
- Assets: gasgiant planet frame 03, takeoff/landing clips, research-computer
feed; planets.png/.psd updated
- SaveManager.latest() picks the filled slot with the newest savedAt
(unparseable timestamps count as oldest; ties break to the higher slot)
- MenuScene wires a Continue button above New Game, grayed out while the
bank is empty, that stages the restore via prepareLoad and cuts into
GameScene without a confirmation beat
- Shift menu layout down to make room and park the Reroll button fully
outside the seed field so its edge no longer bites the field
- Cover latest() behavior in dev/saves.test.mjs and update README and
PROJECT_NOTES to reflect the finished save/load feature
- New shared audio voices: js/utils/Sfx.js (playSfxOn/stopSfxOn/sfxPlayingOn)
and js/utils/Music.js (loop voice + shuffle playlist), both with v4 guard
rails (cache.audio.has, stopByKey, isPlaying) so missing assets never throw.
- data/music.json: menu loop, shuffled deep-space soundtrack for GameScene,
and per-world surface loops keyed by planets.png frame; new mp3 assets in
assets/music/.
- data/sfx.json: add ui_hover/ui_click/ui_window/ui_close/mining_loop and a
dedicated scan track; wire UI components (buttons, panels, popups, save
vault) to the shared voice via scene.playSfx seam.
- GameScene: start/stop the shuffle on create/shutdown, stop both soundtrack
and mining hum on 'sleep' (landing launch+sleep) and resume on 'wake';
mining hum loops while beam is live and stops quietly on 'stopped'.
- SurfaceScene: preload and loop the world's track from landing through
takeoff; fix landing frame hand-off to pass sheetFrame instead of the
texture Frame object.
- MenuScene: preload SFX + menu music, start the menu hum in create, stop it
on the 'shutdown' event (v4 never calls shutdown() on transition).
- data/ship.json → stats: hullIntegrity/shields/cargoHold/mineralStorage,
exposed as ship.stats for future combat/trading/mining systems.
- Tests: dev/sfx.test.mjs and dev/music.test.mjs cover the shared voices,
guards, and data contracts; ship-behavior and system-hud tests extended
for base stats and the mining hum lifecycle.
- New CommsPanel UI: world-anchored rusty-metal/green-phosphor console that opens on planet or station click, showing name decode, reputation bar (41 marks, -20 to +20), and REQUEST LANDING / LAND / CANCEL buttons
- New Station entity with procedural rendering (deep-space station ring + solar wings, or waypoint beacon), solid collision, and comms-target support
- data/stations.json configures station kinds, sizes, ship clearance; added to manifest
- GameScene wires click-to-fly + panel open together, handles button/outside/ESC close race, ESC priority, and commsAction seam for future landing logic
- Reputation.marksFor() computes lit-mark count for the gauge; covered by new unit tests in dev/reputation.test.mjs
- Dev tooling: comms-click (real-input interaction test), comms-shot (screenshot states), wdshot setup-step logging
- 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 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>
The player starts with a level-1 tether anchored on the home world:
a circular zone 5120 px from the planet's center. The ship may fly
anywhere in the UNION of its tethers' zones — where zones overlap there
is no line and no wall — and the union's boundary is a hard barrier,
rendered as a thick cyberpunk glitch dotted line (marching dashes,
additive glow + RGB fringe, ambient glitch bursts with dash flicker,
radial displacement and data drops, contact shudder + camera kick +
throttled console toast where the ship bumps it).
- data/tether.json: level radii (5120 x 1.25^lv), the starting tether,
barrier line/look, glitch and contact tuning (manifest-registered)
- js/tether/Tether.js: pure range math (union membership, clamp to the
nearest union boundary point + normal, visibleArcs = each tether's
share of the union boundary) — Node-tested
- js/tether/TetherField.js: scene-facing field — add/remove/setLevel
seam for future builds/upgrades, per-frame ship constraint, and the
barrier renderer (on-screen dot culling only)
- js/scenes/GameScene.js: home tether at the system origin, HUD
readout (level / range / anchor per tether), click-to-fly and
autopilot targets clamped to the union boundary, contact feedback,
destruction on shutdown
- dev/tether.test.mjs: 29 checks incl. the two-direction boundary
property (no line in overlaps, no gaps in the line) and a numeric
nearest-boundary cross-check (worst 0.79 px)
- dev/smoke-game.mjs: ?tethers / ?homeLevel / ?report dev hooks for
manual and headless verification
- README + PROJECT_NOTES: the system, its rules and its layering
Verified in headless Chromium: clean boot (menu + game), barrier
rendering (calm and glitch-burst frames), union boundary with two
tethers (arcs meet at the rim crossings, lens is line-free), ship
clamped exactly onto the rim from outside, contact toast fired.
- Load `assets/images/ships-player.png` as a Phaser spritesheet via
`data/ship.json` (`texture`, `frameWidth`, `frameHeight`, `frame`)
- Add `artFacing` config; Ship applies a constant `artOffset` so heading
math is unchanged while the frame art (facing north) renders correctly
- Scale sprite as `(size * scale) / frameWidth` to preserve the 46 px world
hull size and collision radius regardless of frame dimensions
- Fall back to the built-in procedural dart when the sheet is missing or
fails to load, with a console warning in GameScene.create()
- Update ship-behavior tests to account for `artOffset` in heading checks
- Add source art (`ships-player.psd`, landed-ship reference) and a demo
video; document the new pattern in README and PROJECT_NOTES
- DiscoveryCompass name tags are now interactive buttons with hover/press feedback; firing onSelect hands the target id to the scene, which retargets the ship via GameScene.autopilotTo (aim at the keep-out rim on the approach side).
- Compass layout reserves the command-deck strip (reserveBottom) so chips/arrows are never buried under the deck.
- Click-to-fly now ignores clicks that land on a compass chip (DiscoveryCompass.contains), keeping autopilot and fly-here from colliding.
- Tests cover the chip hit test, onSelect seam, and reserveBottom clamping; docs updated to describe the new autopilot behavior.
- Port the menu's GlitchText chromatic fringe to ActionBar: additive
magenta/cyan icon ghosts, label ghosts with per-slot phase, and a panel
outline ghost that activates during glitch bursts.
- Add a tiled-scanline overlay (1 dark row per pitch) matching CyberOverlay,
configurable via actionbar.scanline with theme.overlay.scanline defaults.
- Replace idleGhost with animation.rgb (idleOffset/burstOffset/idleAlpha/
burstAlpha); level now decays ~90 ms after triggerBurst for the fast-snap
GlitchText feel while slice bars linger.
- Update README, PROJECT_NOTES, and research-builds tests to cover the new
scanline and rgb config keys.
- New ActionBar component (js/ui/ActionBar.js) renders a procedural cyberpunk
bottom bar with six slots (Research, Build, Ship, two reserved, Menu),
boot flicker, rail comet, glitch bursts, and RGB shimmer; fully driven by
data/actionbar.json
- Data contracts for the player's progression loop: research.json (time-based,
one project at a time, gates builds/research) and builds.json (credits +
minerals, ship/planet/station categories), both with _template docs and
empty maps; registered in manifest.json
- GameScene wires the deck in, routes clicks over it away from fly-to, pins
the hint above the bar, and drives per-frame update/shutdown
- New dev/research-builds.test.mjs pins the data contract (manifest entries,
rule knobs, template fields, six-slot order)
- cdpshot.mjs: cross-platform temp dir + --no-sandbox for container/CI
- README and PROJECT_NOTES updated with the new loop, deck docs, and a Phaser
v4 scrollFactor-on-screen-fixed-container quirk
- 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.
- Boot the game from a static server with no build step (Phaser 4 vendored in lib/)
- Main menu (New Game button) and GameScene where clicking makes the ship fly there
- All tunables live in data/*.json (game/menu/ship), loaded via manifest + Config singleton
- Ship behavior driven by arcade physics (thrust, drag, maxSpeed, arrival) with a Node test harness (dev/ship-behavior.test.mjs) and a dev smoke page that boots straight into GameScene
- Project conventions documented in docs/PROJECT_NOTES.md; README rewritten to describe layout, run instructions, and dev tools