picker/tests/sim.html
2026-10-09 13:45:54 +02:00

57 lines
2.6 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Picker frame simulator</title>
<link rel="stylesheet" href="../css/app.css">
<style>#info{position:fixed;left:8px;bottom:8px;font:12px monospace;color:#8f8;background:#000a;padding:4px 8px}</style>
</head>
<body>
<canvas id="stage"></canvas>
<div id="info"></div>
<script type="module">
// Renders a single frame of a simulated game at time ?t= (ms) without
// relying on requestAnimationFrame, so headless screenshots are deterministic.
// ?mode=one|pickN|teams|order|elimination &n=4 &t=9000 &theme=neon
// &style=flood|confetti|spotlight|shockwave|calm (force reveal style)
// &lift=ms (one finger lifts at this time)
import { Game } from '../js/game.js';
import { Renderer } from '../js/renderer.js';
import { getTheme } from '../js/themes.js';
const p = new URLSearchParams(location.search);
const settings = { mode: p.get('mode') || 'one', pickN: +(p.get('k') || 2), teams: +(p.get('teams') || 2) };
const n = +(p.get('n') || 4);
const T = +(p.get('t') || 0);
const lift = p.has('lift') ? +p.get('lift') : null;
const events = [];
const renderer = new Renderer(document.getElementById('stage'));
renderer.setTheme(getTheme(p.get('theme') || 'neon'));
const game = new Game({
emit: (type, data) => { events.push(type); renderer.onEvent(type, data || {}, now, game); },
getSettings: () => settings,
isReduced: () => p.has('reduced'),
});
if (p.get('style')) {
const orig = game.reveal.bind(game);
game.reveal = (t, w) => { orig(t, w); if (game.revealStyle !== 'teams') { game.revealStyle = p.get('style'); renderer.onEvent('reveal', { style: game.revealStyle, winners: w, plan: game.plan }, t, game); } };
}
const base = performance.now() + 10;
let now = base;
const w = innerWidth, h = innerHeight, rad = Math.min(w, h) * 0.32;
for (let i = 0; i < n; i++) {
const a = -Math.PI / 2 + (i / n) * Math.PI * 2;
game.fingerDown('f' + i, w / 2 + Math.cos(a) * rad, h / 2 + Math.sin(a) * rad, now);
}
let lifted = false;
for (let t = 0; t <= T; t += 16) {
now = base + t;
if (lift != null && !lifted && t >= lift) { game.fingerUp('f0', now); lifted = true; }
game.update(now);
renderer.draw(game, now);
}
document.getElementById("info").textContent = `${innerWidth}x${innerHeight} c=${renderer.canvas.clientWidth}x${renderer.canvas.clientHeight} px=${renderer.canvas.width}x${renderer.canvas.height} dpr=${devicePixelRatio} t=${T} phase=${game.phase} style=${game.revealStyle} events=${[...new Set(events)].join(',')}`;
</script>
</body>
</html>