- constrainShip on Planet, Star, Station, JumpGate, and AsteroidCluster now
returns a contact boolean (true only when position/velocity/acceleration
actually changed) so the scene can distinguish "touched" from "no-op".
- GameScene.onPostUpdate reads those flags and, if the ship is in its
Shift+click thrust state, calls stop() + setState('normal', 'contact')
the first frame any solid or the tether rim touches it — the hold ends
and the ship rests on the rim instead of driving through.
- Non-thrust ships are left alone by the rule; their existing arrival/brake
logic still owns their stop.
- dev/contact.test.mjs: headless tests covering no-contact outside the
keep-out, contact + push-out + inward-motion strip on approach, no
spurious contact while sliding off the rim, the full thrust-into-planet
stop-dead-on-rim integration, and that the rule only fires in thrust.
- dev/smoke-game.mjs: add a third thrusttest check (c) verifying a
Shift+click straight into the planet stops it dead on the rim.
- 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