← back to Wild Orbs Opus
test/profile.mjs
63 lines
/** Per-phase render profiler. `node test/profile.mjs [--headed]` */
import { chromium } from 'playwright';
import { fileURLToPath, pathToFileURL } from 'node:url';
import path from 'node:path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const GAME = pathToFileURL(path.join(__dirname, '..', 'index.html')).href;
const headed = process.argv.includes('--headed');
const browser = await chromium.launch({
headless: !headed,
args: headed ? [] : ['--use-angle=metal', '--enable-gpu', '--ignore-gpu-blocklist']
});
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto(GAME);
await page.waitForTimeout(400);
await page.keyboard.press('Enter');
await page.waitForTimeout(400);
const out = await page.evaluate(async () => {
// heavy but representative field
orbs.length = 0;
for (let i = 0; i < 30; i++) orbs.push(makeOrb(Math.random() * innerWidth, Math.random() * innerHeight, 3));
for (let i = 0; i < 10; i++) hunters.push({ x: Math.random() * innerWidth, y: Math.random() * innerHeight, vx: 1, vy: 1, r: 6, life: 9e5, max: 9e5, a: 0, wig: 0, spd: .1 });
for (let i = 0; i < 200; i++) burst(Math.random() * innerWidth, Math.random() * innerHeight, 6, '#ffcc88', 3, { life: 9e5 });
ship.inv = 9e5;
const phases = {
bg: () => { ctx.drawImage(bgc, 0, 0, W, H); },
twinkle: drawTwinkle,
orbs: drawOrbs,
particles: drawParticles,
hunters: drawHunters,
bullets: drawBullets,
ship: drawShip,
vignette: drawVignette,
hud: drawHUD,
fullFrame: render
};
const res = {};
for (const [name, fn] of Object.entries(phases)) {
fn(); // warm
const t0 = performance.now();
const N = 30;
for (let i = 0; i < N; i++) fn();
res[name] = +((performance.now() - t0) / N).toFixed(2);
}
res._counts = { orbs: orbs.length, parts: parts.length, hunters: hunters.length };
return res;
});
console.log(headed ? 'HEADED (real GPU)' : 'HEADLESS');
console.log(JSON.stringify(out, null, 2));
// real-world sustained fps
const fps = await page.evaluate(async () => {
let n = 0; const t0 = performance.now();
await new Promise(res => { const t = () => { n++; (performance.now() - t0 < 2000) ? requestAnimationFrame(t) : res(); }; requestAnimationFrame(t); });
return +(n / ((performance.now() - t0) / 1000)).toFixed(1);
});
console.log('sustained fps:', fps);
await browser.close();