web3district commited on
Commit
cbc9ad8
·
verified ·
1 Parent(s): 6b438dc

before the app asked to access microphone and now not please fix - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +201 -46
index.html CHANGED
@@ -146,6 +146,9 @@
146
  <button id="add-player" class="bg-primary-600 hover:bg-primary-700 text-white py-2 px-6 rounded-xl flex items-center">
147
  <i class="fas fa-user-plus mr-2"></i> Add Player
148
  </button>
 
 
 
149
  <button id="buzz-test" class="bg-warning-600 hover:bg-warning-700 text-white py-2 px-6 rounded-xl flex items-center">
150
  <i class="fas fa-bolt mr-2"></i> Test Buzz
151
  </button>
@@ -238,6 +241,40 @@
238
  </div>
239
  </div>
240
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
  <script>
243
  // Game state variables
@@ -290,12 +327,27 @@
290
 
291
  // Buttons
292
  document.getElementById('add-player').addEventListener('click', openAddPlayerModal);
 
293
  document.getElementById('buzz-test').addEventListener('click', simulateBuzz);
294
  document.getElementById('new-game').addEventListener('click', startNewGame);
295
  document.getElementById('play-again').addEventListener('click', startNewGame);
296
  document.getElementById('cancel-player').addEventListener('click', closeAddPlayerModal);
297
  document.getElementById('save-player').addEventListener('click', addNewPlayer);
 
 
298
  document.querySelector('#game-over-modal button').addEventListener('click', () => gameOverModal.classList.add('hidden'));
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
  // Initialize the game
301
  function initGame() {
@@ -306,54 +358,33 @@
306
  // Set up audio listening
307
  async function setupMicrophone() {
308
  try {
309
- gameState.audioContext = new (window.AudioContext || window.webkitAudioContext)();
310
- gameState.analyser = gameState.audioContext.createAnalyser();
 
 
 
311
 
312
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
313
- gameState.microphone = gameState.audioContext.createMediaStreamSource(stream);
314
- gameState.microphone.connect(gameState.analyser);
315
 
316
- gameState.analyser.fftSize = 256;
317
- const bufferLength = gameState.analyser.frequencyBinCount;
318
- const dataArray = new Uint8Array(bufferLength);
 
 
319
 
320
- const detectSound = () => {
321
- if (!gameState.gameActive) return;
322
-
323
- gameState.analyser.getByteFrequencyData(dataArray);
324
-
325
- let total = 0;
326
- for (let i = 0; i < bufferLength; i++) {
327
- total += dataArray[i];
328
- }
329
- const average = total / bufferLength;
330
-
331
- // Update buzzer indicator status
332
- if (average > 60) {
333
- buzzerStatusEl.classList.remove('bg-gray-500');
334
- buzzerStatusEl.classList.add('animate-pulse-fast');
335
-
336
- if (average > 80) {
337
- // Trigger buzz detection
338
- handleBuzzDetected();
339
- // Flash red for buzz
340
- buzzerStatusEl.classList.remove('bg-green-500', 'bg-yellow-500');
341
- buzzerStatusEl.classList.add('bg-red-500');
342
- } else {
343
- // Sound detected but not buzzing yet
344
- buzzerStatusEl.classList.add('bg-yellow-500');
345
- }
346
- } else {
347
- buzzerStatusEl.classList.remove('bg-red-500', 'bg-yellow-500', 'animate-pulse-fast');
348
- buzzerStatusEl.classList.add('bg-green-500');
349
- }
350
-
351
- requestAnimationFrame(detectSound);
352
- };
353
 
354
- detectSound();
355
  buzzerStatusEl.classList.remove('bg-gray-500');
356
  buzzerStatusEl.classList.add('bg-green-500');
 
 
 
 
 
 
357
  } catch (err) {
358
  buzzerStatusEl.classList.remove('bg-gray-500');
359
  buzzerStatusEl.classList.add('bg-red-500');
@@ -715,12 +746,135 @@
715
  updatePlayerListDisplay();
716
  gameOverModal.classList.add('hidden');
717
 
718
- // Setup microphone if not already done
719
- if (!gameState.audioContext) {
720
- setupMicrophone();
721
- }
722
  }
723
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  // Simulate a buzz for testing
725
  function simulateBuzz() {
726
  handleBuzzDetected();
@@ -741,6 +895,7 @@
741
  document.addEventListener('DOMContentLoaded', () => {
742
  initGame();
743
  updateLifeDisplay();
 
744
  });
745
  </script>
746
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=web3district/operation-table" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
146
  <button id="add-player" class="bg-primary-600 hover:bg-primary-700 text-white py-2 px-6 rounded-xl flex items-center">
147
  <i class="fas fa-user-plus mr-2"></i> Add Player
148
  </button>
149
+ <button id="calibrate" class="bg-secondary-600 hover:bg-secondary-700 text-white py-2 px-6 rounded-xl flex items-center">
150
+ <i class="fas fa-sliders-h mr-2"></i> Calibrate
151
+ </button>
152
  <button id="buzz-test" class="bg-warning-600 hover:bg-warning-700 text-white py-2 px-6 rounded-xl flex items-center">
153
  <i class="fas fa-bolt mr-2"></i> Test Buzz
154
  </button>
 
241
  </div>
242
  </div>
243
  </div>
244
+
245
+ <!-- Calibration Modal -->
246
+ <div id="calibration-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50 hidden">
247
+ <div class="bg-gray-800 rounded-2xl max-w-md w-full p-8">
248
+ <h2 class="text-2xl font-bold mb-6 text-center">Calibrate Buzzer</h2>
249
+
250
+ <div class="mb-6">
251
+ <p class="mb-4">Press the buzzer from your Operation game 3-5 times to calibrate. The detector will learn the frequency pattern of your specific buzzer.</p>
252
+ <div class="bg-gray-700 rounded-lg p-4 mb-4">
253
+ <div class="flex items-center justify-between mb-2">
254
+ <span>Buzz Detections:</span>
255
+ <span id="calibration-count">0</span>
256
+ </div>
257
+ <div class="h-4 bg-gray-600 rounded-full overflow-hidden">
258
+ <div id="calibration-progress" class="h-full bg-success-600" style="width: 0%"></div>
259
+ </div>
260
+ </div>
261
+ <div class="text-center">
262
+ <div id="calibration-status" class="inline-block px-3 py-1 rounded-full text-sm text-gray-200 bg-gray-700 mb-4">
263
+ Ready to calibrate
264
+ </div>
265
+ <div id="sound-level" class="w-full h-2 bg-gray-700 rounded-full overflow-hidden mb-2">
266
+ <div class="h-full bg-primary-600" style="width: 0%"></div>
267
+ </div>
268
+ <div class="text-xs text-gray-400">Current sound level</div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="flex gap-3">
273
+ <button id="cancel-calibration" class="flex-1 bg-gray-700 hover:bg-gray-600 py-3 rounded-xl font-medium">Cancel</button>
274
+ <button id="finish-calibration" class="flex-1 bg-primary-600 hover:bg-primary-700 py-3 rounded-xl font-medium">Finish</button>
275
+ </div>
276
+ </div>
277
+ </div>
278
 
279
  <script>
280
  // Game state variables
 
327
 
328
  // Buttons
329
  document.getElementById('add-player').addEventListener('click', openAddPlayerModal);
330
+ document.getElementById('calibrate').addEventListener('click', startCalibration);
331
  document.getElementById('buzz-test').addEventListener('click', simulateBuzz);
332
  document.getElementById('new-game').addEventListener('click', startNewGame);
333
  document.getElementById('play-again').addEventListener('click', startNewGame);
334
  document.getElementById('cancel-player').addEventListener('click', closeAddPlayerModal);
335
  document.getElementById('save-player').addEventListener('click', addNewPlayer);
336
+ document.getElementById('cancel-calibration').addEventListener('click', cancelCalibration);
337
+ document.getElementById('finish-calibration').addEventListener('click', finishCalibration);
338
  document.querySelector('#game-over-modal button').addEventListener('click', () => gameOverModal.classList.add('hidden'));
339
+
340
+ // Audio detection settings
341
+ let audioSettings = {
342
+ minFrequency: 1000, // Default minimum frequency
343
+ maxFrequency: 3000, // Default maximum frequency
344
+ threshold: 0.7, // Default volume threshold
345
+ calibrated: false,
346
+ calibrationSamples: []
347
+ };
348
+
349
+ // Microphone stream
350
+ let microphoneStream = null;
351
 
352
  // Initialize the game
353
  function initGame() {
 
358
  // Set up audio listening
359
  async function setupMicrophone() {
360
  try {
361
+ if (!gameState.audioContext) {
362
+ gameState.audioContext = new (window.AudioContext || window.webkitAudioContext)();
363
+ gameState.analyser = gameState.audioContext.createAnalyser();
364
+ gameState.analyser.fftSize = 2048;
365
+ }
366
 
367
+ if (microphoneStream) {
368
+ microphoneStream.getTracks().forEach(track => track.stop());
369
+ }
370
 
371
+ microphoneStream = await navigator.mediaDevices.getUserMedia({ audio: {
372
+ echoCancellation: false,
373
+ noiseSuppression: false,
374
+ autoGainControl: false
375
+ }});
376
 
377
+ gameState.microphone = gameState.audioContext.createMediaStreamSource(microphoneStream);
378
+ gameState.microphone.connect(gameState.analyser);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
 
380
  buzzerStatusEl.classList.remove('bg-gray-500');
381
  buzzerStatusEl.classList.add('bg-green-500');
382
+
383
+ if (!audioSettings.calibrated) {
384
+ startCalibration();
385
+ } else {
386
+ startAudioDetection();
387
+ }
388
  } catch (err) {
389
  buzzerStatusEl.classList.remove('bg-gray-500');
390
  buzzerStatusEl.classList.add('bg-red-500');
 
746
  updatePlayerListDisplay();
747
  gameOverModal.classList.add('hidden');
748
 
749
+ // Setup microphone
750
+ setupMicrophone();
 
 
751
  }
752
 
753
+ // Start calibration mode
754
+ function startCalibration() {
755
+ audioSettings.calibrationSamples = [];
756
+ document.getElementById('calibration-count').textContent = '0';
757
+ document.getElementById('calibration-progress').style.width = '0%';
758
+ document.getElementById('calibration-status').textContent = 'Making initial analysis...';
759
+ document.getElementById('calibration-status').className = 'inline-block px-3 py-1 rounded-full text-sm text-gray-200 bg-gray-700 mb-4';
760
+
761
+ calibrationModal.classList.remove('hidden');
762
+ startAudioDetection(true);
763
+ }
764
+
765
+ // Cancel calibration
766
+ function cancelCalibration() {
767
+ calibrationModal.classList.add('hidden');
768
+ if (gameState.gameActive) {
769
+ startAudioDetection();
770
+ }
771
+ }
772
+
773
+ // Finish calibration and calculate thresholds
774
+ function finishCalibration() {
775
+ if (audioSettings.calibrationSamples.length > 0) {
776
+ // Calculate average frequency and volume thresholds
777
+ const avgFreq = audioSettings.calibrationSamples.reduce((sum, val) => sum + val.frequency, 0) / audioSettings.calibrationSamples.length;
778
+ const avgVol = audioSettings.calibrationSamples.reduce((sum, val) => sum + val.volume, 0) / audioSettings.calibrationSamples.length;
779
+
780
+ // Set detection thresholds with some buffer
781
+ audioSettings.minFrequency = Math.max(0, avgFreq - 200);
782
+ audioSettings.maxFrequency = avgFreq + 200;
783
+ audioSettings.threshold = avgVol * 0.7; // 70% of average volume
784
+ audioSettings.calibrated = true;
785
+
786
+ document.getElementById('calibration-status').textContent = 'Calibration complete!';
787
+ document.getElementById('calibration-status').className = 'inline-block px-3 py-1 rounded-full text-sm text-white bg-success-600 mb-4';
788
+
789
+ setTimeout(() => {
790
+ calibrationModal.classList.add('hidden');
791
+ if (gameState.gameActive) {
792
+ startAudioDetection();
793
+ }
794
+ }, 1000);
795
+ }
796
+ }
797
+
798
+ // Start audio detection
799
+ function startAudioDetection(isCalibrating = false) {
800
+ const bufferLength = gameState.analyser.frequencyBinCount;
801
+ const dataArray = new Uint8Array(bufferLength);
802
+ const frequencyData = new Float32Array(bufferLength);
803
+
804
+ const sampleRate = gameState.audioContext.sampleRate;
805
+ const minFreq = isCalibrating ? 0 : audioSettings.minFrequency;
806
+ const maxFreq = isCalibrating ? sampleRate/2 : audioSettings.maxFrequency;
807
+
808
+ const detectSound = () => {
809
+ if (!gameState.gameActive && !isCalibrating) return;
810
+
811
+ gameState.analyser.getByteFrequencyData(dataArray);
812
+ gameState.analyser.getFloatFrequencyData(frequencyData);
813
+
814
+ // Get frequency with peak volume
815
+ let maxVolume = -Infinity;
816
+ let peakFrequency = 0;
817
+ let totalVolume = 0;
818
+
819
+ for (let i = 0; i < bufferLength; i++) {
820
+ const freq = i * sampleRate / bufferLength;
821
+ if (freq >= minFreq && freq <= maxFreq) {
822
+ if (dataArray[i] > maxVolume) {
823
+ maxVolume = dataArray[i];
824
+ peakFrequency = freq;
825
+ }
826
+ totalVolume += dataArray[i];
827
+ }
828
+ }
829
+
830
+ const avgVolume = totalVolume / bufferLength;
831
+
832
+ // Update sound level indicator for calibration
833
+ if (isCalibrating) {
834
+ const soundLevelBar = document.querySelector('#sound-level div');
835
+ const normalizedVolume = Math.min(100, Math.max(0, (avgVolume / 255) * 100));
836
+ soundLevelBar.style.width = `${normalizedVolume}%`;
837
+ }
838
+
839
+ // Detect buzz - during calibration or normal play
840
+ if (avgVolume > (isCalibrating ? 30 : audioSettings.threshold * 255)) {
841
+ if (isCalibrating) {
842
+ // During calibration, record the frequency signature
843
+ audioSettings.calibrationSamples.push({
844
+ frequency: peakFrequency,
845
+ volume: avgVolume / 255
846
+ });
847
+
848
+ const count = audioSettings.calibrationSamples.length;
849
+ document.getElementById('calibration-count').textContent = count;
850
+ document.getElementById('calibration-progress').style.width = `${Math.min(100, count * 20)}%`;
851
+
852
+ if (count >= 3) {
853
+ document.getElementById('calibration-status').textContent = 'Good samples collected!';
854
+ document.getElementById('calibration-status').className = 'inline-block px-3 py-1 rounded-full text-sm text-white bg-success-600 mb-4';
855
+ }
856
+ } else {
857
+ // During normal gameplay, trigger buzz effects
858
+ handleBuzzDetected();
859
+ buzzerStatusEl.classList.remove('bg-green-500', 'bg-yellow-500');
860
+ buzzerStatusEl.classList.add('bg-red-500', 'animate-buzz');
861
+ setTimeout(() => {
862
+ buzzerStatusEl.classList.remove('animate-buzz');
863
+ }, 500);
864
+ }
865
+ } else {
866
+ buzzerStatusEl.classList.remove('bg-red-500', 'animate-buzz');
867
+ if (gameState.gameActive) {
868
+ buzzerStatusEl.classList.add('bg-green-500');
869
+ }
870
+ }
871
+
872
+ requestAnimationFrame(detectSound);
873
+ };
874
+
875
+ detectSound();
876
+ }
877
+
878
  // Simulate a buzz for testing
879
  function simulateBuzz() {
880
  handleBuzzDetected();
 
895
  document.addEventListener('DOMContentLoaded', () => {
896
  initGame();
897
  updateLifeDisplay();
898
+ setupMicrophone(); // Request mic access on load
899
  });
900
  </script>
901
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=web3district/operation-table" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>