84 lines
3.3 KiB
JavaScript
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;
|