feat(mapillary): street-level layer core — coverage, sequences, viewer bridge, query engine

Camera-driven Mapillary coverage (z0–5 overview points from orbit, z11–14
ground-clamped sequence lines below 60 km), per-sequence image cones, an
embedded MapillaryJS viewer bridge with a camera-follow mode, sprite icons
for map features, and a query engine that turns a plan into a streamed
z14 tile fan-out. Registers an on-globe CC BY-SA 4.0 credit while enabled.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Fable 5.1 committed 2026-09-23 15:44:32 +01:00
1 parent 0d41b6be54
commit fa5710bcf2
46 files changed
+9935 -32

No files matched your search

+1
View File
@@ -4,6 +4,7 @@ const CONTROL_LAYER_IDS = Object.freeze({
militaryFlightsLayer: 'military',
satellitesLayer: 'satellites',
cctvLayer: 'cctv',
mapillaryLayer: 'mapillary',
radioLayer: 'radio',
bikeshareLayer: 'bikeshare',
transitLayer: 'transit',
+1
View File
@@ -93,6 +93,7 @@ test('controls bind catalog instances rather than similarly named defaults', ()
'military-awareness',
'military-installations',
'rocket-launches',
'mapillary',
];
const layers = ids.map((id) => ({ id }));
const catalog = createLayerCatalog(layers, metadata(layers));
+14
View File
@@ -18,6 +18,7 @@ import { createApplicationAwareness } from './layers/militaryAwareness.js';
import { createApplicationFirms } from './layers/firms.js';
import { createApplicationEarthquakes } from './layers/earthquakes.js';
import { createApplicationCables } from './layers/submarineCables.js';
import { createApplicationMapillary } from './layers/mapillary.js';
import { createInfrastructureLayers } from '../data/infrastructure.js';
import { localGeoJsonServices } from './localGeojsonServices.js';
import { createBhoteKoshiEventLayer } from '../data/bhoteKoshiEvent.js';
@@ -44,6 +45,18 @@ const SOURCE_METHODS = Object.freeze({
firms: ['getSnapshot'],
earthquakes: ['getSnapshot'],
cables: ['fetch'],
mapillary: [
'getStatus',
'getTile',
'queryFeatures',
'plan',
'geocode',
'getImage',
'getSequenceImages',
'nearestImages',
'getMapFeature',
'spriteUrl',
],
});
/** Construct the current catalog without choosing any source provider.
@@ -112,6 +125,7 @@ export function createApplicationCatalog({
military,
createApplicationEarthquakes({ source: sources.earthquakes }),
createApplicationAlpr({ surface, source: sources.alpr }),
createApplicationMapillary({ surface, source: sources.mapillary }),
satellites,
createApplicationLaunches({ source: sources.launches, satellites }),
createApplicationTraffic({ source: sources.traffic }),
+1 -1
View File
@@ -39,7 +39,7 @@ test('catalogs construct distinct layers and classification from their supplied
signal: b.signal,
surface: fixtureSurface(b.signal),
});
assert.equal(first.layers.length, 21);
assert.equal(first.layers.length, 22);
assert.ok(first.get('transit'));
const order = first.layers.map(({ id }) => id);
assert.deepEqual(
+19
View File
@@ -0,0 +1,19 @@
import { createMapillaryLayer } from '../../layers/mapillary/index.js';
import * as sprites from '../../data/spriteOrder.js';
import * as picking from '../../data/pickRegistry.js';
import * as input from '../../data/inputOwnership.js';
import * as render from '../../renderGovernor.js';
/** Construct the Mapillary layer using the application scene owners and a supplied source. */
export function createApplicationMapillary({ surface, source }) {
return createMapillaryLayer({
source,
services: {
sprites,
picking,
input,
render,
ground: surface?.groundFloor ?? null,
},
});
}