fix(cockpit): a provider's subject rides where it is drawn, and the documented provider rides a moving train

- A frame with no speedMps gets an exact anchor: an inertial one ran on at
  zero speed and closed at 0.75 m/s, so the camera fell kilometres behind a
  moving train. The docs example now passes speedMps and anchor: 'exact',
  a name for its HUD, and isEntryAllowed for a train bound to its line.
- Transit's snapshot height is the floor where playback draws the vehicle,
  not the newest report's floor uphill, and null while that floor is cold,
  so a view waits for the surface instead of standing on the ellipsoid.
- Rail's direction follows playback once it has placed the train: a report
  that runs back (a reversal, or GPS jitter) no longer turns the view
  while the drawn train still runs forward.
- A frame's id is trimmed as the candidate's is.
- A double-click on the selected vessel no longer enters an application's
  subject that took entry after it.
- The docs import from gods-eye-view/..., the package's name.
This commit is contained in:
Sameh Khamis committed 2026-11-13 18:23:50 -08:00
1 parent 974023510f
commit 4bb7b411e9
10 files changed
+161 -21

No files matched your search

+22
View File
@@ -1114,6 +1114,28 @@ test('a subject first seen together with a built-in one comes after it', async (
assert.equal(store.presence.entryKind, 'vessel');
});
test("a double-click on the selected vessel does not enter an application's subject", async (t) => {
const clock = manualClock(t, 10_000);
const ride = subjectProvider();
ride.subject.candidate = null;
const { cockpit, store, viewer } = fixture(t, {
providers: [ride],
vessel: VESSEL,
});
cockpit.syncEntry();
// The application's subject is selected after the vessel: it takes entry.
clock.advance(500);
ride.subject.candidate = { id: 'a1', name: 'Example 12', selectedAt: 1 };
cockpit.syncEntry();
assert.equal(cockpit.resolveEntryKind(), 'example-kind');
// Every world position lands under the pointer, the vessel's sprite too.
viewer.scene.cartesianToCanvasCoordinates = (_position, result = {}) =>
Object.assign(result, { x: 400, y: 300 });
assert.equal(cockpit.onSceneDoubleClick({ x: 400, y: 300 }), false);
await settle();
assert.notEqual(store.presence.active, true);
});
test('a provider view with look turns with the arrow keys and words its readout', async (t) => {
const clock = manualClock(t, 10_000);
const ride = subjectProvider();