// 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'); }