Multiplayer coordinate foundation (no network service implemented)

navigation.snapshot() emits schema gripen-state/1: id, simulationTimeS,
WGS84 latitudeDeg/longitudeDeg, altitudeMslM, true heading, pitch/roll in
radians, speed in m/s. ellipsoidHeightM is null: MSL is not GNSS ellipsoid
height. A future server must agree on vertical datum and simulation time.

geodesy.relativePosition(packet, observer) maps any peer into the local
view using common UTM 33N metres (EPSG:32633) and an observer-relative
origin/heading. navigation.relative(packet) exposes the same conversion.
The scene and map use the same project() function. Do not transmit local
Three.js mesh coordinates; each observer renders from its own origin.

Future work: authenticated transport/session ownership, stable player IDs,
authoritative clock, interpolation/extrapolation, stale-track removal and
rendered peer meshes. The current packet is not an implemented multiplayer
system and its local simulationTimeS is not a synchronized network clock.

Tests: scripts/test_geodesy.js checks known UTM central-meridian point,
1 km WGS84 motion, observer-relative peer separation, vertical MSL
separation, mapped runway start and DEM height. test_navigation.js checks
the complete route and manual control. Both bundle with esbuild for Node.
