- Add MineralHud component (js/ui/MineralHud.js) showing "MINERALS n / N"
plus a fill bar in the upper-right corner, replacing the old tether
stack. One tween drives both the counting number and the bar so they
never drift; a cyan flash ripples on landings; amber at capacity.
- Wire Mining to emit an onOre(gained, hold) seam per extraction tick and
per fragment landing so the HUD fills live as the rock shrinks, not
only at the batch 'absorbed' event.
- Remove refreshTetherHud / fmtRange from GameScene; instantiate MineralHud
in create(), feed it via refreshMineralHud() from ore seams and mining
events, destroy on shutdown.
- Add data/mineralhud.json config (corner pad, bar geometry, count-up and
flash tuning) and register it in the manifest.
- Tests: new dev/mineral-hud.test.mjs covering layout, count-up/bar sync,
superseded-tween guard, capacity/clamping, teardown; extend
dev/mining.test.mjs to assert onOre ticks; drop tether-HUD checks from
dev/system-hud.test.mjs; add setOrigin/setScrollFactor no-ops to the
Phaser stub.
- Extract minerals from the latched asteroid at ratePerSec × miningSpeed; each mineral shrinks the rock by 1 px so the beam stays latched to its rim.
- Break rocks that lose ~1/3 of their original size: large ones halve in place (beam keeps mining one half), small ones shatter into pieces that fly home and load the hold.
- Add ship.minerals hold with addMinerals/setMinerals capped at stats.mineralStorage; a full hold ends the run instead of grinding the rock away.
- Persist the hold in save/restore (captureState writes ship.minerals, applyRestore restores it) and keep legacy saves working when the field is absent.
- Play new mining_split sfx on each break and surface split/absorbed/storageFull events as console toasts.
- Expose AsteroidCluster rock surgery (setSize/addRock/removeMember) for runtime splits, and add headless Phaser stub + loader plus a mining test suite covering extraction, halving, shattering, full-hold stop, and the hold API.
- Introduce `Ship.state` ('normal' | 'mining') with `setState()` and an
`onStateChange` callback so the scene can react to state exits.
- Any player-initiated movement (world click or compass autopilot) now
drops the ship back to 'normal', which ends the mining sequence via the
scene's handler; Mining.update() enforces the gate as a belt-and-braces.
- Rename `Mining.isLocked` to `isActive` and update GameScene click logic:
clicks no longer hold during extension — they move the ship and abort the
arm's reach.
- Tighten the popup-button swallow window from 300 ms to 20 ms and add a
`containsScreen()` hit-test so only the exact button press is consumed,
not subsequent deliberate clicks on the panel area.
- Expand the headless mining test to cover the new movement-abort contract:
world click mid-extension breaks the arm, autopilot retracts the beam,
and ship state transitions are asserted at every stage.
- Click a rock to open a world-anchored mining popup (Mine/Stop/Cancel)
- Mining state machine locks the ship during the ~1.5 s arm extension, then fires an animated beam with ore motes, shock rings, sparks, and periodic surges
- ESC breaks the beam or closes the menu; outside clicks dismiss without flying
- Generalize the top-center console toast so discovery, tether, and mining calls share one slot
- Add a "mining" SFX entry (system-scan.mp3) and update preload/test to cover all configured sounds
- Ship a headless browser test (dev/mining-test.*) that drives the full arm sequence through the real input pipeline