Files
gods-eye-view/src/layers/vessels/state.js
T
Wilmer AlzateandClaude Opus 5.5 367827e742 perf(vessels): let the scene idle with AIS vessels enabled
Vessels move only when a poll lands, yet enabling the layer held the
continuous render loop for its lifetime, so a parked vessels-only scene
rendered every frame. The layer now:

- requests a frame for every forced visibility pass (new data, selection);
- leaves one trailing frame when the camera moved inside the 800 ms
  visibility cadence, so the view the camera stopped on is evaluated. It is
  keyed to camera motion alone: the pass's own label publication requests a
  frame, and scheduling on that looped at ~1.2 Hz;
- holds 'ais-vessels' only while focus emphasis is animating.

The 80 ms focus pass, which runs while anything is tracked, also skips hidden
sprites whose focus state is at rest (new spriteFocusAtRest) and whose alpha
is already 1: advancing them changes nothing, and with a 12k worldwide feed
they are most of the fleet.

Measured: a parked vessels-only scene (headless SwiftShader) went from
continuous mode and 28 frames in 5 s to idle and 0; horizon visibility had no
mismatches after the camera moved and settled. The focus pass over 12,000
vessels (11,353 hidden) went from ~4.0 ms to ~1.2 ms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 13:01:45 -05:00

87 lines
2.9 KiB
JavaScript

import { createVesselFeed } from './ingestion.js';
import { VesselRecords } from './records.js';
import * as Cesium from 'cesium';
import { DEFAULT_AIS_RUNTIME } from './policy.js';
export function createVesselState({ source, services }) {
const {
setOverlayEntries,
setOverlaySourceVisible,
clearOverlaySource,
hitTestWorldOverlay,
} = services.overlay;
const vesselState = {};
vesselState._source = source;
/** Camera pose signature at the last vessel rotation pass. */
vesselState._lastCamPoseSig = '';
vesselState._scratchFocusScreen = new Cesium.Cartesian2();
vesselState.DEFAULT_VESSEL_OVERLAY_HOST = Object.freeze({
setEntries: setOverlayEntries,
setVisible: setOverlaySourceVisible,
clearSource: clearOverlaySource,
hitTest: hitTestWorldOverlay,
});
vesselState._vesselOverlayHost = vesselState.DEFAULT_VESSEL_OVERLAY_HOST;
vesselState._aisRuntime = DEFAULT_AIS_RUNTIME;
vesselState._aisSessionSequence = 0;
/**
* True once the EGM96 geoid grid has loaded (fire-and-forget warm at
* enable(), aircraft idiom — see militaryFlights.js). Gates all synchronous
* geoidHeight() reads so a poll can never throw pre-load.
* @type {boolean}
*/
vesselState._geoidReady = false;
/** @type {Map<string, string>} `${cssColor}:${variant}` -> chevron SVG data URL */
vesselState.shipIconCache = new Map();
vesselState.state = {
feed: createVesselFeed(),
records: new VesselRecords({ now: () => vesselState._aisRuntime.now() }),
viewer: null,
billboardCollection: null,
clickHandler: null,
/** Exact EventTarget currently holding the Escape listener. */
keyTarget: null,
/** Exact callback registered on keyTarget. */
keydownHandler: null,
/** Cesium trackedEntityChanged listener disposer. */
trackedEntityRemover: null,
/** Test-only factory used to exercise enable-time interaction installation. */
interactionHandlerFactory: null,
/** Test-only key target paired with interactionHandlerFactory. */
interactionKeyTarget: null,
preRenderRemover: null,
/** Pending timer that renders one frame after a cadence-skipped pass. */
trailingVisibilityTimer: null,
lastVisibilityUpdate: 0,
lastFocusUpdate: 0,
/** Sprites whose animated emphasis remains outside the 1.0 deadband. */
activeFocusCount: 0,
activeLabelCount: 0,
selectedRecord: null,
/** @type {{setPositions: Function, clear: Function, destroy: Function}|null} Selected-vessel fading trail */
trail: null,
/** @type {Cesium.Cartesian3[]} Chronological trail vertices (oldest first) */
trailPositions: [],
/** @type {string|null} MMSI that owns the active selected-vessel trail. */
trailMmsi: null,
/** @type {number} Monotonic token — invalidates in-flight backfill responses */
trailBackfillToken: 0,
trailAbort: null,
};
return vesselState;
}