mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
feat(ui): switch between Cesium and Navara in Visual Presets
Remember the chosen engine and restore the current view after navigation. Keep the standalone JavaScript UI and retire the Dioxus migration and Cesium removal milestones.
This commit is contained in:
1 parent
dc7a7c4d53
commit
1da65dc264
7 files changed
+171
-1
No files matched your search
@@ -213,6 +213,8 @@ Choose a first-run mission, or try these in order. The GIFs show Google Photorea
|
||||
7. **Talk to it** _(needs an OpenAI key)_: _"Take me to LAX and select the nearest airborne aircraft."_
|
||||
8. **Come home.** Hit **Reset Globe** — or just say _"zoom out to a globe view."_
|
||||
|
||||
Open **Visual Presets → Globe Engine** to switch between Cesium and experimental Navara. The page reloads at the current view and remembers your choice. A link with `?engine=cesium` or `?engine=navara` overrides the saved choice. A fresh visit starts with Cesium.
|
||||
|
||||
**Keyboard:** `1`–`7` visual styles · `H` HUD · `D` detection · `C` cockpit · `` ` `` frame rate · `Esc` out. Trackpad pinch zooms the globe.
|
||||
|
||||
---
|
||||
|
||||
@@ -1080,6 +1080,7 @@
|
||||
"build/navaraAssets.js",
|
||||
"scripts/qa-engine-bench.mjs",
|
||||
"scripts/qa-engine-shell.mjs",
|
||||
"scripts/qa-engine-switch.mjs",
|
||||
"scripts/qa/navara-contract.html",
|
||||
"scripts/qa/navaraContractPage.js",
|
||||
"scripts/qa/tileCache.mjs",
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { blockPaidQaMaps } from './qa-map-policy.mjs';
|
||||
import { installTileCache } from './qa/tileCache.mjs';
|
||||
|
||||
const base = new URL(process.argv[2]);
|
||||
if (
|
||||
!['localhost', '127.0.0.1'].includes(base.hostname) ||
|
||||
['', '4173', '4185', '4186', '4187', '4188', '4189', '4194'].includes(
|
||||
base.port,
|
||||
)
|
||||
) {
|
||||
throw new Error('Supply an unreserved local preview URL');
|
||||
}
|
||||
base.search = '?welcome=0&look=cinematic';
|
||||
base.hash = 'v=2&lat=42.3554&lon=-71.0605&alt=6000&heading=0&pitch=-90&map=osm';
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
args: ['--use-angle=metal', '--enable-gpu'],
|
||||
});
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await blockPaidQaMaps(page);
|
||||
await installTileCache(page);
|
||||
await page.evaluateOnNewDocument(() => {
|
||||
localStorage.setItem('gev:first-run-mission:v1', 'suppressed');
|
||||
});
|
||||
await page.setViewport({ width: 1280, height: 800 });
|
||||
const errors = [];
|
||||
page.on('pageerror', (error) => errors.push(error.message));
|
||||
async function ready(kind) {
|
||||
await page.waitForFunction(
|
||||
(kind) =>
|
||||
window.__godsEyeView?.engine?.kind === kind &&
|
||||
document.getElementById('loading-screen')?.classList.contains('hidden'),
|
||||
{ timeout: 90000 },
|
||||
kind,
|
||||
);
|
||||
await page.evaluate(async () => {
|
||||
await window.__godsEyeView.styleManager.initialRestorePromise;
|
||||
if (window.__GOOGLE_MAPS_API_KEY__ || window.__godsEyeView.tileset)
|
||||
throw new Error('Keyless preview required');
|
||||
});
|
||||
assert.equal(await page.$eval('#globe-engine', (el) => el.value), kind);
|
||||
}
|
||||
const stored = () => page.evaluate(() => localStorage.getItem('gev.engine'));
|
||||
async function switchTo(kind) {
|
||||
if (
|
||||
await page.$eval(
|
||||
'#control-panel-toggle',
|
||||
(el) => el.getAttribute('aria-expanded') !== 'true',
|
||||
)
|
||||
) {
|
||||
await page.focus('#control-panel-toggle');
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
await page.waitForSelector('#globe-engine', { visible: true });
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
|
||||
page.select('#globe-engine', kind),
|
||||
]);
|
||||
await ready(kind);
|
||||
const url = new URL(page.url());
|
||||
assert.equal(url.searchParams.get('engine'), kind);
|
||||
assert.equal(url.searchParams.get('look'), 'cinematic');
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assert.equal(hash.get('map'), 'osm');
|
||||
assert.ok(Math.abs(Number(hash.get('lat')) - 42.3554) < 0.01);
|
||||
assert.ok(Math.abs(Number(hash.get('lon')) + 71.0605) < 0.01);
|
||||
assert.ok(Math.abs(Number(hash.get('alt')) - 6000) < 30);
|
||||
const view = await page.evaluate(() => {
|
||||
const { engine, mapStackController } = window.__godsEyeView;
|
||||
const { latitude, longitude, height } = engine.camera.pose().cartographic;
|
||||
return {
|
||||
latitude: latitude * (180 / Math.PI),
|
||||
longitude: longitude * (180 / Math.PI),
|
||||
height,
|
||||
map: mapStackController.getActiveId(),
|
||||
};
|
||||
});
|
||||
assert.equal(view.map, 'osm');
|
||||
assert.ok(Math.abs(view.latitude - 42.3554) < 0.01);
|
||||
assert.ok(Math.abs(view.longitude + 71.0605) < 0.01);
|
||||
assert.ok(Math.abs(view.height - 6000) < 30);
|
||||
}
|
||||
await page.goto(base.href, { waitUntil: 'domcontentloaded' });
|
||||
await ready('cesium');
|
||||
await switchTo('navara');
|
||||
assert.equal(await stored(), 'navara');
|
||||
await page.goBack({ waitUntil: 'domcontentloaded' });
|
||||
await ready('cesium');
|
||||
await page.goto(base.href, { waitUntil: 'domcontentloaded' });
|
||||
await ready('navara');
|
||||
await switchTo('cesium');
|
||||
assert.equal(await stored(), 'cesium');
|
||||
await page.evaluate(() => {
|
||||
const write = Storage.prototype.setItem;
|
||||
Storage.prototype.setItem = function (key, value) {
|
||||
if (key === 'gev.engine')
|
||||
throw new DOMException('Blocked', 'SecurityError');
|
||||
return write.call(this, key, value);
|
||||
};
|
||||
});
|
||||
await switchTo('navara');
|
||||
assert.equal(await stored(), 'cesium');
|
||||
assert.deepEqual(errors, []);
|
||||
console.log(
|
||||
'PASS Cesium default, both switches, share pose/map, Back, remembered engine, blocked preference storage',
|
||||
);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
@@ -522,6 +522,12 @@ export class ShareLinkManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Save the current view before leaving the page. */
|
||||
flush() {
|
||||
clearTimeout(this._debounceTimer);
|
||||
this._updateHash();
|
||||
}
|
||||
|
||||
_scheduleUpdate() {
|
||||
if (this._destroyed || this._initialRestorePending) return;
|
||||
clearTimeout(this._debounceTimer);
|
||||
|
||||
Vendored
+33
-1
@@ -1,8 +1,40 @@
|
||||
import { createApplicationControls } from '../app/controls.js';
|
||||
import { getStandaloneCatalog } from './catalog.js';
|
||||
import { ENGINE_STORAGE_KEY } from '../app/engineChoice.js';
|
||||
|
||||
export function createStandaloneControls(options) {
|
||||
return createApplicationControls({
|
||||
const controls = createApplicationControls({
|
||||
catalog: options?.catalog ?? getStandaloneCatalog(),
|
||||
...options,
|
||||
});
|
||||
const select = document.getElementById('globe-engine');
|
||||
const container = document.getElementById('globe-engine-control');
|
||||
if (select && container) {
|
||||
const current = options.scene.engine.kind;
|
||||
select.value = current;
|
||||
const switchEngine = () => {
|
||||
const next = select.value;
|
||||
if (next === current || !['cesium', 'navara'].includes(next)) return;
|
||||
controls.styleManager.shareLinkManager.flush();
|
||||
const url = new URL(window.location.href);
|
||||
// Keep Back meaningful even when this visit began without ?engine=.
|
||||
url.searchParams.set('engine', current);
|
||||
window.history.replaceState(window.history.state, '', url);
|
||||
url.searchParams.set('engine', next);
|
||||
try {
|
||||
window.localStorage.setItem(ENGINE_STORAGE_KEY, next);
|
||||
} catch {
|
||||
// The explicit URL also works when storage is blocked.
|
||||
}
|
||||
select.value = current;
|
||||
window.location.assign(url);
|
||||
};
|
||||
select.addEventListener('change', switchEngine);
|
||||
container.hidden = false;
|
||||
options.defer(() => {
|
||||
select.removeEventListener('change', switchEngine);
|
||||
container.hidden = true;
|
||||
});
|
||||
}
|
||||
return controls;
|
||||
}
|
||||
@@ -824,6 +824,15 @@
|
||||
}
|
||||
|
||||
/* Map Source tiles live with Visual Presets in the bottom command tray. */
|
||||
#globe-engine-control label {
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#globe-engine:focus-visible {
|
||||
outline: 2px solid currentColor;
|
||||
}
|
||||
|
||||
.map-source-section {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
|
||||
@@ -49,6 +49,14 @@
|
||||
<span class="btn-key">7</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="globe-engine-control" hidden>
|
||||
<label class="map-source-heading" for="globe-engine">GLOBE ENGINE
|
||||
<select class="pp-select" id="globe-engine">
|
||||
<option value="cesium">Cesium</option>
|
||||
<option value="navara">Navara</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<section class="map-source-section" aria-labelledby="map-source-label">
|
||||
<div class="map-source-heading">
|
||||
<span id="map-source-label">MAP SOURCE</span>
|
||||
|
||||
Reference in new issue
Block a user