Commit Graph

117 Commits

Author SHA1 Message Date
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