@@ -20,14 +20,24 @@ let touchStartX = 0;
2020let touchStartY = 0 ;
2121let minSwipeDistance = 50 ; // Minimum distance for swipe gesture
2222
23- const audioContext = new ( window . AudioContext || window . webkitAudioContext ) ( ) ;
23+ // Initialize AudioContext - will be created after user interaction
24+ let audioContext = null ;
2425
25- // Add a click listener to resume audio context
26- document . body . addEventListener ( 'click' , ( ) => {
26+ // Function to initialize/resume audio context
27+ const initAudioContext = ( ) => {
28+ if ( ! audioContext ) {
29+ audioContext = new ( window . AudioContext || window . webkitAudioContext ) ( ) ;
30+ }
2731 if ( audioContext . state === 'suspended' ) {
2832 audioContext . resume ( ) ;
2933 }
30- } ) ;
34+ return audioContext ;
35+ } ;
36+
37+ // Add multiple event listeners to resume audio context (required by browsers)
38+ document . addEventListener ( 'click' , initAudioContext , { once : false } ) ;
39+ document . addEventListener ( 'touchstart' , initAudioContext , { once : false } ) ;
40+ document . addEventListener ( 'keydown' , initAudioContext , { once : false } ) ;
3141
3242// Haptic feedback function
3343const hapticFeedback = ( type = 'light' ) => {
@@ -133,24 +143,35 @@ gameBoard.addEventListener('touchend', handleTouchEnd, { passive: false });
133143
134144// Create longer, more arcade-style sound effects
135145const playSound = ( type ) => {
136- if ( ! audioContext || audioContext . state === 'suspended' ) return ;
146+ // Initialize audio context if needed
147+ const ctx = initAudioContext ( ) ;
148+ if ( ! ctx || ctx . state === 'suspended' ) {
149+ // Try to resume if suspended
150+ if ( ctx && ctx . state === 'suspended' ) {
151+ ctx . resume ( ) . catch ( ( ) => {
152+ // If resume fails, audio won't play - that's okay
153+ return ;
154+ } ) ;
155+ }
156+ return ;
157+ }
137158
138- const now = audioContext . currentTime ;
159+ const now = ctx . currentTime ;
139160 const duration = type === 'win' ? 1.2 : type === 'lose' ? 1.0 : type === 'draw' ? 0.8 : 0.3 ;
140161
141162 switch ( type ) {
142163 case 'move' :
143164 // Bouncy arcade beep for moves
144- const osc1 = audioContext . createOscillator ( ) ;
145- const gain1 = audioContext . createGain ( ) ;
165+ const osc1 = ctx . createOscillator ( ) ;
166+ const gain1 = ctx . createGain ( ) ;
146167 osc1 . type = 'square' ;
147168 osc1 . frequency . setValueAtTime ( 400 , now ) ;
148169 osc1 . frequency . exponentialRampToValueAtTime ( 600 , now + 0.15 ) ;
149170 osc1 . frequency . exponentialRampToValueAtTime ( 300 , now + 0.3 ) ;
150171 gain1 . gain . setValueAtTime ( 0.3 , now ) ;
151172 gain1 . gain . exponentialRampToValueAtTime ( 0.01 , now + duration ) ;
152173 osc1 . connect ( gain1 ) ;
153- gain1 . connect ( audioContext . destination ) ;
174+ gain1 . connect ( ctx . destination ) ;
154175 osc1 . start ( now ) ;
155176 osc1 . stop ( now + duration ) ;
156177 break ;
@@ -159,15 +180,15 @@ const playSound = (type) => {
159180 // Victory fanfare - ascending chord sequence
160181 const notes = [ 523.25 , 659.25 , 783.99 , 1046.50 ] ; // C5, E5, G5, C6
161182 notes . forEach ( ( freq , i ) => {
162- const osc = audioContext . createOscillator ( ) ;
163- const gain = audioContext . createGain ( ) ;
183+ const osc = ctx . createOscillator ( ) ;
184+ const gain = ctx . createGain ( ) ;
164185 osc . type = 'sine' ;
165186 osc . frequency . setValueAtTime ( freq , now ) ;
166187 gain . gain . setValueAtTime ( 0 , now + i * 0.15 ) ;
167188 gain . gain . linearRampToValueAtTime ( 0.4 , now + i * 0.15 + 0.05 ) ;
168189 gain . gain . exponentialRampToValueAtTime ( 0.01 , now + duration - i * 0.1 ) ;
169190 osc . connect ( gain ) ;
170- gain . connect ( audioContext . destination ) ;
191+ gain . connect ( ctx . destination ) ;
171192 osc . start ( now + i * 0.15 ) ;
172193 osc . stop ( now + duration ) ;
173194 } ) ;
@@ -177,15 +198,15 @@ const playSound = (type) => {
177198 // Defeat sound - descending notes
178199 const loseNotes = [ 523.25 , 440 , 349.23 , 261.63 ] ; // C5, A4, F4, C4
179200 loseNotes . forEach ( ( freq , i ) => {
180- const osc = audioContext . createOscillator ( ) ;
181- const gain = audioContext . createGain ( ) ;
201+ const osc = ctx . createOscillator ( ) ;
202+ const gain = ctx . createGain ( ) ;
182203 osc . type = 'sawtooth' ;
183204 osc . frequency . setValueAtTime ( freq , now ) ;
184205 gain . gain . setValueAtTime ( 0 , now + i * 0.2 ) ;
185206 gain . gain . linearRampToValueAtTime ( 0.35 , now + i * 0.2 + 0.05 ) ;
186207 gain . gain . exponentialRampToValueAtTime ( 0.01 , now + i * 0.2 + 0.25 ) ;
187208 osc . connect ( gain ) ;
188- gain . connect ( audioContext . destination ) ;
209+ gain . connect ( ctx . destination ) ;
189210 osc . start ( now + i * 0.2 ) ;
190211 osc . stop ( now + i * 0.2 + 0.3 ) ;
191212 } ) ;
@@ -194,24 +215,24 @@ const playSound = (type) => {
194215 case 'draw' :
195216 // Neutral draw sound - two tones
196217 [ 440 , 523.25 ] . forEach ( ( freq , i ) => {
197- const osc = audioContext . createOscillator ( ) ;
198- const gain = audioContext . createGain ( ) ;
218+ const osc = ctx . createOscillator ( ) ;
219+ const gain = ctx . createGain ( ) ;
199220 osc . type = 'triangle' ;
200221 osc . frequency . setValueAtTime ( freq , now + i * 0.2 ) ;
201222 gain . gain . setValueAtTime ( 0 , now + i * 0.2 ) ;
202223 gain . gain . linearRampToValueAtTime ( 0.3 , now + i * 0.2 + 0.05 ) ;
203224 gain . gain . exponentialRampToValueAtTime ( 0.01 , now + i * 0.2 + 0.35 ) ;
204225 osc . connect ( gain ) ;
205- gain . connect ( audioContext . destination ) ;
226+ gain . connect ( ctx . destination ) ;
206227 osc . start ( now + i * 0.2 ) ;
207228 osc . stop ( now + i * 0.2 + 0.4 ) ;
208229 } ) ;
209230 break ;
210231
211232 case 'restart' :
212233 // Quick restart beep
213- const osc2 = audioContext . createOscillator ( ) ;
214- const gain2 = audioContext . createGain ( ) ;
234+ const osc2 = ctx . createOscillator ( ) ;
235+ const gain2 = ctx . createGain ( ) ;
215236 osc2 . type = 'square' ;
216237 osc2 . frequency . setValueAtTime ( 600 , now ) ;
217238 osc2 . frequency . exponentialRampToValueAtTime ( 800 , now + 0.15 ) ;
0 commit comments