mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-13 06:42:23 +00:00
Merge commit '0ceee8df40b97c6c693e86a4443794cd4ed1ff35' into HEAD
This commit is contained in:
commit
f878efe22d
306 files changed
+39352
-1624
No files matched your search
@@ -679,6 +679,7 @@
|
||||
"src/voice/control.js",
|
||||
"src/voice/realtimeBackend.js",
|
||||
"src/voice/realtimeBackend.test.mjs",
|
||||
"src/voice/realtimeViewportPolicy.test.mjs",
|
||||
"src/agent/worldPacket.test.mjs",
|
||||
"src/voice/layerSummary.js",
|
||||
"src/app/sources.js",
|
||||
@@ -1230,6 +1231,7 @@
|
||||
"src/data/firmsIntensity.js",
|
||||
"src/data/firmsIntensity.test.mjs",
|
||||
"src/ui/layerPanel/RowSwitch.vue",
|
||||
"src/ui/layerPanel/RowRange.vue",
|
||||
"src/ui/layerPanel/RowSlider.vue",
|
||||
"src/sources/phaseTiming.test.mjs",
|
||||
"scripts/build-census-places.mjs",
|
||||
@@ -1284,6 +1286,13 @@
|
||||
"src/voice/panelLayout.js",
|
||||
"src/voice/textChat.js",
|
||||
"src/voice/textProtocol.js",
|
||||
"src/layers/shipwrecks/records.test.mjs",
|
||||
"src/layers/shipwrecks/cards.test.mjs",
|
||||
"src/layers/shipwrecks/eras.test.mjs",
|
||||
"src/layers/shipwrecks/period.test.mjs",
|
||||
"src/layers/shipwrecks/index.test.mjs",
|
||||
"src/layers/shipwrecks/source.test.mjs",
|
||||
"src/data/shipwrecksProxy.test.mjs",
|
||||
"src/app/sourceComposition.js",
|
||||
"src/app/sourceComposition.test.mjs",
|
||||
"src/data/dataCredits.js",
|
||||
@@ -1294,6 +1303,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"src/ui/views/panels/CockpitSignalList.vue",
|
||||
"src/ui/views/panels/CockpitUtilityControls.vue",
|
||||
"src/ui/cockpitBriefPages.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/ui/cockpitContextState.js",
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
@@ -73,6 +74,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -507,6 +509,7 @@
|
||||
"server/providers/regional/weather-effects.js",
|
||||
"server/providers/regional/weather.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/geoDistance.js",
|
||||
"src/nominatimGeocode.js",
|
||||
"src/sources/httpBody.js",
|
||||
@@ -529,6 +532,32 @@
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"news-provider": {
|
||||
"runtime": "node",
|
||||
"exports": ["./server/providers/news"],
|
||||
"modules": [
|
||||
"server/providers/news.js",
|
||||
"server/providers/news/keyed.js",
|
||||
"server/providers/news/categorize.js",
|
||||
"server/providers/news/areas.js",
|
||||
"server/providers/news/gdeltEvents.js",
|
||||
"server/providers/news/upstream.js",
|
||||
"server/providers/common/http.js",
|
||||
"server/providers/common/same-site.js",
|
||||
"src/data/adminBoundaries.js",
|
||||
"src/data/bundledJson.js",
|
||||
"src/data/retryableLoad.js",
|
||||
"src/data/local_data/natural_earth/countries.json",
|
||||
"src/data/local_data/natural_earth/disputed_areas.json",
|
||||
"src/layers/news/source.js",
|
||||
"src/layers/news/records.js",
|
||||
"src/localRequestGate.mjs",
|
||||
"src/sources/httpBody.js",
|
||||
"src/sources/capability.js",
|
||||
"src/i18n/marker.js"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"openai-provider": {
|
||||
"runtime": "node",
|
||||
"exports": ["./server/providers/openai"],
|
||||
@@ -607,6 +636,7 @@
|
||||
"src/search/nominatim.js",
|
||||
"src/nominatimGeocode.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/geoDistance.js",
|
||||
"src/data/naturalEarthRegions.js",
|
||||
"src/data/bundledJson.js",
|
||||
@@ -656,6 +686,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -704,6 +735,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -730,6 +762,7 @@
|
||||
"src/ui/rail/focusSafeChildren.js",
|
||||
"src/ui/layerPanel/RowText.vue",
|
||||
"src/ui/layerPanel/RowSwitch.vue",
|
||||
"src/ui/layerPanel/RowRange.vue",
|
||||
"src/ui/layerPanel/RowSlider.vue",
|
||||
"src/ui/railTimeline.js",
|
||||
"src/ui/clearLayersControl.js",
|
||||
@@ -745,6 +778,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -765,6 +799,11 @@
|
||||
"src/ui/rail/RailTimeline.vue",
|
||||
"src/ui/rail/rangeValue.js",
|
||||
"src/ui/weather/WeatherReadout.vue",
|
||||
"src/ui/newsPanel.js",
|
||||
"src/ui/news/NewsFeed.vue",
|
||||
"src/ui/news/NewsCard.vue",
|
||||
"src/ui/kit/UiEmpty.vue",
|
||||
"src/ui/kit/UiSelect.js",
|
||||
"src/ui/kit/UiButton.vue",
|
||||
"src/ui/kit/UiBadge.vue",
|
||||
"src/ui/rail/fieldValue.js",
|
||||
@@ -788,6 +827,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -815,6 +855,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -845,6 +886,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -882,6 +924,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -906,6 +949,7 @@
|
||||
"src/ui/cockpit.js",
|
||||
"src/ui/cockpitBriefing.js",
|
||||
"src/ui/cockpitBriefPages.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/ui/cockpitContextState.js",
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
@@ -951,6 +995,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -978,6 +1023,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1065,6 +1111,7 @@
|
||||
"src/ui/cockpit.js",
|
||||
"src/ui/cockpitBriefing.js",
|
||||
"src/ui/cockpitBriefPages.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/ui/cockpitContextState.js",
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
@@ -1116,6 +1163,7 @@
|
||||
"src/ui/rail/focusSafeChildren.js",
|
||||
"src/ui/layerPanel/RowText.vue",
|
||||
"src/ui/layerPanel/RowSwitch.vue",
|
||||
"src/ui/layerPanel/RowRange.vue",
|
||||
"src/ui/layerPanel/RowSlider.vue",
|
||||
"src/ui/railTimeline.js",
|
||||
"src/ui/layers.js",
|
||||
@@ -1180,6 +1228,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1213,6 +1262,11 @@
|
||||
"src/ui/rail/RailTimeline.vue",
|
||||
"src/ui/rail/rangeValue.js",
|
||||
"src/ui/weather/WeatherReadout.vue",
|
||||
"src/ui/newsPanel.js",
|
||||
"src/ui/news/NewsFeed.vue",
|
||||
"src/ui/news/NewsCard.vue",
|
||||
"src/ui/kit/UiEmpty.vue",
|
||||
"src/ui/kit/UiSelect.js",
|
||||
"src/ui/stores/streetLevel.js",
|
||||
"src/ui/stores/cctv.js",
|
||||
"src/ui/stores/radio.js",
|
||||
@@ -1283,6 +1337,7 @@
|
||||
"src/ui/styles/first-run.css",
|
||||
"src/ui/styles/provider-settings.css",
|
||||
"src/ui/styles/weather.css",
|
||||
"src/ui/styles/news.css",
|
||||
"src/ui/styles/recent-imagery.css"
|
||||
],
|
||||
"external": []
|
||||
@@ -1372,6 +1427,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1447,7 +1503,11 @@
|
||||
"src/layers/flights/state.js",
|
||||
"src/layers/flights/testing.js",
|
||||
"src/layers/flights/tracking.js",
|
||||
"src/data/trailContinuity.js",
|
||||
"src/layers/flights/records.js",
|
||||
"src/layers/flights/clockFollow.js",
|
||||
"src/time/snapshotTimeline.js",
|
||||
"src/sources/live/contract.js",
|
||||
"src/layers/flights/recordPolicy.js",
|
||||
"src/layers/flights/snapshotRenderer.js",
|
||||
"src/layers/flights/modelSpec.js",
|
||||
@@ -1459,6 +1519,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1502,6 +1563,9 @@
|
||||
"src/layers/military/controller.js",
|
||||
"src/layers/military/index.js",
|
||||
"src/layers/military/ingestion.js",
|
||||
"src/layers/military/clockFollow.js",
|
||||
"src/time/snapshotTimeline.js",
|
||||
"src/sources/live/contract.js",
|
||||
"src/layers/military/lifecycle.js",
|
||||
"src/layers/military/motion.js",
|
||||
"src/layers/military/policy.js",
|
||||
@@ -1510,6 +1574,7 @@
|
||||
"src/layers/military/state.js",
|
||||
"src/layers/military/testing.js",
|
||||
"src/layers/military/tracking.js",
|
||||
"src/data/trailContinuity.js",
|
||||
"src/layers/military/records.js",
|
||||
"src/layers/military/recordPolicy.js",
|
||||
"src/layers/military/snapshotRenderer.js",
|
||||
@@ -1521,6 +1586,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1528,6 +1594,7 @@
|
||||
"src/i18n/locales/uk.json",
|
||||
"src/i18n/locales/zh-CN.json",
|
||||
"src/i18n/locales/zh-Hant.json",
|
||||
"src/ui/unitLabels.js",
|
||||
"src/time/worldClock.js",
|
||||
"src/time/julian.js"
|
||||
],
|
||||
@@ -1573,6 +1640,10 @@
|
||||
"src/layers/vessels/evidence.js",
|
||||
"src/layers/vessels/index.js",
|
||||
"src/layers/vessels/ingestion.js",
|
||||
"src/layers/vessels/motion.js",
|
||||
"src/time/snapshotTimeline.js",
|
||||
"src/time/worldClock.js",
|
||||
"src/sources/live/contract.js",
|
||||
"src/layers/vessels/cameraArea.js",
|
||||
"src/layers/vessels/viewArea.js",
|
||||
"src/layers/vessels/lifecycle.js",
|
||||
@@ -1598,6 +1669,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1635,6 +1707,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1676,6 +1749,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1716,6 +1790,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1764,6 +1839,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1816,6 +1892,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1863,6 +1940,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1926,6 +2004,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -1963,6 +2042,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2020,6 +2100,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2092,6 +2173,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2133,6 +2215,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2183,6 +2266,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2213,6 +2297,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2277,6 +2362,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2355,6 +2441,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -2523,8 +2610,10 @@
|
||||
"src/data/detectionCohort.js",
|
||||
"src/data/detectionDraw.js",
|
||||
"src/data/detectionPolicy.js",
|
||||
"src/data/detectionOcclusion.js",
|
||||
"src/data/detectionPresentation.js",
|
||||
"src/data/detectionRenderDemand.js",
|
||||
"src/data/sceneOcclusionProbe.js",
|
||||
"src/data/earthquakes.js",
|
||||
"src/data/fireAnchors.js",
|
||||
"src/data/firmsAdapt.js",
|
||||
@@ -2603,6 +2692,7 @@
|
||||
"src/data/trafficPresetStyle.js",
|
||||
"src/data/trafficQueue.js",
|
||||
"src/data/trailRenderer.js",
|
||||
"src/data/trailContinuity.js",
|
||||
"src/data/vesselLabels.js",
|
||||
"src/data/vesselTypes.js",
|
||||
"src/firstRunExperience.js",
|
||||
@@ -2703,6 +2793,8 @@
|
||||
"src/layers/flights/enrichment.js",
|
||||
"src/layers/flights/evidence.js",
|
||||
"src/layers/flights/index.js",
|
||||
"src/layers/flights/clockFollow.js",
|
||||
"src/time/snapshotTimeline.js",
|
||||
"src/layers/flights/ingestion.js",
|
||||
"src/layers/flights/lifecycle.js",
|
||||
"src/layers/flights/motion.js",
|
||||
@@ -2744,6 +2836,7 @@
|
||||
"src/layers/launches/testing.js",
|
||||
"src/layers/military/controller.js",
|
||||
"src/layers/military/index.js",
|
||||
"src/layers/military/clockFollow.js",
|
||||
"src/layers/military/ingestion.js",
|
||||
"src/layers/military/lifecycle.js",
|
||||
"src/layers/military/motion.js",
|
||||
@@ -2826,6 +2919,7 @@
|
||||
"src/layers/vessels/cards.js",
|
||||
"src/layers/vessels/evidence.js",
|
||||
"src/layers/vessels/index.js",
|
||||
"src/layers/vessels/motion.js",
|
||||
"src/layers/vessels/cameraArea.js",
|
||||
"src/layers/vessels/ingestion.js",
|
||||
"src/layers/vessels/viewArea.js",
|
||||
@@ -2922,6 +3016,7 @@
|
||||
"src/ui/cockpit.js",
|
||||
"src/ui/cockpitBriefing.js",
|
||||
"src/ui/cockpitBriefPages.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/ui/cockpitContextState.js",
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
@@ -2968,6 +3063,7 @@
|
||||
"src/ui/rail/focusSafeChildren.js",
|
||||
"src/ui/layerPanel/RowText.vue",
|
||||
"src/ui/layerPanel/RowSwitch.vue",
|
||||
"src/ui/layerPanel/RowRange.vue",
|
||||
"src/ui/layerPanel/RowSlider.vue",
|
||||
"src/ui/railTimeline.js",
|
||||
"src/ui/layers.js",
|
||||
@@ -3097,11 +3193,25 @@
|
||||
"src/layers/ghostMaps/records.js",
|
||||
"src/layers/ghostMaps/kml.js",
|
||||
"src/layers/ghostMaps/source.js",
|
||||
"src/app/layers/shipwrecks.js",
|
||||
"src/layers/shipwrecks/index.js",
|
||||
"src/layers/shipwrecks/source.js",
|
||||
"src/layers/shipwrecks/records.js",
|
||||
"src/layers/shipwrecks/cards.js",
|
||||
"src/layers/shipwrecks/eras.js",
|
||||
"src/layers/shipwrecks/period.js",
|
||||
"src/app/layers/droneAirspace.js",
|
||||
"src/layers/droneAirspace/index.js",
|
||||
"src/layers/droneAirspace/source.js",
|
||||
"src/layers/droneAirspace/records.js",
|
||||
"src/layers/droneAirspace/cards.js",
|
||||
"src/app/layers/news.js",
|
||||
"src/layers/news/index.js",
|
||||
"src/layers/news/model.js",
|
||||
"src/layers/news/records.js",
|
||||
"src/layers/news/source.js",
|
||||
"src/layers/news/sprites.js",
|
||||
"src/layers/news/cards.js",
|
||||
"src/layers/cctv/sourcePolicy.js",
|
||||
"src/sources/reference.js",
|
||||
"src/search/nominatim.js",
|
||||
@@ -3305,6 +3415,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -3354,6 +3465,10 @@
|
||||
"src/ui/rail/RailTimeline.vue",
|
||||
"src/ui/rail/rangeValue.js",
|
||||
"src/ui/weather/WeatherReadout.vue",
|
||||
"src/ui/newsPanel.js",
|
||||
"src/ui/news/NewsFeed.vue",
|
||||
"src/ui/news/NewsCard.vue",
|
||||
"src/ui/kit/UiSelect.js",
|
||||
"src/ui/recentImagery/RecentImageryCard.vue",
|
||||
"src/ui/recentImagery/RecentImageryReadout.vue",
|
||||
"src/ui/stores/streetLevel.js",
|
||||
@@ -3601,6 +3716,7 @@
|
||||
"src/data/trafficPresetStyle.js",
|
||||
"src/data/trafficQueue.js",
|
||||
"src/data/trailRenderer.js",
|
||||
"src/data/trailContinuity.js",
|
||||
"src/data/vesselLabels.js",
|
||||
"src/data/vesselTypes.js",
|
||||
"src/keylessGeocoder.js",
|
||||
@@ -3691,6 +3807,9 @@
|
||||
"src/layers/flights/enrichment.js",
|
||||
"src/layers/flights/evidence.js",
|
||||
"src/layers/flights/index.js",
|
||||
"src/layers/flights/clockFollow.js",
|
||||
"src/time/snapshotTimeline.js",
|
||||
"src/sources/live/contract.js",
|
||||
"src/layers/flights/ingestion.js",
|
||||
"src/layers/flights/lifecycle.js",
|
||||
"src/layers/flights/motion.js",
|
||||
@@ -3732,6 +3851,7 @@
|
||||
"src/layers/launches/testing.js",
|
||||
"src/layers/military/controller.js",
|
||||
"src/layers/military/index.js",
|
||||
"src/layers/military/clockFollow.js",
|
||||
"src/layers/military/ingestion.js",
|
||||
"src/layers/military/lifecycle.js",
|
||||
"src/layers/military/motion.js",
|
||||
@@ -3813,6 +3933,7 @@
|
||||
"src/layers/vessels/cards.js",
|
||||
"src/layers/vessels/evidence.js",
|
||||
"src/layers/vessels/index.js",
|
||||
"src/layers/vessels/motion.js",
|
||||
"src/layers/vessels/cameraArea.js",
|
||||
"src/layers/vessels/ingestion.js",
|
||||
"src/layers/vessels/viewArea.js",
|
||||
@@ -3893,15 +4014,30 @@
|
||||
"src/layers/ghostMaps/records.js",
|
||||
"src/layers/ghostMaps/kml.js",
|
||||
"src/layers/ghostMaps/source.js",
|
||||
"src/app/layers/shipwrecks.js",
|
||||
"src/layers/shipwrecks/index.js",
|
||||
"src/layers/shipwrecks/source.js",
|
||||
"src/layers/shipwrecks/records.js",
|
||||
"src/layers/shipwrecks/cards.js",
|
||||
"src/layers/shipwrecks/eras.js",
|
||||
"src/layers/shipwrecks/period.js",
|
||||
"src/app/layers/droneAirspace.js",
|
||||
"src/layers/droneAirspace/index.js",
|
||||
"src/layers/droneAirspace/source.js",
|
||||
"src/layers/droneAirspace/records.js",
|
||||
"src/layers/droneAirspace/cards.js",
|
||||
"src/app/layers/news.js",
|
||||
"src/layers/news/index.js",
|
||||
"src/layers/news/model.js",
|
||||
"src/layers/news/records.js",
|
||||
"src/layers/news/source.js",
|
||||
"src/layers/news/sprites.js",
|
||||
"src/layers/news/cards.js",
|
||||
"src/layers/cctv/sourcePolicy.js",
|
||||
"src/search/nominatim.js",
|
||||
"src/nominatimGeocode.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
"src/sources/nominatim.js",
|
||||
@@ -3969,6 +4105,8 @@
|
||||
"src/data/detection.js",
|
||||
"src/data/detectionRenderDemand.js",
|
||||
"src/data/detectionPresentation.js",
|
||||
"src/data/detectionOcclusion.js",
|
||||
"src/data/sceneOcclusionProbe.js",
|
||||
"src/data/modelEligibility.js",
|
||||
"src/app/layers/recentImagery.js",
|
||||
"src/layers/recentImagery/index.js",
|
||||
@@ -4043,6 +4181,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4175,6 +4314,7 @@
|
||||
"src/search/nominatim.js",
|
||||
"src/nominatimGeocode.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
"src/sources/nominatim.js",
|
||||
@@ -4227,6 +4367,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4260,6 +4401,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4314,6 +4456,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4352,6 +4495,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4458,6 +4602,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4481,7 +4626,11 @@
|
||||
},
|
||||
"regional-source": {
|
||||
"exports": ["./sources/regional"],
|
||||
"modules": ["src/data/regionalModel.js", "src/geoDistance.js"],
|
||||
"modules": [
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/geoDistance.js"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"voice-action-schemas": {
|
||||
@@ -4531,6 +4680,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4690,6 +4840,7 @@
|
||||
"src/search/google.js",
|
||||
"src/search/geospatial.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/geoDistance.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
@@ -4714,6 +4865,7 @@
|
||||
"src/nominatimGeocode.js",
|
||||
"src/search/geospatial.js",
|
||||
"src/data/regionalModel.js",
|
||||
"src/data/regionalNewsWindow.js",
|
||||
"src/geoDistance.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js"
|
||||
@@ -4823,6 +4975,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4878,6 +5031,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4941,6 +5095,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -4965,6 +5120,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -5035,6 +5191,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -5059,6 +5216,17 @@
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"news-source": {
|
||||
"exports": ["./layers/news/source"],
|
||||
"modules": [
|
||||
"src/layers/news/source.js",
|
||||
"src/layers/news/records.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/sources/capability.js",
|
||||
"src/i18n/marker.js"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
"perimeters-source": {
|
||||
"exports": ["./layers/perimeters/source"],
|
||||
"modules": [
|
||||
@@ -5084,6 +5252,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -5291,6 +5460,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
@@ -5337,6 +5507,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Trail freeze gate: freezing a trail chunk never shows a blank frame.
|
||||
*
|
||||
* A tracked aircraft's trail is cut into chunks; every chunk but the newest
|
||||
* is frozen into static geometry, which Cesium builds asynchronously. Until
|
||||
* that geometry is in the scene, the chunk keeps being drawn dynamically.
|
||||
*
|
||||
* This gate drives the real app and a real Cesium scene: it draws a trail of
|
||||
* CHUNK_POINTS points (all dynamic), then adds one point so the first chunk
|
||||
* freezes, and on every rendered frame after that it checks two things:
|
||||
* 1. every frozen chunk is either still drawn by a dynamic polyline or its
|
||||
* static geometry is in the scene (DataSourceDisplay reports DONE);
|
||||
* 2. the number of trail-coloured pixels never drops below 90% of the
|
||||
* count measured just before the freeze.
|
||||
* It also checks that clearing the trail releases every chunk entity.
|
||||
*
|
||||
* The camera is held still while the gate runs.
|
||||
*
|
||||
* Needs a running dev server:
|
||||
* node scripts/qa-trail-freeze.mjs [--url http://localhost:4173]
|
||||
*/
|
||||
import puppeteer from 'puppeteer';
|
||||
import { chromeExecutablePath } from './qa-chrome.mjs';
|
||||
|
||||
const urlFlag = process.argv.indexOf('--url');
|
||||
const APP_URL =
|
||||
urlFlag > 0 ? process.argv[urlFlag + 1] : 'http://localhost:4173';
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: 'new',
|
||||
protocolTimeout: 300_000,
|
||||
executablePath: chromeExecutablePath(),
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--use-gl=angle',
|
||||
'--use-angle=swiftshader',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-renderer-backgrounding',
|
||||
'--window-size=960,640',
|
||||
],
|
||||
});
|
||||
|
||||
let failed = false;
|
||||
const report = (name, ok, detail) => {
|
||||
if (!ok) failed = true;
|
||||
console.log(
|
||||
` [${ok ? 'PASS' : 'FAIL'}] ${name}${detail ? ` — ${detail}` : ''}`,
|
||||
);
|
||||
};
|
||||
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await page.setViewport({ width: 960, height: 640 });
|
||||
await page.goto(APP_URL, { waitUntil: 'domcontentloaded', timeout: 120_000 });
|
||||
await page.waitForFunction(
|
||||
() =>
|
||||
window.__godsEyeView?.viewer &&
|
||||
document.getElementById('loading-screen')?.classList.contains('hidden'),
|
||||
{ timeout: 180_000 },
|
||||
);
|
||||
|
||||
const result = await page.evaluate(async () => {
|
||||
// The exact Cesium module the renderer uses, so classes are shared.
|
||||
const source = await (await fetch('/src/data/trailRenderer.js')).text();
|
||||
const cesiumUrl = source.match(/from\s+["']([^"']*cesium[^"']*)["']/)[1];
|
||||
const Cesium = await import(cesiumUrl);
|
||||
const { createTrail, CHUNK_POINTS } =
|
||||
await import('/src/data/trailRenderer.js');
|
||||
const viewer = window.__godsEyeView.viewer;
|
||||
const scene = viewer.scene;
|
||||
const nextFrame = () =>
|
||||
new Promise((resolve) => {
|
||||
const remove = scene.postRender.addEventListener(() => {
|
||||
remove();
|
||||
resolve();
|
||||
});
|
||||
scene.requestRender();
|
||||
});
|
||||
|
||||
// A line across the middle of the current view, in mid-air in front of
|
||||
// the camera, so terrain and buildings never hide it.
|
||||
viewer.camera.cancelFlight?.();
|
||||
const camera = viewer.camera;
|
||||
const ahead = Cesium.Cartesian3.add(
|
||||
camera.positionWC,
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
camera.directionWC,
|
||||
3_000,
|
||||
new Cesium.Cartesian3(),
|
||||
),
|
||||
new Cesium.Cartesian3(),
|
||||
);
|
||||
const points = Array.from({ length: CHUNK_POINTS + 1 }, (_, i) =>
|
||||
Cesium.Cartesian3.add(
|
||||
ahead,
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
camera.rightWC,
|
||||
-1_200 + (2_400 * i) / CHUNK_POINTS,
|
||||
new Cesium.Cartesian3(),
|
||||
),
|
||||
new Cesium.Cartesian3(),
|
||||
),
|
||||
);
|
||||
const added = [];
|
||||
const removed = [];
|
||||
const add = viewer.entities.add.bind(viewer.entities);
|
||||
const remove = viewer.entities.remove.bind(viewer.entities);
|
||||
viewer.entities.add = (definition) => {
|
||||
const entity = add(definition);
|
||||
if (String(entity.id).startsWith('gev-trail:')) added.push(entity);
|
||||
return entity;
|
||||
};
|
||||
viewer.entities.remove = (entity) => {
|
||||
if (String(entity?.id).startsWith('gev-trail:')) removed.push(entity);
|
||||
return remove(entity);
|
||||
};
|
||||
|
||||
const gl = scene.context._gl;
|
||||
const width = gl.drawingBufferWidth;
|
||||
const height = gl.drawingBufferHeight;
|
||||
const pixels = new Uint8Array(width * height * 4);
|
||||
// Magenta trail: count pixels that are clearly magenta.
|
||||
const countTrailPixels = () => {
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
let count = 0;
|
||||
for (let p = 0; p < pixels.length; p += 4) {
|
||||
const r = pixels[p];
|
||||
const g = pixels[p + 1];
|
||||
const b = pixels[p + 2];
|
||||
if (r > 150 && b > 150 && g < 110) count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
const trail = createTrail(viewer, { color: '#ff00ff', width: 8 });
|
||||
trail.setPositions(points.slice(0, CHUNK_POINTS));
|
||||
for (let i = 0; i < 20; i++) await nextFrame();
|
||||
const before = trail._chunksForTest();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
let lit = 0;
|
||||
for (let p = 0; p < pixels.length; p += 4)
|
||||
if (pixels[p] || pixels[p + 1] || pixels[p + 2]) lit++;
|
||||
const cam = viewer.camera.positionCartographic;
|
||||
const diagnostics = {
|
||||
lit,
|
||||
size: [width, height],
|
||||
camera: [
|
||||
Cesium.Math.toDegrees(cam.longitude),
|
||||
Cesium.Math.toDegrees(cam.latitude),
|
||||
cam.height,
|
||||
],
|
||||
preserveDrawingBuffer: gl.getContextAttributes().preserveDrawingBuffer,
|
||||
};
|
||||
let baseline = 0;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await nextFrame();
|
||||
baseline = Math.max(baseline, countTrailPixels());
|
||||
}
|
||||
|
||||
trail.setPositions(points);
|
||||
const frames = [];
|
||||
const sphere = new Cesium.BoundingSphere();
|
||||
let resolvedAt = null;
|
||||
for (let i = 0; i < 400; i++) {
|
||||
await nextFrame();
|
||||
const state = trail._chunksForTest();
|
||||
const covered = state.frozen.every(
|
||||
(chunk) =>
|
||||
chunk.standIn ||
|
||||
viewer.dataSourceDisplay.getBoundingSphere(
|
||||
chunk.entity,
|
||||
false,
|
||||
sphere,
|
||||
) === Cesium.BoundingSphereState.DONE,
|
||||
);
|
||||
frames.push({ covered, pixels: countTrailPixels() });
|
||||
if (resolvedAt == null && state.frozen.every((c) => !c.standIn))
|
||||
resolvedAt = i;
|
||||
if (resolvedAt != null && i > resolvedAt + 30) break;
|
||||
}
|
||||
|
||||
trail.clear();
|
||||
for (let i = 0; i < 3; i++) await nextFrame();
|
||||
const frozenAfterClear = trail._chunksForTest().frozen.length;
|
||||
trail.destroy();
|
||||
const leaked = added.filter((entity) => !removed.includes(entity)).length;
|
||||
viewer.entities.add = add;
|
||||
viewer.entities.remove = remove;
|
||||
return {
|
||||
chunkPoints: CHUNK_POINTS,
|
||||
diagnostics,
|
||||
frozenBefore: before.frozen.length,
|
||||
baseline,
|
||||
frames,
|
||||
resolvedAt,
|
||||
frozenAfterClear,
|
||||
entities: added.length,
|
||||
leaked,
|
||||
};
|
||||
});
|
||||
|
||||
if (process.env.GEV_TEST_VERBOSE)
|
||||
console.log(JSON.stringify(result.diagnostics));
|
||||
const minPixels = Math.min(...result.frames.map((frame) => frame.pixels));
|
||||
report(
|
||||
'the trail draws before the freeze',
|
||||
result.baseline > 200 && result.frozenBefore === 0,
|
||||
`baseline=${result.baseline} trail pixels, frozen chunks=${result.frozenBefore}`,
|
||||
);
|
||||
report(
|
||||
'the frozen chunk reaches the scene as static geometry',
|
||||
result.resolvedAt != null,
|
||||
`stand-in dropped after ${result.resolvedAt} frames`,
|
||||
);
|
||||
report(
|
||||
'every frame after the freeze draws the frozen chunk (dynamic copy or static geometry)',
|
||||
result.frames.every((frame) => frame.covered),
|
||||
`${result.frames.length} frames checked`,
|
||||
);
|
||||
report(
|
||||
'no blank frame: trail pixels never drop below 90% of the pre-freeze count',
|
||||
minPixels >= 0.9 * result.baseline,
|
||||
`min=${minPixels} baseline=${result.baseline}`,
|
||||
);
|
||||
report(
|
||||
'clearing and destroying release every trail entity',
|
||||
result.frozenAfterClear === 0 && result.leaked === 0,
|
||||
`entities created=${result.entities} leaked=${result.leaked}`,
|
||||
);
|
||||
} catch (error) {
|
||||
report('gate ran', false, error.message);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
console.log(failed ? 'RESULT: FAIL' : 'RESULT: PASS');
|
||||
process.exit(failed ? 1 : 0);
|
||||
@@ -801,7 +801,7 @@ try {
|
||||
);
|
||||
check(
|
||||
`${preset.name}: the icon raster cache stays bounded`,
|
||||
styling.iconCacheSize <= 6 * 2 * 3,
|
||||
styling.iconCacheSize <= 6 * 2 * 3 * 2,
|
||||
`${styling.iconCacheSize} rasters`,
|
||||
);
|
||||
}
|
||||
|
||||
+153
-21
@@ -42,8 +42,9 @@
|
||||
* and a real mouse click on the tracked plane is a
|
||||
* NO-OP (no deselect, no camera spike).
|
||||
* M3. AGE-OUT RELEASE — when the tracked plane's fixes stop arriving
|
||||
* (3 missed polls via the shim), tracking clears and
|
||||
* the camera is RELEASED IN PLACE: viewer.trackedEntity
|
||||
* it stays tracked (STALE, then SIGNAL LOST) until
|
||||
* 10 min after its newest fix; then tracking clears
|
||||
* and the camera is RELEASED IN PLACE: viewer.trackedEntity
|
||||
* undefined, NO jump (owner decision 2026-07-02 —
|
||||
* the old ~80 km overview flyTo is gone).
|
||||
*
|
||||
@@ -362,7 +363,12 @@ async function main() {
|
||||
'Synthetica', // 2 origin_country
|
||||
Math.floor(Date.now() / 1000), // 3 time_position
|
||||
Math.floor(Date.now() / 1000), // 4 last_contact
|
||||
f.lon, // 5 longitude
|
||||
// A plane given `moveFromMs` flies east at its reported speed
|
||||
// (the trail-head check needs a moving icon); others hold still.
|
||||
Number.isFinite(f.moveFromMs)
|
||||
? f.lon + (f.vel * (Date.now() - f.moveFromMs)) / 1000
|
||||
/ (111320 * Math.cos((f.lat * Math.PI) / 180))
|
||||
: f.lon, // 5 longitude
|
||||
f.lat, // 6 latitude
|
||||
f.alt, // 7 baro_altitude (m)
|
||||
f.onGround === true, // 8 on_ground (ground-traffic phase flips this live)
|
||||
@@ -1498,6 +1504,110 @@ async function main() {
|
||||
`max=${maxDelta.toFixed(3)} m over ${samples.length} frames (tol ${JITTER_TOL_M} m, mode=${modelUp ? 'model-matrix' : 'display-contract'})`);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// TRAIL HEAD ENDS AT THE DRAWN ICON, every rendered frame.
|
||||
// The head's last vertex is where the tracked plane is drawn (the
|
||||
// display position, or the model's tail anchor while the model is the
|
||||
// visual). getTrackedInfo reports the dead-reckoned position without
|
||||
// the brief post-report easing; its gap is logged, not asserted.
|
||||
// ============================================================
|
||||
console.log('\nTrail head — ends at the drawn icon on every frame');
|
||||
// The fixture planes repeat one position, so the icon holds and draws no
|
||||
// head. Fly the tracked one east for this check; the display runs 30 s
|
||||
// behind, so give it time to reach the moving reports.
|
||||
await evalPage((icao) => {
|
||||
const f = window.__SYNTH.flights.find((p) => p.icao === icao);
|
||||
f.moveFromMs = Date.now();
|
||||
}, trackedIcao);
|
||||
await sleep(55_000);
|
||||
const headSamples = await sampleFrames(page, 40, (icao) => {
|
||||
const viewer = window.__godsEyeView.viewer;
|
||||
const fl = window.__godsEyeView.dataManager.layers.get('flights').module;
|
||||
const ent = viewer.trackedEntity;
|
||||
const time = viewer.clock.currentTime;
|
||||
const head = viewer.entities.values.find((e) => String(e.id).startsWith('gev-trail:fl-head-'));
|
||||
const line = head?.polyline?.positions?.getValue(time);
|
||||
const drawn = ent?.position?.getValue(time);
|
||||
if (!line?.length || !drawn) return null;
|
||||
const end = line[line.length - 1];
|
||||
const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
const ti = fl.getTrackedInfo();
|
||||
let infoGap = null;
|
||||
if (ti && ti.icao24 === icao) {
|
||||
// WGS84 lat/lon → ECEF on the ellipsoid; the angle at the centre to
|
||||
// the drawn position, times the mean radius, is the ground gap.
|
||||
const a = 6378137, e2 = 6.69437999014e-3;
|
||||
const lat = (ti.latitude * Math.PI) / 180, lon = (ti.longitude * Math.PI) / 180;
|
||||
const n = a / Math.sqrt(1 - e2 * Math.sin(lat) ** 2);
|
||||
const p = {
|
||||
x: n * Math.cos(lat) * Math.cos(lon),
|
||||
y: n * Math.cos(lat) * Math.sin(lon),
|
||||
z: n * (1 - e2) * Math.sin(lat),
|
||||
};
|
||||
const dot = p.x * drawn.x + p.y * drawn.y + p.z * drawn.z;
|
||||
const cos = dot / (Math.hypot(p.x, p.y, p.z) * Math.hypot(drawn.x, drawn.y, drawn.z));
|
||||
infoGap = 6371008.8 * Math.acos(Math.min(1, cos));
|
||||
}
|
||||
// While the 3D model is the visual the head ends at the model's tail
|
||||
// anchor, which sits on the drawn (pixel-size-enlarged) model.
|
||||
const model = window.__findTrackedModel ? window.__findTrackedModel() : null;
|
||||
const sphere = model && model.ready && model.show ? model.boundingSphere : null;
|
||||
// boundingSphere leaves out the minimum-pixel-size enlargement that
|
||||
// computedScale carries; the drawn model is that much larger.
|
||||
const enlarge = sphere && Number.isFinite(model.computedScale) && model.scale > 0
|
||||
? Math.max(1, model.computedScale / model.scale)
|
||||
: 1;
|
||||
const radius = sphere ? sphere.radius * enlarge : null;
|
||||
return {
|
||||
end: dist(end, drawn),
|
||||
onModel: sphere ? dist(end, sphere.center) <= radius + 50 : false,
|
||||
modelRadius: radius,
|
||||
infoGap,
|
||||
vertices: line.length,
|
||||
};
|
||||
}, trackedIcao);
|
||||
// The same reading between frames, the way a page script polls it: the
|
||||
// head holds the last rendered frame while getTrackedInfo dead-reckons
|
||||
// the current instant. Logged only, to tell the two apart.
|
||||
const betweenFrames = [];
|
||||
for (let i = 0; i < 8; i++) {
|
||||
await sleep(600);
|
||||
betweenFrames.push(await evalPage((icao) => {
|
||||
const viewer = window.__godsEyeView.viewer;
|
||||
const head = viewer.entities.values.find((e) => String(e.id).startsWith('gev-trail:fl-head-'));
|
||||
const line = head?.polyline?.positions?.getValue(viewer.clock.currentTime);
|
||||
const drawn = viewer.trackedEntity?.position?.getValue(viewer.clock.currentTime);
|
||||
if (!line?.length || !drawn) return null;
|
||||
const end = line[line.length - 1];
|
||||
return Math.hypot(end.x - drawn.x, end.y - drawn.y, end.z - drawn.z);
|
||||
}, trackedIcao));
|
||||
}
|
||||
console.log(` (between frames: head end vs entity position, m: ${
|
||||
betweenFrames.map((v) => (v == null ? '-' : v.toFixed(1))).join(' ')})`);
|
||||
// Freeze the plane where it got to, so later checks see a still contact.
|
||||
await evalPage((icao) => {
|
||||
const f = window.__SYNTH.flights.find((p) => p.icao === icao);
|
||||
f.lon += (f.vel * (Date.now() - f.moveFromMs)) / 1000
|
||||
/ (111320 * Math.cos((f.lat * Math.PI) / 180));
|
||||
delete f.moveFromMs;
|
||||
}, trackedIcao);
|
||||
const headUsable = headSamples.values.filter((v) => v != null);
|
||||
if (headUsable.length < 10) {
|
||||
skip('trail head: ends at the drawn icon on every frame',
|
||||
`only ${headUsable.length} frames with a drawn head (timedOut=${headSamples.timedOut})`);
|
||||
} else {
|
||||
const worst = Math.max(...headUsable.map((v) => v.end));
|
||||
const off = headUsable.filter((v) => !(v.end <= 50 || v.onModel));
|
||||
const onModel = headUsable.filter((v) => v.end > 50 && v.onModel).length;
|
||||
const radii = headUsable.map((v) => v.modelRadius).filter((v) => v != null);
|
||||
const gaps = headUsable.map((v) => v.infoGap).filter((v) => v != null);
|
||||
record('trail head: last vertex on the drawn icon (within 50 m, or on the drawn 3D model) on every frame',
|
||||
off.length === 0,
|
||||
`${off.length} of ${headUsable.length} frames off; max end-to-centre=${worst.toFixed(1)} m, ${onModel} frames ending on the model's tail (model radius ${
|
||||
radii.length ? Math.max(...radii).toFixed(0) : 'n/a'} m); getTrackedInfo vs drawn icon max=${
|
||||
gaps.length ? Math.max(...gaps).toFixed(1) : 'n/a'} m (logged only)`);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// INVARIANT 2: NO PULL-OUT on a track switch
|
||||
// tracking B while tracking A must not fly to ~80 km overview.
|
||||
@@ -1744,7 +1854,8 @@ async function main() {
|
||||
|
||||
// ============================================================
|
||||
// REGRESSION M3 (rewritten 2026-07-02 — deliberate behavior change):
|
||||
// when the TRACKED plane ages out (3 missed polls), tracking must clear
|
||||
// when the TRACKED plane ages out (10 min after its newest fix, past the
|
||||
// 3 missed polls that remove an untracked plane), tracking must clear
|
||||
// and the camera must be RELEASED IN PLACE — viewer.trackedEntity
|
||||
// undefined and NO jump (the old contract flew an ~80 km overview; the
|
||||
// owner field-ruled that wrong: "it randomly zooms way up and loses my
|
||||
@@ -1765,27 +1876,48 @@ async function main() {
|
||||
const beforeTracking = !!fl.getTrackedInfo();
|
||||
// Simulate the age-out via the shim: the plane stops arriving.
|
||||
window.__SYNTH.flights = window.__SYNTH.flights.filter((f) => f.icao !== icao);
|
||||
// MISSING_POLL_LIMIT = 3 consecutive absent polls → removal + clear.
|
||||
// Capture the camera pose right BEFORE the removing poll — the follow
|
||||
// camera drifts with the coasting plane until the instant of release,
|
||||
// so this is the "where the user was looking" reference.
|
||||
// The tracked plane outlives MISSING_POLL_LIMIT (3 absent polls): it is
|
||||
// kept until 10 min after its newest fix, so the camera keeps its target.
|
||||
await fl.update(v);
|
||||
await fl.update(v);
|
||||
const c0 = v.camera.positionCartographic;
|
||||
const atAgeOut = {
|
||||
lonDeg: (c0.longitude * 180) / Math.PI,
|
||||
latDeg: (c0.latitude * 180) / Math.PI,
|
||||
height: c0.height,
|
||||
};
|
||||
await fl.update(v); // third miss → removal + clear + in-place release
|
||||
return {
|
||||
beforeTracking,
|
||||
atAgeOut,
|
||||
stillTrackedAfter: !!fl.getTrackedInfo(),
|
||||
viewerStillTracking: !!v.trackedEntity,
|
||||
};
|
||||
await fl.update(v);
|
||||
const trackedThroughMisses = !!fl.getTrackedInfo();
|
||||
// Jump the page clock past the 10 min retention instead of waiting.
|
||||
const realNow = Date.now;
|
||||
Date.now = () => realNow() + 11 * 60 * 1000;
|
||||
try {
|
||||
// Let the follow camera settle on the stopped plane, then capture the
|
||||
// pose right BEFORE the removing poll: the "where the user was
|
||||
// looking" reference.
|
||||
await new Promise((res) => {
|
||||
const stop = v.scene.postRender.addEventListener(() => {
|
||||
stop();
|
||||
res();
|
||||
});
|
||||
v.scene.requestRender();
|
||||
});
|
||||
const c0 = v.camera.positionCartographic;
|
||||
const atAgeOut = {
|
||||
lonDeg: (c0.longitude * 180) / Math.PI,
|
||||
latDeg: (c0.latitude * 180) / Math.PI,
|
||||
height: c0.height,
|
||||
};
|
||||
await fl.update(v); // past retention → removal + clear + in-place release
|
||||
return {
|
||||
beforeTracking,
|
||||
trackedThroughMisses,
|
||||
atAgeOut,
|
||||
stillTrackedAfter: !!fl.getTrackedInfo(),
|
||||
viewerStillTracking: !!v.trackedEntity,
|
||||
};
|
||||
} finally {
|
||||
Date.now = realNow;
|
||||
}
|
||||
}, m3Icao);
|
||||
|
||||
record('M3: the tracked plane stays tracked through 3 missed polls (kept 10 min after its newest fix)',
|
||||
m3.trackedThroughMisses,
|
||||
`trackedThroughMisses=${m3.trackedThroughMisses}`);
|
||||
record('M3: tracking cleared after the tracked plane ages out (getTrackedInfo null)',
|
||||
m3.beforeTracking && !m3.stillTrackedAfter,
|
||||
`before=${m3.beforeTracking} trackedAfter=${m3.stillTrackedAfter}`);
|
||||
|
||||
Reference in new issue
Block a user