// Audio-reactive visualizer for the player bar. // Uses Canvas2D (simpler + lighter than Three.js for a tiny radial visualizer). // Feeds bass energy to the synthwave grid background via window.briTunesBg. const canvas = document.getElementById('player-viz'); const audio = document.getElementById('player-audio'); if (canvas && audio) { const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const ctx = canvas.getContext('2d'); let audioCtx = null; let analyser = null; let freqData = null; let hooked = false; let rafId = null; let visible = true; function resize() { const rect = canvas.getBoundingClientRect(); const dpr = Math.min(window.devicePixelRatio || 1, 2); canvas.width = Math.max(1, Math.round(rect.width * dpr)); canvas.height = Math.max(1, Math.round(rect.height * dpr)); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } resize(); window.addEventListener('resize', resize); function hookAudio() { if (hooked) return; try { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const src = audioCtx.createMediaElementSource(audio); analyser = audioCtx.createAnalyser(); analyser.fftSize = 128; // 64 freq bins analyser.smoothingTimeConstant = 0.82; freqData = new Uint8Array(analyser.frequencyBinCount); src.connect(analyser); analyser.connect(audioCtx.destination); hooked = true; } catch (err) { console.warn('[player-viz] could not hook audio:', err.message); } } window.addEventListener('briTunes:play', () => { hookAudio(); if (audioCtx && audioCtx.state === 'suspended') audioCtx.resume(); if (!rafId && !reduced) rafId = requestAnimationFrame(frame); }); audio.addEventListener('play', () => { // Covers the case where native