diff --git a/plugin/contents/ui/dancer.html b/plugin/contents/ui/dancer.html index 53eb3d3..16caced 100644 --- a/plugin/contents/ui/dancer.html +++ b/plugin/contents/ui/dancer.html @@ -1802,7 +1802,15 @@ globeCanvas.style.cssText = 'opacity:0;transition:opacity 1.5s ease;'; sunEl.appendChild(globeCanvas); 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. ±Y não são afetados pelo lrot, ±X e ±Z orbitam entre si. */ @@ -1818,6 +1826,7 @@ const MIRROR_LIGHTS = [ ]; function drawGlobe(ts) { + if (!balada && baladaAmt < 0.01) { globeLoopOn = false; lastGlobeTs = 0; return; } requestAnimationFrame(drawGlobe); if (baladaAmt < 0.01) { lastGlobeTs = 0; return; } globeCanvas.style.opacity = chuva ? 0 : baladaAmt; @@ -1900,7 +1909,6 @@ function drawGlobe(ts) { gctx.restore(); } -requestAnimationFrame(drawGlobe); const discoDots = document.getElementById('discoDots'); const strobeEl = document.getElementById('strobe'); @@ -1959,22 +1967,6 @@ setInterval(() => { if (baladaAmt > 0.3 && discoDots.childElementCount < 28) spawnDiscoDot(); }, 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 ── */ function globeBeat() { if (!balada || !sunEl) return; @@ -1989,7 +1981,7 @@ setInterval(() => { if (balada) globeBeat(); }, BEAT_MS); function setBaladaMode(on) { if (on === balada) return; balada = on; - if (on) setChuvaMode(false); + if (on) { setChuvaMode(false); startGlobeLoop(); } document.body.classList.toggle('balada', balada); /* opacidade do globo é controlada por drawGlobe via baladaAmt */ } @@ -2066,16 +2058,26 @@ 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) { - requestAnimationFrame(drawRain); const dt = lastRainTs ? Math.min((ts - lastRainTs) / 1000, 0.05) : 0; lastRainTs = ts; chuvaAmt += ((chuva ? 1 : 0) - chuvaAmt) * Math.min(1, dt * 0.5); const W = rainCanvas.width, H = rainCanvas.height; rctx.clearRect(0, 0, W, H); + if (!chuva && chuvaAmt < 0.005) { rainLoopOn = false; return; } + requestAnimationFrame(drawRain); if (chuvaAmt < 0.005) return; rainDrops.forEach(d => { @@ -2112,6 +2114,8 @@ function triggerLightning() { }, delay); delay += 100 + (Math.random() * 110 | 0); } + /* limpa o tom azulado do strobe depois da rajada */ + setTimeout(() => { strobeEl.style.background = ''; }, delay + 300); } (function scheduleLightning() { @@ -2123,7 +2127,7 @@ function triggerLightning() { function setChuvaMode(on) { if (on === chuva) return; chuva = on; - if (on) setBaladaMode(false); + if (on) { setBaladaMode(false); startRainLoop(); } document.body.classList.toggle('chuva', chuva); if (on) { fogWisps.forEach(w => { @@ -2156,7 +2160,7 @@ let chuvaFileVal = null; if (window.innerWidth > 0 && window.innerHeight > 0) { resizeRain(); initRain(); - requestAnimationFrame(drawRain); + if (chuva) startRainLoop(); } else { setTimeout(initRainOnLoad, 80); }