57 lines
2.6 KiB
HTML
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>
|