refactor: idle-friendly render loops, drop dead strobe code

Rain and globe rAF loops now start on demand and stop when their
effect fully fades, instead of ticking every frame forever. Lightning
clears the bluish strobe tint after each burst. Removed triggerStrobe,
which was disabled and unreferenced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015HtPHsTnDcLVSCiF5FGHZj
This commit is contained in:
vini 2026-07-19 10:23:16 -03:00
parent f20d8adf4f
commit de994bced9

View file

@ -1802,7 +1802,15 @@ globeCanvas.style.cssText =
'opacity:0;transition:opacity 1.5s ease;'; 'opacity:0;transition:opacity 1.5s ease;';
sunEl.appendChild(globeCanvas); sunEl.appendChild(globeCanvas);
const gctx = globeCanvas.getContext('2d'); const gctx = globeCanvas.getContext('2d');
let globeRot = 0, lastGlobeTs = 0; let globeRot = 0, lastGlobeTs = 0, globeLoopOn = false;
/* Loop roda só enquanto o globo é visível — dorme quando baladaAmt zera */
function startGlobeLoop() {
if (globeLoopOn) return;
globeLoopOn = true;
lastGlobeTs = 0;
requestAnimationFrame(drawGlobe);
}
/* 8 luzes nos eixos ortogonais — cobertura 360° garantida. /* 8 luzes nos eixos ortogonais — cobertura 360° garantida.
±Y não são afetados pelo lrot, ±X e ±Z orbitam entre si. */ ±Y não são afetados pelo lrot, ±X e ±Z orbitam entre si. */
@ -1818,6 +1826,7 @@ const MIRROR_LIGHTS = [
]; ];
function drawGlobe(ts) { function drawGlobe(ts) {
if (!balada && baladaAmt < 0.01) { globeLoopOn = false; lastGlobeTs = 0; return; }
requestAnimationFrame(drawGlobe); requestAnimationFrame(drawGlobe);
if (baladaAmt < 0.01) { lastGlobeTs = 0; return; } if (baladaAmt < 0.01) { lastGlobeTs = 0; return; }
globeCanvas.style.opacity = chuva ? 0 : baladaAmt; globeCanvas.style.opacity = chuva ? 0 : baladaAmt;
@ -1900,7 +1909,6 @@ function drawGlobe(ts) {
gctx.restore(); gctx.restore();
} }
requestAnimationFrame(drawGlobe);
const discoDots = document.getElementById('discoDots'); const discoDots = document.getElementById('discoDots');
const strobeEl = document.getElementById('strobe'); const strobeEl = document.getElementById('strobe');
@ -1959,22 +1967,6 @@ setInterval(() => {
if (baladaAmt > 0.3 && discoDots.childElementCount < 28) spawnDiscoDot(); if (baladaAmt > 0.3 && discoDots.childElementCount < 28) spawnDiscoDot();
}, 280); }, 280);
/* ── Strobe no beat ── */
let strobeCooldown = false;
function triggerStrobe() {
if (!balada || strobeCooldown) return;
strobeCooldown = true;
strobeEl.style.transition = 'none';
strobeEl.style.opacity = '0.2';
setTimeout(() => {
strobeEl.style.transition = 'opacity 0.3s ease';
strobeEl.style.opacity = '0';
setTimeout(() => { strobeCooldown = false; }, 600);
}, 50);
}
/* strobe desativado — muito agressivo visualmente */
/* setInterval(() => { if (balada && Math.random() < 0.35) triggerStrobe(); }, BEAT_MS * 2); */
/* ── Pulso do sol/disco no beat ── */ /* ── Pulso do sol/disco no beat ── */
function globeBeat() { function globeBeat() {
if (!balada || !sunEl) return; if (!balada || !sunEl) return;
@ -1989,7 +1981,7 @@ setInterval(() => { if (balada) globeBeat(); }, BEAT_MS);
function setBaladaMode(on) { function setBaladaMode(on) {
if (on === balada) return; if (on === balada) return;
balada = on; balada = on;
if (on) setChuvaMode(false); if (on) { setChuvaMode(false); startGlobeLoop(); }
document.body.classList.toggle('balada', balada); document.body.classList.toggle('balada', balada);
/* opacidade do globo é controlada por drawGlobe via baladaAmt */ /* opacidade do globo é controlada por drawGlobe via baladaAmt */
} }
@ -2067,15 +2059,25 @@ function initRain() {
} }
let lastRainTs = 0; let lastRainTs = 0;
let rainLoopOn = false;
/* Loop roda só enquanto há chuva visível — dorme quando chuvaAmt zera */
function startRainLoop() {
if (rainLoopOn) return;
rainLoopOn = true;
lastRainTs = 0;
requestAnimationFrame(drawRain);
}
function drawRain(ts) { function drawRain(ts) {
requestAnimationFrame(drawRain);
const dt = lastRainTs ? Math.min((ts - lastRainTs) / 1000, 0.05) : 0; const dt = lastRainTs ? Math.min((ts - lastRainTs) / 1000, 0.05) : 0;
lastRainTs = ts; lastRainTs = ts;
chuvaAmt += ((chuva ? 1 : 0) - chuvaAmt) * Math.min(1, dt * 0.5); chuvaAmt += ((chuva ? 1 : 0) - chuvaAmt) * Math.min(1, dt * 0.5);
const W = rainCanvas.width, H = rainCanvas.height; const W = rainCanvas.width, H = rainCanvas.height;
rctx.clearRect(0, 0, W, H); rctx.clearRect(0, 0, W, H);
if (!chuva && chuvaAmt < 0.005) { rainLoopOn = false; return; }
requestAnimationFrame(drawRain);
if (chuvaAmt < 0.005) return; if (chuvaAmt < 0.005) return;
rainDrops.forEach(d => { rainDrops.forEach(d => {
@ -2112,6 +2114,8 @@ function triggerLightning() {
}, delay); }, delay);
delay += 100 + (Math.random() * 110 | 0); delay += 100 + (Math.random() * 110 | 0);
} }
/* limpa o tom azulado do strobe depois da rajada */
setTimeout(() => { strobeEl.style.background = ''; }, delay + 300);
} }
(function scheduleLightning() { (function scheduleLightning() {
@ -2123,7 +2127,7 @@ function triggerLightning() {
function setChuvaMode(on) { function setChuvaMode(on) {
if (on === chuva) return; if (on === chuva) return;
chuva = on; chuva = on;
if (on) setBaladaMode(false); if (on) { setBaladaMode(false); startRainLoop(); }
document.body.classList.toggle('chuva', chuva); document.body.classList.toggle('chuva', chuva);
if (on) { if (on) {
fogWisps.forEach(w => { fogWisps.forEach(w => {
@ -2156,7 +2160,7 @@ let chuvaFileVal = null;
if (window.innerWidth > 0 && window.innerHeight > 0) { if (window.innerWidth > 0 && window.innerHeight > 0) {
resizeRain(); resizeRain();
initRain(); initRain();
requestAnimationFrame(drawRain); if (chuva) startRainLoop();
} else { } else {
setTimeout(initRainOnLoad, 80); setTimeout(initRainOnLoad, 80);
} }