- 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.
- Generate 4–8 rock groups per system with seeded placement, spacing, and slow tumble/drift motion driven by data/asteroids.json
- Add AsteroidCluster entity (Phaser container) with halo, dust motes, per-rock spins, and ship keep-out collision reusing Planet.resolve
- Integrate clusters into GameScene: load spritesheet, constrain ship post-physics, include in click-to-fly/autopilot/discovery/compass
- Synthesise unique cluster names via NameGenerator.asteroid (syllables + field suffix)
- Add dev test suite and ?seed= param for deterministic galaxy generation
- Load `assets/images/ships-player.png` as a Phaser spritesheet via
`data/ship.json` (`texture`, `frameWidth`, `frameHeight`, `frame`)
- Add `artFacing` config; Ship applies a constant `artOffset` so heading
math is unchanged while the frame art (facing north) renders correctly
- Scale sprite as `(size * scale) / frameWidth` to preserve the 46 px world
hull size and collision radius regardless of frame dimensions
- Fall back to the built-in procedural dart when the sheet is missing or
fails to load, with a console warning in GameScene.create()
- Update ship-behavior tests to account for `artOffset` in heading checks
- Add source art (`ships-player.psd`, landed-ship reference) and a demo
video; document the new pattern in README and PROJECT_NOTES
- Discovery rule: ship within `discovery.distance` (540 px) of a world's edge discovers it once per system; state is pure, save-ready (`Discovery.toJSON/fromJSON`)
- Off-screen compass (`DiscoveryCompass`): themed screen-edge arrows with type/name chips point back at discovered worlds; geometry helpers (`edgeAnchor`, `circleInView`, `lerpAngle`) exported for Node tests
- Solar-system layout: `layoutSystemPlanets` places generated worlds in a deterministic annular band around the home world, enforcing edge-to-edge separation and per-class scale/tint from `data/planets.json`
- All system planets are solid to the ship (collision + click-clamp), not just home
- Rim ping + HUD toast on discovery (`celebrateDiscovery`)
- New planet class pools (rocky/gas/ice/lava) with frames, `classScale`, `classTint`, and `typeLabels`
- Smoke-game dev hooks: `?ship=x,y` and `?near=px` for screenshotting discovery/compass states
- Node test suite (`dev/discovery.test.mjs`) covering rule boundaries, per-system state, JSON round-trip, layout bounds/determinism, compass geometry, and class pools
- Allow planet kinds to specify multiple sheet frames and pick one with a seed-derived Rng so the same galaxy always gets the same home world.
- Add Ethnocentric and Centauri font assets.
Adds the player's home planet to the starting system, rendered from the new
planets.png spritesheet. The planet is a solid disc: the ship may come within
shipClearance of its rim but can never cross it, and clicks on the planet
clamp to the keep-out rim so the ship always has a reachable destination.
- js/entities/Planet.js: solid-disc entity with a circle keep-out constraint
(constrainShip/resolve, pure and scene-free) plus edgePoint/aimPoint helpers
- data/planets.json (+ manifest entry): texture, frame size, scale, homePlanet,
shipClearance, spawnDistanceFromEdge
- Ship.js: exposes a radius (half the hull width) for the keep-out math
- GameScene.js: loads the spritesheet, spawns the home world at the origin,
starts the ship ~150 px off its rim in a seed-derived direction, and applies
the constraint each frame after the ship moves
- dev/planet.test.mjs: Node tests of the constraint against real config;
dev/test-game.html gains a <base href> so asset paths resolve from /dev
- Boot the game from a static server with no build step (Phaser 4 vendored in lib/)
- Main menu (New Game button) and GameScene where clicking makes the ship fly there
- All tunables live in data/*.json (game/menu/ship), loaded via manifest + Config singleton
- Ship behavior driven by arcade physics (thrust, drag, maxSpeed, arrival) with a Node test harness (dev/ship-behavior.test.mjs) and a dev smoke page that boots straight into GameScene
- Project conventions documented in docs/PROJECT_NOTES.md; README rewritten to describe layout, run instructions, and dev tools