diff --git a/src/lib/generators/air-quality/AirQualityGen.svelte b/src/lib/generators/air-quality/AirQualityGen.svelte index f2688a6..c05bde6 100644 --- a/src/lib/generators/air-quality/AirQualityGen.svelte +++ b/src/lib/generators/air-quality/AirQualityGen.svelte @@ -25,6 +25,9 @@ window.innerWidth < 768); const vizSize = isMobile ? 280 : 400; + // Screen Wake Lock to prevent screen from sleeping during playback + let wakeLock: WakeLockSentinel | null = null; + // Audio components let noiseSynth: Tone.NoiseSynth | null = null; let reverb: Tone.Reverb | null = null; @@ -68,6 +71,36 @@ return Math.max(0.2, Math.min(0.7, (speed / 20) * 0.5 + 0.2)); }); + // Request wake lock to prevent screen from sleeping + const requestWakeLock = async (): Promise => { + try { + if ('wakeLock' in navigator) { + wakeLock = await navigator.wakeLock.request('screen'); + console.log('Wake Lock is active (Air Quality)'); + + // Handle wake lock release (e.g., when tab is hidden) + wakeLock.addEventListener('release', () => { + console.log('Wake Lock was released (Air Quality)'); + }); + } + } catch (err) { + console.error('Failed to request wake lock:', err); + } + }; + + // Release wake lock + const releaseWakeLock = async (): Promise => { + if (wakeLock !== null) { + try { + await wakeLock.release(); + wakeLock = null; + console.log('Wake Lock released (Air Quality)'); + } catch (err) { + console.error('Failed to release wake lock:', err); + } + } + }; + // Initialize audio components const initializeAudio = async (): Promise => { try { @@ -140,6 +173,9 @@ Tone.getTransport().start(); } + // Request wake lock to prevent screen sleep + await requestWakeLock(); + isPlaying = true; } catch (error) { console.error('Error starting air quality loop:', error); @@ -147,7 +183,7 @@ }; // Stop the loop - const stopLoop = (): void => { + const stopLoop = async (): Promise => { if (loop) { loop.stop(); loop.dispose(); @@ -155,6 +191,9 @@ } // Don't stop transport - let WeatherGen control it isPlaying = false; + + // Release wake lock when stopping + await releaseWakeLock(); }; // Toggle playback @@ -210,6 +249,10 @@ if (loop && loop.state !== 'started') { loop.start(0); } + // Re-request wake lock if it was released + if (wakeLock === null) { + await requestWakeLock(); + } } }; @@ -220,7 +263,10 @@ }; }); - onDestroy(() => { + onDestroy(async () => { + // Release wake lock on component destroy + await releaseWakeLock(); + if (loop) { loop.dispose(); } diff --git a/src/lib/generators/weather/WeatherGen.svelte b/src/lib/generators/weather/WeatherGen.svelte index d93efbb..87154c7 100644 --- a/src/lib/generators/weather/WeatherGen.svelte +++ b/src/lib/generators/weather/WeatherGen.svelte @@ -37,6 +37,9 @@ window.innerWidth < 768); const vizSize = isMobile ? 280 : 400; + // Screen Wake Lock to prevent screen from sleeping during playback + let wakeLock: WakeLockSentinel | null = null; + // Audio components let synth: Tone.PolySynth | null = null; let arpSynth: Tone.Synth | null = null; @@ -154,6 +157,36 @@ return '16n'; }); + // Request wake lock to prevent screen from sleeping + const requestWakeLock = async (): Promise => { + try { + if ('wakeLock' in navigator) { + wakeLock = await navigator.wakeLock.request('screen'); + console.log('Wake Lock is active'); + + // Handle wake lock release (e.g., when tab is hidden) + wakeLock.addEventListener('release', () => { + console.log('Wake Lock was released'); + }); + } + } catch (err) { + console.error('Failed to request wake lock:', err); + } + }; + + // Release wake lock + const releaseWakeLock = async (): Promise => { + if (wakeLock !== null) { + try { + await wakeLock.release(); + wakeLock = null; + console.log('Wake Lock released'); + } catch (err) { + console.error('Failed to release wake lock:', err); + } + } + }; + // Initialize audio components const initializeAudio = async (): Promise => { try { @@ -308,6 +341,10 @@ bassSequence.start(0); Tone.getTransport().start(); + + // Request wake lock to prevent screen sleep + await requestWakeLock(); + isPlaying = true; } catch (error) { console.error('Error starting sequence:', error); @@ -315,7 +352,7 @@ }; // Stop the sequence - const stopSequence = (): void => { + const stopSequence = async (): Promise => { if (sequence) { sequence.stop(); sequence.dispose(); @@ -339,6 +376,9 @@ Tone.getTransport().stop(); Tone.getTransport().cancel(); isPlaying = false; + + // Release wake lock when stopping + await releaseWakeLock(); }; // Toggle playback @@ -415,6 +455,10 @@ if (Tone.getTransport().state !== 'started') { Tone.getTransport().start(); } + // Re-request wake lock if it was released + if (wakeLock === null) { + await requestWakeLock(); + } } }; @@ -425,7 +469,10 @@ }; }); - onDestroy(() => { + onDestroy(async () => { + // Release wake lock on component destroy + await releaseWakeLock(); + if (sequence) { sequence.dispose(); }