mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 15:52:21 +00:00
feat(alpr): render camera markers on Navara
Separate native scene ownership from shared ALPR source and selection state, and add bounded Navara sprites with the existing direction/card overlay. Preserve marker artwork, picking, floor retries and source attribution. Fix lost post-render wakeups and redundant mobile rail mutations, and keep HUD typewriter dimensions stable so static views settle without extra frames. Add parser-fed dev/preview and legacy evidence, including retained failures. Common W2 terrain and combined performance gates remain open.
This commit is contained in:
1 parent
9d587c1d37
commit
46b3aceafc
23 files changed
+2081
-181
No files matched your search
@@ -6,15 +6,18 @@
|
||||
* `<dir>/clip.mp4` through ffmpeg's concat demuxer with per-frame
|
||||
* durations, so held frames last as long as they did on screen.
|
||||
* - `installFrameProbe(page)` measures every animation frame in the page:
|
||||
* the requestAnimationFrame interval and, for frames Cesium rendered, the
|
||||
* CPU time between `scene.preUpdate` and `scene.postRender`.
|
||||
* the requestAnimationFrame interval and, for rendered frames, the
|
||||
* CPU time between engine preUpdate and postRender events.
|
||||
* - `frameStats(frames)` reduces a probe window to count / mean / p50 / p95.
|
||||
* - `moveCamera(page, view, seconds)` eases the camera like a drag or wheel
|
||||
* zoom rather than teleporting it.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
/** Percentile of a numeric list (nearest rank); NaN for an empty list. */
|
||||
export function percentile(values, p) {
|
||||
@@ -25,7 +28,7 @@ export function percentile(values, p) {
|
||||
];
|
||||
}
|
||||
|
||||
/** Summarize probe frames: rAF interval and Cesium render CPU time (ms). */
|
||||
/** Summarize probe frames: rAF interval and engine render CPU time (ms). */
|
||||
export function frameStats(frames) {
|
||||
const intervals = frames.map((f) => f.dt).filter(Number.isFinite);
|
||||
const renders = frames.map((f) => f.renderMs).filter(Number.isFinite);
|
||||
@@ -49,16 +52,17 @@ export function frameStats(frames) {
|
||||
export async function installFrameProbe(page) {
|
||||
await page.evaluate(() => {
|
||||
if (window.__gevFrameProbe) return;
|
||||
const { viewer } = window.__godsEyeView;
|
||||
const { viewer, engine } = window.__godsEyeView;
|
||||
const events = viewer?.scene ?? engine.frames;
|
||||
const probe = { frames: [], started: 0 };
|
||||
window.__gevFrameProbe = probe;
|
||||
let last = performance.now();
|
||||
let renderStart = null;
|
||||
let pendingRender = null;
|
||||
viewer.scene.preUpdate.addEventListener(() => {
|
||||
events.preUpdate.addEventListener(() => {
|
||||
renderStart = performance.now();
|
||||
});
|
||||
viewer.scene.postRender.addEventListener(() => {
|
||||
events.postRender.addEventListener(() => {
|
||||
if (renderStart !== null) pendingRender = performance.now() - renderStart;
|
||||
renderStart = null;
|
||||
});
|
||||
@@ -98,6 +102,34 @@ export function pageNow(page) {
|
||||
* @param {number} seconds Flight duration; 0 jumps.
|
||||
*/
|
||||
export async function moveCamera(page, view, seconds) {
|
||||
if (
|
||||
await page.evaluate(() => window.__godsEyeView.engine?.kind === 'navara')
|
||||
) {
|
||||
await page.evaluate(
|
||||
async (v, duration) => {
|
||||
const geo = await import('/src/geo/index.js');
|
||||
const camera = window.__godsEyeView.engine.camera;
|
||||
camera.cancelFlight();
|
||||
await new Promise((resolve) =>
|
||||
camera.flyTo({
|
||||
destination: geo.cartesian3.fromDegrees(v.lon, v.lat, v.height),
|
||||
orientation: {
|
||||
heading: ((v.heading ?? 0) * Math.PI) / 180,
|
||||
pitch: ((v.pitch ?? -45) * Math.PI) / 180,
|
||||
roll: 0,
|
||||
},
|
||||
duration,
|
||||
maximumHeight: Math.max(v.height, camera.height()),
|
||||
complete: resolve,
|
||||
cancel: resolve,
|
||||
}),
|
||||
);
|
||||
},
|
||||
view,
|
||||
seconds,
|
||||
);
|
||||
return;
|
||||
}
|
||||
await page.evaluate(
|
||||
(v, duration) =>
|
||||
new Promise((resolve) => {
|
||||
@@ -191,7 +223,8 @@ export async function createScreencast(page, dir, options = {}) {
|
||||
const list = path.join(dir, 'frames.txt');
|
||||
fs.writeFileSync(list, `${lines.join('\n')}\n`);
|
||||
const clip = path.join(dir, 'clip.mp4');
|
||||
execFileSync('ffmpeg', [
|
||||
// Keep servicing Puppeteer's request interception while encoding.
|
||||
await execFileAsync('ffmpeg', [
|
||||
'-y',
|
||||
'-loglevel',
|
||||
'error',
|
||||
|
||||
Reference in new issue
Block a user