refactor(flights): Cesium rendering behind a renderer interface

Task 10a. The flights logic no longer imports Cesium: every Cesium object it
built moved one for one into the shared aircraft renderer
(src/layers/aircraft/render/cesium.js; contract in render/contract.js), with
the flights' parameters in src/layers/flights/render/cesium.js, registered
for 'cesium' in the renderer registry and created at init(viewer, {engine}).

- Fleet: BillboardCollection + sprite-order slot; sprites stay Billboard
  handles (field vocabulary documented for the Navara renderer).
- Models: fleet/tracked/preload glTF loads (asynchronous:false, MIX tint, IR
  boost as `unlit` → the UNLIT CustomShader), the model collection, setPose
  (same HPR frame with airplane.glb's 180° offset).
- Tracked: the ENU billboard Entity with its position/colour/rotation
  callbacks, viewFrom, followed through viewer.trackedEntity + the one exact
  tracked frame (kept as is; engine.camera.follow on Cesium would also end
  the follow on any camera command, a behaviour change).
- Trail: the entity trail (data/trailRenderer, unchanged: its Primitive
  predecessor failed below the mesh) and the live head segment.
- View: camera/scene reads, frame number, frustum and horizon tests,
  projection, render requests, frame events, evidence render-loop hold.
- Clicks and Escape go through the engine's selection dispatcher (the
  ScreenSpaceEventHandler and keydown listener are gone); the cross-layer
  untrack watches the renderer's follow.
- Colours are engine-neutral Rgba (src/layers/shared/color.js), bit-equal to
  the Cesium.Color constants they replace; NearFarScalar → nearFarScale.
- Cesium math in the logic → src/geo.
- check-import-directions: cesium only in render/cesium*.js and three/Navara
  only in render/navara*.js for flights, aircraft and shared; a layer's
  Navara renderer only through navaraMode's import().

Source-text tests updated with the moved code, same meaning:
- readLayerSource reads a layer's render/*.js and, for the aircraft layers,
  aircraft/render/*.js (GLB-load, tracked-entity, CallbackProperty checks).
- modelScale.test: _normalBillboardScaleByDistance reads nearFarScale(...).
- spriteOrder.test: flights' enable calls fleet.restoreOrderOnEnable(); the
  renderer wires it to restoreSpriteOrderOnEnable('flights', viewer).
- trackingClickGesture.test: the flights gesture rules are the dispatcher's
  (selection gesture before select, click classifier before the empty-space
  clear); flights answers the empty click with a user-origin clear.
- militaryAwareness.test: flights' hasContact guard reads fleet.visible().
- ownership.test: the services fixture names selection and renderer.

New tests: color, the Cesium aircraft renderer (contract, collections, pose,
loads, frustum/horizon, tracked entity, follow, trail head, adopted
collections), the flights logic over a plain-data renderer and a fake engine
(fleet, click-select, no-op on the tracked visual, empty-click release), the
boundary rule.

W1 replay vs 7c7422e2: counts, known objects, screen points (0 px), tracking
poses (0 m), requests and shots (same sha256) identical. Main chunk
2,890,982 B (+6.2 KB, +0.21 %: the renderer indirection).
This commit is contained in:
German Khokhlov committed 2026-10-17 01:04:25 +04:00
1 parent 8e702f0c3b
commit 7f13ef4a87
33 files changed
+1974 -748

No files matched your search

+38
View File
@@ -30,6 +30,18 @@ const globeEngine = (file) => /^src\/globe\/(?:cesium|navara)\//.test(file);
const cesiumPackage = /^(?:cesium(?:\/|$)|@cesium\/)/;
// Navara renders through three.js and its postprocessing peer.
const navaraPackage = /^(?:(?:three|postprocessing)(?:\/|$)|@navaramap\/)/;
// Phase 3: the layers moved onto layer renderers (the *a tasks) keep each
// engine in their renderers: cesium only in render/cesium*.js, three and
// Navara only in render/navara*.js. The list grows with each moved layer.
const RENDERED_LAYER_DIRS = [
'src/layers/flights/',
'src/layers/aircraft/',
'src/layers/shared/',
];
const renderedLayer = (file) =>
RENDERED_LAYER_DIRS.some((dir) => file.startsWith(dir));
const cesiumLayerRenderer = (file) => /\/render\/cesium[^/]*\.js$/.test(file);
const navaraLayerRenderer = (file) => /\/render\/navara[^/]*\.js$/.test(file);
const renderer = (file) =>
/^src\/(?:ui|app|standalone|overlays)\//.test(file) ||
/^src\/layers\/[^/]+\/(?:index|rendering|snapshotRenderer|overlay|presentation|cards|controls)\.js$/.test(
@@ -123,6 +135,18 @@ export function checkImportDirections(root) {
target = path.resolve(root, exported);
} else {
record.external.push(specifier);
if (renderedLayer(file) && !tests(file)) {
if (cesiumPackage.test(specifier) && !cesiumLayerRenderer(file))
report(
file,
`cesium only in the layer's render/cesium*.js: ${specifier}`,
);
if (navaraPackage.test(specifier) && !navaraLayerRenderer(file))
report(
file,
`three and Navara only in the layer's render/navara*.js: ${specifier}`,
);
}
if (
file.startsWith('src/') &&
(builtins.has(specifier) || specifier.startsWith('node:'))
@@ -157,6 +181,20 @@ export function checkImportDirections(root) {
file,
`The Navara engine loads only through a dynamic import(): ${to}`,
);
// Like the engine, a layer's Navara renderer reaches the app only
// through the Navara mode's import() (src/app/navaraMode.js).
if (
navaraLayerRenderer(to) &&
!navaraLayerRenderer(file) &&
!(
file === 'src/app/navaraMode.js' &&
analysis.dynamicImports.includes(specifier)
)
)
report(
file,
`A Navara layer renderer loads only through the Navara mode's dynamic import(): ${to}`,
);
if (file.startsWith('src/') && to.startsWith('server/'))
report(file, `Browser imports server: ${to}`);
if (
+7
View File
@@ -321,6 +321,13 @@
"src/layers/flights/testing.js",
"src/layers/flights/evidence.js",
"src/layers/flights/ingestion.js",
"src/layers/flights/render/cesium.js",
"src/layers/flights/renderer.test.mjs",
"src/layers/aircraft/render/cesium.test.mjs",
"src/layers/aircraft/render/cesium.js",
"src/layers/aircraft/render/contract.js",
"src/layers/shared/color.test.mjs",
"src/layers/shared/color.js",
"src/layers/flights/queries.js",
"src/layers/flights/index.js",
"src/layers/flights/enrichment.js",
+12 -3
View File
@@ -896,7 +896,8 @@
"src/geo/developerError.js",
"src/time/clock.js",
"src/globe/contract.js",
"src/globe/cesium/engineFromViewer.js"
"src/globe/cesium/engineFromViewer.js",
"src/layers/shared/color.js"
],
"external": ["cesium"]
},
@@ -2587,7 +2588,11 @@
"src/globe/surfaceDetail.js",
"src/globe/navara/followGestures.js",
"src/app/layers/directory.js",
"src/app/layers/renderers.js"
"src/app/layers/renderers.js",
"src/layers/aircraft/render/cesium.js",
"src/layers/flights/render/cesium.js",
"src/data/selectionDispatcher.js",
"src/layers/shared/color.js"
],
"external": [
"hls.js",
@@ -3158,7 +3163,11 @@
"src/globe/follow.js",
"src/globe/cesium/follow.js",
"src/app/layers/directory.js",
"src/app/layers/renderers.js"
"src/app/layers/renderers.js",
"src/layers/aircraft/render/cesium.js",
"src/data/selectionDispatcher.js",
"src/layers/shared/color.js",
"src/layers/flights/render/cesium.js"
],
"external": [
"hls.js",