<!DOCTYPE html>
<html>
<head><title>WASM Frame Benchmark</title></head>
<body>
<h2>WASM Frame Benchmark</h2>
<pre id="out">Loading WASM module...</pre>
<script type="module">
import init, { WasmNes } from "./pkg/neser.js";
const out = document.getElementById("out");
function log(msg) { out.textContent += "\n" + msg; }
async function run() {
await init("./pkg/neser_bg.wasm");
const SAFE_ROM_BASENAME = /^[A-Za-z0-9._-]+$/;
const romName = new URLSearchParams(location.search).get("rom");
if (!romName) throw new Error("Missing ?rom=<file>. Provide a ROM filename in web/roms/.");
if (!SAFE_ROM_BASENAME.test(romName)) throw new Error("Invalid ROM name. Only letters, numbers, dot, underscore, or dash allowed.");
const frames = parseInt(new URLSearchParams(location.search).get("frames") || "600", 10);
log(`Fetching ROM: ${romName}`);
const resp = await fetch(`roms/${encodeURIComponent(romName)}`);
if (!resp.ok) throw new Error(`Failed to fetch ROM: ${resp.status}`);
const romData = new Uint8Array(await resp.arrayBuffer());
const nes = new WasmNes();
nes.load_rom(romData, romName);
log(`ROM loaded. Running ${frames} frames...`);
for (let i = 0; i < 60; i++) nes.render_frame();
log("Starting timed run (look for 'bench' marker in DevTools Performance tab)...");
performance.mark("bench-start");
const t0 = performance.now();
for (let i = 0; i < frames; i++) nes.render_frame();
const elapsed = performance.now() - t0;
performance.mark("bench-end");
performance.measure("bench", "bench-start", "bench-end");
const perFrame = elapsed / frames;
const fps = 1000 / perFrame;
log(`Total: ${elapsed.toFixed(1)}ms`);
log(`Per frame: ${perFrame.toFixed(3)}ms`);
log(`FPS: ${fps.toFixed(1)}`);
log("\nStability check (5 runs):");
for (let r = 1; r <= 5; r++) {
const t = performance.now();
for (let i = 0; i < frames; i++) nes.render_frame();
const e = performance.now() - t;
log(` Run ${r}: ${(e / frames).toFixed(3)}ms/frame`);
}
log("\nDone.");
}
run().catch(e => log("ERROR: " + e));
</script>
</body>
</html>