91 lines
3.5 KiB
JavaScript
91 lines
3.5 KiB
JavaScript
/**
|
|
* Dev: screenshot the mining context menu — in the REAL web font — and
|
|
* report whether the buttons fit inside the panel.
|
|
*
|
|
* The menu sizes itself from its buttons (js/ui/MiningPopup.js), and the
|
|
* buttons measure their label in whatever font is live at construction.
|
|
* index.html waits for the typefaces before boot (js/main.js → awaitFonts),
|
|
* so this probe does the same before creating the game.
|
|
*
|
|
* python3 -m http.server 8080
|
|
* node dev/wdshot.mjs http://localhost:8080/dev/popup-shot.html /tmp/popup.png \
|
|
* 'window.__POPUP_SHOT__(); return window.__POPUP_SHOT__RESULT__;' 40000 5000
|
|
*/
|
|
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';
|
|
|
|
const data = await ConfigLoader.load();
|
|
config.init(data);
|
|
|
|
// The game measures its UI text in the web font (Centauri) — wait for it
|
|
// BEFORE the scenes build any text (same contract as js/main.js).
|
|
const __fonts = globalThis.document?.fonts;
|
|
if (__fonts && typeof __fonts.load === 'function') {
|
|
const fams = ['header', 'body']
|
|
.map((k) => config.get(`theme.fonts.${k}.family`))
|
|
.filter((f) => typeof f === 'string' && f.length > 0);
|
|
if (fams.length > 0) {
|
|
await Promise.race([
|
|
Promise.allSettled(fams.map((f) => __fonts.load(`16px "${f}"`).catch(() => {}))),
|
|
new Promise((r) => setTimeout(r, 2000)),
|
|
]);
|
|
}
|
|
}
|
|
|
|
// A deterministic galaxy (same clusters every run) + quiet audio in headless.
|
|
globalThis.__ORBIT_DEV_SEED = 'MINING';
|
|
const gameConfig = createGameConfig();
|
|
gameConfig.scene = [GameScene]; // GameScene boots first
|
|
if (typeof Phaser !== 'undefined') Phaser.NoAudioContext = true;
|
|
|
|
const game = new Phaser.Game(gameConfig);
|
|
window.game = game;
|
|
|
|
/**
|
|
* Frame the first cluster, open the mining menu on it, pump until the open
|
|
* tween is done, and report the panel/button geometry (px).
|
|
*/
|
|
window.__POPUP_SHOT__ = () => {
|
|
const g = window.game;
|
|
const s = g.scene.getScene('GameScene');
|
|
if (!s || !Array.isArray(s.asteroidClusters) || s.asteroidClusters.length === 0) {
|
|
return { ready: false, note: s ? 'no clusters (yet?)' : 'no scene' };
|
|
}
|
|
const c = s.asteroidClusters[0];
|
|
const m = c.members[0];
|
|
|
|
// Park the ship by the rock so the camera frames it, and centre on it.
|
|
s.ship.stop();
|
|
s.ship.x = m.wx + 34;
|
|
s.ship.y = m.wy - 22;
|
|
const cam = s.cameras.main;
|
|
cam.scrollX = m.wx - cam.width / 2;
|
|
cam.scrollY = m.wy - cam.height / 2;
|
|
|
|
const rock = { cluster: c, member: m, x: m.wx, y: m.wy };
|
|
s.openMiningMenu(rock, { x: cam.width / 2, y: m.wy - cam.scrollY });
|
|
|
|
// Pump until the open tween (150 ms) is done — this box freezes rAF.
|
|
for (let i = 0; i < 300 && s.miningPopup.alpha < 0.999; i++) g.loop.step(performance.now());
|
|
|
|
const pop = s.miningPopup;
|
|
const r = {
|
|
ready: true,
|
|
fontStatus: __fonts?.status ?? 'n/a',
|
|
header: pop.headerText.text,
|
|
headerW: Math.round(pop.headerText.width),
|
|
panelW: pop.W,
|
|
panelH: pop.H,
|
|
primary: { label: pop.primaryBtn.labelText.text, labelW: Math.round(pop.primaryBtn.labelText.width), btnW: pop.primaryBtn.style.width },
|
|
cancel: { label: pop.cancelBtn.labelText.text, labelW: Math.round(pop.cancelBtn.labelText.width), btnW: pop.cancelBtn.style.width },
|
|
primaryFits: pop.primaryBtn.style.width + 24 <= pop.W,
|
|
cancelFits: pop.cancelBtn.style.width + 24 <= pop.W,
|
|
headerFits: pop.headerText.width <= pop.W - 16,
|
|
};
|
|
window.__POPUP_SHOT__RESULT__ = r;
|
|
return r;
|
|
};
|