feat(outlines): restore voice outlines without public Overpass

use bundled place boundaries and shared OpenFreeMap tiles before a guarded Nominatim fallback

preserve multipart shapes, holes and cancellation,
and keep pending annotations visible while ground sampling finishes across frames

keep non-Latin name distinctions when selecting provider results,
and retain an outline anchor only when it lies in filled geometry
This commit is contained in:
manjunath committed 2026-10-27 13:24:02 +00:00
commit d4434aa6d7
1489 files changed
+196442 -12353

No files matched your search

+15 -1
View File
@@ -1,11 +1,13 @@
import { createStandaloneCatalog } from './catalog.js';
import { createStandalonePlaceSearch } from './placeSearch.js';
import { CITY_POIS } from '../locations.js';
import { CITY_POIS } from '../cityPois.js';
import { createApplication } from '../app/application.js';
import { createStandaloneScene } from './scene.js';
import { createStandaloneControls } from './controls.js';
import { createStandaloneData } from './data.js';
import { createStandaloneTools } from './tools.js';
import { resolveLocale, applyDocumentLanguage } from '../i18n/locale.js';
import { applyDocumentTranslations, setLocale } from '../i18n/index.js';
// The existing controls and layer catalog contain page-scoped state.
let constructed = false;
@@ -16,11 +18,21 @@ export function createStandaloneApplication({
cesiumToken,
geospatial = {},
voice = {},
sources = {},
streetLevelProviders,
allowQaRegistration = false,
}) {
if (constructed)
throw new Error('The standalone application already owns this page');
constructed = true;
// Locale is resolved before any UI initialization so <html lang>/<html dir>
// and every catalog lookup agree from the first painted frame. Module
// scripts execute after parsing, so the DOM is ready here and every
// data-i18n* element honors the resolved locale without a reload.
const activeLocale = resolveLocale();
setLocale(activeLocale);
applyDocumentLanguage(document, activeLocale);
applyDocumentTranslations(document);
const loadingScreen = document.getElementById('loading-screen');
const loaderStatus = loadingScreen.querySelector('.loader-status');
let placeSearch;
@@ -43,6 +55,8 @@ export function createStandaloneApplication({
loaderStatus,
});
catalog = createStandaloneCatalog({
sources,
streetLevelProviders,
nepalBoundaryResolver: (signal) =>
scene.operations.annotationResolver.resolveRegionRingForQuery(
'Nepal',
+4 -1
View File
@@ -7,6 +7,8 @@ export { createStandaloneReferenceSources } from './layerSources.js';
/** Create fresh layer instances using the existing standalone source choices. */
export function createStandaloneCatalog({
nepalBoundaryResolver,
sources = {},
streetLevelProviders,
signal = new AbortController().signal,
surface = createSurfaceServices({
terrainSource: createApplicationRequestServices().terrain,
@@ -16,7 +18,8 @@ export function createStandaloneCatalog({
return createApplicationCatalog({
nepalBoundaryResolver,
surface,
sources: createStandaloneLayerSources(),
sources: createStandaloneLayerSources(sources),
streetLevelProviders,
signal,
vesselOptions: {
maxRows: import.meta.env?.VITE_AIS_LIVE_MAX_ROWS,
+35 -15
View File
@@ -1,8 +1,10 @@
import { createDirectionsSource } from '../layers/directions/source.js';
import { createRecentImagerySource } from '../layers/recentImagery/source.js';
import { createOpenFreeMapSource } from '../sources/openFreeMap.js';
import {
createOpenSkySource,
createAdsbLolSource,
createAisStreamSource,
createFlightSource,
createMilitarySource,
createVesselSource,
} from '../sources/live/standalone.js';
import { createCctvSource } from '../layers/cctv/source.js';
import { createRadioSource } from '../layers/radio/source.js';
@@ -17,23 +19,32 @@ import { createWeatherSource } from '../layers/weather/source.js';
import { createCycloneSource } from '../layers/cyclones/source.js';
import { createWindSource } from '../layers/wind/source.js';
import { createFirmsSource } from '../layers/firms/source.js';
import { createGhostMapsSource } from '../layers/ghostMaps/source.js';
import { createMapillarySource } from '../layers/streetLevel/providers/mapillary/source.js';
import { createReferenceSources } from '../sources/reference.js';
export { createReferenceSources as createStandaloneReferenceSources } from '../sources/reference.js';
/** Select standalone providers without starting their acquisition. */
export function createStandaloneLayerSources({
createMapTiles = createOpenFreeMapSource,
} = {}) {
// Each subsystem owns its own request lifetime and local result cache. The
// sources still share the bounded decoded-tile owner inside OpenFreeMap.
const trafficTiles = createMapTiles();
const installationTiles = createMapTiles();
return {
export function createStandaloneLayerSources(
overrides = {},
{ createMapTiles = createOpenFreeMapSource } = {},
) {
if (!overrides || typeof overrides !== 'object' || Array.isArray(overrides))
throw new TypeError('Source overrides must be an object');
const trafficTiles = createMapTiles({
selectDecoded: ({ roads }) => ({ roads }),
});
const installationTiles = createMapTiles({
selectDecoded: ({ military }) => ({ military }),
});
const defaults = {
...createReferenceSources(),
flights: createOpenSkySource(),
military: createAdsbLolSource(),
vessels: createAisStreamSource({
apiUrl: import.meta.env?.VITE_AIS_LIVE_API_URL || '/api/ais-live',
directions: createDirectionsSource(),
'recent-imagery': createRecentImagerySource(),
flights: createFlightSource(),
military: createMilitarySource(),
vessels: createVesselSource({
apiUrl: import.meta.env?.VITE_AIS_LIVE_API_URL || '/api/vessels',
// Resolved against the document's address, which a panel host may
// serve from its own scheme.
origin: () => globalThis.document?.baseURI ?? 'http://localhost',
@@ -48,8 +59,17 @@ export function createStandaloneLayerSources({
launches: createLaunchSource(),
alpr: createAlprTileSource(),
firms: createFirmsSource(),
's2-ghostmaps': createGhostMapsSource(),
wind: createWindSource(),
weather: createWeatherSource(),
cyclones: createCycloneSource(),
mapillary: createMapillarySource({
token: import.meta.env?.MAPILLARY_CLIENT_TOKEN || '',
}),
};
for (const name of Object.keys(overrides)) {
if (!Object.hasOwn(defaults, name))
throw new TypeError(`Unknown source: ${name}`);
}
return { ...defaults, ...overrides };
}
+28 -15
View File
@@ -4,25 +4,38 @@ import { createStandaloneLayerSources } from './layerSources.js';
test('traffic and installations own separate local OpenFreeMap lifetimes', () => {
const mapTiles = [];
const sources = createStandaloneLayerSources({
createMapTiles() {
const source = {
clears: 0,
clear() {
this.clears++;
},
getMetadata: async () => ({
template: 'https://tiles.openfreemap.org/planet/test/{z}/{x}/{y}.pbf',
}),
fetchBounds: async () => ({ tiles: [], loadedTiles: [] }),
};
mapTiles.push(source);
return source;
const mapTileOptions = [];
const sources = createStandaloneLayerSources(
{},
{
createMapTiles(options) {
mapTileOptions.push(options);
const source = {
clears: 0,
clear() {
this.clears++;
},
getMetadata: async () => ({
template:
'https://tiles.openfreemap.org/planet/test/{z}/{x}/{y}.pbf',
}),
fetchBounds: async () => ({ tiles: [], loadedTiles: [] }),
};
mapTiles.push(source);
return source;
},
},
});
);
assert.equal(mapTiles.length, 2);
assert.notEqual(mapTiles[0], mapTiles[1]);
const decoded = { roads: ['road'], military: ['site'] };
assert.deepEqual(mapTileOptions[0].selectDecoded(decoded), {
roads: ['road'],
});
assert.deepEqual(mapTileOptions[1].selectDecoded(decoded), {
military: ['site'],
});
sources.traffic.resetFlowTileCache();
assert.deepEqual(
mapTiles.map((source) => source.clears),
+6 -1
View File
@@ -17,6 +17,11 @@ export function createStandaloneTools(options) {
},
},
...options,
voice: { toolCatalog: loadToolCatalog, ...options?.voice },
voice: {
supportedProviders: ['openai', 'gemini'],
panel: true,
toolCatalog: loadToolCatalog,
...options?.voice,
},
});
}
-1
View File
@@ -1 +0,0 @@
export { StyleManager } from '../ui/composition.js';