zeroed-some/dougk / f86d428

Browse files

tweak sound a bnit

Authored by espadonne
SHA
f86d4288f7acf974765964bc1ab7f4a1a11811e8
Parents
704f01b
Tree
5a62231

2 changed files

StatusFile+-
M src/renderers/three/index.js 9 0
M src/renderers/three/sounds.js 28 11
src/renderers/three/index.jsmodified
@@ -38,6 +38,15 @@ function createToonGradient() {
3838
 export function start(container) {
3939
   if (animationId) return
4040
 
41
+  // Unlock audio on any user interaction (document level for mobile)
42
+  const unlockEvents = ['touchstart', 'touchend', 'pointerdown', 'click', 'keydown']
43
+  const unlockHandler = () => {
44
+    unlockAudio()
45
+    // Remove all listeners after first unlock
46
+    unlockEvents.forEach(e => document.removeEventListener(e, unlockHandler))
47
+  }
48
+  unlockEvents.forEach(e => document.addEventListener(e, unlockHandler, { passive: true }))
49
+
4150
   // Scene
4251
   scene = new THREE.Scene()
4352
   scene.background = new THREE.Color(0x55a04b)
src/renderers/three/sounds.jsmodified
@@ -13,34 +13,51 @@ function getContext() {
1313
 // Must be called on first user interaction to enable audio on mobile
1414
 export function unlockAudio() {
1515
   if (unlocked) return
16
+  unlocked = true // Set immediately to prevent multiple attempts
1617
 
17
-  const ctx = getContext()
18
+  // Create context fresh during user gesture (mobile requirement)
19
+  if (!audioContext) {
20
+    audioContext = new (window.AudioContext || window.webkitAudioContext)()
21
+  }
22
+
23
+  const ctx = audioContext
1824
 
19
-  // Resume if suspended
25
+  // Resume synchronously - don't wait for promise
2026
   if (ctx.state === 'suspended') {
2127
     ctx.resume()
2228
   }
2329
 
24
-  // Play a silent buffer to fully unlock on iOS/mobile
25
-  const silentBuffer = ctx.createBuffer(1, 1, ctx.sampleRate)
26
-  const source = ctx.createBufferSource()
27
-  source.buffer = silentBuffer
28
-  source.connect(ctx.destination)
29
-  source.start(0)
30
+  // Immediately play a sound to force audio pipeline open
31
+  // Must happen synchronously in the user gesture
32
+  try {
33
+    const osc = ctx.createOscillator()
34
+    const gain = ctx.createGain()
35
+
36
+    osc.type = 'triangle'
37
+    osc.frequency.value = 200
38
+    gain.gain.value = 0.001 // Nearly silent
3039
 
31
-  unlocked = true
40
+    osc.connect(gain)
41
+    gain.connect(ctx.destination)
42
+
43
+    osc.start(0)
44
+    osc.stop(ctx.currentTime + 0.1)
45
+  } catch (e) {
46
+    console.warn('Unlock sound failed:', e)
47
+  }
3248
 }
3349
 
3450
 // Damp crunch sound - wet bread being chomped
3551
 export function playMonch() {
3652
   const ctx = getContext()
37
-  const now = ctx.currentTime
3853
 
39
-  // Resume context if suspended (browser autoplay policy)
54
+  // Try to resume if needed, but don't block
4055
   if (ctx.state === 'suspended') {
4156
     ctx.resume()
4257
   }
4358
 
59
+  const now = ctx.currentTime
60
+
4461
   // Master output - keep it gentle
4562
   const master = ctx.createGain()
4663
   master.gain.value = 0.25