- 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
- 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
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- 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
- 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
- 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.
- 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.
- 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
- The sub-bar was anchored to the MENU button's center + half-height, which
made it spill over the command deck's top rail (buttons are inset below
the bar's top edge). Anchor y is now the deck's top edge so the bar's
bottom edge sits on the deck.
- Update landing.json rocky land-02/03 entries to reference their own
rocky surface/takeoff/shop videos instead of reusing gasgiant/terran
assets, and add the new rocky-shop-03.mp4 video.
- Temporarily disable per-class planet tints in GameScene (option still
accepted by Planet for when we re-enable it).
- 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.
- 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
- `_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
- 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
- Clicking a planet or station now opens the comms panel without moving the ship; world clicks are no longer fly-here targets, keeping mining beams live during panel interaction
- Add double-click (350 ms) skip for landing and takeoff clips in SurfaceScene so players can cut to the deck or flight world immediately
- Push restored mineral hold through the upper-right HUD on load so the readout matches the saved value instead of staying at zero
- Replace removed Phaser v4 Container.removeChildren() with removeAll(true) in JumpGate and Station destroy paths
- Update landing.json shop entries for terran frames 2–3 and document the new skip behavior
- Add dev harnesses for surface-skip, hold-restore, scene-restart, container-probe, and import probes; extend comms-click and saves-ui tests to cover the new interactions
- Add new video assets `terran-surface-03.mp4` and `terran-takeoff-03.mp4`
- Fix the third terran entry in `landing.json`, which was incorrectly
duplicating the first entry, so it now references the new 03 videos
- Introduce data/gates.json + js/galaxy/JumpNetwork.js: a strongly-connected, degree-limited spanning tree over the nearest-star graph (plus local shortcuts) so every system holds 1–3 gates, all jumps are local, and no system is closed or trapped
- Place each gate on the tether circle of an anchor (planet / space station / home world), facing its destination star; enforce radius band, clearance from anchors, and gap between gates in SystemGenerator.layoutGates
- Add the JumpGate entity (procedural twin-pylon portal) with the same solid contract as Planet/Station, discoverable in cyan, listed in the HUD dossier; wire into GameScene solids + discovery
- Guarantee every system holds at least one gate anchor (barren systems get a deep-space station); cap the home system at 3 objects so it fits the tighter band
- Rework solar-system layout to a full pairwise band [minSpacing, maxSpacing] with rotation tuned toward gate bearings; update tests and docs accordingly
- Change radiusGrowth from 1.25 to 2.0 so level N doubles the previous
level (L2 = 10240, L3 = 20480, L4 = 40960 px)
- Update all data descriptions, docs, and test defaults to match
- Add refreshHudTetherLevel() in SurfaceScene so the HUD line re-decodes
when a tether build completes while on-surface
- Rename rocky-planet-02 asset (typo fix), add 03-a/03-b variants,
point rocky frames at indices 6–8 in planets.json
- Add dev/tether-flow harness to exercise the full L2 build flow end-to-end
- SHOP button now swaps the looping surface clip for the world's `shop`
video (e.g. terran-shop-01.mp4); pressing again swaps back. The slot
relabels between "Shop" and "Leave Shop" via a new ActionBar.setLabel.
- data/landing.json gains a per-frame `shop` entry; worlds without one get
a console note instead of a clip.
- SurfaceScene: toggleShop/leaveShop manage the shop video (pause/resume,
visibility), error handling falls back to the surface loop, and cleanup
on takeoff/shutdown disposes the new video and note glyphs.
- ActionBar: slots store their base fontSize so setLabel can shrink-to-fit
long labels; paintSlot re-asserts hover state after relabeling.
- GameScene now passes the world's type label and tether level into the SurfaceScene launch payload; new tetherLevelFor() resolves a world's anchored tether (by label or anchor position) for that line.
- SurfaceScene builds/decodes a two-line HUD (Ethnocentric name in the menu title shade with black stroke, Centauri line below) while the surface clip loops, driven by the shared scramble decode; it is torn down on take-off and shutdown.
- landing.json gains a hud config block for margins, fonts, spacing, strokes, and colors.
- Added dev-only harnesses (surface-hud.html/.mjs test page and surface-hud-shot.html/.mjs screenshot probe) to verify the HUD styling, decode settle, payload, and teardown in headless Firefox.
- Introduce a `takeoff` video entry in landing.json for each world; missing/
null entries leave the surface instantly (no regression)
- SurfaceScene.takeOff now plays the one-shot take-off clip full-screen,
hides the deck, and only then stops the scene and wakes GameScene
- Guard against a clip that never starts or runs past its duration so the
player is never stranded; finishTakeoff is idempotent
- Update surface-flow/surface-shot dev harnesses to assert and screenshot
the new take-off stage
- Re-map gas giant frames in planets.json from [0,1,2] to [3,4,5] to match
their sheet positions
- New SurfaceScene overlays GameScene when the player requests landing:
plays a one-shot landing clip, then a looping surface clip behind a
dedicated command deck (Shop/Build/Ship + Take Off + Menu).
- Wire comms panel "Request Landing" / "Land" buttons to launch the
surface; TAKE OFF stops SurfaceScene and wakes GameScene so the run
resumes exactly where it left off.
- ActionBar accepts an optional `buttons` override so scenes can supply a
different slot list while sharing layout/colors/animation.
- SavePanel gains a `stateScene` option so saves from the surface read
state from the paused GameScene underneath.
- Add data/landing.json (per-frame video map) and four placeholder
surface clips; CommsPanel now passes its full target payload through to
onAction so landing metadata survives the round-trip.
- Add dev harnesses: headless-Firefox screenshot helper, click-path test
for the real user flow, and a surface-flow assertion suite with parked
screenshot pages.