zeroed-some/dougk / 704f01b

Browse files

touchstart listener, silent buffer trick, resume suspended context

Authored by espadonne
SHA
704f01b753fa3572d3b055147be7c43e81405840
Parents
50b0455
Tree
482c822

2 changed files

StatusFile+-
M src/renderers/three/index.js 7 0
M src/renderers/three/sounds.js 22 0
src/renderers/three/index.jsmodified
@@ -7,6 +7,7 @@ import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'
77
 import { createDoug } from './duck.js'
88
 import { createPond } from './pond.js'
99
 import { BreadManager } from './bread.js'
10
+import { unlockAudio } from './sounds.js'
1011
 
1112
 let scene, camera, renderer, composer, outlinePass
1213
 let doug, pond, breadManager
@@ -102,7 +103,13 @@ export function start(container) {
102103
   const raycaster = new THREE.Raycaster()
103104
   const mouse = new THREE.Vector2()
104105
 
106
+  // Unlock audio on first touch (for mobile)
107
+  renderer.domElement.addEventListener('touchstart', unlockAudio, { once: true })
108
+
105109
   renderer.domElement.addEventListener('click', (event) => {
110
+    // Unlock audio on first interaction (required for mobile)
111
+    unlockAudio()
112
+
106113
     mouse.x = (event.clientX / window.innerWidth) * 2 - 1
107114
     mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
108115
 
src/renderers/three/sounds.jsmodified
@@ -1,6 +1,7 @@
11
 // Web Audio API sound synthesis for dougk
22
 
33
 let audioContext = null
4
+let unlocked = false
45
 
56
 function getContext() {
67
   if (!audioContext) {
@@ -9,6 +10,27 @@ function getContext() {
910
   return audioContext
1011
 }
1112
 
13
+// Must be called on first user interaction to enable audio on mobile
14
+export function unlockAudio() {
15
+  if (unlocked) return
16
+
17
+  const ctx = getContext()
18
+
19
+  // Resume if suspended
20
+  if (ctx.state === 'suspended') {
21
+    ctx.resume()
22
+  }
23
+
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
+
31
+  unlocked = true
32
+}
33
+
1234
 // Damp crunch sound - wet bread being chomped
1335
 export function playMonch() {
1436
   const ctx = getContext()