Commit Graph

197 Commits

Author SHA1 Message Date
Brian Fertig 1d0622a3d5 Integrate combat into the main game with auto-fire and a combat bar
- Add CombatSystem: owns the hostile pack, tracers, player armor/energy,
  auto-fire (nearest-in-range), swept-hit collisions, rams, respawn — all
  driven by data/combat.json `game.*` / `energy` sections
- Add CombatBar (Diablo 4 style): vertical shields + hull gauges on the
  left, energy gauge on the right, eight skill seats (keys 1–8) in the
  middle; shown in place of the action deck while combat is live
- `?combat` now boots the normal game with the pack spawning when the
  player starts (mouse steers, cannon auto-fires); the standalone WASD
  range remains at `/combat` / `combat.html`
- GameScene wires the system into its update loop, solid constraints, and
  click-through gate; exposes `window.__ORBIT_COMBAT__` for DevTools
- Extend combat tests to cover CombatSystem lifecycle (spawn, auto-fire,
  hits, rams, armor, respawn, cast stub, destroy)
2026-09-15 22:03:07 -06:00
Brian Fertig 15fe08a926 Add combat sandbox: standalone arena to tune combat before it ships
- New `combat.html` + `/combat` dev-server route + `index.html?combat`
  boot a fixed arena where the player ship fights a pack of enemy craft;
  all tuning lives in `data/combat.json` (thrust, hulls, shields, lance,
  rams, respawns).
- Add `js/combat/` modules: CombatScene, EnemyShip (standoff-ring AI +
  lance), Bullet, Fx, StarDrift, and pure rules in Combat.js (armor
  damage, orbit step) exercised by the new `dev/combat.test.mjs`.
- Extract shared `awaitFonts` into `js/utils/Fonts.js` so both the game
  and sandbox boots use one copy.
- Preload the enemy spritesheet in GameScene so the texture is ready when
  combat ships in; add `ships-enemy.png` (+ `.psd`) art.
- Expose `window.__COMBAT__` (reset, spawnEnemy, player, kills) for
  devtools tuning; R resets the range, P freezes it.
2026-09-15 20:54:33 -06:00
Brian Fertig 4b8ddae8d9 Halve trade margins: distance bands -> x0.75/x1.15/x1.85/x2.75/x3.75
f' = 0.25 + f/2 on every band (x1.0/1.8/3.2/5.0/7.0): with the origin buy
fixed at x0.5, per-unit profit lands at exactly ~half the original in every
band (30->17, 67->35, 130->66, 218->110, 382->192 cr for the average
product) while distance stays the dominant term and the curve's shape is
preserved. Data-only change (economy.json); docs/ECONOMY.md table + example
updated. All invariants re-verified (anti-loop, monotone distance, far pays
more than buy, 1-hop viable) and the economy/cargo/shop-UI/scout suites
pass. dev/economics-report.mjs gains an ECON_BANDS=... A/B override and
dev/economy-bands-audit.mjs sweeps the band invariants on any band set.
2026-09-15 11:38:57 -06:00
Brian Fertig 15eaf26c03 Change cargo bay builds to cost credits + minerals
- Rebalance the three cargo hold upgrades (8/12/16) from a credits-only sink to a mixed cost of credits and minerals, so expanding the hold draws on both trade income and the mining economy.
- Update research descriptions, build data, tests, docs, and code comments to reflect the new two-resource costs.
2026-09-14 19:27:55 -06:00
Brian Fertig 138096cd2b Add Cargo research category with quest and build-completion gates
- Introduce data/research/cargo.json: a 3-node chain (8 → 12 → 16 bays) where each node is a blueprint that unlocks the matching ship-hold build
- Add `build` gate field to ResearchModel.js (attachBuildGates) so a node can require a named build to be completed before it becomes researchable, composing with the existing quest gate
- Wire both gates in GameScene and ResearchWindow so node availability, lock notes, and the RESEARCH button reflect quest + build state
- Gate cargo_bay_8 on the special_delivery quest; cargo_bay_12/16 on Improved/Advanced Mining Storage builds
- Update builds.json to require the corresponding research nodes for cargo-bay-8/-12/-16
- Add comprehensive tests covering the cargo tree structure, pure DAG availability, live gate composition, and build-side lock-step
2026-09-14 19:13:56 -06:00
Brian Fertig 8810ec1b3d Rework BUY-list rows: title line carries name · inventory · price · step
- Split each row into a title line (name, "N left"/"SOLD OUT" strip, price,
  stepper with `stock.gap` padding between blocks) and a full-width desc line.
- Add `buyList.stock` config (w, gap, fontSize, color) for the inventory strip
  and use it for sizing/truncation so the name never collides with the strip.
- Update `_btnXs`, `_nameMaxW`, `_descMaxW` layout helpers to place the right
  block on the title line and give line 2 the row's full text width.
- Refresh shop-ui tests to assert title-line padding, truncation budget, and
  desc wrap within the full row width.
2026-09-14 18:56:27 -06:00
Brian Fertig 828a5b8c38 Implement economy model v2: one world, one good with daily batch stock
- Replace producer/demand class pricing with strict 1:1 origin assignment;
  each settled system sells exactly its signature good at a discounted origin
  price, and the catalog remainder becomes a hub pool resold by stations/capitals
- Make banded hop distance the dominant sell-price factor (x1.0 to x7.0),
  with planet-type demand as a secondary +10% modifier, and cap every shop's
  sell price at its own buy price to eliminate the v1 infinite-credit loop
- Add Stock.js for the time-gated daily batch (6 units per origin per wall-clock
  day) — the economy's only stateful piece; wire it through GameScene,
  SaveData capture/restore/reset, and the shop UI stepper clamp + SOLD OUT strip
- Update Economy.js with assignOrigins pass, new buyPrice/sellPrice/shopFor
  logic, tradePreview stock-cap backstop (buyback exempt), and distanceFactor
- Rework shop UI: BuyList shows "N left"/"SOLD OUT" per batch-limited row and
  clamps the stepper; ScoutPanel shows MADE IN (origin system) instead of GROWN ON;
  ShopView wires stockRemaining/stockCapsFor/spendStock into preview and confirm
- Update all dev tests (economy, cargo, shop-ui, saves) to assert model v2
  invariants including the anti-loop sweep, batch clamp/backstop, and save round-trip
2026-09-14 18:22:21 -06:00
Brian Fertig f0578f1a38 Gate mining Tier-3 research on Special Delivery quest claim
- Add an optional node quest field so research techs can require a named quest's reward to be claimed before becoming available.
- Wire the scene's live questClaimed predicate into ResearchModel.attachQuestGates and the research tree loaders so node states, the RESEARCH button, and LOCKED readouts all honor the gate.
- Gate mining premium_arm and advanced_storage on the Special Delivery quest, and add data/test coverage for the quest-gate behavior.
2026-09-14 15:12:07 -06:00
Brian Fertig 30b62fc57f Add dev/run-all runner and self-contained test setup
- Every `dev/*.test.mjs` now imports the Phaser stub loader, so plain
  `node dev/<name>.test.mjs` works without `--import`.
- New `dev/run-all.mjs` runs the whole suite in isolated Node processes
  with filtering, concurrency, timeouts, and aggregated failure output.
- Update README and adjust dynamic imports/paths for headless test reliability.
2026-09-14 10:35:55 -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 afa7a00c29 Add Tier-3 mining research nodes and premium ship upgrades
- Add `premium_arm` and `advanced_storage` research nodes (Tier 3) to the mining tech tree, each gated by its Tier-2 parent.
- Add `mining-arm-premium` (4.0 minerals/s) and `mining-storage-advanced` (500 capacity) ship builds in data/builds.json.
- Update existing Tier-2 nodes to declare their new children in `unlocks.research`.
- Extend test suites for the two new research nodes, their build wiring, cost/affordability, DAG layout (3 rows), and availability gating.
2026-09-13 23:20:00 -06:00
Brian Fertig 58aab347c2 Add OAC "new research" audio beat on research sign-off end
- Arm `oac-research-new` (trigger `researchNew`) from `_commEnded` when the `oac-research-complete` sign-off finishes and `researchAnyAvailable()` is true, so the hub FIFO plays it right behind the sign-off
- Register the new audio-only comm in `data/comms.json` and move `researchNew` out of the reserved trigger list
- Update roster count to 25 and add node checks for the beat's fields, clip presence, and zero delay in `dev/comms.test.mjs`
- Add headless browser harness (`dev/new-research-shot.html`/`.mjs`) that verifies the seam, gating (in-flight vs available), and FIFO ordering through the real `onEnd` hook
- Ship `assets/videos/arid-shop-03.mp4`
2026-09-13 20:52:28 -06:00
Brian Fertig 1f39c25c2f Add READY-RESEARCH attention cue on deck slot and console tabs
- New ShimmerCue module: pure shimmerPhase/drawShimmer cycle (yellow band sweeps face, comet runs cut-corner edge), shared by both surfaces
- ActionBar gains setShimmer + a dedicated additive layer; the RESEARCH slot wears the full face+edge recipe while a tech can start and the console is closed
- ResearchWindow._paintCues paints the edge-only shimmer on every category tab whose tree still holds an available tech, plus the ACK pulse on the "Unlock Jumpgates" plate (or SYSTEM tab when off-screen)
- GameScene._applyResearchCue switches one cue at a time: deck slot when console closed, console cues when open; rests while a project runs (maxConcurrent 1), under standby, or under the tutorial finger
- ResearchModel.hasAvailable and SystemCategory.gatesReady/gatesNodeId encode the ready rules
- data: actionbar.json animation.shimmer, research.json fx.tabShimmer (#ffd84d, comm-pulse yellow family)
- dev: Node test (research-cue.test.mjs) pinning the pure cycle model + slot/tab behavior; browser verify page (research-cue-shot.html/.mjs) with CDP capture poses
- assets: arid-surface-03 / arid-takeoff-03 videos
2026-09-13 19:48:53 -06:00
Brian Fertig 4334d8cc93 Add tutorial "pointing finger" highlight for starter quest
- New TutorialGuide.js beat table picks which control to pulse based on live comms/research records, so a loaded run resumes the same beat
- ActionBar and ResearchWindow gain setHighlight() with pulsing rims (ACKNOWLEDGE-style sonar rings in the console) that hide under deck standby/locked slots/closed window
- GameScene applies the highlight per frame before surfaces draw, tracks scanPressed one-shot, and reads targets from data/quests.json → tutorial
- Add tutorial section to quests.json plus tests for beat table, ActionBar rim gating, and data consistency (slot ids, console node matches starter research check)
2026-09-13 18:48:06 -06:00
Brian Fertig 5408616bbf Add engine flare and exhaust trail to ship
- New `js/visuals/EngineFlare.js` drives nozzle glow, ignition burst, and a short fading exhaust plume from the two side-pod engines, driven by the ship's live throttle so braking dims it and Shift+click lights it up full
- Configurable via new `thrustFx` block in `data/ship.json` (enabled flag, core/plume colors)
- Hooked into GameScene lifecycle: created per scene restart, updated from the scene clock, cleaned up on landing sleep and scene destroy so nothing survives frozen mid-glow
- Add dev harnesses for visual verification: `dev/engine-flare-test.mjs` (headless Chromium CDP walk through idle → ignite → burn → coast → settled with screenshots) and `dev/particle-probe.{html,mjs}` to confirm particle velocity follows the emitter's heading
- Add new arid planet art asset
2026-09-13 17:43:14 -06:00
Brian Fertig cedee9f58e Add galaxy-wide planet-class balance via a shared deck deal
- New `js/galaxy/PlanetClasses.js` deals non-home planets from one shared deck so every class lands at ~1/N of the galaxy while star type still flavors local systems
- Config knob `systems.planetClassBalance` (enabled + bias) blends an even split with the star-mix preference; bias 0 = exactly even, 1 = old free preference
- Stamp `galaxy.planetClasses` is read back by content generator, frame pass, economy, and type preview so lazy/eager generation agree
- `rollSystemComposition` accepts optional stamped classes; falls back to per-type weighted draws when balance is off or stamp absent
- Fix arid-surface video path in landing.json (was pointing at ice surface)
- Update shop-ui and trade-scout tests to pick rows the current system actually wants, and handle home-world exit resolution
2026-09-13 16:23:31 -06:00
Brian Fertig 8ff7f0ee12 Add 'Special Delivery' payoff comms chain on surface departure
- Register Carol as a comm sender with her video clip and role
- Add four ack beats (carol-delivered-1/2/3, oac-delivered-1) under the new 'deliveredLaunch' trigger, fired when the player launches after selling the package
- Arm the chain in GameScene.onSurfaceDeparture once story.delivered is set, with the once-ledger keeping it a one-shot
- Update comms tests to cover Carol's registration, the four-beat sequence ordering, and re-arm deduplication
2026-09-13 15:29:21 -06:00
Brian Fertig f38b3c0b86 Add special-delivery launch comms assets and seam test
- Stage the payoff audio (carol q3 05-07, oac q3 01) and video assets
  (arid-surface-02, carol character) backing the launch-after-sale beat.
- Add dev/delivery-launch.test.mjs pinning GameScene.onSurfaceDeparture:
  arms 'deliveredLaunch' once on post-delivery departure from any world,
  stays quiet pre-delivery, preserves the capital leg (launchedFromCapital,
  home routing, quest refresh), and keeps the arm firing on the defensive
  already-home no-op.
2026-09-13 15:29:00 -06:00
Brian Fertig 942de11dde Move the surface shop gate from the deck slot to the Buy/Sell tab
The Shop button on the deck is now always live — the shop sub-bar opens on every world. The "Special Delivery" capital-landing witness now gates only the shop's Buy/Sell tab (ShopView reads GameScene.isTradeUnlocked, which replaces isShopUnlocked), so trading stays dark until the player lands on the neutral capital while the rest of the shop UI is reachable everywhere.

- Rename GameScene.isShopUnlocked → isTradeUnlocked and update all references (SaveData, SurfaceScene, quests.json comments)
- Remove the deck-slot enable guard in SurfaceScene.toggleShop / setBarLocked; the slot now re-arms with the rest of the deck
- Add ShopView.isTradeUnlocked + gate checks in setTab / _onTabTap; gray the Buy/Sell tab via _refreshTabs until the gate lifts
- Update dev probes (scout-*, shop-*) to lift gs.story.capitalLanded so the trade panel is reachable
- Extend shop-ui.test.mjs with a TRADE GATE case covering closed/lifted states
2026-09-13 14:46:59 -06:00
Brian Fertig 55db379a93 Move Special Delivery package handoff to the bar scene's DONE beat
- Ship now starts with cargoHold 0; the bar vignette's DONE press builds
  out 4 bays (effects.cargoHold) and then places the special-package,
  making the parcel aboard the "cargoUpgraded" step's witness instead of
  a build-state check.
- Remove the old capital-landing handoff and SurfaceScene package flag;
  onVignetteComplete in GameScene applies effects + handoff in order and
  refreshes the quest checklist.
- Persist cargoHold through saves and gate jumps so the upgraded hold and
  its goods survive a scene restart or load (old saves fall back to the
  carried goods count).
- Add arid-land/takeoff 02 assets, fix landing.json slot 3 mapping, and
  extend dev tests (jump-cargo probe, saves round-trip, vignette flow) to
  cover the new beat ordering and persistence.
2026-09-13 14:09:16 -06:00
Brian Fertig bd8b161584 Add planet vignette dialogue system with bar meeting scene
- Introduce VignetteHub/VignetteWindow/VignetteModel to play quest-gated
  dialogue scenes over location clips on the surface (bar/shop)
- Ship first scene: Special Delivery step 1 (Trestle + Carol at the bar),
  replacing the old capitalLanded check with a vignettePlayed witness
- Add q3 speech clips for Carol and Trestle; remove retired q2 Carol clips
- Wire save/restore of the played ledger, deck lock while a scene holds,
  per-sound music ducking under voices, and window sizing to each line
- Add dev flow test (dev/vignette-flow.html/mjs) and model unit tests
- Point landing.json ice-land-01 entry at the new arid-* video assets
2026-09-13 13:13:51 -06:00
Brian Fertig fb4c8d1d3c Add Explore drawer with Bar service and monotonic quest checklist steps
- Replace the surface deck's SHIP slot with an EXPLORE drawer that folds up a full-width secondary bar (MenuSubBar span mode) carrying per-world service items resolved by a `where` clause matcher (world / planetClass / faction, case-insensitive, list any-match)
- Add the neutral capital's BAR clip toggle: swaps the surface loop for the world's bar video, relabels the slot to LEAVE BAR, and locks every other deck + drawer button until pressed back
- Record quest checklist steps as DONE on the ledger (QuestState.completed set) so a step that stands on the home world keeps standing after the ship leaves; save/load round-trips the witness and old saves degrade cleanly
- QuestWindow fresh open now lands on the run's priority quest (tracker HUD seam) with its tab activated, falling back to the active tab's first quest when no priority is set
- MenuButton.setLabel re-fits the panel and hit rect in place for the LEAVE BAR relabel; ExploreBar.js provides the pure worldContext / matchesWhere / resolveItems item logic
- Add dev tests: explore.test.mjs (deck, items, where-clause, span, relabel) and quest-window.test.mjs (open landing + priority), plus updates to quests/research-builds tests for the new surface deck layout
2026-09-13 10:45:57 -06:00
Brian Fertig 1e3beccb22 Add "Special Delivery" quest with package handoff and shop gating
- New main quest granted after claiming "Leaving the Nest": land at the neutral capital (the bar), upgrade cargo bays, then deliver the sealed package to the home world.
- Introduce a non-tradeable `special-package` good (sheet frame 114) that no shop stocks or buys back; `Economy.isTradeable` filters it out of every floor and the sell grid refuses to queue it.
- Record story witnesses (`capitalLanded`, `launchedFromCapital`, `lastLandedWorld`, `delivered`) in a registry-backed ledger, persisted via SaveData so progress survives load and reset clears it.
- Gate the surface shop behind the capital landing: deck slot disabled and `toggleShop` refuses until `isShopUnlocked`.
- On capital departure, set the destination back to the home world so the compass marks the delivery leg; delivery proof is monotonic once recorded.
- Surface console note announces the package handoff when it first lands in the hold.
- Extend economy and quest test suites to cover the new check types, non-tradeable exclusion, unlock chain, and save/load of the story ledger.
2026-09-13 08:49:50 -06:00
Brian Fertig efaa559efa Rework "Leaving the Nest" arrival to the capital world with voice
- Split trestle-arrive into an arrive-1/2 ack pair, both voiced (new q2-04/q2-05 clips)
- Quest now completes on reaching the neutral capital planet instead of entering the neighboring system; add _atCapitalWorld proximity check and arm arrival in _checkDestinationReached
- Gate capital-world landing until the quest reward is claimed, with a new capitalDenyToast denial
- Update tests, save-data comments, and fix lava-shop-02 asset reference
2026-09-12 23:16:49 -06:00
Brian Fertig b6523808fa Name scout exits by their world, not just the system
- TradeScout now resolves each exit's specific object (planet of that class, deep-space station, or home world) and exposes objectId/objectName so the destination points at the route's final stop rather than a bare system.
- SurfaceScene dialog and toast show "WORLD · SYSTEM" and pass the object id to GameScene.setDestination; null falls back to system level.
- ScoutPanel exit rows display the world name + hops instead of the class label, drop the per-section tap hint and footer (they collided with the last row in a short panel), and rename "SIGHT ON" to "SOUGHT ON".
- Save/restore now carries ship.credits and ship.cargo across jumps; GameScene restores both and refreshes the credits HUD. Saves tests cover capture, prepare, and legacy records without these fields.
- trade-scout tests assert every exit has objectId/objectName and that resolved ids are real objects of the exit class; scout-dest test verifies the confirmed destination names a real world.
- Add dev/scout-overlap probe (html + mjs) to screenshot the scout panel and numerically report any overlapping text boxes.
- Ship lava-planet-03 art and lava-land-03 video assets.
2026-09-12 20:53:16 -06:00
Brian Fertig 7549c91df1 Add set-destination from trade scout, shop HUD, and green sell selection
- Trade scout best-exit rows now open a "SET DESTINATION" confirm dialog
  (SurfaceScene.askSetDestination + ConfirmOverlay), confirming sets the
  GameScene destination; local-system exits are rejected with a note.
- Surface scene builds a corner credits/minerals readout over the shop clip,
  refreshed after trades and torn down on leave.
- Sell-bay selection restyled: green stroke + tinted fill + upper-left
  checkmark badge (data/shopui.json slot config), replacing the cyan ring.
- Add lava/capital-neutral music, videos, and landing data entries; remove
  tresle.png in favor of capital-neutral-surface.png.
- New dev probes: scout-dest, shop-hud, shop-select-shot, map-dest-shot,
  cdp-cast; extend shop-ui.test.mjs for selection visuals and exit taps.
2026-09-12 19:12:16 -06:00
Brian Fertig 141cbdb156 Add route-target pulse halo to gates, planets, and stations
- New shared RoutePulse entity draws a steady ring + two radar ripples
  scaled to the host's keepout radius, with configurable alpha/period
- JumpGate wears the full pulse (route.pulse) when it is the route's next
  stop; Planet and Station wear the subdued variant (route.objectPulse)
  when they are the destination object in the destination system
- GameScene marks exactly one entity per frame via setRouteTarget() and
  drives its update loop; all others are cleared
- Add data/gates.json sections for pulse and objectPulse geometry/alpha
- Rename laval-surface-02.png to lava-surface-02.png and add the
  corresponding video asset
- Extend jumpgate, planet, and station test stubs with Phaser Display.Color
  and recording graphics; add dev/route-pulse.test.mjs unit tests and
  dev/route-pulse-live.{html,mjs} browser integration checks
2026-09-12 16:35:05 -06:00
Brian Fertig 338a45e782 Add dual-shimmer rim to READY quest rows in the tracker HUD
- New js/ui/PerimeterShimmer.js: constant amber base rim + glow, and two comets in counter-streams (amber CW, neon cyan CCW) tracing the cut-corner plate perimeter; pure arc math (perimeterPath / arcPoint / arcPolyline) exported for bare-Node tests
- QuestTrackerHud promotes READY rows to the console's cut-corner plate (CyberShape.rectPoints), drives PerimeterShimmer per-frame on the absolute clock so repaints never reset comet phase, and fires a one-shot rim flash when a row is claimed; shimmers are torn down with each paint
- data/quests.json gains tracker.shimmer config (enabled, notch, periodMs, dashFrac, phaseOffsetPerRow, claimFlashMs, base, comets)
- CyberShape.rectPoints added for absolute-coord cut-corner polygons
- New dev/perimeter-shimmer.test.mjs covering arc math, counter-streams, absolute-phase invariance, degenerate configs; quest-tracker tests extended for shimmer lifecycle and claim flash
2026-09-12 11:42:56 -06:00
Brian Fertig 54989d3a3a Make BUY/SELL a toggle and save pending trade across panel close
- Pressing the open tab now closes the panel (back to entry state) instead of
  rebuilding it; pressing again re-opens with the selection restored, so hiding
  the panel no longer loses the player's pending trade.
- Save the SELL/BUY maps onto ShopView (_pendingSell/_pendingBuy) on toggle-close
  and tab switch; _restorePendingSelection() re-applies them when the panel is
  rebuilt. The sub-bar stays live while closed: NET shows the delta, Clear
  cancels the saved trade, Confirm executes it.
- preview()/clear()/_afterTrade()/_hasAnySelection() now treat a null tab with a
  pending selection as an active trade, so the buyback path is no longer shadowed.
- Rename ScoutPanel.data to report: Phaser's GameObject reserves .data (its Data
  manager), and a plain object there crashed GameObject.destroy(). Update all
  callers in ShopView, tests, and dev/shop-shot.mjs.
- Simplify the scout price line to credits only ("9 CR") and drop the now-unused
  priceSell style from shopui.json; update goods.png/psd.
- Add setSellMap()/setBuyMap() to TradeGrid/BuyList to restore a saved selection
  onto freshly rebuilt panels, and cover the toggle flow in shop-ui.test.mjs plus
  a toggle probe in dev/shop-shot.mjs.
2026-09-12 11:19:39 -06:00
Brian Fertig 564b086c6a Add trade scout panel to inspect goods and charted exits in shop
- Tap a BUY-list row's box (outside the stepper) to swap the cargo grid for a strategy report showing the good's identity, producer/demand classes, and top-N charted exits ranked by sell price with per-unit profit.
- New pure TradeScout module computes the report from galaxy data and visited systems; new ScoutPanel renders it over the SELL grid area.
- BuyList gains tap detection (distinguishing taps from drags), a focus glow on the scouted row, and an onRowTap hook.
- ShopView wires open/close/swap semantics: same box toggles off, different box swaps report, dead-space or panel tap closes and restores cargo grid; sell-grid input is disabled while scout is shown.
- Add Trestle character art, Carol Q2 speech lines, shopui.json scout config section, and tests for both the pure logic and UI integration.
2026-09-12 10:28:13 -06:00
Brian Fertig 071f3ac0e4 Align shop sub-bar to span full action deck width
- Widen the tab sub-bar from a button-width pill to the full deck span (left/right edges of the main action bar), centering it on that span.
- Pack tabs at the left edge and Clear/Confirm + NET readout at the right edge, compressing gaps rather than button widths when the deck is narrow.
- Right-anchor the NET value (origin 1,0.5) and reserve its widest slot so growing totals never shift the label or overflow the bar.
- Extend SurfaceScene.shopAnchor to expose left/right edges for the sub-bar layout.
- Add sub-bar probe assertions in dev/shop-shot.mjs and unit tests in dev/shop-ui.test.mjs covering span, alignment, non-overlap, and NET math.
- Add carol character image and lava-land video assets.
2026-09-12 09:44:30 -06:00
Brian Fertig e9eda003b4 Fix shop buy-list clipping and add a scrollbar
- Rows that spill past the viewport edge used to render whole, ghosting over
  the BUY title or onto the Confirm bar; now only elements fully inside the
  window render (this Phaser build can't crop glyphs), and row plates draw
  just their in-window slice for a clean cut.
- Clipped-out steppers are no longer tappable: hit-testing gates on element
  containment, not just row visibility.
- Add a right-edge scrollbar (track + drag/jump thumb) that tracks scroll
  position and hides when content fits the viewport.
- Extend shop-shot/dev tests to verify the clip invariant, dead-click
  behavior, and scrollbar geometry; add a geckodriver screenshot helper.
2026-09-12 09:21:05 -06:00
Brian Fertig 71f8bf6fe4 Fix shop buy-row bar position and stepper hitbox anchoring
- Center the row background plate on its own local origin so it no longer double-offsets with the object's world position, eliminating the right/down drift and stretched spacing.
- Switch stepper glyphs to a centered (0.5, 0.5) origin and recompute the tap area live inside hitAreaCallback against the current glyph size, so the box stays centered on the visible button even as qty text re-measures.
- Add dev/shop-shot probes that assert bar fillRect coords and verify plus/minus clicks register on the glyph while a point in the old mis-anchored gap does not.
- Extend landing.json with additional land/surface/takeoff/shop video entries.
2026-09-12 08:54:50 -06:00
Brian Fertig c3d5e7fe74 Span the trade panel to the screen edges: SELL flush with the planet text, BUY out to the same right padding
The panel was centered as a group; now the SELL grid's left edge sits at
the surface HUD's planet-text left edge (landing.hud.marginX, 24px —
same key the HUD name/line use) so the cargo grid lines up vertically
with the planet name above it, and the BUY list stretches from just
past the grid all the way to the right edge minus that same padding
(1280px window: BUY list 560 -> 770px wide; the 440px floor stays as
the narrow-window fallback). The 16px gap between the panels is
unchanged, and the sub-bar still anchors to the deck's Shop button.
shopui.json's buyList.w is now only the headless fallback width.
2026-09-12 00:06:17 -06:00
Brian Fertig cc4a15cafd Widen the BUY list right up against the SELL grid; the row description drops to 11px and wraps to two lines without touching the price/stepper
The center column is gone: Confirm + Clear move onto the tab sub-bar
([tabs] | [Clear][Confirm] | NET value), serving both the trade and
buyback tabs, so the two panels sit side by side with just a bit of
padding between (grid.centerW 208 -> 16). The row description keeps the
smaller font, word-wraps inside the text column (wrap width stops
before the price), and the char-count budget now spans two lines so the
headless path stays bounded; rowH grows 64 -> 72 to fit both lines.
The buttons persist across tab switches (they were content before and
died with it), Confirm stays grayed while the trade is invalid, and the
stub gains setX/setY so the bar layout is testable.
2026-09-11 23:47:43 -06:00
Brian Fertig 3fdd825570 Lock the deck while the shop is up: only LEAVE SHOP stays live
While the shop clip is on screen (the SHOP slot reads LEAVE SHOP), the
command deck's other slots — Build, Ship, Quests, Take Off, Menu — go
standby: dim, no hover, no press, clicks swallowed — the same inert
language as the 'ack' comm's deck hold. The press that opened the shop
is the only way out; the slots re-arm on LEAVE SHOP (and if the shop
clip fails to load).

  js/ui/ActionBar.js     setSlotEnabled(id, on) — per-slot lock: arms/
                         disarms one slot (input off, standby paint);
                         setEnabled (deck-wide standby) keeps each slot's
                         flag in sync and still owns input over a
                         per-slot unlock; setHover/press guard on it;
                         setLabel no longer repaints a locked slot live
  js/scenes/SurfaceScene setDeckLocked(locked) — lock everything but
                         SHOP on enter (toggleShop), release on leave
                         (leaveShop) + the broken-clip fallback
  dev/actionbar.test.mjs new — slot lock / deck lock / standby-priority /
                         label-kept-locked, headless
  docs/ECONOMY.md §12    the deck-lock bullet

All headless suites that passed before still pass (the five pre-existing
failures — music/quest-tracker/system-hud/galaxy-labels/jumpgate —
import SurfaceScene, which extends Phaser.Scene that the headless stub
doesn't provide; they fail identically without this change).
2026-09-11 23:31:54 -06:00
Brian Fertig a2d211a981 Rework the BUY side: a scrollable list of wide rows (icon + name +
description + price + stepper) instead of the 4×4 icon grid

Each stock good is now ONE WIDE ROW — the good's icon, its name + a
one-line description (the good's flavor), and the price + a −/qty/+
stepper on the right — the way the user wanted the shop list to read.
The stock (12–16 goods) outgrows the panel, so the list SCROLLS:
drag on the row area or the mouse wheel; rows outside the window are
clipped (row-based alpha clipping — this Phaser build has no
ScrollContainer/camera clip), and hidden rows' steppers are
non-interactive. The selection is data (goodId→qty), so stepping a
good works whether its row is on screen or not.

  js/ui/shop/BuyList.js   new — the scrollable BUY list (rows, drag +
                          wheel scroll, per-row steppers, flavor text)
  js/ui/shop/TradeGrid.js SELL-only now — the BUY mode (steppers, stock
                          rendering, buy-selection data) is stripped;
                          one grid, one purpose
  js/ui/shop/ShopView.js  composes TradeGrid (SELL) + BuyList (BUY);
                          the BUY panel sizes itself to the SELL grid's
                          height (top- AND bottom-aligned)
  data/shopui.json        buyList row/typography knobs (name, desc,
                          price, row bg/border, selection accent)
  dev/shop-ui.test.mjs    BUY assertions rewritten for the list + a new
                          SCROLL section (scroll clamps, row clipping,
                          stepping off-screen rows)
  dev/shop-shot.mjs       BUY probe → the row's inline text (no tooltip)
  docs/ECONOMY.md §12     the BUY bullet + mockup now describe the list

The BUY side's name + price used to live in a hover tooltip because a
grid cell is too small for text; a wide row carries them inline, so the
tooltip stays on the SELL side only. All headless suites green
(shop-ui, economy, cargo, builds, ship-behavior).
2026-09-11 23:23:15 -06:00
Brian Fertig 2b860cc899 Move the live NET readout from the panel center onto the tab sub-bar
The pending trade's credit delta now sits at the right end of the
Buy/Sell + Buyback sub-bar, past a hairline divider — tabs AND the
credit math on one console, one glance apart (entry state dims it to
0 cr). The center column keeps Confirm/Clear (re-centered); the
buyback panel's Confirm moves up to sit just below its rows.

Knobs: data/shopui.json → preview (bar sizing, zeroColor, divider).
Docs: docs/ECONOMY.md §12 mockups + bullets follow the new layout.
Tests: dev/shop-ui.test.mjs asserts the bar's NET readout mirrors the
pending trade (+N cr while picking, 0 cr after Confirm).
2026-09-11 22:09:49 -06:00
Brian Fertig 05b6f573c3 Add signature gemstone as guaranteed local buy in every shop
- Ensure each class's gemstone (tier 3–4 producer good) always appears on the shop floor, swapping into the least-important slot when at max stock to preserve size and avoid duplicates.
- Add a test sweeping every system/class to verify the world's "jewel" is present, produced, and premium in all shops.
2026-09-11 21:58:05 -06:00
Brian Fertig 36ef43119d Show shop cell name + price in a hover tooltip instead of over the icon
- TradeGrid cells now render only the good's icon; hovering a usable cell reveals a shared per-grid tooltip with the name and "sell/buy for N cr" price line, anchored above (or below on the top row) and clamped to the panel.
- Per-cell name/price text objects are removed; a single `label` remains only for locked/empty state ("locked", "—").
- data/shopui.json: add `tooltip` section (bg, border, pad, gap, font sizes) and bump `iconScale` to 0.62 so icons fill the now-cleaner cell.
- Apply theme fonts throughout the shop UI — Ethnocentric for section titles, Centauri for body text, tooltip, stepper, and buttons via `fontStack()`.
- dev/shop-shot.mjs: replace old layout probe with a hover-tooltip probe (structure check, programmatic + real mousemove hovers on sell/buy cells, pointerout hide) and await web fonts before boot so screenshots use the real typefaces.
- dev/shop-ui.test.mjs: new HOVER TOOLTIP suite asserting tooltip visibility, text content, locked/empty suppression, unhover, buy-side pricing, and theme font application.
2026-09-11 21:39:51 -06:00
Brian Fertig 77d649276c Rework shop UI to cyberpunk sub-bar + entry state, fix panel geometry
- Shop now opens on the tab sub-bar only (shop video plays); clicking Buy/Sell reveals the trade panel — showcases the clip before the UI takes over.
- Tab bar and Confirm/Clear are now MenuButtons in a console-blue sub-bar that rests above the command deck, anchored to the deck's Shop button (MenuSubBar recipe), replacing the old top-of-screen custom buttons.
- Fix trade panel vertical placement: a Container's (x,y) is a pure translation of local space (verified via dev/cbox-test.html), so the grid position IS the panel top-left; setting it to topY + h/2 treated it as a centered origin and clipped bottom rows. Panel now anchors just under the HUD planet text via SurfaceScene.shopTopY().
- Parent TradeGrid plate/title to the grid container so they render above the shop video (scene-level depth-0 objects drew behind it in this build).
- Add dev probes (dev/cbox-test.html, dev/shop-shot.{html,mjs}) and update phaser-stub/test stubs for setSize/setBlendMode/rectangle; document entry state + sub-bar in docs/ECONOMY.md.
2026-09-11 21:19:32 -06:00
Brian Fertig 1b4cba9f4f Add shop buy/sell UI, cargo hold, and cargo bay upgrades
- Introduce CargoHold (pure class) as the ship's trade-goods carrier: fixed bays, one good each, capacity = unlocked bays, save/restore round-trip. Ship.cargo + setCargoHold/cargoRoom wired into stats.
- Add three credit-costed cargo builds (cargo-bay-8/12/16) that expand the hold 4→8→12→16 (MAX wins). BuildWindow affordability now covers both minerals and credits; GameScene.beginBuild debits credit lines and _applyCargoUpgrade expands the hold on completion.
- Add tradePreview/resultingCargo to Economy.js as the shop's pure calculator: sell/buy pricing, net credits, the two caps (can't go negative, end hold fits capacity), and atomic sell-to-free-room-for-buy.
- New ShopView + TradeGrid compose the buy/sell screen over the shop clip: SELL grid of cargo bays (tap to check), BUY grid with quantity steppers, live NET preview, Confirm/Clear, and a session-local Buyback tab (neutral undo at the sale price, locked until a sale). Wired into SurfaceScene's SHOP button.
- data/shopui.json drives the shop layout/animation knobs; economy.json gains cargo.maxSlots (16-slot grid); ship.json base cargoHold drops to 4 unlocked bays.
- Headless tests: dev/cargo.test.mjs (hold rules + trade preview caps), dev/shop-ui.test.mjs (construct, sell, buy, caps, buyback, clear), plus updated builds/ship-behavior suites; phaser-stub gains Geom.Rectangle for the hitArea path.
2026-09-11 20:11:34 -06:00
Brian Fertig 5f54cc327e Add trade economy engine, credits currency, and goods catalog
- New Economy.js price/stock engine: deterministic buy/sell prices based on
  producer/demand classes and hop distance (regional availability model)
- Goods catalog (114 goods, 9 categories) with spritesheet mapping and
  per-class producer/demand roles
- Credits state on Ship (add/spend/set/canAfford), save/restore support,
  and upper-right HUD stacked above the minerals readout
- Quest reward payout now supports credits alongside minerals
- cargoHold reduced to 4 units for initial play balance
- Economy generation pass in Galaxy.js computes classBySystem and
  producerHops via multi-source BFS over the jump network
- dev/economy.test.mjs validates determinism, fixed prices, trade loop
  profitability, distance scaling, shop floor composition, and icon mapping
- docs/ECONOMY.md: full design doc covering pricing model, gemstone system,
  and locked decisions
2026-09-11 18:36:30 -06:00
Brian Fertig 63ea50928d Light up BUILT rows and name the world each build was installed on
- BUILT rows are now lit — accent fill, glow ring, icon halo, and a
  stamped seal — so installed upgrades read as done at a glance.
- The readout now names the world a build was actually installed on
  (new BuildState.builtOn): ship upgrades show "SHIP-WIDE · INSTALLED
  FROM KEPLER-186F" instead of the planet the console sits on.
- BUILT outranks BUSY, so an installed upgrade no longer reads as
  waiting while another build is in flight; its cost line reads PAID.
- Category tabs gain progress pips: filled = built, pulsing = in
  progress, hollow = not yet.
- Dev-only headless harness (dev/build-shot.html/.mjs) boots the game
  and stages the full row-state matrix for one-frame screenshots.
- Refresh the planet sheet artwork (planets.png/.psd).
2026-09-11 14:24:15 -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 32215fa737 Add thunder audio on lightning strike edges
- Play a soft thunder SFX (sfx_thunder_01..04 at volume 0.35) on the
  strobe's 0→>0 edge, once per strike; mid-strobe frames stay silent.
- Move `wasOn` latch after the thunder check so it reflects the previous
  frame's state (fixes arm-frame and edge detection).
- Add `thunder: false` config to silence the voice while keeping the bolt.
- Cover with tests: arm frame silent, one clap per strike, mute path.
2026-09-10 23:11:35 -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 3137a800bf Add "Leaving the Nest" quest chain and READY tracker state
- New second main quest "Leaving the Nest" (data/quests.json) that unlocks when the starter quest's reward is claimed, with four checks: system charted, gates activated, Trestle talked, Trestle met
- Quest unlock chain in QuestState (isUnlockMet / grantUnlocked) and GameScene._grantUnlockedQuests — grants on claim + scene create for loaded saves, announces via SFX, OAC quest-grant voice (new oac-quest-new comm), and NEW QUEST toast
- Trestle story beats: three-brief ACK sequence (trestle-brief-1/2/3, trigger trestleBrief) armed when home jumpgates go online, and arrival beat (trestle-arrive, trigger trestleArrival) on landing in a neighbor system; CommsHub gains onStart hook so the played-ledger marks feed quest checks live
- Quest check types: systemCharted, gatesActivated, trestleTalked, trestleMet — evaluated in GameScene._questCheckEval / _trestleCheck against the comms played-ledger (survives reloads; mid-sequence quit re-arms only unplayed beats)
- System-complete milestone moved from research completion to the chart-completing discovery (celebrateDiscovery), one fire per system via _systemCompleteSeen set
- QuestTrackerHud READY state: completed-unclaimed rows turn amber with breathing tint, percent reads "READY" (bold), one-shot flash + diamond burst on flip, CLAIM REWARD button in row popup claims in place; silent when tracker is slid off (toast + chime carry it)
- New speech clips (trestle q2-01/02/03), lava-takeoff video, updated lava-land video, renamed lava-planet image, new laval-surface image
- Dev: quest-ready.html/mjs capture harness for the READY state shot; tests updated across comms, quests, quest-tracker, and system-hud suites
2026-09-10 20:29:47 -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 6dcc340a3b Add system-complete comm and audioPool random clip support
- Introduce the oac-system-complete visual comm that fires on the
  'systemComplete' trigger when a system's jumpgate research unlocks,
  arming before the generic researchComplete sign-off so the FIFO plays
  specific -> generic.
- Support an optional audioPool list of speech clips in CommsModel; the
  hub picks one at random per arm so only the chosen clip is fetched and
  cached, with validation that audio comms need a clip or pool.
- Wire GameScene to trigger systemComplete on activateGates when the
  system nav chart is complete.
- Update comms tests for the new comm, pool normalization/asset rolling,
  roster counts, and add a tether-rules audit script plus station shop
  video references and lava assets.
2026-09-09 22:20:30 -06:00
Brian Fertig c84e64c5b0 Add world preview (?type=) for judging landable worlds/stations
- New js/galaxy/TypeSystems.js: parseTypeSpec + pickPreviewSystem rank the seeded galaxy richest-first, exact face always beats a reskin fallback, optional ?fx= type filter.
- GameScene reads ?type=<class>[-NN] / ss[-NN], spawns the ship beside the target world/station, anchors its landing tether, and reskins the sheet frame when no world wears it so landing clips + surface loop follow.
- dev/type-preview.test.mjs exercises parsing, real-galaxy picks (exact/reskin/determinism/filter), crafted ranking, and bad inputs in bare Node.
- Smoke boot registers SurfaceScene alongside GameScene since the landing flow launches it on top of the flight scene.
2026-09-09 16:46:24 -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 a946a13a19 Fix save panel layout, text overflow, and animation timing bugs
- Slot cards: fit content lines to card width (wrap, shrink, ellipsize)
  and stack them by measured height so long names no longer spill into
  neighbouring slots; bump fill opacity to reduce bleed-through.
- SavePanel open choreography now lands only after every card stagger
  and footer rise complete — the old state-gated loop dropped row 2.
- Move feedback toast inside the panel on the subtitle line, hiding the
  header while it shows (old spot collided with the O.A.C. comms box).
- ConfirmOverlay: reset to base size each show, fit title/body text into
  the plate before laying out, and make the body fully opaque so card
  text no longer bleeds through.
- Add dev screenshot harness (save-shot.html/mjs) and extend the saves
  UI test with overflow, stagger-completion, and toast-position checks.
- Update planet sprites and add/refresh SFX + music assets.
2026-09-09 14:43:28 -06:00
Brian Fertig b33aecade2 Rename firstForeignPlanet trigger to firstWorld and make busy() type-awa
- The Trestle intro comm now fires on the first discovered world (the
  starter quest's own witness, `discoveredWorldCount`) instead of the
  first planet in a foreign system, so the comm and the quest can never
  drift; delayMs drops to 0 so it lands at the moment of discovery.
- The scene's `busy()` contract is now comm-type-aware: audio-only comms
  (voice, no box, no pause) ride over in-progress actions like mining or
  a scan sweep, while ack/visual comms still wait; modal windows and a
  jump in flight block every type.
- Add the `comms-mine` dev harness that walks the type-aware busy
  contract (free scene → real mining → audio comm mid-mining → jump) and
  update the trestle dev scripts/tests to the new trigger and witness.
- Arm the pair on scene-create for loaded saves that already hold
  discovered worlds, and widen the cdp-shot ready dump.
- Add ice-shop art/video assets.
2026-09-09 13:00:25 -06:00
Brian Fertig 8afe4c78c6 Add Trestle's first-foreign-planet intro comm pair and ACK pulse cue
- Introduce the `firstForeignPlanet` trigger: when the player discovers a planet in a non-home system, Trestle (new out-of-system mentor character) delivers a two-part ack comm pair (meetup + quest claim), with dedicated video and speech assets.
- Make audio cache keys folder-scoped so characters with identically-named clips (e.g. both having `intro-01.mp3`) don't collide in the loader.
- Add an amber pulsing attention cue (halo + staggered sonar rings) on the ACKNOWLEDGE button for ack comms, driven per-frame from CommsBox.update().
- Put the ActionBar deck into a standby state while an ack comm holds: slots go inert (no hover/press), dimmed visually; re-arms when the comm ends. GameScene wires this via `actionBar.setEnabled()` each frame based on `comms.paused`.
- Extend MenuButton to accept a custom border color so the ACK button can wear the box's amber against the cyan UI.
- Add dev self-check harnesses (`comms-trestle.mjs`, `comms-trestle-hold.mjs`) and update existing tests to cover the new pair, folder-scoped keys, deck standby behavior, and pulse animation.
- Disable browser module caching in CDP probe/shot scripts to avoid stale ES modules shadowing on-disk changes during dev testing.
2026-09-09 12:12:34 -06:00
Brian Fertig 881a94a1b6 Add full OAC tutorial comms chain and ice-surface video assets
- Wire 10 new comm beats (oac-tether, oac-scan, oac-upgrade, oac-minerals,
  oac-fly-mine, oac-first-cluster, oac-research-complete, oac-tether2,
  oac-relaunch, oac-explore) into data/comms.json with their triggers,
  speech clips, and FIFO ordering
- Add trigger arming in GameScene (firstScan, tetherResearch, firstCluster,
  minerals200, researchComplete) and SurfaceScene (tetherL2Launch)
- Make CommsHub.trigger idempotent so a double-click can't queue the same
  comm twice
- Fix landing.json to use ice-surface-02/03.mp4 instead of rocky variants;
  add the two new ice-surface videos and an ice-shop image
- Add speech clips intro-05 through intro-10 and research-complete
- Expand dev/comms-intro.mjs into a full 10-step walkthrough self-check,
  add dev/comms-upgrade-hold page for screenshotting the longest comm, and
  update dev/comms.test.mjs to cover the new roster
2026-09-09 11:28:22 -06:00
Brian Fertig aaa953d654 Added Comms Feature 2026-09-09 10:10: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 fa3e0cb1f8 Add research completion celebration and progress pips to console
- Fire a one-shot ignition (expanding rings, edge pulse, child flares) when a project completes; queue it if the console is closed or on another tab, dropping stale events after 15s
- Add per-tech progress pips on each category tab showing done/in-progress/not-yet states, with a pulse on the active one
- Light up unlocked nodes with an accent glow ring, icon halo, and a stamped seal glyph replacing the plain checkmark
- Add dev harnesses for screenshotting the live completion treatment and verifying the queued-celebration path
2026-09-08 22:37:28 -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 bc8d5359c7 Add asteroid field depletion and restyle station compass + research edge
- Mining now fires `onDepleted` when a cluster's last rock is consumed; GameScene splices the depleted cluster out of world entities, solids, content record, and map chart, then records its id for persistence
- SaveData captures/restores `depletedClusters` so mined-out fields stay gone across save/load (legacy saves default to empty set)
- Change station compass color from red (#ff4d5e) to bright purple (#c84dff) in data and all UI references
- ResearchWindow: thicken tech-tree edges to 3px core + wide glow, add crawling dash animation on unpowered links, endpoint socket dots, and a comet-trail pulse on powered edges
2026-09-08 13:18:48 -06:00
Brian Fertig 9e7d7c1257 Add quest tracker HUD with priority system and live checklist
- New QuestTrackerHud component slides in below the system dossier once it folds, showing active quests (main story first) with a live progress checklist under the priority quest
- Priority quest: player can set/clear via row popup or console; auto-assigns to first active story quest; cleared state sticks until a grant or claim re-arms it
- QuestWindow gains SET PRIORITY / CLEAR PRIORITY controls and openAt() to land on a specific quest (used by SHOW MORE / VIEW QUEST)
- GameScene wires the tracker into the dossier lifecycle: hidden while expanded, slides out before expand, slides in on collapse; pointerdown contract prevents world clicks from leaking through rows and popups
- SurfaceScene delegates priority changes to the sleeping GameScene's ledger
- QuestState serializes/deserializes priority + cleared flag for save round-trips
- quests.json gains a tracker section (title, maxVisible, slideMs, toast configs)
- New dev/quest-tracker.test.mjs pins the full contract; dev/quests.test.mjs extended with priority and tracker-knob checks; system-hud test updated for the extra tracker elements
2026-09-08 12:55:10 -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 92520a0503 Fix tether visible-arc logic for exact internal tangency
- Treat k <= -1 as "other zone contains this rim" so a level-1 gate
  tether at exactly the level-2 anchor's range no longer draws a spurious
  full circle inside the union.
- Update doc comment to clarify external vs internal tangency cases.
- Add regression tests covering the d + rInner = rOuter boundary case.
- Add spacestation music and surface video assets.
2026-09-08 11:24:02 -06:00
Brian Fertig 5efc5dfe61 Updated tests 2026-09-08 10:36:48 -06:00
Brian Fertig 9b7bf334e4 Remove reserved action bar slots; all six now carry actions
- Drop the empty "reserved" slot from both the flight and surface decks so every slot is a live button
- Update GameScene docstring to list the actual six slots (Research, Scan, Ship, Quests, Map, Menu)
- Add original screenshot assets for scene 01 interiors
2026-09-08 09:58:32 -06:00
Brian Fertig ce26b38df9 Add quests console with live progress tracking and claimable rewards
- Introduce QuestState ledger (granted/claimed ids) persisted via SaveData, with safe fromJSON validation that drops unknown ids and enforces claimed ⊆ granted
- Define the starter quest "Start Your Journey" in data/quests.json with four live checks: research node, lifetime asteroid mining, home tether level, and discovered world count
- Add totalMined counter tracked on each ore event to support the mining requirement independently of cargo hold
- Build QuestWindow (full-screen console at depth 80) with video feed, category tabs (Main Story live, Side Quests standby), quest list, detail plate with checklist and CLAIM REWARD action
- Wire QUESTS slot into both flight and surface command decks right of SHIP; SurfaceScene delegates snapshot/claim to the sleeping GameScene while rendering its own console notes
- Grant starter quest on first boot with delayed toast; announce "QUEST READY" once per quest when all checks complete
- Update research-builds tests for seven-slot deck layout; add dev/quests.test.mjs covering data contract, ledger behavior, save round-trip, and deck slot placement
2026-09-08 09:32:12 -06:00
Brian Fertig b1ae21e95e Changes to Research Areas 2026-09-07 23:10:47 -06:00
Brian Fertig 1c5767b095 Add deep-space station variants with spritesheet art and landing support
- Introduce StationFrames.js galaxy-wide pass that spreads spacestations.png
  variant frames across the galaxy, avoiding collisions among neighbor stars
- Stamp settlement.stationFrame in SystemGenerator so content carries the
  assigned variant (lazy === eager)
- Render deep-space stations from the spritesheet when available; keep
  procedural fallback for waypoints and missing textures
- Extend comms target with isStation/frame and allow REQUEST LANDING on
  deep-space stations, passing station flag into SurfaceScene
- Add landing.stationVideos entries and music.stationFrames slots keyed by
  variant frame; surface/shop clips degrade gracefully until authored
- Add dev tooling: station-shot page/runner for world/panel/land/deck states
  and a Node test asserting variant spread beats naive random assignment
2026-09-07 22:23:12 -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 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 a846562782 Fix gate facing so gates sit on the destination side of system center
- Sort gate candidates by destination-side before tier, so an on-ray point behind the center loses to any destination-side aimed/scan point
- Add a new soft "facing from the center" check in tests: when some anchor's tether circle reaches the destination side (maxProj + tether > 0), the gate must lie there; a single far planet may still take the best aimed point
- Prefer a destination-side aimed candidate in the clearance fallback
2026-09-07 14:37:21 -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 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 642c2cc016 Add dev dialog-shot probe for map confirm screenshot
- Adds a standalone Phaser dev harness that boots GameScene, opens the MAP console, hovers a discovered object, and triggers the ENGAGE AUTOPILOT confirm so it can be captured via headless Firefox.
- Records dialog state, scrim alpha, panel command buffer, and target-deferral assertions to verify the confirm renders correctly and leaves ship.target null until ENGAGE.
- Includes a rocky-shop video asset for reference in the shot workflow.
2026-09-07 10:27:45 -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 94cc87a177 Fix map tooltip ghosting by parenting it to the window container
- ttPlate/ttName/ttSub/ttHint were created as bare scene objects at depth 5, so they painted behind the map window (depth 80) and were never hidden on close, leaving a lingering "TAP TO PLOT COURSE" button on the world
- Add them to the ttCont container (which is inside MapWindow) so they paint with the window, fade with its close tween, and hide with ttCont
- Add dev/map-click.html + dev/map-click.mjs regression harness that opens the map, hovers/clicks a discovered object, verifies autopilot targeting, and checks no tooltip lingers after close
- Add rocky-surface-02.png asset
2026-09-07 08:35:53 -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 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