Give each engine its own extensions in place of the navaraViews map

What only one engine has now travels with the engine instead of a
WeakMap in navaraMode.js: engine.extensions.navara holds Navara's view,
its SDK classes and the daylight reset, engine.extensions.cesium the
Cesium viewer. The contract documents the field as outside the contract,
and the coupling report counts its reads outside src/globe in place of
the navaraViews reads (27, unchanged).
This commit is contained in:
German Khokhlov committed 2026-11-07 01:28:51 +04:00
1 parent 2213be6566
commit 48988015f1
6 files changed
+61 -47

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@
"viewerLines": 2424, "viewerLines": 2424,
"navaraKindChecks": 17, "navaraKindChecks": 17,
"engineSniffCalls": 51, "engineSniffCalls": 51,
"navaraViewsReads": 27, "engineExtensionReads": 27,
"groundEffectPasses": 9, "groundEffectPasses": 9,
"cesiumSdkLoads": 6, "cesiumSdkLoads": 6,
"screenSpaceHandlerFiles": 20, "screenSpaceHandlerFiles": 20,
+5 -4
View File
@@ -103,13 +103,14 @@ export const ENGINE_COUPLING_METRICS = Object.freeze([
), ),
}, },
{ {
id: 'navaraViewsReads', id: 'engineExtensionReads',
label: 'Raw Navara reads through navaraViews', label: 'Reads of engine.extensions (cesium, navara) outside src/globe',
measure: (files) => measure: (files) =>
files files
.filter(({ file }) => !inEngine(file)) .filter(({ file }) => !inGlobe(file))
.reduce( .reduce(
(sum, { text }) => sum + countMatches(text, /\bnavaraViews\.get\(/), (sum, { text }) =>
sum + countMatches(text, /\bextensions\??\.(?:navara|cesium)\b/),
0, 0,
), ),
}, },
+31 -42
View File
@@ -26,9 +26,6 @@ import {
} from './navaraTools.js'; } from './navaraTools.js';
import { createRecentImageryPanel } from '../ui/recentImagery.js'; import { createRecentImageryPanel } from '../ui/recentImagery.js';
// Native mesh capability stays at the composition boundary.
const navaraViews = new WeakMap();
/** /**
* An imported file's data source drawn on `engine` (UTILITIES ▸ Import); the * An imported file's data source drawn on `engine` (UTILITIES ▸ Import); the
* drawing loads on first use, like the layers' Navara renderers. * drawing loads on first use, like the layers' Navara renderers.
@@ -37,7 +34,7 @@ async function drawImported(engine, dataSource) {
const { drawImportedSource, measureImportImages } = const { drawImportedSource, measureImportImages } =
await import('../layers/shared/render/navaraStory.js'); await import('../layers/shared/render/navaraStory.js');
const sizes = await measureImportImages(dataSource); const sizes = await measureImportImages(dataSource);
return drawImportedSource(engine, navaraViews.get(engine), dataSource, { return drawImportedSource(engine, engine.extensions.navara, dataSource, {
sizes, sizes,
}); });
} }
@@ -102,7 +99,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createRecentImageryNavaraRenderer(engine, { createRecentImageryNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
transit: async () => { transit: async () => {
@@ -111,7 +108,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createTransitNavaraRenderer(engine, { createTransitNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
cctv: async () => { cctv: async () => {
@@ -120,7 +117,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createCctvNavaraRenderer(engine, { createCctvNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
'alpr-cameras': async () => 'alpr-cameras': async () =>
@@ -141,7 +138,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createWeatherNavaraRenderer( createWeatherNavaraRenderer(
engine, engine,
navaraViews.get(engine), engine.extensions.navara,
options, options,
); );
}, },
@@ -151,42 +148,42 @@ export async function registerNavaraLayerRenderers() {
const { createNepalEventDisplay } = const { createNepalEventDisplay } =
await import('../layers/bhoteKoshi/render/navara.js'); await import('../layers/bhoteKoshi/render/navara.js');
return (engine) => return (engine) =>
createNepalEventDisplay(engine, navaraViews.get(engine)); createNepalEventDisplay(engine, engine.extensions.navara);
}, },
'bhote-koshi-locator': async () => { 'bhote-koshi-locator': async () => {
const { drawStorySource } = const { drawStorySource } =
await import('../layers/shared/render/navaraStory.js'); await import('../layers/shared/render/navaraStory.js');
return (engine, { data }) => return (engine, { data }) =>
drawStorySource(engine, navaraViews.get(engine), data); drawStorySource(engine, engine.extensions.navara, data);
}, },
'street-level': async () => { 'street-level': async () => {
const { createStreetMap } = const { createStreetMap } =
await import('../layers/streetLevel/render/navara.js'); await import('../layers/streetLevel/render/navara.js');
return (engine) => createStreetMap(engine, navaraViews.get(engine)); return (engine) => createStreetMap(engine, engine.extensions.navara);
}, },
traffic: async () => { traffic: async () => {
const { createTrafficNavaraRenderer } = const { createTrafficNavaraRenderer } =
await import('../layers/traffic/render/navara.js'); await import('../layers/traffic/render/navara.js');
return (engine) => return (engine) =>
createTrafficNavaraRenderer(engine, navaraViews.get(engine)); createTrafficNavaraRenderer(engine, engine.extensions.navara);
}, },
directions: async () => { directions: async () => {
const { createDirectionsNavaraRenderer } = const { createDirectionsNavaraRenderer } =
await import('../layers/directions/render/navara.js'); await import('../layers/directions/render/navara.js');
return (engine) => return (engine) =>
createDirectionsNavaraRenderer(engine, navaraViews.get(engine)); createDirectionsNavaraRenderer(engine, engine.extensions.navara);
}, },
'telegeography-submarine-cables': async () => { 'telegeography-submarine-cables': async () => {
const { createNavaraCables } = const { createNavaraCables } =
await import('../layers/submarineCables/render/navara.js'); await import('../layers/submarineCables/render/navara.js');
return (engine, { overlayHost }) => return (engine, { overlayHost }) =>
createNavaraCables(engine, navaraViews.get(engine), overlayHost); createNavaraCables(engine, engine.extensions.navara, overlayHost);
}, },
wind: async () => { wind: async () => {
const { createWindNavaraRenderer } = const { createWindNavaraRenderer } =
await import('../layers/wind/render/navara.js'); await import('../layers/wind/render/navara.js');
return (engine) => return (engine) =>
createWindNavaraRenderer(engine, navaraViews.get(engine)); createWindNavaraRenderer(engine, engine.extensions.navara);
}, },
'weather-cyclones': async () => { 'weather-cyclones': async () => {
const { createCyclonesNavaraRenderer } = const { createCyclonesNavaraRenderer } =
@@ -194,7 +191,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createCyclonesNavaraRenderer( createCyclonesNavaraRenderer(
engine, engine,
navaraViews.get(engine).view, engine.extensions.navara.view,
options, options,
); );
}, },
@@ -207,7 +204,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, { config, services }) => return (engine, { config, services }) =>
createInfrastructureNavaraRenderer( createInfrastructureNavaraRenderer(
engine, engine,
navaraViews.get(engine), engine.extensions.navara,
config, config,
services, services,
); );
@@ -218,13 +215,13 @@ export async function registerNavaraLayerRenderers() {
const { createGhostMapsNavaraRenderer } = const { createGhostMapsNavaraRenderer } =
await import('../layers/ghostMaps/render/navara.js'); await import('../layers/ghostMaps/render/navara.js');
return (engine) => return (engine) =>
createGhostMapsNavaraRenderer(engine, navaraViews.get(engine).view); createGhostMapsNavaraRenderer(engine, engine.extensions.navara.view);
}, },
'military-awareness': async () => { 'military-awareness': async () => {
const { createAwarenessNavaraRenderer } = const { createAwarenessNavaraRenderer } =
await import('../layers/awareness/render/navara.js'); await import('../layers/awareness/render/navara.js');
return (engine) => return (engine) =>
createAwarenessNavaraRenderer(engine, navaraViews.get(engine)); createAwarenessNavaraRenderer(engine, engine.extensions.navara);
}, },
'military-installations': async () => { 'military-installations': async () => {
const { createInstallationsNavaraRenderer } = const { createInstallationsNavaraRenderer } =
@@ -232,7 +229,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createInstallationsNavaraRenderer(engine, { createInstallationsNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
'local-firms': async () => { 'local-firms': async () => {
@@ -241,7 +238,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createFirmsNavaraRenderer(engine, { createFirmsNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
'osm-places': async () => 'osm-places': async () =>
@@ -251,25 +248,25 @@ export async function registerNavaraLayerRenderers() {
const { createDroneAirspaceNavaraRenderer } = const { createDroneAirspaceNavaraRenderer } =
await import('../layers/droneAirspace/render/navara.js'); await import('../layers/droneAirspace/render/navara.js');
return (engine) => return (engine) =>
createDroneAirspaceNavaraRenderer(engine, navaraViews.get(engine)); createDroneAirspaceNavaraRenderer(engine, engine.extensions.navara);
}, },
'fire-perimeters': async () => { 'fire-perimeters': async () => {
const { createPerimetersNavaraRenderer } = const { createPerimetersNavaraRenderer } =
await import('../layers/perimeters/render/navara.js'); await import('../layers/perimeters/render/navara.js');
return (engine) => return (engine) =>
createPerimetersNavaraRenderer(engine, navaraViews.get(engine)); createPerimetersNavaraRenderer(engine, engine.extensions.navara);
}, },
'gnss-integrity': async () => { 'gnss-integrity': async () => {
const { createGnssNavaraRenderer } = const { createGnssNavaraRenderer } =
await import('../layers/gnss/render/navara.js'); await import('../layers/gnss/render/navara.js');
return (engine) => return (engine) =>
createGnssNavaraRenderer(engine, navaraViews.get(engine)); createGnssNavaraRenderer(engine, engine.extensions.navara);
}, },
'air-quality': async () => { 'air-quality': async () => {
const { createAirQualityNavaraRenderer } = const { createAirQualityNavaraRenderer } =
await import('../layers/airQuality/render/navara.js'); await import('../layers/airQuality/render/navara.js');
return (engine) => return (engine) =>
createAirQualityNavaraRenderer(engine, navaraViews.get(engine)); createAirQualityNavaraRenderer(engine, engine.extensions.navara);
}, },
earthquakes: async () => { earthquakes: async () => {
const { createEarthquakesNavaraRenderer } = const { createEarthquakesNavaraRenderer } =
@@ -277,7 +274,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createEarthquakesNavaraRenderer(engine, { createEarthquakesNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
'rocket-launches': async () => { 'rocket-launches': async () => {
@@ -286,7 +283,7 @@ export async function registerNavaraLayerRenderers() {
return (engine, options) => return (engine, options) =>
createLaunchesNavaraRenderer(engine, { createLaunchesNavaraRenderer(engine, {
...options, ...options,
...navaraViews.get(engine), ...engine.extensions.navara,
}); });
}, },
satellites: async () => satellites: async () =>
@@ -352,17 +349,6 @@ export async function createNavaraScene({
}); });
defer(() => globe.destroy()); defer(() => globe.destroy());
const { engine } = globe; const { engine } = globe;
navaraViews.set(engine, {
view: globe.view,
alignDaylightToRestoredView: globe.alignDaylightToRestoredView,
MeshDesc: globe.MeshDesc,
NavaraColor: globe.NavaraColor,
EffectDesc: globe.LayerEffectDesc,
NavaraEffect: globe.NavaraEffect,
DrapedMesh: globe.DrapedMesh,
setupMaterialForDrape: globe.setupMaterialForDrape,
});
defer(() => navaraViews.delete(engine));
// The layers drawn on Navara (their render/navara.js), before the catalog // The layers drawn on Navara (their render/navara.js), before the catalog
// asks the registry which layers this engine shows. // asks the registry which layers this engine shows.
await registerNavaraLayerRenderers(); await registerNavaraLayerRenderers();
@@ -400,7 +386,7 @@ export async function createNavaraScene({
const packGraphics = () => const packGraphics = () =>
(packRenderer ??= createNavaraPackRenderer( (packRenderer ??= createNavaraPackRenderer(
engine, engine,
navaraViews.get(engine), engine.extensions.navara,
)); ));
return { return {
viewer: null, viewer: null,
@@ -446,8 +432,7 @@ export function attachViewerlessTools(
) { ) {
const { dataManager } = data; const { dataManager } = data;
void styleManager.initialRestorePromise?.then(() => { void styleManager.initialRestorePromise?.then(() => {
if (!signal.aborted) if (!signal.aborted) engine.extensions.navara.alignDaylightToRestoredView();
navaraViews.get(engine)?.alignDaylightToRestoredView?.();
}); });
const recentImagery = dataManager.layers.get('recent-imagery')?.module; const recentImagery = dataManager.layers.get('recent-imagery')?.module;
if (recentImagery) { if (recentImagery) {
@@ -500,7 +485,11 @@ export function attachViewerlessTools(
defer(() => styleManager._clearPersistentStatusNotice?.()); defer(() => styleManager._clearPersistentStatusNotice?.());
// The page session's annotation board, Draw and Import on this engine // The page session's annotation board, Draw and Import on this engine
// (src/app/navaraTools.js). // (src/app/navaraTools.js).
const tools = { engine, views: navaraViews.get(engine), mapStackController }; const tools = {
engine,
views: engine.extensions?.navara,
mapStackController,
};
const context = { const context = {
operations, operations,
placeSearch, placeSearch,
+2
View File
@@ -82,6 +82,8 @@ export function createCesiumEngine(viewer, options = {}) {
let destroyed = false; let destroyed = false;
return { return {
kind: 'cesium', kind: 'cesium',
// What only Cesium has, for code still written against the viewer.
extensions: Object.freeze({ cesium: Object.freeze({ viewer }) }),
host: { host: {
container: viewer.container, container: viewer.container,
canvas, canvas,
+5
View File
@@ -482,6 +482,11 @@
* @property {GlobeLines} lines The layers' dynamic polylines. * @property {GlobeLines} lines The layers' dynamic polylines.
* @property {() => void} destroy * @property {() => void} destroy
* @property {() => boolean} isDestroyed True once destroy() has run. * @property {() => boolean} isDestroyed True once destroy() has run.
* @property {{ cesium?: object, navara?: object }} [extensions]
* What only one engine has, under its kind: Cesium's Viewer, Navara's view
* and SDK classes. Not part of the contract: only code written against that
* engine reads it, and scripts/report-engine-coupling.mjs counts each read
* outside src/globe.
*/ */
export const ENGINE_KINDS = Object.freeze(['cesium', 'navara']); export const ENGINE_KINDS = Object.freeze(['cesium', 'navara']);
+17
View File
@@ -248,6 +248,23 @@ export async function createNavaraGlobe({ container, search, hd = false }) {
throw error; throw error;
} }
let destroyed = false; let destroyed = false;
// What only Navara has, for the code written against Navara itself (its
// layer renderers): the view, the SDK classes and the daylight reset.
engine.extensions = Object.freeze({
navara: Object.freeze({
view,
MeshDesc,
NavaraColor,
EffectDesc: layerEffectDesc(EffectDesc),
NavaraEffect,
DrapedMesh,
setupMaterialForDrape,
alignDaylightToRestoredView() {
look.resetDaylight();
engine.render.request('restored-daylight');
},
}),
});
return { return {
view, view,
engine, engine,