const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const big = document.createElement('canvas');
const bctx = big.getContext('2d');
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 paintFull(w, h) {
const r = mulberry32(9);
const g = bctx.createLinearGradient(0, 0, 0, h);
g.addColorStop(0, 'hsl(255 45% 55%)'); g.addColorStop(1, 'hsl(230 40% 22%)');
bctx.fillStyle = g; bctx.fillRect(0, 0, w, h);
bctx.beginPath(); bctx.arc(w * 0.62, h * 0.2, Math.min(w, h) * 0.07, 0, Math.PI * 2); bctx.fillStyle = 'hsl(50 85% 78%)'; bctx.fill();
for (let l = 0; l < 3; l++) {
bctx.beginPath(); bctx.moveTo(0, h);
for (let i = 0; i <= 10; i++) { const x = w * i / 10; const y = h * (0.55 + l * 0.12) - r() * h * 0.1; bctx.lineTo(x, y); }
bctx.lineTo(w, h); bctx.closePath();
bctx.fillStyle = 'hsl(255 30% ' + (16 + l * 10) + '%)'; bctx.fill();
}
}
function rebuild() {
const dpr = Math.min(devicePixelRatio || 1, 2);
cv.width = innerWidth * dpr; cv.height = innerHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
big.width = innerWidth; big.height = innerHeight;
paintFull(innerWidth, innerHeight);
}
addEventListener('resize', rebuild); rebuild();
const core = { x: 0.32, y: 0.3, w: 0.36, h: 0.4 };
function rectAt(g) {
const cx = core.x + core.w / 2, cy = core.y + core.h / 2;
const cw = core.w + (1 - core.w) * g, ch = core.h + (1 - core.h) * g;
return { x: cx - cw / 2, y: cy - ch / 2, w: cw, h: ch };
}
function render(g) {
const w = innerWidth, h = innerHeight;
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = 'rgba(255,255,255,0.05)';
for (let y = 0; y < h; y += 14) for (let x = 0; x < w; x += 14) ctx.fillRect(x, y, 2, 2);
const r = rectAt(g);
const rx = r.x * w, ry = r.y * h, rw = r.w * w, rh = r.h * h;
ctx.save(); ctx.beginPath(); ctx.rect(rx, ry, rw, rh); ctx.clip();
ctx.drawImage(big, 0, 0, w, h);
ctx.restore();
ctx.setLineDash([6, 4]); ctx.strokeStyle = 'rgba(255,255,255,0.75)'; ctx.lineWidth = 1.5;
ctx.strokeRect(rx, ry, rw, rh); ctx.setLineDash([]);
const cr = { x: core.x * w, y: core.y * h, w: core.w * w, h: core.h * h };
ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 2; ctx.strokeRect(cr.x, cr.y, cr.w, cr.h);
}
let g = 0, dir = 1;
function loop() {
render(g);
g += dir * 0.012;
if (g >= 1) { g = 1; dir = 0; setTimeout(() => { dir = -1; }, 1000); }
if (g <= 0 && dir === -1) { g = 0; dir = 0; setTimeout(() => { dir = 1; }, 800); }
setTimeout(loop, 30);
}
loop();