- 8 new enemy types (frames 50–57) split 4/4: combo seekers fire flank-angle homing missiles with capped turn-rate; elementals throw darts that bloom into growing, damage-ticking electrified zones
- Balance follows the faction rule (2× damage, 3.5× armor vs pirate raider), documented in combat.json comments
- New `flank_barrage` and `shock_dart` abilities in EnemyAbilities.js with shared `stepShock` frame step wired into CombatSystem.update
- Generalized `_combatBootMode` to accept any id from `factionIds()` so new factions need no code change
- Painted frames 50–57 in ships-enemy.png/.psd; added capital-mindweave-surface-01 reference art
- Tests: dev/zenith.test.mjs (Node), dev/zenith-arena-browser.mjs (Playwright), updated combat.test.mjs roster and sheet-art checks, extended cdp-faction-arena.mjs with zenith tab
- Register 8 Apex (frames 30-37) and 8 Mindweave (frames 40-47) in
data/combat.json enemyTypes at 2x damage / 3.5x armor vs the pirate,
each with a distinct weapon pattern and ability kit
- New shared skill layer (js/combat/EnemyAbilities.js): cloaked ambush,
flank strafe, blink reposition, illusion decoys, telekinetic waves;
wired into CombatSystem update/collide with cloak gating on fire,
targeting, and player skills
- Add sweep/spiral/shell weapon patterns in js/combat/Weapons.js
- New ?combat=apex / ?combat=mindweave duel arena with an in-game
DuelPicker (keys 1-8 / click, 0 = whole pack); plain ?combat demo
unchanged
- Paint the 16 missing spritesheet frames (ships-enemy.png) so the
fighters are visible; add a PNG alpha regression test guarding against
blank cells
- Add dev/cdp-faction-arena.mjs CDP smoke check and extend
dev/combat.test.mjs with faction roster, balance, ability, duel, and
sheet-pixel checks
- Inferno (Offense, seat 2): flame arcs home on the nearest 2 hostiles
(3 from rank 4) and ignite a burn that ticks on the combat loop's clock;
scales in duration and per-tick damage with rank.
- Nanobots (Passive, no seat): mends 1% of max hull every 2s per point;
a full hull banks nothing.
- Wire flameArc + hullRegen effect handlers in SkillEffects.js and the
arc/burn/step logic in CombatSystem.js.
- Add firstPassiveOf() / hullRegen() to the skill ledger so the combat
loop can read the mend's interval and color off the ranked def.
- Update icon sheet, dev shots, and the browser/combat/data test suites for
the two new skills.
- Combat bands split at level 6 (5–7), 9–12, and 13+ (9–12 cap) with
weighted pirate rosters; compose() now draws `pirateTypes` from the band
roster and GameScene uses it when spawning one-shots.
- Patrol encounters gain tiered bands (levels 6+) with mixed rosters,
fatter rolling waves (up to 20 deep / 6 concurrent), contact-count odds
overrides, and per-tier `xpScale` dials; legacy array rosters normalize
to the weighted table.
- Bounty hunts replace the stubbed marksman band with tuned tiers
(marksman 6–10, deadeye 11–14, apex 15+): growing pickets and escorts,
escort roster mixes, elite armor/damage scales 3×–4×, and `xpScale`
trims so payout pace tracks the curve.
- Tests updated to assert the new band shapes, roster draws, XP scaling,
and tier resolution; skills-bar screenshots refreshed.
- Raise a new GameOverOverlay (scrim, semi-transparent "GAME OVER" headline, Return to Main Menu / Continue) when the player's hull breaks in combat
- Add _playerWentDown beat that freezes the world and owns the screen, gating input and the update loop while active
- Route the death decision through a skill seam (_playerDeathRespawns / _syncDeathFlowRespawn) so a future respawnOnDeath skill can override; default ends the run
- Wire Continue to resume the newest save (SaveManager.latest -> prepareLoad) then scene.restart, mirroring the menu's Continue
- Update combat.json playerShip comment to reflect the real death flow replacing the placeholder respawn in the main game
- Add toxic-takeoff-01.mp4 asset
- Strung hostiles dim to the data's fx.stunAlpha and show a crackling discharge (Fx.stunArms) while the snare holds, then recover with a release beat when the stun expires or on kill/revive
- Add Fx.stunArms/killStunArms + jagBolt helpers for the per-frame discharge (jagged bolts, sparks, hull stutters) tied to the snare's clock
- Store per-craft stun color/alpha from the bola catch and drive hold/release via _stunHoldFrame/_stunRelease in CombatSystem
- Add dev/stun-shot.mjs CDP script + screenshots, extend combat tests for dim/discharge/release, bump skills-bar test timeout, reformat skills.json, refresh toxic-land video
- Define both skills in data/skills.json with energy, cooldown, ranks, seats,
and per-rank stun/decoy durations
- Implement projectile flight, target intercept, capture radius, and stun in
CombatSystem (launchBoleadoras / _stepBoleadoras / _snagBola)
- Implement Blink: spawn a decoy sprite at the old position, teleport the
hull to a random visible-screen point, and let the decoy absorb aggro and
enemy bolts until its clock expires
- Add bola orb/string visuals and snag readout in Fx.js (bolaStart/Step/Stop,
snag)
- Register new combat SFX events (bola_snag, blink) in CombatSfx.js
- Extend SkillEffects with stunMs/decoyMs helpers and boleadoras/blink handlers
- Update tests: Wraith model checks, Boleadoras/Blink combat behavior, decoy
aggro/fizzle, and SFX event roster
- Add canvas-drawn comet head, arrival fireball, and damage-radius ring textures in Fx.js, replacing the old single-dot streak/ring combo
- Switch all ram-related (and general glow) sprites from ADD to SCREEN blend to fix the "dark box" artifact over semi-transparent nebula backgrounds
- Introduce ember trail particles that linger ~1 s behind the hull during the dash, plus a flickering comet head that rides the ship and is released on impact
- Add `ramBlast()` impact sequence: ignition flash, blooming fireball, exact damage-radius ring, shock ripples, and debris sparks
- Wire in the heaviest camera shake beat (`ram`) and layer the data's sfxEvent under a thunder boom at impact
- Bump skill fx `ringLifeMs` to 480 so the damage-radius ring lingers long enough to read
- Add dev CDP harnesses (`cdp.mjs`, `ram-shot.mjs`, `ram-video.mjs`) and reference stills/video for the charge's three key frames
- Add `skillWindow` to the full-screen click guard so clicks don't
steer the ship or fold panels while the skill tree is open.
- Include the skill window in the shared `_frozen` condition so the
world parks (throttle/velocity cleared) behind it, matching the
class console and level-up marquee contract.
- Replace per-skill rows with a scrollable tile grid (authored `node` cells or
auto-layout by dependency depth), elbow join lines, rank badges and empty sockets
- Add detail drawer at bottom third showing the selected skill's copy plus ADD A SKILL
POINT, RESET and ASSIGN/CLEAR SEAT actions
- Introduce a console session in SkillState: points spent while open are PENDING and
resettable; closing commits them; reset cascades down a branch bought this session
or refuses when it would strand a committed point
- Wire GameScene onReset/onClose doors, toast copy and passive re-roll on refund
- Move all tree geometry/palette knobs into data/skills.json (window.tree) with clamped
fallbacks in SkillModel.windowSpec()
- Add pure treeLayout()/classTreeLayout() to SkillModel for canvas-free layout tests
- Expand dev/skills-window-browser.test.mjs to verify regions, tile placement, session
lifecycle, scroller (wheel/drag/thumb), and pixel-prove the gold join line
- Update README, PROJECT_NOTES and screenshot fixtures
- New `data/skills.json` (registered in manifest) owns every number/string for the
per-class skill trees, type taxonomy, seat table, bar look, and window copy;
code only reads behavior off it so adding a third skill is a data edit.
- Pure skill model + ledger (`js/skills/SkillModel.js`, `SkillState.js`): rank
points from the class bank, spend-through-unlock edges, seat bindings, save
round-trip via `record.playerSkills` (old saves load as an empty ledger).
- Combat runtime in `CombatSystem.js`: cast pipeline with per-skill recharge
clocks, energy spend/regen (now on by default), Ramming Charge dash + arrival
blast (4x..12x weapon damage by rank), Reinforced Plating hull pool re-rolled
from base so it never compounds; charge passes through the pack and settles once.
- UI: full-screen Skill Tree console (`js/ui/SkillWindow.js`) opened from the ship
console's SKILL TREE door (lit when the class owns a tree), combat bar seats draw
icon/rank/cooldown/affordability states with click-to-assign and right-click clear,
keys 1-8 cast or place.
- Evidence: new Node + Playwright suites (`skills.test.mjs`, `skills-combat.test.mjs`,
`skills-bar-browser.test.mjs`, `skills-window-browser.test.mjs`,
`skills-devdoor-browser.test.mjs`) plus screenshots in `dev/shots/`; README and
PROJECT_NOTES document the layer and dev doors (`?skill`, `?skilltree`).
- Add three arid theme tracks (arid-01/02/03) and a new spacestation-03 track
- Point station 15-17 at the new arid tracks instead of reusing lava
- Add spacestation variant 2 and reorder existing station frame mappings
- Hold jumps while the escort convoy is linked or setting down: the
player must have the transport, its surviving escorts, and the gate
all on screen before leaving the system.
- Close the destination world's landing door until the transport has
reached it (phase delivered) or been destroyed (phase failed), so a
lost convoy never blocks the reset remedy.
- Arm OAC's escortDeny visual beat plus flat toasts on both denials.
- Register the transport captain character and add neutral-transport-link
(convoy link greeting) and neutral-transport-delivery (delivery thanks)
comms with audio pools, all once:false so they re-arm per contract.
- Require the convoy to be on screen before the delivery begins, not just
the destination world.
- Update escort-flow and comms tests for the new witness gates, landing
door, and transport captain beats.
- Add `_encountersLockedByQuest()` to GameScene: while the delivery
chain is live (not yet completed AND claimed), keep the encounter
director from rolling. Quests disabled = gate off too.
- AND the new scene-side hold into `encounters.update`'s `allowed` so
the pure clock stays untouched; document the contract in Encounters.js.
- Ship new transport sprite assets (ships-transport.png/.psd).
- Pass `wordWrap` as `{ width, useAdvancedWrap }` instead of a bare number; Phaser 4 ignores the Phaser 3 shape so description copy was running off the panel.
- Add dev-only CDP probe (`dev/jobboard-wrap-*`) that boots to the Job Board, selects a posting, and dumps text-object geometry + overflow vs the panel's right edge.
- Commit captured probe artifacts (`dev/shots/jb-wrap.{png,json}`) as a regression reference.
- Add neutral ally assets: music, attack/scan/scan-complete speech lines, and pilot video.
- New EncounterDirector (js/combat/Encounters.js): pure, data-driven clock that rolls pirate / neutral / mixed encounters in neutral non-home systems on a ~45–90s interval at 50–60% chance, one at a time with a 30–60s cooldown, never during a live wave run or on a downed player.
- Neutral ally ships (js/combat/NeutralShip.js) on spritesheet frames 20–27: escort the player for a per-ship 10–15s window, engage the nearest pirate in mixed fights, then break off and fly off-screen; player-safe by construction (never targeted or damaged by ally bolts/seekers).
- Pirate targeting generalized so hostiles can draw aggro onto escorts when the player is out of range; escort and pirate bolts/missiles collide with each other but not the player.
- Group size scales with combat level (1–2 low → 4–5 high, bands in data/combat.json); encounter hostiles are one-shots so the fight ends when the sky clears.
- New 'volley' weapon pattern (wide staggered-speed fan) and owner-tagged bolts/missiles for ally vs enemy routing in Weapons.js.
- Neutral roster config + encounters section added to data/combat.json; EnemyTypes gains neutralTypeConfig/Ids/SheetList.
- Tests: dev/encounters.test.mjs (cadence, gate, weights, size bands), dev/neutral.test.mjs (roster, escort AI, targeting, no friendly fire), plus combat/xp test updates; CDP probes and encounter-hud-check for in-browser HUD verification.
- Replace ships-enemy.png with revised artwork
- Update the corresponding Photoshop source (ships-enemy.psd)
- Add original reference image under assets/images/originals/
- Raiders now roll an attack comm on-screen (50%) or on rolling-wave arrival (20%), and a defeat comm on kill (20%), driven by per-type config in combat.json
- New bounty-attack comm fires when the wanted leader's fight stands up in GameScene._fireBountyEngagements
- Ship 12 pirate speech clips, 3 enemy video clips, and register three new senders (pirate, pirate_defeat, pirate_bounty) in comms.json
- Wire onComm seam through CombatSystem so the scene can arm CommsHub triggers; rolls are no-ops when the seam is absent
- Add combat, bounty-hunt, and comms test coverage for the new roll logic, trigger arming, asset presence, and roster count
- Stamp `c.lockAt` as elapsed beat time instead of an absolute scene-clock value, so `el >= c.lockAt` holds and the slots actually lock onto the final level during a live session (previously they kept cycling random digits)
- Add regression test 6 covering a marquee on a scene clock at 60s
- Refresh marquee dev screenshots
- Add trestle-q4-04/05 speech assets
- CargoHold gains a parallel `costs` ledger (credits/unit actually paid, or null when no cost is on file), kept aligned across add/remove/set/capacity/dropFirstNot and serialized via toJSON/fromJSON
- ShopView stamps each bought bay with the trade's unit price so the console can compare exit prices against what was really paid
- ShipScreenModel/ShipWindow surface per-bay costs, a total-cost hold meta line, and a "PAID" chip + reference line in the bay manifest; bays with no cost read "NO COST" instead of inventing one
- GameScene passes the bay's recorded cost into scoutGood() so exit profits re-baseline against the purchase (falling back to the catalog value when absent), and restore/quest-handoff paths load null costs cleanly for legacy saves
- Adds arid-shop-02 video asset and updates cargo/saves/ship-window/shop-ui tests to cover the new ledger
- Add arid-shop-01.mp4 video and arid-shop-02.png image assets
- Correct arid land 01/02 entries in landing.json to reference arid-shop instead of ice-shop
- Cargo deliveries set from the ship manifest or surface scout now read brown on the compass and in-world pulse; story-quest and manual picks keep the route's orange
- Add `destination.kind` ('manual' | 'cargo' | 'quest') to save/load so the mark survives a session
- Carve out held "Special Delivery" quest: a cargo pick that matches its home delivery flips to kind 'quest' so the story keeps orange
- Thread the resolved mark color through JumpGate/Planet/Station `setRouteTarget` and DiscoveryCompass entry recoloring
- Fix lava shop clip references in landing.json (ice-shop → lava-shop) and add arid-shop-01.png asset
- Extend dev probes: ship-cargo-compass checks brown/orange per kind, scout-dest asserts cargo kind, ship-shot gains a park shot for the off-screen route arrow
- Add `dev/ship-cargo-compass.{html,mjs}`: headless end-to-end flow of the SHIP console → CARGO HOLDS → bay exit → CONFIRM, then Phase A (route gate marked orange on the compass with suppressed ordinary entry), hop-by-hop jumps, Phase B (destination object marked orange with subdued pulse), and REACHED clearing.
- Add `assets/videos/lava-shop-01.mp4` video asset.
- ShipWindow hosts a ConfirmOverlay (depth 30) so the SET DESTINATION dialog always paints above the console chrome
- Each remote exit row in the bay manifest becomes a hit-testable tap surface with hover state; local-system rows read HERE and stay inert
- Tapping a row opens the confirm dialog built from shipScreen.json templates; CONFIRM fires onSetDestination(systemId, objectId) through GameScene.setDestination, same seam as the map console
- ESC cancels the dialog before closing the console; closing the console cancels an open dialog to avoid orphan scrim
- Add dev/ship-cargo-dest.test.mjs covering hosting, row tappability, ask/confirm/cancel/close/repaint paths
- Update landing.json arid-land-03 shop reference from ice-shop-03 to arid-shop-03
- Add lava-shop-01.png and lava-shop-03.png assets
- Extend dev/ship-shot.mjs with ?tapExit / ?clickExit probes for headless verification
- Bump CLAIM REWARD plate from depth 31 to 65 so it renders above compass arrows, toasts, deck blocks, and the sub-bar while still staying below modals (70) and full-screen consoles (80).
- Update ship.mp4 asset.
- Void in-flight count-up tween when max changes so a late landing can't redraw against the old cap (250/250 → full after cap grew to 500)
- Add regression test for mid-count-up capacity restore voiding the stale tween
- Archive completed ship-screen goal and add ship.mp4 asset
- Add patrol category rules: target selection (own system or faction neighbor via jump gates), deterministic waypoint route builder inside tether regions with anchor clearance and separation constraints, completable fallback for degenerate fields
- Extend SideQuestState ledger with active slot, claimed marks, and per-contract route records (waypoints + visited indices); save/restore round-trips all new fields with invariant re-establishment
- Wire GameScene seams: acceptSideQuest establishes the patrol route on the ledger; setActiveSideQuest / claimSideQuest manage the active slot and pay out exactly once; updatePatrol checks in waypoints per frame and completes the contract; _drawPatrolMarkers paints in-world beacons; patrolCompassTarget drives the yellow off-screen compass arrow (waypoint or gate)
- JobBoardWindow walks the full door state machine: ACCEPT → SET PATROL ACTIVE → active plate → CLAIM REWARD → claimed plate, with destination and route-progress lines in the detail readout
- Quests console side tab is now live: accepted contracts appear in questSnapshot with waypoint checklist, progress, reward, and claimable from the same CLAIM REWARD / SET PRIORITY doors as story quests
- SurfaceScene exposes activateSurfaceJob / claimSurfaceJob and routes side ids through the existing claim/priority seams
- Add capital-neutral-shop video + image assets; update landing.json to reference them
- Update all headless tests (sidequests, jobboard, quests) to cover patrol target/route/ledger/scene-seam behavior
- The player's home system is safe space (no enemies), so no work should be posted on its board.
- worldContext now exposes isHomeSystem from GameScene; matchesWhere handles boolean values with list any-match.
- data/actionbar.json gives jobBoard a { isHomeSystem: false } clause instead of showing everywhere.
- explore.test.mjs covers home/non-home worlds, stations, and boolean-clause matching.
- Added the jobboard.mp4 bar clip asset; updated SurfaceScene/GameScene comments to reflect the new rule.
- Add OAC "enemies detected" / "enemies defeated" visual comms with random voice pools, fired on CombatSystem active-flag flips
- Deny jumping or landing while a fight is live so the wave run can't be escaped or hidden on a surface
- Move the 'Pirate Problems' ambush trigger to the midpoint of the entry-gate → capital-world stretch, persisting lastJumpFrom through saves for a stable midpoint
- Replace dot tracers with elongated glowing bolts (trail band + core streak + head bloom)
and a directional muzzle flare in both the range and main-game contexts.
- Add enemy impact reads: core flash, directional sparks along the travel vector,
cyan arc ripple on shield hits vs orange shards on hull hits, white craft hit-flash,
and a polished damage-number pop.
- Add player shield-sphere strike effect: full-sphere outline + bright arc centered on
the laser's incoming bearing, radial ripple, spark burst, and a shield-collapse cue
when shields break to hull.
- Add subtle world-camera shake on player hits, enemy kills, and shield-break while
keeping the HUD/combat bar perfectly still via the fx-ui camera split.
- Expose new visual knobs (bolt size/trail, muzzle, arc span, shake intensity) in
data/combat.json; fix Fx.update destroying ships on tintFlash expiry.
- New main-story quest granted after 'Special Delivery' is claimed AND its payoff comms are ACKed all the way through (unlocks.acked gate)
- Three-step checklist: speak with Trestle (trestleQ4 warning beats), defend from a rolling wave of six raiders at the gate-to-capital midpoint, return to the Neutral Capital World
- CombatSystem.startWaves gains an origin option so ambush enemies materialize in a ring around a specified point rather than off-screen around the ship
- CommsHub fires a new onAck hook before onEnd so the scene can record acknowledgments and run its grant pass in the same tick
- QuestState.isUnlockMet / grantUnlocked accept a gates.acked set; GameScene supplies it from the comms acked-ledger
- SaveData captures/restores comms.acked, combat.done, and story.capitalReturned; resetRunState clears all three on New Game
- Combat is now built for every scene (not just ?combat demo); the hostile pack spawns only in the sandbox boot
- Test suites updated: quest unlock gating, ambush wave shape, roster count 25→28, save round-trip of new ledgers
- Replace vertical gauges with draining hull/shield/energy orbs
(hull with overlapping shield on the left, energy on the right).
- Share the main game's CombatBar in the combat range and add
range energy tracking with optional regen.
- Make gauge hit flashes shape-aware: circle orbs get a soft bloom,
rects keep the legacy white pulse.
- Update combat data and assets for the new orb-strip storyboard.
- New `combat.html` + `/combat` dev-server route + `index.html?combat`
boot a fixed arena where the player ship fights a pack of enemy craft;
all tuning lives in `data/combat.json` (thrust, hulls, shields, lance,
rams, respawns).
- Add `js/combat/` modules: CombatScene, EnemyShip (standoff-ring AI +
lance), Bullet, Fx, StarDrift, and pure rules in Combat.js (armor
damage, orbit step) exercised by the new `dev/combat.test.mjs`.
- Extract shared `awaitFonts` into `js/utils/Fonts.js` so both the game
and sandbox boots use one copy.
- Preload the enemy spritesheet in GameScene so the texture is ready when
combat ships in; add `ships-enemy.png` (+ `.psd`) art.
- Expose `window.__COMBAT__` (reset, spawnEnemy, player, kills) for
devtools tuning; R resets the range, P freezes it.
- Arm `oac-research-new` (trigger `researchNew`) from `_commEnded` when the `oac-research-complete` sign-off finishes and `researchAnyAvailable()` is true, so the hub FIFO plays it right behind the sign-off
- Register the new audio-only comm in `data/comms.json` and move `researchNew` out of the reserved trigger list
- Update roster count to 25 and add node checks for the beat's fields, clip presence, and zero delay in `dev/comms.test.mjs`
- Add headless browser harness (`dev/new-research-shot.html`/`.mjs`) that verifies the seam, gating (in-flight vs available), and FIFO ordering through the real `onEnd` hook
- Ship `assets/videos/arid-shop-03.mp4`
- New ShimmerCue module: pure shimmerPhase/drawShimmer cycle (yellow band sweeps face, comet runs cut-corner edge), shared by both surfaces
- ActionBar gains setShimmer + a dedicated additive layer; the RESEARCH slot wears the full face+edge recipe while a tech can start and the console is closed
- ResearchWindow._paintCues paints the edge-only shimmer on every category tab whose tree still holds an available tech, plus the ACK pulse on the "Unlock Jumpgates" plate (or SYSTEM tab when off-screen)
- GameScene._applyResearchCue switches one cue at a time: deck slot when console closed, console cues when open; rests while a project runs (maxConcurrent 1), under standby, or under the tutorial finger
- ResearchModel.hasAvailable and SystemCategory.gatesReady/gatesNodeId encode the ready rules
- data: actionbar.json animation.shimmer, research.json fx.tabShimmer (#ffd84d, comm-pulse yellow family)
- dev: Node test (research-cue.test.mjs) pinning the pure cycle model + slot/tab behavior; browser verify page (research-cue-shot.html/.mjs) with CDP capture poses
- assets: arid-surface-03 / arid-takeoff-03 videos
- New TutorialGuide.js beat table picks which control to pulse based on live comms/research records, so a loaded run resumes the same beat
- ActionBar and ResearchWindow gain setHighlight() with pulsing rims (ACKNOWLEDGE-style sonar rings in the console) that hide under deck standby/locked slots/closed window
- GameScene applies the highlight per frame before surfaces draw, tracks scanPressed one-shot, and reads targets from data/quests.json → tutorial
- Add tutorial section to quests.json plus tests for beat table, ActionBar rim gating, and data consistency (slot ids, console node matches starter research check)
- New `js/visuals/EngineFlare.js` drives nozzle glow, ignition burst, and a short fading exhaust plume from the two side-pod engines, driven by the ship's live throttle so braking dims it and Shift+click lights it up full
- Configurable via new `thrustFx` block in `data/ship.json` (enabled flag, core/plume colors)
- Hooked into GameScene lifecycle: created per scene restart, updated from the scene clock, cleaned up on landing sleep and scene destroy so nothing survives frozen mid-glow
- Add dev harnesses for visual verification: `dev/engine-flare-test.mjs` (headless Chromium CDP walk through idle → ignite → burn → coast → settled with screenshots) and `dev/particle-probe.{html,mjs}` to confirm particle velocity follows the emitter's heading
- Add new arid planet art asset
- Stage the payoff audio (carol q3 05-07, oac q3 01) and video assets
(arid-surface-02, carol character) backing the launch-after-sale beat.
- Add dev/delivery-launch.test.mjs pinning GameScene.onSurfaceDeparture:
arms 'deliveredLaunch' once on post-delivery departure from any world,
stays quiet pre-delivery, preserves the capital leg (launchedFromCapital,
home routing, quest refresh), and keeps the arm firing on the defensive
already-home no-op.
- Ship now starts with cargoHold 0; the bar vignette's DONE press builds
out 4 bays (effects.cargoHold) and then places the special-package,
making the parcel aboard the "cargoUpgraded" step's witness instead of
a build-state check.
- Remove the old capital-landing handoff and SurfaceScene package flag;
onVignetteComplete in GameScene applies effects + handoff in order and
refreshes the quest checklist.
- Persist cargoHold through saves and gate jumps so the upgraded hold and
its goods survive a scene restart or load (old saves fall back to the
carried goods count).
- Add arid-land/takeoff 02 assets, fix landing.json slot 3 mapping, and
extend dev tests (jump-cargo probe, saves round-trip, vignette flow) to
cover the new beat ordering and persistence.
- Introduce VignetteHub/VignetteWindow/VignetteModel to play quest-gated
dialogue scenes over location clips on the surface (bar/shop)
- Ship first scene: Special Delivery step 1 (Trestle + Carol at the bar),
replacing the old capitalLanded check with a vignettePlayed witness
- Add q3 speech clips for Carol and Trestle; remove retired q2 Carol clips
- Wire save/restore of the played ledger, deck lock while a scene holds,
per-sound music ducking under voices, and window sizing to each line
- Add dev flow test (dev/vignette-flow.html/mjs) and model unit tests
- Point landing.json ice-land-01 entry at the new arid-* video assets
- 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
- New main quest granted after claiming "Leaving the Nest": land at the neutral capital (the bar), upgrade cargo bays, then deliver the sealed package to the home world.
- Introduce a non-tradeable `special-package` good (sheet frame 114) that no shop stocks or buys back; `Economy.isTradeable` filters it out of every floor and the sell grid refuses to queue it.
- Record story witnesses (`capitalLanded`, `launchedFromCapital`, `lastLandedWorld`, `delivered`) in a registry-backed ledger, persisted via SaveData so progress survives load and reset clears it.
- Gate the surface shop behind the capital landing: deck slot disabled and `toggleShop` refuses until `isShopUnlocked`.
- On capital departure, set the destination back to the home world so the compass marks the delivery leg; delivery proof is monotonic once recorded.
- Surface console note announces the package handoff when it first lands in the hold.
- Extend economy and quest test suites to cover the new check types, non-tradeable exclusion, unlock chain, and save/load of the story ledger.
- 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