.wrap{position:relative;width:100%;height:100%}
#cv{position:absolute;inset:0;width:100%;height:100%;image-rendering:pixelated}
.panel{position:absolute;top:10px;left:10px;z-index:2;padding:6px 10px;border-radius:10px;
background:rgba(13,13,18,0.55);backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,0.15);
font-family:ui-monospace,monospace;font-size:11.5px;color:#f1f0ec}
.panel b{color:var(--accent)}
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const sEl = document.getElementById('s');
const SW = 48, SH = 30;
const small = document.createElement('canvas'); small.width = SW; small.height = SH;
const sctx = small.getContext('2d');
function fit() { const dpr = Math.min(devicePixelRatio || 1, 2); cv.width = innerWidth * dpr; cv.height = innerHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.imageSmoothingEnabled = false; }
addEventListener('resize', fit); fit();
function mulberry32(a) { return function () { a |= 0; a = a + 0x6D2B79F5 | 0; let t = Math.imul(a ^ a >>> 15, 1 | a); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }
function paintTarget() {
const r = mulberry32(15);
const g = sctx.createLinearGradient(0, 0, 0, SH);
g.addColorStop(0, 'hsl(200 55% 65%)'); g.addColorStop(1, 'hsl(210 45% 30%)');
sctx.fillStyle = g; sctx.fillRect(0, 0, SW, SH);
sctx.beginPath(); sctx.arc(SW * 0.7, SH * 0.25, SH * 0.14, 0, Math.PI * 2); sctx.fillStyle = 'hsl(45 90% 75%)'; sctx.fill();
for (let l = 0; l < 2; l++) {
sctx.beginPath(); sctx.moveTo(0, SH);
for (let i = 0; i <= 6; i++) { const x = SW * i / 6; const y = SH * (0.5 + l * 0.18) - r() * SH * 0.14; sctx.lineTo(x, y); }
sctx.lineTo(SW, SH); sctx.closePath();
sctx.fillStyle = 'hsl(150 40% ' + (18 + l * 12) + '%)'; sctx.fill();
}
}
function noiseCanvas(seed) {
const r = mulberry32(seed);
const tmp = document.createElement('canvas'); tmp.width = SW; tmp.height = SH;
const tctx = tmp.getContext('2d');
const id = tctx.createImageData(SW, SH);
for (let i = 0; i < id.data.length; i += 4) { const v = Math.floor(r() * 255); id.data[i] = v; id.data[i + 1] = v; id.data[i + 2] = v; id.data[i + 3] = 255; }
tctx.putImageData(id, 0, 0);
return tmp;
}
function drawStep(k, N) {
paintTarget();
const f = 1 - k / N;
if (f > 0.01) { sctx.globalAlpha = f; sctx.drawImage(noiseCanvas(1000 + k), 0, 0); sctx.globalAlpha = 1; }
ctx.clearRect(0, 0, innerWidth, innerHeight);
ctx.drawImage(small, 0, 0, innerWidth, innerHeight);
}
const N = 24;
let k = 0;
function tick() {
drawStep(Math.min(k, N), N);
sEl.textContent = Math.min(k, N);
const delay = k > N ? 1300 : 130;
k++;
if (k > N + 1) k = 0;
setTimeout(tick, delay);
}
tick();