91 lines
3.7 KiB
JavaScript
91 lines
3.7 KiB
JavaScript
// Key-gated features (Wave 4.1) — the upstream God's Eye View extras, built in
|
|
// but dormant until a working key activates them. Keys live in assets/keys.json
|
|
// (gitignored — copy assets/keys.json.example) and are CLIENT-EXPOSED by
|
|
// design: restrict each key at its provider (see README §Key-gated extras).
|
|
// No file / empty key = the feature stays hidden or explains itself.
|
|
//
|
|
// google → "3D" basemap mode: Google Photorealistic 3D Tiles (metered 🔴)
|
|
// cesiumIon → "Bing" basemap mode: Bing aerial via Cesium ion (free 🟡)
|
|
// tomtom → Traffic flow overlay layer (free 🟡)
|
|
//
|
|
// OpenAI voice is NOT here — its key must never ship to a server; see voice.js.
|
|
|
|
export async function loadKeys() {
|
|
try {
|
|
const r = await fetch('assets/keys.json', { cache: 'no-store' });
|
|
if (r.ok) return await r.json();
|
|
} catch { /* absent file = no keys, by design */ }
|
|
return {};
|
|
}
|
|
|
|
// hooks: { onBasemapReady(kind, resource), mode3dActive(), solarActive() }
|
|
export async function initKeyed(ctx, hooks) {
|
|
const { viewer, Cesium } = ctx;
|
|
const keys = await loadKeys();
|
|
|
|
// ---- Bing aerial (Cesium ion asset 2) → "Bing" basemap mode ----
|
|
if (keys.cesiumIon) {
|
|
try {
|
|
Cesium.Ion.defaultAccessToken = keys.cesiumIon;
|
|
const prov = await Cesium.IonImageryProvider.fromAssetId(2);
|
|
const layer = viewer.imageryLayers.addImageryProvider(prov);
|
|
layer.show = false;
|
|
hooks.onBasemapReady('bing', layer);
|
|
} catch (err) {
|
|
console.warn('[godsigh] Cesium ion key configured but Bing failed:', err);
|
|
}
|
|
}
|
|
|
|
// ---- Google Photorealistic 3D Tiles → "3D" basemap mode ----
|
|
if (keys.google) {
|
|
try {
|
|
const tiles = await Cesium.Cesium3DTileset.fromUrl(
|
|
`https://tile.googleapis.com/v1/3dtiles/root.json?key=${encodeURIComponent(keys.google)}`,
|
|
{ showCreditsOnScreen: true }, // Google attribution is a licence condition
|
|
);
|
|
tiles.show = false;
|
|
viewer.scene.primitives.add(tiles);
|
|
// keyed.js owns tiles.show: on only in 3D mode and never inside Solar
|
|
// System mode (which hides the globe but not this primitive — without
|
|
// this, tiles would render under the orrery and stream paid quota).
|
|
viewer.scene.preUpdate.addEventListener(() => {
|
|
const want = hooks.mode3dActive() && !hooks.solarActive();
|
|
if (tiles.show !== want) tiles.show = want;
|
|
});
|
|
hooks.onBasemapReady('3d', tiles);
|
|
} catch (err) {
|
|
console.warn('[godsigh] Google key configured but 3D tiles failed:', err);
|
|
}
|
|
}
|
|
|
|
// ---- TomTom live traffic flow — row always present so the capability is
|
|
// discoverable; keyless it just says how to get the (free) key. ----
|
|
initTraffic(ctx, keys.tomtom);
|
|
|
|
return keys;
|
|
}
|
|
|
|
function initTraffic({ viewer, ui, Cesium }, key) {
|
|
let layer = null;
|
|
if (key) {
|
|
const prov = new Cesium.UrlTemplateImageryProvider({
|
|
url: `https://api.tomtom.com/traffic/map/4/tile/flow/relative0/{z}/{x}/{y}.png?key=${encodeURIComponent(key)}`,
|
|
maximumLevel: 20,
|
|
credit: 'Traffic © TomTom',
|
|
});
|
|
layer = viewer.imageryLayers.addImageryProvider(prov);
|
|
layer.alpha = 0.75;
|
|
layer.show = false;
|
|
}
|
|
ui.addLayer('tomtom', 'Traffic flow (TomTom)', false, (on) => {
|
|
if (!layer) {
|
|
// ponytail: key is not validated up front; a bad key just renders no tiles
|
|
ui.setStatus('tomtom', on ? 'needs key — assets/keys.json (free: developer.tomtom.com)' : '', on ? 'warn' : 'off');
|
|
return;
|
|
}
|
|
layer.show = on;
|
|
ui.setStatus('tomtom', on ? 'live congestion tiles · © TomTom' : '', on ? 'ok' : 'off');
|
|
}, 'Context');
|
|
ui.setStatus('tomtom', key ? 'key loaded — toggle on' : 'off — free key unlocks', 'off');
|
|
}
|