Commit Graph

61 Commits

Author SHA1 Message Date
Brian Fertig 568b1feaf2 Add route/destination visualization to map console
- 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
2026-09-07 21:48:50 -06:00
Brian Fertig bfd85c8e1f Extend route compass to mark the destination object as final stop
- 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.
2026-09-07 20:36:11 -06:00
Brian Fertig a5152590db Add SET DESTINATION route plotting with compass guidance
- 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.
2026-09-07 20:10:15 -06:00
Brian Fertig efe17f3d2e Add SYSTEM tab and zoom-bloom star art to the map console
- New "System" socket in MapWindow: a charted star's chart drawn by the
  same painter as Current System (no ship/tethers), armed until the player
  picks that star on the Galaxy tab, then wakes with its map.
- Galaxy tab click flow changes: a visited star opens its chart in the
  System tab (onStarOpen) instead of confirming a jump; uncharted stars
  are readouts only and a lit lane to an uncharted star pops nothing.
- Zoom-bloom star art (GalaxyChart.starArtSpec + GalaxyView blit):
  diffraction spikes, per-type crowns (granulation, prominences, binary
  companion, habitable rings, nebula disc, void horizon) and a surface
  wobble fade in as you zoom; all angles/phases seeded per system.
- Star hit-testing now scales with the dot size and includes a crowded
  cluster dead band so lanes/empty space between stars no longer trigger
  hover.
- New systemChartSnapshot() in SystemChart.js plus tests covering shape,
  coverage, discovery flags, stats and determinism.
- Set Destination dialog (System tab) acknowledges the pick via
  onSetDestination; destination model is still being defined.
- Added spacestation image/video assets for future use.
2026-09-07 18:56:48 -06:00
Brian Fertig 22c2ccfcd2 Add GALAXY tab to the MAP console with whole-galaxy chart, jump lanes, a
- 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.
2026-09-07 15:59:47 -06:00
Brian Fertig 963b2b5bc2 Redesign galaxy as sparse 60-system spanning-tree maze without rendered
- 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
2026-09-07 14:12:40 -06:00
Brian Fertig 8f6e7bf539 Fix menu sub-bar anchor to rest on deck top edge, not button
- The sub-bar was anchored to the MENU button's center + half-height, which
  made it spill over the command deck's top rail (buttons are inset below
  the bar's top edge). Anchor y is now the deck's top edge so the bar's
  bottom edge sits on the deck.
- Update landing.json rocky land-02/03 entries to reference their own
  rocky surface/takeoff/shop videos instead of reusing gasgiant/terran
  assets, and add the new rocky-shop-03.mp4 video.
- Temporarily disable per-class planet tints in GameScene (option still
  accepted by Planet for when we re-enable it).
2026-09-07 12:23:50 -06:00
Brian Fertig 546e5c9bf3 Add Mining research category and ship-scoped build upgrades
- 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
2026-09-07 11:50:36 -06:00
Brian Fertig 146dc207df Add compact far-display mode to the discovery compass
- Targets beyond `farDistance` from the ship fold to a small text-less chip with a shrunken arrow, reducing visual clutter for distant objects
- Hovering a far chip expands it to the full readout after an intent delay; hovering off folds it back only after a grace period, so quick flicks don't pop or yank it
- Assign per-type compass accent colors: green for planets (data/planets.json), red for stations (data/stations.json), gray for asteroid clusters (already present)
- Export `isFarTarget` and `syncEntryMode` as pure helpers for Node testing; add far-display coverage to dev/discovery.test.mjs
- Add a headless integration driver (dev/compass-far.html + .mjs) that boots GameScene, parks the ship between near and far targets, and exercises the hover-intent lifecycle end-to-end
- Pass the ship position into `compass.refresh()` from GameScene so the compass can compute per-target far/near state each frame
2026-09-07 11:07:20 -06:00
Brian Fertig aa8cf8e091 Add autopilot confirm dialog and wheel zoom / drag pan to the map consol
- Clicking a charted object now opens an ENGAGE AUTOPILOT confirm before
  committing: CONFIRM plots the course and closes the console; CANCEL,
  scrim click, or ESC leave the map untouched (ESC is routed to the dialog
  first in GameScene).
- Wheel zoom (1x-8x) re-renders the chart crisp about the cursor, drag pans
  the zoomed view with frame-edge clamping, and double-tap on empty plate
  resets to 1x; each system remembers its last view.
- Fix ConfirmOverlay steady-state so it holds open values instead of
  collapsing to a 2px line once the open animation lands.
- Fix Phaser v4 hit-area space (unscaled frame coords) and hover/course-line
  destination offset by the plate origin so the full plate is clickable and
  decor draws at the correct world position.
- Add dev/map-click.mjs coverage for dialog, zoom, pan, and real-input paths;
  add rocky takeoff/landing video assets.
2026-09-07 10:27:29 -06:00
Brian Fertig ebd26ad7ba Stop thrusting ship dead when it hits an obstacle or the tether rim
- constrainShip on Planet, Star, Station, JumpGate, and AsteroidCluster now
  returns a contact boolean (true only when position/velocity/acceleration
  actually changed) so the scene can distinguish "touched" from "no-op".
- GameScene.onPostUpdate reads those flags and, if the ship is in its
  Shift+click thrust state, calls stop() + setState('normal', 'contact')
  the first frame any solid or the tether rim touches it — the hold ends
  and the ship rests on the rim instead of driving through.
- Non-thrust ships are left alone by the rule; their existing arrival/brake
  logic still owns their stop.
- dev/contact.test.mjs: headless tests covering no-contact outside the
  keep-out, contact + push-out + inward-motion strip on approach, no
  spurious contact while sliding off the rim, the full thrust-into-planet
  stop-dead-on-rim integration, and that the rule only fires in thrust.
- dev/smoke-game.mjs: add a third thrusttest check (c) verifying a
  Shift+click straight into the planet stops it dead on the rim.
2026-09-07 00:21:30 -06:00
Brian Fertig 75c9f99ecb Add Shift+click throttle lock for committed-heading flight
- Ship gains a `thrust` state and `thrustToward()` that commits to the heading toward the click point and holds full throttle past it, until a plain click or stop steers out.
- GameScene pointer handler branches on `pointer.event.shiftKey`: Shift+click locks the heading (raw aim), plain click still flies to the clamped stop point.
- Mining teardown no longer stomps the ship state when the player has already moved it into `thrust`/`normal`.
- Update hint text and add unit tests (tests 7–10) plus a live-scene smoke harness (`?thrusttest=1`) verifying past-click flight, steer-back arrival, stop braking, and mining-exit signaling.
2026-09-07 00:06:57 -06:00
Brian Fertig be6e9fc558 Add MAP console with system chart and fog-of-war
- Introduce MapWindow (js/ui/MapWindow.js): full-screen cartography overlay
  with a left video feed, CURRENT SYSTEM / GALAXY(standby) tabs, a canvas
  system chart (discovered planets/stations/gates/rock fields, tether union
  boundary, fog-of-war dim outside the tether), and a discovery/resources
  readout with segmented bars + legend. Clicking a discovered object plots
  the course via autopilot.
- Add SystemChart.js (js/galaxy/SystemChart.js) with pure geometry/stats:
  chartBounds, fitToRect, navDiscoveryStats, resourceStats — Node-testable
  in dev/system-chart.test.mjs.
- Wire MAP into the deck (ActionBar + GameScene): new 'map' slot right of
  SHIP, full-screen open/close contract, ESC handling, snapshot polling,
  and video preload for assets/videos/map.mp4.
- Add data/map.json (manifest entry) driving all map colors, tabs, stats,
  legend, sweep, glitch, hover, and click copy.
- Two-beat menu intro synced to the mainmenu track crescendo: beat 1 shows
  console chrome + subtitle; beat 2 (revealDelay, default 3200 ms) reveals
  title, bloom, buttons, seed decode, and a signature glitch.
- Fix rocky landing surface/takeoff assets in data/landing.json to point at
  the new rocky-surface-01.mp4 / rocky-takeoff-01.mp4 clips.
- Dev tooling: dev/map-shot.{html,mjs} (headless screenshot driver),
  dev/menu-intro-test.{html,mjs} (intro verification), and updated
  research-builds.test.mjs for the new MAP slot ordering.
2026-09-06 23:43:35 -06:00
Brian Fertig d78b7ad505 Add gate comm window and sprite-based jump gate rendering
- 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
2026-09-06 20:26:06 -06:00
Brian Fertig 0950b143f5 Add stars as central bodies of non-home systems and fix home-system iden
- 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
2026-09-06 19:34:49 -06:00
Brian Fertig 507d00f818 Add full-screen warp clip to gate jumps
- 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
2026-09-06 18:08:29 -06:00
Brian Fertig ff557f87ba Fix jumpgate activation bug and add NAV chart diagnostics
- `_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
2026-09-06 17:41:29 -06:00
Brian Fertig 5a67dbb206 Implement gate jump travel between systems
- 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
2026-09-06 16:37:48 -06:00
Brian Fertig a3a229a72d Add per-system research category that unlocks jump gates
- 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.
2026-09-06 15:56:38 -06:00
Brian Fertig cb82da4935 Decouple comms panel from fly-to and add double-click clip skip
- 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
2026-09-06 15:08:32 -06:00
Brian Fertig 0b92cb7b98 Galaxy refactor: 200 systems, object-composition, dormant gates, frame diversity
- 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.
2026-09-06 13:06:29 -06:00
Brian Fertig a1aa25b5ba Add jump gate network and in-system gate placement
- 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
2026-09-06 11:56:26 -06:00
Brian Fertig 4fd1f05359 Bump tether radius growth to 2× and refresh HUD on build completion
- 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
2026-09-05 19:52:54 -06:00
Brian Fertig 1d1cb2c150 Add build console with tether-l2 install, dev server, and diagnostics
- 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
2026-09-05 18:55:29 -06:00
Brian Fertig d7f8e2101f Add shop clip toggle to surface deck
- SHOP button now swaps the looping surface clip for the world's `shop`
  video (e.g. terran-shop-01.mp4); pressing again swaps back. The slot
  relabels between "Shop" and "Leave Shop" via a new ActionBar.setLabel.
- data/landing.json gains a per-frame `shop` entry; worlds without one get
  a console note instead of a clip.
- SurfaceScene: toggleShop/leaveShop manage the shop video (pause/resume,
  visibility), error handling falls back to the surface loop, and cleanup
  on takeoff/shutdown disposes the new video and note glyphs.
- ActionBar: slots store their base fontSize so setLabel can shrink-to-fit
  long labels; paintSlot re-asserts hover state after relabeling.
2026-09-05 15:50:09 -06:00
Brian Fertig 7138d153fa Add research console with Exploration tech tree and save persistence
- 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
2026-09-05 14:59:27 -06:00
Brian Fertig 407f6d6175 Add Continue button to main menu for resuming newest save
- 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
2026-09-05 12:30:16 -06:00
Brian Fertig ee2e874f41 Replace tether HUD with live mineral hold readout bar
- Add MineralHud component (js/ui/MineralHud.js) showing "MINERALS n / N"
  plus a fill bar in the upper-right corner, replacing the old tether
  stack. One tween drives both the counting number and the bar so they
  never drift; a cyan flash ripples on landings; amber at capacity.
- Wire Mining to emit an onOre(gained, hold) seam per extraction tick and
  per fragment landing so the HUD fills live as the rock shrinks, not
  only at the batch 'absorbed' event.
- Remove refreshTetherHud / fmtRange from GameScene; instantiate MineralHud
  in create(), feed it via refreshMineralHud() from ore seams and mining
  events, destroy on shutdown.
- Add data/mineralhud.json config (corner pad, bar geometry, count-up and
  flash tuning) and register it in the manifest.
- Tests: new dev/mineral-hud.test.mjs covering layout, count-up/bar sync,
  superseded-tween guard, capacity/clamping, teardown; extend
  dev/mining.test.mjs to assert onOre ticks; drop tether-HUD checks from
  dev/system-hud.test.mjs; add setOrigin/setScrollFactor no-ops to the
  Phaser stub.
2026-09-05 12:12:18 -06:00
Brian Fertig 520cba85f6 Add mining economy: rock shrink, split/shatter, and mineral hold
- Extract minerals from the latched asteroid at ratePerSec × miningSpeed; each mineral shrinks the rock by 1 px so the beam stays latched to its rim.
- Break rocks that lose ~1/3 of their original size: large ones halve in place (beam keeps mining one half), small ones shatter into pieces that fly home and load the hold.
- Add ship.minerals hold with addMinerals/setMinerals capped at stats.mineralStorage; a full hold ends the run instead of grinding the rock away.
- Persist the hold in save/restore (captureState writes ship.minerals, applyRestore restores it) and keep legacy saves working when the field is absent.
- Play new mining_split sfx on each break and surface split/absorbed/storageFull events as console toasts.
- Expose AsteroidCluster rock surgery (setSize/addRock/removeMember) for runtime splits, and add headless Phaser stub + loader plus a mining test suite covering extraction, halving, shattering, full-hold stop, and the hold API.
2026-09-05 11:18:35 -06:00
Brian Fertig 9ca0fa55a8 Add music system, UI SFX, and ship base stats
- 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.
2026-09-05 10:10:18 -06:00
Brian Fertig d0bd840dbc Add deep-scan sonar pulse replacing the Build action button
- Swap the command deck's "Build" slot for a "Scan" slot that fires an
  omnidirectional sonar pulse from the ship across the tether region.
- The wavefront is clipped to the union of tether circles: it is absorbed
  at the rim (bright absorbing arc + TetherField.excite shiver) instead of
  flying into empty space.
- Objects inside the region ring as the front crosses them (shock rings,
  RGB ghost, scale pulse); the starfield ripples and the camera thumps /
  rolls with the wave, then restores itself on completion or cancel.
- New modules: js/scan/ScanPulse.js (rendering + lifecycle),
  js/scan/ScanGeometry.js (pure circle-circle window math).
- All tuning lives in data/scan.json; the one SFX is the new "scan" key
  in data/sfx.json. Results are a seam for now — finishScan logs the
  in-region objects and reports the count in the console slot.
- Tests: dev/scan.test.mjs (geometry unit tests) and
  dev/scan-test.html/.mjs (headless flow test driving the real scene).
- Add Terran shop placeholder assets (two PNGs + one MP4).
2026-09-05 00:29:17 -06:00
Brian Fertig cd4d751edd Add upper-left surface HUD showing planet name, type, and tether level
- GameScene now passes the world's type label and tether level into the SurfaceScene launch payload; new tetherLevelFor() resolves a world's anchored tether (by label or anchor position) for that line.
- SurfaceScene builds/decodes a two-line HUD (Ethnocentric name in the menu title shade with black stroke, Centauri line below) while the surface clip loops, driven by the shared scramble decode; it is torn down on take-off and shutdown.
- landing.json gains a hud config block for margins, fonts, spacing, strokes, and colors.
- Added dev-only harnesses (surface-hud.html/.mjs test page and surface-hud-shot.html/.mjs screenshot probe) to verify the HUD styling, decode settle, payload, and teardown in headless Firefox.
2026-09-04 23:23:41 -06:00
Brian Fertig 1cbbf502df Add take-off clip to surface scene before resuming flight
- Introduce a `takeoff` video entry in landing.json for each world; missing/
  null entries leave the surface instantly (no regression)
- SurfaceScene.takeOff now plays the one-shot take-off clip full-screen,
  hides the deck, and only then stops the scene and wakes GameScene
- Guard against a clip that never starts or runs past its duration so the
  player is never stranded; finishTakeoff is idempotent
- Update surface-flow/surface-shot dev harnesses to assert and screenshot
  the new take-off stage
- Re-map gas giant frames in planets.json from [0,1,2] to [3,4,5] to match
  their sheet positions
2026-09-04 22:44:51 -06:00
Brian Fertig 69875c1ff0 Fix video sizing and replace fixed landing timeout with playback-aware g
- Introduce `attachClip` to set volume, cover-fit, and re-fit on the first presented frame (`created`) so clips no longer render ~3.4× zoomed in due to v4 placeholder sizes.
- Use `setScale` instead of `setDisplaySize` in `fitCover`, which is stable across frame swaps that preserve scale rather than size.
- Drop the blanket 8s safety valve that cut ~15s landing clips in half; replace with two targeted guards: a 5s stalled check (no playback progress) and a duration-based cap (duration + 5s margin).
2026-09-04 22:34:10 -06:00
Brian Fertig dd7000638a Add SurfaceScene with landing video and surface deck
- New SurfaceScene overlays GameScene when the player requests landing:
  plays a one-shot landing clip, then a looping surface clip behind a
  dedicated command deck (Shop/Build/Ship + Take Off + Menu).
- Wire comms panel "Request Landing" / "Land" buttons to launch the
  surface; TAKE OFF stops SurfaceScene and wakes GameScene so the run
  resumes exactly where it left off.
- ActionBar accepts an optional `buttons` override so scenes can supply a
  different slot list while sharing layout/colors/animation.
- SavePanel gains a `stateScene` option so saves from the surface read
  state from the paused GameScene underneath.
- Add data/landing.json (per-frame video map) and four placeholder
  surface clips; CommsPanel now passes its full target payload through to
  onAction so landing metadata survives the round-trip.
- Add dev harnesses: headless-Firefox screenshot helper, click-path test
  for the real user flow, and a surface-flow assertion suite with parked
  screenshot pages.
2026-09-04 21:25:44 -06:00
Brian Fertig d933914ac3 Add comms panel and free-space station entities
- 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
2026-09-04 19:45:12 -06:00
Brian Fertig 0c30985588 Add reputation data layer with stable place identity
- 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
2026-09-04 18:37:44 -06:00
Brian Fertig 75767dc5a5 Add ship state machine and let movement break the mining sequence
- Introduce `Ship.state` ('normal' | 'mining') with `setState()` and an
  `onStateChange` callback so the scene can react to state exits.
- Any player-initiated movement (world click or compass autopilot) now
  drops the ship back to 'normal', which ends the mining sequence via the
  scene's handler; Mining.update() enforces the gate as a belt-and-braces.
- Rename `Mining.isLocked` to `isActive` and update GameScene click logic:
  clicks no longer hold during extension — they move the ship and abort the
  arm's reach.
- Tighten the popup-button swallow window from 300 ms to 20 ms and add a
  `containsScreen()` hit-test so only the exact button press is consumed,
  not subsequent deliberate clicks on the panel area.
- Expand the headless mining test to cover the new movement-abort contract:
  world click mid-extension breaks the arm, autopilot retracts the beam,
  and ship state transitions are asserted at every stage.
2026-09-04 18:06:33 -06:00
Brian Fertig b4b656f6e4 Add asteroid mining: energy arm, beam FX, and context menu
- Click a rock to open a world-anchored mining popup (Mine/Stop/Cancel)
- Mining state machine locks the ship during the ~1.5 s arm extension, then fires an animated beam with ore motes, shock rings, sparks, and periodic surges
- ESC breaks the beam or closes the menu; outside clicks dismiss without flying
- Generalize the top-center console toast so discovery, tether, and mining calls share one slot
- Add a "mining" SFX entry (system-scan.mp3) and update preload/test to cover all configured sounds
- Ship a headless browser test (dev/mining-test.*) that drives the full arm sequence through the real input pipeline
2026-09-04 17:09:16 -06:00
Brian Fertig 834be56557 Move tether toast to center of screen
- Reposition the tether toast from top-center (y=26) to ~75 px above
  screen center so it doesn't overlap the discovery toast.
- Update comments to reflect the new placement.
2026-09-04 13:33:23 -06:00
Brian Fertig f45e3d1cfd Close sub-menu on click-outside and guard compass autopilot during dismi
- GameScene now closes the menu sub-bar for any pointerdown outside it
  instead of only swallowing clicks that land on the panel, so world, deck,
  HUD, and compass taps all dismiss without triggering fly-here, dossier,
  or navigation side effects.
- autopilotTo() bails while the bar is open or closing, preventing a
  racing compass chip click from navigating after it just dismissed the bar.
- Add MenuSubBar.closing getter so callers can detect the close animation
  state and treat the bar as input-dead during that window.
- Ship a headless CDP test (dev/clickout-test.html/.mjs) that drives the
  real Phaser input pipeline to verify every dismiss path, button firing,
  re-openability, and the autopilot guard.
2026-09-04 13:26:45 -06:00
Brian Fertig 217ba6bedb Add save/load system with 10-slot localStorage bank and UI
- SaveManager: 10-slot localStorage bank (put/get/clear/list/export), corrupt-bank recovery, failed-write surfacing, bulk JSON export
- SaveData: captureState / prepareLoad / consumeRestore / resetRunState — seed + player state round-trip through a shared registry
- MenuSubBar: fold-up drawer off the deck's MENU button (Save Game / Load Game / Return to Main Menu) with animated open/close
- SavePanel: 10-slot pop-up in save or load mode; overwrite + load confirm dialogs; "download all" bulk export; toast feedback
- ConfirmOverlay: split-open confirm dialog for destructive actions
- SlotCard, Toast: per-slot cards and inline feedback strips
- MenuScene: Load Game button (grayed while bank is empty) opens the same panel in load mode
- GameScene: menu sub-bar + save panel wired into deck action, ESC handling, input blocking while modal, applyRestore on scene boot
- Tether HUD moved from above the MENU button to upper-right corner, stacking downward
- MenuButton: disabled (grayed) state and screenFixed option for scrolling-camera UI
- New SFX assets (ui-click, ui-hover) + updated existing FX; gasgiant planet image
- Dev tooling: cdp-firefox.mjs, wdshot.mjs (headless Firefox via geckodriver), saves-ui-test.html/.mjs (integration driver), saves.test.mjs (Node unit tests), system-hud test updates
2026-09-04 13:09:08 -06:00
Brian Fertig 2d1265d592 Add SFX, dossier toggle/auto-fold, and tether HUD repositioning
- Add sound effects (construct, deconstruct, discovery) with config in data/sfx.json; play on dossier arrival/fold and new-object discovery; silently no-op when disabled or asset missing
- Rework the system dossier into a full lifecycle: open-by-default on arrival, one-shot auto-fold at 10 s, click-to-toggle (name + caret), reverse deconstruction order, state caret that swings with the open/closed state
- Add ScrambleDecode `reverse` mode so lines can deconstruct (value → static → '') for the fold animation
- Reposition the tether readout to bottom-right above the deck's MENU button, right-aligned and bottom-anchored; fall back to left column when the deck is disabled
- Expand decode and system-hud tests to cover reverse decode, the full dossier lifecycle (toggle, auto-fold cancellation, mid-animation guard), tether HUD layout, and SFX wiring
2026-09-04 10:25:37 -06:00
Brian Fertig fbd0e56f1f Extract shared decode scramble and apply it to the system dossier HUD
- New `js/utils/Decode.js` with a pure `ScrambleDecode` class plus
  `DECODE_CHARS`, `DECODE_DURATION`, and a per-line `decodeDur()` helper,
  so one effect serves both scenes.
- MenuScene now delegates its seed scramble to the shared utility instead
  of inlining the reveal math and alphabet.
- GameScene's system dossier types itself in on arrival: each line starts
  empty and decodes left-to-right, staggered top-to-bottom, with the
  timeline anchored on the first update frame; state self-clears once all
  lines settle so `update()` pays nothing afterward.
- Add Node dev tests for the shared effect contract (`dev/decode.test.mjs`)
  and for the real GameScene dossier decode against actual galaxy/report
  data with a stubbed scene (`dev/system-hud.test.mjs`).
- Document both new test commands in the README and update the planets
  PSD asset.
2026-09-04 09:52:05 -06:00
Brian Fertig 2b37be7494 Fix asteroid rock overlap and add distinct compass color for clusters
- 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
2026-09-04 08:45:28 -06:00
Brian Fertig ec7671d0cb Add asteroid clusters as discoverable, solid objects in each star system
- 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
2026-09-04 08:34:55 -06:00
Brian Fertig 48dfc7cd8f Rework solar system layout to orbit rings with minSpacing/maxNeighbor ru
- 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
2026-09-03 23:01:47 -06:00
Brian Fertig a1db1cc672 Give the home world a real name from the bank, and show object names on the compass
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>
2026-09-03 22:41:06 -06:00
Brian Fertig 30af365c68 Add the tether: the player's range, a level-1 zone (5120 px) with a glitchy barrier rim
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.
2026-09-03 22:03:29 -06:00
Brian Fertig 23fcbe7176 Replace procedural ship sprite with spritesheet art and facing offset
- 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
2026-09-03 21:40:33 -06:00