Commit Graph

62 Commits

Author SHA1 Message Date
Brian Fertig 27a9a59c03 Add combat soundtrack that swaps in when combat goes live
- Introduce `music.combat` playlist (same shuffled contract as `game`) with its own per-context volume override (`volumes.combat`).
- Add `GameScene.setCombatMusic(active)` wired to the `_setCombatBar` seam: combat live stops the deep-space shuffle and starts the combat one; combat over swaps back unless the scene is asleep on a world's surface.
- Track sleep/wake with `_asleep` so the wake handler resumes the correct context (combat if still active, otherwise deep-space).
- Generalize `startMusicShuffleOn` to take a `context` parameter for independent volume resolution.
- Update preload to queue combat tracks under their derived keys and extend tests for combat shuffle, context swap, re-fire, asleep behavior, and data contract.
2026-09-20 20:38:07 -06:00
Brian Fertig 4312177c3d Add BOUNTY HUNT side quest with elite combat seam and verification
- Enable the `bounty` category in data/sidequests.json with level-2 gate,
  Neutral-only contexts, encounter chain odds, and 20 written leader dossiers
- Add pure bounty model to SideQuests.js: plan derivation, wave scripts, XP,
  sequential waypoint rule, and completion only via the mark's kill
- Extend combat seam (Waves/CombatSystem/EnemyShip) for a named elite unit
  deployed with the opening group at scaled hull/damage, plus haltWaves() so
  killing the mark stops deployments while survivors stay hostile
- Wire GameScene/SurfaceScene/JobBoardWindow for locked rows, dossier readout,
  sequential check-ins, engagement chain, and single idempotent claim
- Add dev/bounty-hunts.test.mjs (591 checks) and in-browser probe with JSON/PNG
  evidence; update patrol/sidequests tests for the new live category
2026-09-20 20:10:07 -06:00
Brian Fertig 54d2886c91 Remove waypoint kind; allow up to two deep-space stations per system
- Waypoints were comms-only beacons with no landing or trade; a second
  deep-space station is a more useful destination in their place
- The old waypoint chance in systems.json becomes
  deepSpaceStation.second, so a system can roll 0–2 stations
- StationFrames now assigns a distinct sprite variant per station
  (Galaxy.stationFrames is id → [frame, …]) and a two-station system
  always wears two different variants
- Rename the route-gate pulse from "destination's waypoint" to
  "route's next stop" so the term no longer refers to a removed kind
2026-09-14 10:25:19 -06:00
Brian Fertig 831670c8ca Add faction territory floor and ring all stars by ownership
Branch sizes are inherently skewed; previously only the cap (median quota)
applied, so a small faction could start with a one-system sliver.

- FLOOR (balance.minTerritory, data/factions.json): a faction below the
  floor absorbs the nearest unowned eligible overflow first, then the
  richest faction's least-core systems — territory stays contiguous; a
  tiny galaxy with too few eligible systems is best-effort.
- Territory is now tracked per faction: g.factions.factionTerritories is
  the truth, the branch view is derived; capitals are placed inside the
  faction's post-floor territory, so a faction built entirely from
  borrowed space still gets its seat in its own territory.
- The galaxy plate rings EVERY star: faction color for territory, neutral
  silver for wild space (home included) — the ring color is the
  ownership read at a glance.
- dev/factions.test.mjs now checks the floor, cap, disjointness, and
  branch-view invariants; new throwaway diagnostics
  dev/faction-balance.diag.mjs / dev/faction-sweep.diag.mjs sweep seeds
  for the invariants + determinism.
2026-09-11 13:34:35 -06:00
Brian Fertig 608ffb7077 Add Galaxy tab legend key and faction tooltips
- Key the lane/region colors and draw the faction rings/capital
  seat in the GALAXY legend, live from factions.json
- Name a hovered star's standing in the tooltip: territory,
  capital, or wild space
- Add a dev screenshot harness to smoke-test the legend and
  tooltip
2026-09-11 10:10:04 -06:00
Brian Fertig 8e035d0891 Add far-sky lightning bolts to nebula systems
- New NebulaLightning visual: jagged edge-to-edge bolt with branches,
  strobed in the gas base/accent colors, plus a soft distant thunder clap
- Pure seeded math (boltStrobe, strikeCycle, boltShape) in SystemEffectsMath,
  Node-tested for determinism and shape correctness
- Wired into GameScene create/update/destroy lifecycle
- Config block in data/systems.json types.nebula.effect.lightning; docs
  updated with tuning notes and smoke-game probe (?lightning=1&forceStrike=1)
2026-09-10 23:11:21 -06:00
Brian Fertig 84909d6f80 Add front nebula layer with derived accent tint for two-tone gas
- Add `front` block to game.json: depth-11 clouds above the ship (parallax > 1) that drift past the player, creating a "flying through" feel vs. the back layer at depth 3
- Implement `shiftHue` in Color.js to derive the front accent from the system's base atmosphere color (hue rotation + lightness lift), making every nebula a stable two-tone gas
- Refactor NebulaAtmosphere into a data-driven layer array with per-layer depth/tint/parallax/drift; extract `spawnCloud` helper; scale swirl speed by configurable drift
- Add 21 new test checks covering accent math (hue delta, identity, white/black preservation, all 8 palette shades) and two-layer structure (depths, tints, parallax ranges, wrapping, destroy, revert path)
- Stub `Phaser.Math.Between`/`FloatBetween` in phaser-stub for Node tests
- Update PROJECT_NOTES.md to document the two-layer model, accent derivation, and new tuning knobs
2026-09-10 22:48:40 -06:00
Brian Fertig 42bf6c17e0 Add balance quota to cap faction territory sizes
- Branch sizes are inherently skewed and a branch IS its faction's
  territory, so without a cap one faction would dominate the start.
- Each branch now keeps only min(eligible, quota) of its eligible
  middle systems, closest to the middle band (|d−0.5|, index tiebreak);
  quota = the median of the three branches' eligible sizes. The big
  branch's overflow stays neutral wild space; a small branch keeps all.
- Expose g.factions.quota and g.factions.territories for the map's
  territory-region fill.
- Add tests verifying the quota, kept-set membership, near-equal
  faction sizes, and no-faction-outruns-typical-branch invariants.
- Fix landing.json: entry 4 now references ice assets (was mislabeled
  lava land with ice clips); entry 5 uses lava-land-02 + lava surface/
  takeoff clips.
- Add original art asset lava-shop-02.png and update docs to describe
  the balance rule.
2026-09-10 22:18:07 -06:00
Brian Fertig e2878da59c Add faction worldgen layer: territories, capitals, bridges, and arid pla
- Assign each jump-tree branch a faction (apex/mindweave/zenith) with seeded
  shuffle; territory = depth 2..maxDepth-1 per branch, ring + tips stay neutral
- Designate four capital worlds (neutral + one per faction) as the outermost
  planet of their system, with fixed frames 18-21 and faction-owned settlements
- Add cross-branch bridge gates in the middle belt so factions can reach each
  other without routing through the trunk; Dijkstra picks the shorter route
- Introduce arid planet class (always habitable, settles as colony) across all
  system types with rebalanced class weights
- Wire Trestle's last brief to auto-set destination to the neutral capital on
  acknowledgment (CommsHub onEnd → GameScene._commEnded)
- Render faction ring layer + capital seat marks on the galaxy plate; style
  bridge lanes distinctly from trunk edges
- Populate settlement owner from system faction (reputation seam now live);
  SystemReport reads faction label/color
- Add dev/factions.test.mjs covering config, branches, capitals, territory,
  arid, bridges, determinism; update existing tests for new invariants
2026-09-10 21:45:33 -06:00
Brian Fertig 54fbf4091c Rebuild in-system layout around tether discovery + the edge margin
- data/tether.json: new edgeMargin (512 px) — a no-man's-land band around
  every tether rim where NO object sits: discoverable objects are clearly
  inside a tether region (d ≤ radius − edgeMargin) or clearly outside
  (d ≥ radius + edgeMargin), never at the edge (the 'scan doesn't find it
  at the boundary' case)
- SystemGenerator.layoutSystem: the regular N-gon ring (chords put 2- and
  3-object systems past level 2, spread 4-/5-object systems too thin) is
  replaced by a compact ARC at one orbital radius — consecutive objects a
  level-1 tether apart (≤ L1 − edgeMargin — a level-1 chain walks the
  whole system), every other pair off both tether rims (the level-2
  graph is connected — level 2 DEFINITELY discovers; level 3 never
  required); minSpacing now bounds star/home-world→object only,
  neighborMin (2048) is the planet↔planet floor; the step angle is a
  deterministic scan (safe-α) landing the gap near a seeded target
- home world IS a tether anchor: its orbital radius caps at
  L2 − edgeMargin (9728 px); its objects sit 6400–9728 (level-2 zone by
  design — the bootstrap tether), chained to each other at level 1
- gates: anchorMaxDistance 4990 → 4608 (= L1 − edgeMargin) so no gate
  sits at the level-1 rim either (still < 5000, Rule 1); candidate
  ordering is now side > rim-bands > facing tier > order
- Tether.contains: 1 px rim tolerance (a center exactly on the boundary
  counts as inside — float safety on top of the layout margin)
- asteroid placement tetherMargin 96 → 512 (aligned with edgeMargin)
- dev/system-layout.test.mjs (new): level-1 chain, level-2 connectivity,
  edge margin, orbital band, same-seed determinism — 90-system galaxies,
  all green; discovery/jumps/audit tests + PROJECT_NOTES follow the rules
2026-09-10 18:53:30 -06:00
Brian Fertig a8246bb594 Place anchored jump gates on a 3500–4990 px band around their anchor
- Replace the fixed level-1 tether radius (5120 px) with a configurable
  `anchorMinDistance`/`anchorMaxDistance` band (default 3500–4990), capped by
  the tether range, so gate distance from its planet varies per gate while
  staying strictly < 5000 px.
- Generate candidate positions on 8 discrete radius steps spanning the band;
  a seeded preferred step orders them and clearance/gap pressure only pushes
  the gate outward from its preference.
- Update the tether check in `dev/jumps.test.mjs` to assert the gate sits
  within the anchor band rather than merely under the tether radius, and use
  the band max for facing-side calculations.
- Update `dev/tether-rules.audit.mjs` Rule 1 to verify < 5000 px and report
  the distribution of gate→anchor distances across the band.
- Refresh comments in `data/gates.json`, `docs/PROJECT_NOTES.md`, and
  `SystemGenerator.js` to describe the new band-based placement.
2026-09-10 18:37:22 -06:00
Brian Fertig 3b0c150971 Add system effect SFX, per-context music volumes, and storm teardown
- Play thunder claps on habitable storm strikes, solar-flare SFX on red
  dwarf flare onset, and solar-buzz on binary light-trade midpoint
  crossings, all via the shared Sfx voice (new playSfxOneOfOn helper)
- Add per-context music volume overrides (music.volumes) so each context
  can deviate from the global mix; menu ships at full volume
- Expand surface music frames to cover rocky and ice worlds (frames 6-11)
- Teardown per-system effect layers on scene restart (jump) so a previous
  system's storm doesn't keep striking and playing thunder in the new one
- Update planets.png sheet, add gasgiant-03/rocky-01/rocky-02 tracks, and
  register the new SFX assets in GameScene preload
2026-09-09 15:40:26 -06:00
Brian Fertig a4fa37ca46 Auto-install level-1 tether on first landing of any world
- ensureLandingTether runs before SurfaceScene launch so the surface HUD
  already reads Tether Level 1; free + instant, no console step
- Extend tether lookups (_applyBuildEffects, tetherLevelFor,
  _rematerializeBuiltTethers, applyRestore) to include systemStations so
  station tethers anchor, level up, and re-anchor like planets'
- Idempotent: home seed, existing build record, or an already-hosted
  tether all short-circuit; adopt rather than double-anchor
- tether-l1 targets now ["planet", "station"]; update descriptions in
  builds.json, README, PROJECT_NOTES
- Reorder MapWindow tabs to CURRENT SYSTEM / GALAXY / SYSTEM (galaxy is
  the live middle tab) and keep SYSTEM as the armed standby target
2026-09-09 13:11:38 -06:00
Brian Fertig 71cbea2fab Shorten research labels and fix console layout clipping
- Use fixed short button copy for the gates tech ("Unlock Jumpgates") and mining nodes (drop "Mining" prefix) since the tree node has no room for system names or category words
- Raise detail panel height and widen node/button plates so long descriptions and status labels stop bleeding past plate edges
- Add word-wrap to the unlocks line and trim redundant status prefixes ("RESEARCH CONSOLE STANDBY", "PROJECT COMPLETE")
- Fix ice-surface-01 video reference in landing.json (was pointing at rocky-surface)
- Add OAC speech clips and ice surface video asset; update planets.psd
- Tighten tether research descriptions to match the new short-copy style
2026-09-09 08:28:32 -06:00
Brian Fertig f470250721 Force starting system to be a Main Sequence star
- Add `startingSystem.type` config (default "main") that overrides the zone-mixed roll at roster build in Galaxy.js
- Update SystemGenerator doc comment to note the home star class now rolls from the main-sequence table (G/K/M)
- Add tests asserting the starting system is always type "main" across all policies
- Update data/galaxy.json comment and PROJECT_NOTES.md to document the new rule
2026-09-08 21:58:34 -06:00
Brian Fertig 6dc0e99dee Add habitable storm visual effect and ice landing videos
- New StormLayer renders purple cloud clusters with a seeded charge → strike → afterglow envelope in the upper sky, using sprite compositing (back/flash/front trios) rather than shaders
- Add `stormEnvelope` + `sstep01` to SystemEffectsMath.js; refactor NebulaAtmosphere's cloud shape into a shared `cloudAlpha` used by both `drawCloud` and the storm's flash texture
- Extend EmberField with optional per-spark twinkle (rate/depth) so habitable fireflies pulse while redDwarf embers stay steady
- Wire StormLayer create/update/destroy into GameScene alongside the other content effects
- Populate `types.habitable.effect` in systems.json with grade, void, particles, and storm blocks; update landing.json to use ice land/takeoff videos for slots 02 and 03
- Add 7 new test checks covering the storm envelope math, habitable data contract, bundle sanity, and facade apply(); bump live types from three to four
2026-09-08 21:46:15 -06:00
Brian Fertig 729ab09d3e Enhance binary system visuals with two-light void lift, breath, and came
- Add VoidBase content layer (neutral dark+grit surface at depth -1) so the
  grade shader's two-light shadow lift can paint amber/azure onto the void
  (the clear color bypasses filters)
- Extend grade shader with uLift2* and uBreath uniforms: side A glows color 1,
  side B glows color 2 across the seeded axis, with a slow sinusoidal trade
- Wire breath period/depth from config into per-frame update()
- Rework WandererStar to anchor to the camera view each frame (wrap-in +
  parallax trail) so it stays visible in the sky regardless of ship travel;
  increase default core/halo sizes for a more present companion star
- Update systems.json binary effect with lift, breath, void config and larger
  wanderer sizes
- Add test coverage for the new two-light lift, breath animation, and shader
  uniform declarations (59 checks total)
2026-09-08 20:56:14 -06:00
Brian Fertig 627c7fd255 Expand system effects to a composable bundle of sub-effects
- Replace the single `kind: ripple|none` effect with optional per-type blocks (ripple, grade, flare, haze, particles, wanderer) so each archetype wears exactly what it lists
- Add redDwarf visual identity: super-subtle star-anchored ripple that surges on a seeded flare, warm color grade with shadow lift + grain, a gritty red haze behind the stars, and drifting ember dust
- Add binary visual identity: two-color directional split grade plus a wandering companion star (no ripple)
- Generalize the ripple shader/filter to up to two orbiting centers and drive both the ripple amplitude and the grade flash from one shared flare signal
- Stamp per-system fx variation (phase/angle/drift) in SystemGenerator so each system's flare rhythm, split axis, and wanderer path are stable but distinct
- Add EmberField, RedHaze, WandererStar content layers wired into GameScene create/update/shutdown
- Update the data contract, 57-check test suite, project notes, and landing/systems JSON; add ice landing/takeoff video assets
2026-09-08 20:03:41 -06:00
Brian Fertig 125b1657ed Add nebula atmosphere and per-system visual effects
- 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).
2026-09-08 17:41:35 -06:00
Brian Fertig 856508ff01 Change galaxy layout to a 2:1 field and harden jump-network construction
- 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.
2026-09-08 14:51:19 -06:00
Brian Fertig 5e4f94f385 Rework galaxy layout into square Poisson-disk field with zone-based type
- 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.
2026-09-08 14:28:24 -06:00
Brian Fertig f8d62dfe09 Compact the system dossier to identity + faction status
- 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.
2026-09-08 12:07:18 -06:00
Brian Fertig b1ae21e95e Changes to Research Areas 2026-09-07 23:10:47 -06:00
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 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 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 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 d9fc9df829 Cap tether progression at level 3 and remove tether_l4 research node
- 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
2026-09-06 15:20:31 -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 09dfd00dd3 Make every planet settled and simplify system planet counts to a global
- 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.
2026-09-05 20:31:24 -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 70f4954c69 Wire research→build unlocks and add first tether-l2 build entry
- 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
2026-09-05 15:15:08 -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 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 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 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