- 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.
- 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.
- 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.
- 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.
- 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
- 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).
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.
- 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
- 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.
- 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)
- 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
- 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.
- 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
- 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
- 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
- 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.
- 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.
- 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.
- 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
- 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.
- ensureLandingTether runs before SurfaceScene launch so the surface HUD
already reads Tether Level 1; free + instant, no console step
- Extend tether lookups (_applyBuildEffects, tetherLevelFor,
_rematerializeBuiltTethers, applyRestore) to include systemStations so
station tethers anchor, level up, and re-anchor like planets'
- Idempotent: home seed, existing build record, or an already-hosted
tether all short-circuit; adopt rather than double-anchor
- tether-l1 targets now ["planet", "station"]; update descriptions in
builds.json, README, PROJECT_NOTES
- Reorder MapWindow tabs to CURRENT SYSTEM / GALAXY / SYSTEM (galaxy is
the live middle tab) and keep SYSTEM as the armed standby target
- 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.
- 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.
- 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
- 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
- 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
- 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
- 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
- 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)
- 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
- Nebula gas layer: soft coloured cloud sprites at depth 3, tinted with a
per-system palette color assigned deterministically at galaxy generation
(SystemGenerator stamps content.atmosphere.color). Only nebula-type
systems render it; all other types are untouched.
- Ripple effect: a full-screen WebGL composite on the world camera that
displaces the starfield and world objects while the HUD stays crisp via
a new UI/world camera split (UiCameras.js). Data-driven per archetype in
data/systems.json (nebula = ripple, all others = none). Canvas fallback
degrades to no effect.
- Demo mode: ?fx=<type> URL param retargets the run to the richest system
of that archetype, fully charted with all gates active, for judging the
effect in isolation.
- New ice and lava planet art (slots 9–14 in planets.png) replacing the
placeholder terran/rocky/gas reuse.
- Node test suites for the nebula palette/determinism/cloud texture and
the ripple math/data contract/shader/facade (50+ checks, bare Node).
- Replace the square star field with a wide (width × height) field whose
aspect matches the map plate, so the fully-zoomed-out galaxy fills the
plate instead of letterboxing; recompute zone edges for equal-area thirds
under the new diagonal CDF.
- Add fitPadded() in SystemChart.js and use it in GalaxyView.js to frame
the galaxy as a true rectangle fit with a plate-pixel margin, replacing
the old world-unit padding that left stars on the plate edge.
- Rework the JumpNetwork spanning-tree heuristic to "save the stranded
first" (attach the candidate with the fewest unvisited non-barren
neighbors) and strengthen the repair pass: never attach to barren nodes,
guard swaps against cycles via inSubtree(), and add a last-resort
fallback that preserves strong connectivity.
- Update tests (galaxy.test.mjs, system-chart.test.mjs) for the field
bounds and the new fitPadded behavior; refresh README, PROJECT_NOTES,
and data comments to document the 2:1 field and platePadding knob.
- Replace the sparse disk (radius, flatten, spiral arms, per-type radiusBand)
with a seeded square domain placed by Bridson Poisson-disk sampling for
even, organic star spacing (no clumps/voids).
- Add a home→far difficulty axis: each record now carries `d` (0 at the home
corner, 1 at the opposite corner) and a named zone; type distribution is
mixed per zone via `distribution.zoneMix` instead of radial bands.
- Move the starting system to the star nearest the configured corner
(`startingSystem.policy: "corner"`, default SE / lower right), with
`center` and `random` policies still supported.
- Increase default system count from 60 to 90 and retune settlement density
gradient, landing video slots, and test expectations to the new layout.
- 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
- 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
- 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.
- 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.
- Use `video.resume()` instead of `video.play()` in Build, Map, Quest,
and Research windows: Phaser v4's `play()` is a no-op after `pause()`
because the `_playCalled` flag stays true, leaving the feed frozen
after close → reopen. `resume()` handles both first open and re-open.
- Play the 'construct' SFX when the planet HUD lines start their
scramble-decode animation in SurfaceScene.
- 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
- 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
- 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
- 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