orbit/dev/surface-hud-shot.mjs

84 lines
3.3 KiB
JavaScript

/**
* Visual probe for the surface HUD screenshot — PUMP-DRIVEN (like
* dev/landing-click.mjs): this box's headless Firefox freezes rAF/timers
* after first paint, so the page advances only when the runner's poll
* calls __HUD_TICK__(), which steps the engine loop once. It parks on
* the surface stage with the upper-left HUD decoded, then HOLDS
* (__HUD_SHOT__ = 'surface') so dev/shot-firefox.mjs can grab the frame.
*
* python3 -m http.server 8131
* node dev/shot-firefox.mjs http://127.0.0.1:8131/dev/surface-hud-shot.html \
* 'window.__HUD_TICK__(); window.__HUD_SHOT__ === "surface" ? window.__HUD_SHOT__ : null' \
* /tmp/surface-hud.png 60000
*/
import Phaser from '../js/vendor/phaser.js';
import { config } from '../js/config/Config.js';
import { ConfigLoader } from '../js/config/ConfigLoader.js';
import { createGameConfig } from '../js/config/GameConfig.js';
import { GameScene } from '../js/scenes/GameScene.js';
import { SurfaceScene } from '../js/scenes/SurfaceScene.js';
window.__HUD_SHOT__ = 'booting';
const data = await ConfigLoader.load();
config.init(data);
const gameConfig = createGameConfig();
gameConfig.scene = [GameScene, SurfaceScene];
const game = new Phaser.Game(gameConfig);
window.game = game;
const scene = (key) => { try { return game.scene?.getScene(key) ?? null; } catch { return null; } };
let stage = 0;
function tick() {
// v4: do NOT step the loop before boot completes — `game.scene` is
// created during boot, and pumping loop.step() before that wedges boot.
if (!game.loop || !game.scene) return;
try {
game.loop.step(performance.now());
const gs = scene('GameScene');
const ss = scene('SurfaceScene');
switch (stage) {
case 0: // boot: the flight scene is live
if (!(gs && gs.ship)) return;
gs.startLanding(gs.commsTargetFor(gs.planet)); // the real entry point
stage = 1;
return;
case 1: // the surface scene is up → force the loop stage
if (!(ss && ss.sys.isActive())) return;
ss.startSurface();
if (!ss.hudName) ss.buildHud(); // headless: the loop clip may never cache
if (ss.surfaceVideo && ss.surfaceVideo.video) {
ss.surfaceVideo.video.muted = true; // headless autoplay policy
ss.surfaceVideo.video.play().catch(() => {});
}
stage = 2;
return;
case 2: // the HUD's decode has settled → HOLD for the screenshot
if (ss.hudLines !== null) return;
window.__HUD_SHOT__ = 'surface';
window.__HUD_DIAG__ = {
gs: gs.sys.getStatus(),
ss: ss.sys.getStatus(),
ssPhase: ss.phase,
loopCached: ss.cache.video.has(`__surf_loop_${ss.planetFrame}`),
surfaceVideo: !!ss.surfaceVideo,
hudName: ss.hudName?.text,
hudLine: ss.hudLine?.text,
nameStyle: ss.hudName ? [ss.hudName.style.fontFamily, ss.hudName.style.color, ss.hudName.style.stroke, ss.hudName.style.strokeThickness] : null,
lineStyle: ss.hudLine ? [ss.hudLine.style.fontFamily, ss.hudLine.style.color, ss.hudLine.style.stroke] : null,
deckIds: (ss.actionBar?.slots ?? []).map((s) => s.id),
};
stage = 3;
}
} catch (err) {
window.__HUD_SHOT__ = 'FAILED: ' + String(err?.message ?? err);
stage = 99;
}
}
window.__HUD_TICK__ = tick;