p5-phone 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +7 -7
  2. package/dist/p5-phone.js +126 -82
  3. package/dist/p5-phone.min.js +2 -2
  4. package/examples/Phone Sensor Examples/microphone/01_mic_level/index.html +5 -4
  5. package/examples/Phone Sensor Examples/microphone/01_mic_level/sketch.js +15 -1
  6. package/examples/Phone Sensor Examples/microphone/02_speech_recognition/index.html +4 -3
  7. package/examples/Phone Sensor Examples/movement/01_orientation_basic/index.html +3 -3
  8. package/examples/Phone Sensor Examples/movement/02_rotational_velocity/index.html +3 -3
  9. package/examples/Phone Sensor Examples/movement/03_acceleration/index.html +3 -3
  10. package/examples/Phone Sensor Examples/movement/03_acceleration/sketch.js +1 -0
  11. package/examples/Phone Sensor Examples/movement/04_device_shaken/index.html +3 -3
  12. package/examples/Phone Sensor Examples/movement/04_device_shaken/sketch.js +10 -6
  13. package/examples/Phone Sensor Examples/movement/05_device_moved/index.html +3 -3
  14. package/examples/Phone Sensor Examples/movement/05_device_moved/sketch.js +21 -7
  15. package/examples/Phone Sensor Examples/movement/06_device_orientation/index.html +3 -3
  16. package/examples/Phone Sensor Examples/nfc/01_nfc_read/index.html +3 -3
  17. package/examples/Phone Sensor Examples/nfc/01_nfc_read/sketch.js +8 -4
  18. package/examples/Phone Sensor Examples/nfc/02_two_tag_effects/index.html +3 -3
  19. package/examples/Phone Sensor Examples/nfc/02_two_tag_effects/sketch.js +2 -2
  20. package/examples/Phone Sensor Examples/sound/01_dual_audio/index.html +5 -5
  21. package/examples/Phone Sensor Examples/sound/01_dual_audio/sketch.js +107 -152
  22. package/examples/Phone Sensor Examples/sound/02_volume_touches/index.html +5 -5
  23. package/examples/Phone Sensor Examples/sound/02_volume_touches/sketch.js +72 -149
  24. package/examples/Phone Sensor Examples/sound/03_motion_synth/index.html +5 -5
  25. package/examples/Phone Sensor Examples/sound/03_motion_synth/sketch.js +70 -23
  26. package/examples/Phone Sensor Examples/touch/01_touch_basic/index.html +3 -3
  27. package/examples/Phone Sensor Examples/touch/02_touch_zones/index.html +3 -3
  28. package/examples/Phone Sensor Examples/touch/03_touch_count/index.html +3 -3
  29. package/examples/Phone Sensor Examples/touch/04_touch_distance/index.html +3 -3
  30. package/examples/Phone Sensor Examples/touch/05_touch_angle/index.html +3 -3
  31. package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/index.html +3 -3
  32. package/examples/Phone Sensor Examples - Minimal/microphone/01_mic_level/index.html +5 -4
  33. package/examples/Phone Sensor Examples - Minimal/microphone/01_mic_level/sketch.js +18 -2
  34. package/examples/Phone Sensor Examples - Minimal/movement/01_orientation_basic/index.html +3 -2
  35. package/examples/Phone Sensor Examples - Minimal/movement/02_rotational_velocity/index.html +3 -2
  36. package/examples/Phone Sensor Examples - Minimal/movement/03_acceleration/index.html +3 -2
  37. package/examples/Phone Sensor Examples - Minimal/movement/04_device_shaken/index.html +3 -2
  38. package/examples/Phone Sensor Examples - Minimal/movement/04_device_shaken/sketch.js +8 -2
  39. package/examples/Phone Sensor Examples - Minimal/movement/05_device_moved/index.html +3 -2
  40. package/examples/Phone Sensor Examples - Minimal/movement/05_device_moved/sketch.js +18 -2
  41. package/examples/Phone Sensor Examples - Minimal/movement/06_device_orientation/index.html +3 -2
  42. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/index.html +5 -4
  43. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/sketch.js +49 -63
  44. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/index.html +5 -4
  45. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/sketch.js +74 -82
  46. package/examples/Phone Sensor Examples - Minimal/sound/03_motion_synth/index.html +5 -4
  47. package/examples/Phone Sensor Examples - Minimal/sound/03_motion_synth/sketch.js +32 -10
  48. package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/index.html +3 -2
  49. package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/index.html +3 -2
  50. package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/index.html +3 -2
  51. package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/index.html +3 -2
  52. package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/index.html +3 -2
  53. package/examples/Phone Sensor Examples - Minimal/vibration/01_haptic_feedback/index.html +3 -2
  54. package/examples/Phone and Gif/collision/index.html +3 -2
  55. package/examples/Phone and Gif/collision/sketch.js +28 -31
  56. package/examples/Phone and Gif/fetch/index.html +3 -2
  57. package/examples/Phone and Gif/fetch/sketch.js +27 -30
  58. package/examples/Phone and Gif/fly/index.html +3 -2
  59. package/examples/Phone and Gif/fly/sketch.js +19 -22
  60. package/examples/Phone and Gif/roll/index.html +3 -2
  61. package/examples/Phone and Gif/roll/sketch.js +21 -24
  62. package/examples/UIStyles/banner-style/index.html +3 -3
  63. package/examples/UIStyles/canvas-style/index.html +3 -3
  64. package/examples/UIStyles/canvas-style/sketch.js +1 -1
  65. package/examples/UIStyles/custom-element/index.html +3 -3
  66. package/examples/UIStyles/custom-element/sketch.js +1 -1
  67. package/examples/UXcompare/button-vs-movement/index.html +3 -3
  68. package/examples/UXcompare/button-vs-orientation/index.html +3 -3
  69. package/examples/UXcompare/button-vs-shake/index.html +3 -3
  70. package/examples/UXcompare/gyroscope-demo/index.html +3 -3
  71. package/examples/UXcompare/microphone-demo/index.html +4 -4
  72. package/examples/UXcompare/slider-vs-angle/index.html +3 -3
  73. package/examples/UXcompare/slider-vs-distance/index.html +3 -3
  74. package/examples/UXcompare/slider-vs-microphone/index.html +4 -4
  75. package/examples/UXcompare/slider-vs-touches/index.html +3 -3
  76. package/examples/UXcompare/sliders-vs-acceleration/index.html +3 -3
  77. package/examples/UXcompare/sliders-vs-rotation/index.html +3 -3
  78. package/examples/blankTemplate/index.html +4 -4
  79. package/examples/homepage/index.html +246 -1515
  80. package/examples/{homepage-v2 → homepage}/scripts/api-data.js +32 -0
  81. package/examples/{homepage-v2 → homepage}/scripts/examples-data.js +65 -48
  82. package/examples/{homepage-v2 → homepage}/scripts/render.js +97 -11
  83. package/examples/{homepage-v2 → homepage}/styles/main.css +28 -12
  84. package/examples/homepage-v1/index.html +1529 -0
  85. package/examples/homepage-v2/index.html +5 -255
  86. package/examples/ml5/Gaze_detector_class/GazeDetector.js +28 -10
  87. package/examples/ml5/Gaze_detector_class/README.md +9 -4
  88. package/examples/ml5/Gaze_detector_class/index.html +9 -5
  89. package/examples/ml5/PHONE_BodyPose_two_points/index.html +8 -4
  90. package/examples/ml5/PHONE_BodyPose_two_points/sketch.js +24 -5
  91. package/examples/ml5/PHONE_FaceMesh_two_points/index.html +8 -4
  92. package/examples/ml5/PHONE_FaceMesh_two_points/sketch.js +24 -5
  93. package/examples/ml5/PHONE_HandPose_two_points/index.html +8 -4
  94. package/examples/ml5/PHONE_HandPose_two_points/sketch.js +101 -6
  95. package/examples/ml5/THREE_BodyPose_two_points/functions.js +3 -1
  96. package/examples/ml5/THREE_BodyPose_two_points/index.html +8 -0
  97. package/examples/ml5/THREE_BodyPose_two_points/sketch.js +22 -7
  98. package/examples/ml5/THREE_FaceMesh_two_points/functions.js +3 -1
  99. package/examples/ml5/THREE_FaceMesh_two_points/index.html +8 -0
  100. package/examples/ml5/THREE_FaceMesh_two_points/sketch.js +22 -7
  101. package/examples/ml5/THREE_HandPose_two_points/index.html +12 -4
  102. package/package.json +2 -2
  103. package/src/p5-phone.js +126 -82
  104. package/examples/ml5/PHONE_ObjectDetection/index.html +0 -27
  105. package/examples/ml5/PHONE_ObjectDetection/sketch.js +0 -236
  106. /package/examples/{homepage-v2 → homepage}/scripts/navigation.js +0 -0
package/README.md CHANGED
@@ -102,10 +102,10 @@ p5-phone automatically detects the p5.js version and adjusts its internal touch
102
102
 
103
103
  ```html
104
104
  <!-- Minified version (recommended) -->
105
- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.1/dist/p5-phone.min.js"></script>
105
+ <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.3/dist/p5-phone.min.js"></script>
106
106
 
107
107
  <!-- Development version (larger, with comments) -->
108
- <!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.1/dist/p5-phone.js"></script> -->
108
+ <!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.3/dist/p5-phone.js"></script> -->
109
109
  ```
110
110
 
111
111
  ### Basic Setup
@@ -130,11 +130,11 @@ p5-phone automatically detects the p5.js version and adjusts its internal touch
130
130
  </style>
131
131
 
132
132
  <!-- Load p5.js library -->
133
- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
134
- <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
133
+ <script src="https://cdn.jsdelivr.net/npm/p5@2.2.3/lib/p5.js"></script>
134
+ <script src="https://cdn.jsdelivr.net/npm/p5.js-compatibility@0.2.0/src/preload.js"></script>
135
135
 
136
136
  <!-- Load p5-phone library -->
137
- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.1/dist/p5-phone.min.js"></script>
137
+ <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.3/dist/p5-phone.min.js"></script>
138
138
 
139
139
  </head>
140
140
  <body>
@@ -433,7 +433,7 @@ function draw() {
433
433
 
434
434
  **Important:** Microphone examples require the p5.sound library. Add this script tag to your HTML:
435
435
  ```html
436
- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.0/addons/p5.sound.min.js"></script>
436
+ <script src="https://cdn.jsdelivr.net/npm/p5.sound@0.3.0/dist/p5.sound.min.js"></script>
437
437
  ```
438
438
 
439
439
  **Commands:**
@@ -489,7 +489,7 @@ function draw() {
489
489
 
490
490
  **Important:** Sound examples require the p5.sound library. Add this script tag to your HTML:
491
491
  ```html
492
- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.0/addons/p5.sound.min.js"></script>
492
+ <script src="https://cdn.jsdelivr.net/npm/p5.sound@0.3.0/dist/p5.sound.min.js"></script>
493
493
  ```
494
494
 
495
495
  **Commands:**
package/dist/p5-phone.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * p5-phone v1.7.0
2
+ * p5-phone v1.9.2
3
3
  * Simplified mobile hardware access for p5.js - handle sensors, microphone, touch, and browser gestures with ease
4
4
  * https://github.com/npuckett/p5-phone
5
5
  *
@@ -1678,6 +1678,8 @@ window.toggleDebug = toggleDebug;
1678
1678
  window.lockGestures = lockGestures;
1679
1679
  window.enableGyroTap = enableGyroTap;
1680
1680
  window.enableGyroButton = enableGyroButton;
1681
+ window.enableSensorTap = enableGyroTap;
1682
+ window.enableSensorButton = enableGyroButton;
1681
1683
  window.enableMicTap = enableMicTap;
1682
1684
  window.enableMicButton = enableMicButton;
1683
1685
  window.enableSoundTap = enableSoundTap;
@@ -1699,6 +1701,7 @@ window.enableAllButton = enableAllButton;
1699
1701
 
1700
1702
  // Canvas-first-touch style
1701
1703
  window.enableGyroCanvas = enableGyroCanvas;
1704
+ window.enableSensorCanvas = enableGyroCanvas;
1702
1705
  window.enableMicCanvas = enableMicCanvas;
1703
1706
  window.enableSoundCanvas = enableSoundCanvas;
1704
1707
  window.enableSpeechCanvas = enableSpeechCanvas;
@@ -1709,6 +1712,7 @@ window.enableCameraCanvas = enableCameraCanvas;
1709
1712
 
1710
1713
  // Banner style
1711
1714
  window.enableGyroBanner = enableGyroBanner;
1715
+ window.enableSensorBanner = enableGyroBanner;
1712
1716
  window.enableMicBanner = enableMicBanner;
1713
1717
  window.enableSoundBanner = enableSoundBanner;
1714
1718
  window.enableSpeechBanner = enableSpeechBanner;
@@ -1719,6 +1723,7 @@ window.enableCameraBanner = enableCameraBanner;
1719
1723
 
1720
1724
  // Custom element binding
1721
1725
  window.enableGyroOn = enableGyroOn;
1726
+ window.enableSensorOn = enableGyroOn;
1722
1727
  window.enableMicOn = enableMicOn;
1723
1728
  window.enableSoundOn = enableSoundOn;
1724
1729
  window.enableSpeechOn = enableSpeechOn;
@@ -2171,8 +2176,13 @@ class PhoneCamera {
2171
2176
  return { x: 0, y: 0, width: 0, height: 0, scaleX: 1, scaleY: 1 };
2172
2177
  }
2173
2178
 
2174
- const videoWidth = this._video.width;
2175
- const videoHeight = this._video.height;
2179
+ const videoElement = this.videoElement;
2180
+ const videoWidth = (videoElement && videoElement.videoWidth) || this._video.width;
2181
+ const videoHeight = (videoElement && videoElement.videoHeight) || this._video.height;
2182
+
2183
+ if (!videoWidth || !videoHeight) {
2184
+ return { x: 0, y: 0, width: 0, height: 0, scaleX: 1, scaleY: 1 };
2185
+ }
2176
2186
 
2177
2187
  // Get actual canvas DISPLAY dimensions (not drawing buffer dimensions)
2178
2188
  // In p5.js, the width/height globals represent the logical canvas size
@@ -2370,8 +2380,9 @@ class PhoneCamera {
2370
2380
  * Custom draw method for p5.image() compatibility
2371
2381
  * This allows image(cam, x, y) to work
2372
2382
  */
2373
- _draw() {
2374
- if (!this._ready || !this._video) return;
2383
+ _draw(p5Instance = null) {
2384
+ const videoElement = this.videoElement;
2385
+ if (!this._ready || !this._video || !videoElement || videoElement.readyState < 2) return;
2375
2386
 
2376
2387
  const dims = this.getDimensions();
2377
2388
 
@@ -2391,21 +2402,37 @@ class PhoneCamera {
2391
2402
  this._drawDebugLogged = true;
2392
2403
  }
2393
2404
 
2405
+ const context = (p5Instance && p5Instance.drawingContext) ||
2406
+ (typeof drawingContext !== 'undefined' ? drawingContext : null);
2407
+
2408
+ if (!context || typeof context.drawImage !== 'function') return;
2409
+
2410
+ const pushState = (p5Instance && p5Instance.push) ? p5Instance.push.bind(p5Instance) :
2411
+ (typeof push === 'function' ? push : null);
2412
+ const popState = (p5Instance && p5Instance.pop) ? p5Instance.pop.bind(p5Instance) :
2413
+ (typeof pop === 'function' ? pop : null);
2414
+ const translateCanvas = (p5Instance && p5Instance.translate) ? p5Instance.translate.bind(p5Instance) :
2415
+ (typeof translate === 'function' ? translate : null);
2416
+ const scaleCanvas = (p5Instance && p5Instance.scale) ? p5Instance.scale.bind(p5Instance) :
2417
+ (typeof scale === 'function' ? scale : null);
2418
+
2419
+ if (!pushState || !popState || !translateCanvas || !scaleCanvas) return;
2420
+
2394
2421
  // Save current drawing state
2395
- push();
2422
+ pushState();
2396
2423
 
2397
2424
  // Apply mirroring if needed
2398
2425
  if (this._mirror) {
2399
2426
  // Mirror by flipping around the center of the canvas
2400
- translate(canvasWidth, 0);
2401
- scale(-1, 1);
2427
+ translateCanvas(canvasWidth, 0);
2428
+ scaleCanvas(-1, 1);
2402
2429
  // Draw at the same logical position
2403
- image(this._video, dims.x, dims.y, dims.width, dims.height);
2430
+ context.drawImage(videoElement, dims.x, dims.y, dims.width, dims.height);
2404
2431
  } else {
2405
- image(this._video, dims.x, dims.y, dims.width, dims.height);
2432
+ context.drawImage(videoElement, dims.x, dims.y, dims.width, dims.height);
2406
2433
  }
2407
2434
 
2408
- pop();
2435
+ popState();
2409
2436
  }
2410
2437
  }
2411
2438
 
@@ -2512,7 +2539,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2512
2539
 
2513
2540
  // Always use auto-positioning for PhoneCamera
2514
2541
  // The camera calculates the correct position based on mode (fitHeight, fitWidth, etc)
2515
- cam._draw();
2542
+ cam._draw(this);
2516
2543
  } else {
2517
2544
  // Not a PhoneCamera, use original image function
2518
2545
  originalImage.apply(this, args);
@@ -2525,14 +2552,17 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2525
2552
  // =========================================
2526
2553
 
2527
2554
  /**
2528
- * Add functions to p5.js prototype for namespace support
2529
- * This allows using both global functions and p5.prototype.functionName
2555
+ * Add functions to p5.js prototype for namespace support in p5.js 1.x.
2556
+ * p5.js 2.x uses p5.registerAddon() below; registering in both places
2557
+ * creates duplicate globals during p5 2 global-mode binding.
2530
2558
  */
2531
- if (typeof p5 !== 'undefined' && p5.prototype) {
2559
+ if (typeof p5 !== 'undefined' && p5.prototype && typeof p5.registerAddon !== 'function') {
2532
2560
  // Core permission functions
2533
2561
  p5.prototype.lockGestures = lockGestures;
2534
2562
  p5.prototype.enableGyroTap = enableGyroTap;
2535
2563
  p5.prototype.enableGyroButton = enableGyroButton;
2564
+ p5.prototype.enableSensorTap = enableGyroTap;
2565
+ p5.prototype.enableSensorButton = enableGyroButton;
2536
2566
  p5.prototype.enableMicTap = enableMicTap;
2537
2567
  p5.prototype.enableMicButton = enableMicButton;
2538
2568
  p5.prototype.enableSoundTap = enableSoundTap;
@@ -2554,6 +2584,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2554
2584
 
2555
2585
  // Canvas-first-touch style
2556
2586
  p5.prototype.enableGyroCanvas = enableGyroCanvas;
2587
+ p5.prototype.enableSensorCanvas = enableGyroCanvas;
2557
2588
  p5.prototype.enableMicCanvas = enableMicCanvas;
2558
2589
  p5.prototype.enableSoundCanvas = enableSoundCanvas;
2559
2590
  p5.prototype.enableSpeechCanvas = enableSpeechCanvas;
@@ -2564,6 +2595,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2564
2595
 
2565
2596
  // Banner style
2566
2597
  p5.prototype.enableGyroBanner = enableGyroBanner;
2598
+ p5.prototype.enableSensorBanner = enableGyroBanner;
2567
2599
  p5.prototype.enableMicBanner = enableMicBanner;
2568
2600
  p5.prototype.enableSoundBanner = enableSoundBanner;
2569
2601
  p5.prototype.enableSpeechBanner = enableSpeechBanner;
@@ -2574,6 +2606,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2574
2606
 
2575
2607
  // Custom element binding
2576
2608
  p5.prototype.enableGyroOn = enableGyroOn;
2609
+ p5.prototype.enableSensorOn = enableGyroOn;
2577
2610
  p5.prototype.enableMicOn = enableMicOn;
2578
2611
  p5.prototype.enableSoundOn = enableSoundOn;
2579
2612
  p5.prototype.enableSpeechOn = enableSpeechOn;
@@ -2609,73 +2642,84 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2609
2642
  */
2610
2643
  if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
2611
2644
  p5.registerAddon(function(p5, fn, lifecycles) {
2612
- // Register all public functions on the prototype (fn === p5.prototype)
2613
- // Core permission functions
2614
- fn.lockGestures = lockGestures;
2615
- fn.enableGyroTap = enableGyroTap;
2616
- fn.enableGyroButton = enableGyroButton;
2617
- fn.enableMicTap = enableMicTap;
2618
- fn.enableMicButton = enableMicButton;
2619
- fn.enableSoundTap = enableSoundTap;
2620
- fn.enableSoundButton = enableSoundButton;
2621
- fn.enableSpeechTap = enableSpeechTap;
2622
- fn.enableSpeechButton = enableSpeechButton;
2623
- fn.enableVibrationTap = enableVibrationTap;
2624
- fn.enableVibrationButton = enableVibrationButton;
2625
- fn.vibrate = vibrate;
2626
- fn.stopVibration = stopVibration;
2627
- fn.enableNfcTap = enableNfcTap;
2628
- fn.enableNfcButton = enableNfcButton;
2629
- fn.stopNfc = stopNfc;
2630
- fn.setNfcTagAlias = setNfcTagAlias;
2631
- fn.getNfcTagAlias = getNfcTagAlias;
2632
- fn.isNfcTag = isNfcTag;
2633
- fn.enableAllTap = enableAllTap;
2634
- fn.enableAllButton = enableAllButton;
2635
-
2636
- // Canvas-first-touch style
2637
- fn.enableGyroCanvas = enableGyroCanvas;
2638
- fn.enableMicCanvas = enableMicCanvas;
2639
- fn.enableSoundCanvas = enableSoundCanvas;
2640
- fn.enableSpeechCanvas = enableSpeechCanvas;
2641
- fn.enableVibrationCanvas = enableVibrationCanvas;
2642
- fn.enableNfcCanvas = enableNfcCanvas;
2643
- fn.enableAllCanvas = enableAllCanvas;
2644
- fn.enableCameraCanvas = enableCameraCanvas;
2645
-
2646
- // Banner style
2647
- fn.enableGyroBanner = enableGyroBanner;
2648
- fn.enableMicBanner = enableMicBanner;
2649
- fn.enableSoundBanner = enableSoundBanner;
2650
- fn.enableSpeechBanner = enableSpeechBanner;
2651
- fn.enableVibrationBanner = enableVibrationBanner;
2652
- fn.enableNfcBanner = enableNfcBanner;
2653
- fn.enableAllBanner = enableAllBanner;
2654
- fn.enableCameraBanner = enableCameraBanner;
2655
-
2656
- // Custom element binding
2657
- fn.enableGyroOn = enableGyroOn;
2658
- fn.enableMicOn = enableMicOn;
2659
- fn.enableSoundOn = enableSoundOn;
2660
- fn.enableSpeechOn = enableSpeechOn;
2661
- fn.enableVibrationOn = enableVibrationOn;
2662
- fn.enableNfcOn = enableNfcOn;
2663
- fn.enableAllOn = enableAllOn;
2664
- fn.enableCameraOn = enableCameraOn;
2665
-
2666
- // Camera functions
2667
- fn.createPhoneCamera = createPhoneCamera;
2668
- fn.enableCameraButton = enableCameraButton;
2669
- fn.enableCameraTap = enableCameraTap;
2670
-
2671
- // Debug functions
2672
- fn.showDebug = showDebug;
2673
- fn.hideDebug = hideDebug;
2674
- fn.toggleDebug = toggleDebug;
2675
- fn.debug = debug;
2676
- fn.debugError = debugError;
2677
- fn.debugWarn = debugWarn;
2678
-
2645
+ // In p5.js 2 global mode, p5 binds every prototype property onto window.
2646
+ // p5-phone's top-level function declarations already create globals such
2647
+ // as lockGestures, so adding those names to p5.prototype before binding
2648
+ // causes "Cannot redefine property" errors. Attach instance methods after
2649
+ // global binding but before setup() instead.
2650
+ lifecycles.presetup = function() {
2651
+ // Core permission functions
2652
+ this.lockGestures = lockGestures;
2653
+ this.enableGyroTap = enableGyroTap;
2654
+ this.enableGyroButton = enableGyroButton;
2655
+ this.enableSensorTap = enableGyroTap;
2656
+ this.enableSensorButton = enableGyroButton;
2657
+ this.enableMicTap = enableMicTap;
2658
+ this.enableMicButton = enableMicButton;
2659
+ this.enableSoundTap = enableSoundTap;
2660
+ this.enableSoundButton = enableSoundButton;
2661
+ this.enableSpeechTap = enableSpeechTap;
2662
+ this.enableSpeechButton = enableSpeechButton;
2663
+ this.enableVibrationTap = enableVibrationTap;
2664
+ this.enableVibrationButton = enableVibrationButton;
2665
+ this.vibrate = vibrate;
2666
+ this.stopVibration = stopVibration;
2667
+ this.enableNfcTap = enableNfcTap;
2668
+ this.enableNfcButton = enableNfcButton;
2669
+ this.stopNfc = stopNfc;
2670
+ this.setNfcTagAlias = setNfcTagAlias;
2671
+ this.getNfcTagAlias = getNfcTagAlias;
2672
+ this.isNfcTag = isNfcTag;
2673
+ this.enableAllTap = enableAllTap;
2674
+ this.enableAllButton = enableAllButton;
2675
+
2676
+ // Canvas-first-touch style
2677
+ this.enableGyroCanvas = enableGyroCanvas;
2678
+ this.enableSensorCanvas = enableGyroCanvas;
2679
+ this.enableMicCanvas = enableMicCanvas;
2680
+ this.enableSoundCanvas = enableSoundCanvas;
2681
+ this.enableSpeechCanvas = enableSpeechCanvas;
2682
+ this.enableVibrationCanvas = enableVibrationCanvas;
2683
+ this.enableNfcCanvas = enableNfcCanvas;
2684
+ this.enableAllCanvas = enableAllCanvas;
2685
+ this.enableCameraCanvas = enableCameraCanvas;
2686
+
2687
+ // Banner style
2688
+ this.enableGyroBanner = enableGyroBanner;
2689
+ this.enableSensorBanner = enableGyroBanner;
2690
+ this.enableMicBanner = enableMicBanner;
2691
+ this.enableSoundBanner = enableSoundBanner;
2692
+ this.enableSpeechBanner = enableSpeechBanner;
2693
+ this.enableVibrationBanner = enableVibrationBanner;
2694
+ this.enableNfcBanner = enableNfcBanner;
2695
+ this.enableAllBanner = enableAllBanner;
2696
+ this.enableCameraBanner = enableCameraBanner;
2697
+
2698
+ // Custom element binding
2699
+ this.enableGyroOn = enableGyroOn;
2700
+ this.enableSensorOn = enableGyroOn;
2701
+ this.enableMicOn = enableMicOn;
2702
+ this.enableSoundOn = enableSoundOn;
2703
+ this.enableSpeechOn = enableSpeechOn;
2704
+ this.enableVibrationOn = enableVibrationOn;
2705
+ this.enableNfcOn = enableNfcOn;
2706
+ this.enableAllOn = enableAllOn;
2707
+ this.enableCameraOn = enableCameraOn;
2708
+
2709
+ // Camera functions
2710
+ this.createPhoneCamera = createPhoneCamera;
2711
+ this.enableCameraButton = enableCameraButton;
2712
+ this.enableCameraTap = enableCameraTap;
2713
+
2714
+ // Debug functions
2715
+ this.showDebug = showDebug;
2716
+ this.hideDebug = hideDebug;
2717
+ this.toggleDebug = toggleDebug;
2718
+ this.debug = debug;
2719
+ this.debugError = debugError;
2720
+ this.debugWarn = debugWarn;
2721
+ };
2722
+
2679
2723
  console.log('✅ Mobile p5.js Permissions: registered as p5.js 2.0 addon');
2680
2724
  });
2681
2725
  }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * p5-phone v1.7.0
2
+ * p5-phone v1.9.2
3
3
  * Simplified mobile hardware access for p5.js - handle sensors, microphone, touch, and browser gestures with ease
4
4
  * https://github.com/npuckett/p5-phone
5
5
  *
@@ -7,4 +7,4 @@
7
7
  * Released under the MIT License
8
8
  * https://opensource.org/licenses/MIT
9
9
  */
10
- window._originalConsoleError=console.error,window._originalConsoleWarn=console.warn,window._debugErrorHandlersSet||(window._debugErrorHandlersSet=!0,window._earlyErrors=window._earlyErrors||[],window.addEventListener("error",function(e){const n=`${e.error?.message||e.message||"Unknown error"} (${e.filename?e.filename.split("/").pop():"unknown file"}:${e.lineno||"unknown line"})`;console.error("🚨 Error caught:",n),e.error?.stack&&console.error("Stack:",e.error.stack),window._earlyErrors.push({type:"error",message:"JavaScript Error: "+n,stack:e.error?.stack}),!1===window.SHOW_DEBUG||window._debugVisible||"function"==typeof showDebug&&showDebug(),window._debugVisible&&"function"==typeof debugError&&(debugError("JavaScript Error:",n),e.error?.stack&&debugError("Stack trace:",e.error.stack))}),window.addEventListener("unhandledrejection",function(e){const n=e.reason?.message||e.reason||"Unknown promise rejection";console.error("🚨 Promise rejection caught:",n),window._earlyErrors.push({type:"error",message:"Unhandled Promise Rejection: "+n}),window._debugVisible&&"function"==typeof debugError&&debugError("Unhandled Promise Rejection:",n)})),window.sensorsEnabled=!1,window.micEnabled=!1,window.soundEnabled=!1,window.gesturesLocked=!1,window.vibrationEnabled=!1,window.speechEnabled=!1,window.nfcEnabled=!1,window.nfcError="",window.nfcStatus="idle",window.nfcTagAliases={},window.lastNfcMessage=null,window.lastNfcSerialNumber=null,window.lastNfcAlias="";let _micInstance=null,_nfcReader=null,_nfcAbortController=null;const _p5MajorVersion="undefined"!=typeof p5&&p5.VERSION?parseInt(p5.VERSION.split(".")[0],10):1,_isP5v2=_p5MajorVersion>=2;function lockGestures(){window.gesturesLocked||(console.log("🔒 Locking mobile gestures..."),_initializeGestureBlocking(),_initializeP5TouchOverrides(),window.gesturesLocked=!0,console.log("✅ Mobile gestures locked"))}function enableGyroButton(e="ENABLE MOTION SENSORS",n="Requesting motion sensors..."){_createPermissionButton(e,n,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via button")})}function enableGyroTap(e="Tap screen to enable motion sensors"){_createTapToEnable(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via tap")})}function enableMicButton(e="ENABLE MICROPHONE",n="Requesting microphone access..."){_createPermissionButton(e,n,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via button")})}function enableMicTap(e="Tap screen to enable microphone"){_createTapToEnable(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via tap")})}function enableSoundButton(e="ENABLE SOUND",n="Enabling audio..."){_createPermissionButton(e,n,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via button")})}function enableSoundTap(e="Tap screen to enable sound"){_createTapToEnable(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via tap")})}function enableSpeechTap(e="Tap to enable speech recognition"){_createTapToEnable(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via tap")})}function enableSpeechButton(e="ENABLE SPEECH RECOGNITION",n="Enabling speech recognition..."){_createPermissionButton(e,n,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via button")})}function enableVibrationButton(e="ENABLE VIBRATION",n="Enabling vibration..."){_createPermissionButton(e,n,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via button")})}function enableVibrationTap(e="Tap screen to enable vibration"){_createTapToEnable(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via tap")})}function enableNfcButton(e="ENABLE NFC",n="Enabling NFC..."){_createPermissionButton(e,n,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via button")})}function enableNfcTap(e="Tap screen to enable NFC"){_createTapToEnable(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via tap")})}function enableAllButton(e="ENABLE MOTION & MICROPHONE",n="Requesting permissions..."){_createPermissionButton(e,n,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via button")})}function enableAllTap(e="Tap screen to enable motion sensors & microphone"){_createTapToEnable(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via tap")})}function enableGyroCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via canvas touch")})}function enableMicCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via canvas touch")})}function enableSoundCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via canvas touch")})}function enableSpeechCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via canvas touch")})}function enableVibrationCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via canvas touch")})}function enableNfcCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via canvas touch")})}function enableAllCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via canvas touch")})}function enableCameraCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via canvas touch")})}function enableGyroBanner(e="Tap to enable motion sensors",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via banner")})}function enableMicBanner(e="Tap to enable microphone",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via banner")})}function enableSoundBanner(e="Tap to enable sound",n="top"){_createBannerToEnable(e,n,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via banner")})}function enableSpeechBanner(e="Tap to enable speech recognition",n="top"){_createBannerToEnable(e,n,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via banner")})}function enableVibrationBanner(e="Tap to enable vibration",n="top"){_createBannerToEnable(e,n,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via banner")})}function enableNfcBanner(e="Tap to enable NFC",n="top"){_createBannerToEnable(e,n,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via banner")})}function enableAllBanner(e="Tap to enable sensors & microphone",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via banner")})}function enableCameraBanner(e="Tap to enable camera",n="top"){_createBannerToEnable(e,n,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via banner")})}function enableGyroOn(e){_bindPermissionTo(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via custom element")})}function enableMicOn(e){_bindPermissionTo(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via custom element")})}function enableSoundOn(e){_bindPermissionTo(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via custom element")})}function enableSpeechOn(e){_bindPermissionTo(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via custom element")})}function enableVibrationOn(e){_bindPermissionTo(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via custom element")})}function enableNfcOn(e){_bindPermissionTo(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via custom element")})}function enableAllOn(e){_bindPermissionTo(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via custom element")})}function enableCameraOn(e){_bindPermissionTo(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via custom element")})}function vibrate(e){return window.vibrationEnabled?navigator.vibrate?navigator.vibrate(e):(console.warn("⚠️ Vibration API not supported on this device"),!1):(console.warn("⚠️ Vibration not enabled. Call enableVibrationTap() or enableVibrationButton() first."),!1)}function stopVibration(){navigator.vibrate&&navigator.vibrate(0)}function stopNfc(){_nfcAbortController&&(_nfcAbortController.abort(),_nfcAbortController=null),_nfcReader=null,window.nfcEnabled=!1,window.nfcStatus="stopped",console.log("NFC scanning stopped")}function _normalizeNfcText(e){return null==e?"":String(e).trim()}function _normalizeNfcTagId(e){return _normalizeNfcText(e).toLowerCase()}function _nfcTextMatches(e,n){const o=_normalizeNfcText(e).toLowerCase(),t=_normalizeNfcText(n).toLowerCase();return""!==o&&o===t}function setNfcTagAlias(e,n){const o=_normalizeNfcTagId(e),t=_normalizeNfcText(n);return o?(t?window.nfcTagAliases[o]=t:delete window.nfcTagAliases[o],_normalizeNfcTagId(window.lastNfcSerialNumber)===o&&(window.lastNfcAlias=t,window.lastNfcMessage&&(window.lastNfcMessage.alias=t)),t):(console.warn("p5-phone: setNfcTagAlias() needs an NFC serial number"),"")}function getNfcTagAlias(e=window.lastNfcSerialNumber){const n=_normalizeNfcTagId(e);return n&&window.nfcTagAliases[n]||""}function isNfcTag(e,n=window.lastNfcSerialNumber){const o=_normalizeNfcTagId(n),t=_normalizeNfcText(e);return!(!o||!t)&&(o===_normalizeNfcTagId(t)||_nfcTextMatches(getNfcTagAlias(n),t))}async function _requestMotionPermissionsCore(){try{if("undefined"!=typeof DeviceOrientationEvent&&"function"==typeof DeviceOrientationEvent.requestPermission){const e=await DeviceOrientationEvent.requestPermission();if(console.log("Orientation permission:",e),"undefined"!=typeof DeviceMotionEvent&&"function"==typeof DeviceMotionEvent.requestPermission){const e=await DeviceMotionEvent.requestPermission();console.log("Motion permission:",e)}}window.sensorsEnabled=!0}catch(e){console.error("Motion sensor permission error:",e),_debugVisible&&debugError("Motion sensor permission error:",e),window.sensorsEnabled=!0}}async function _requestMicrophonePermissionsCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),"undefined"!=typeof mic&&mic&&mic.start?(mic.start(),_micInstance=mic,window.micEnabled=!0):console.warn("No microphone object found. Create one with: mic = new p5.AudioIn();")}catch(e){console.error("Microphone permission error:",e),_debugVisible&&debugError("Microphone permission error:",e)}}async function _requestSoundOutputCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),window.soundEnabled=!0}catch(e){console.error("Sound output error:",e),_debugVisible&&debugError("Sound output error:",e),window.soundEnabled=!0}}async function _requestSpeechPermissionCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),window.speechEnabled=!0}catch(e){console.error("Speech permission error:",e),_debugVisible&&debugError("Speech permission error:",e)}}async function _requestVibrationPermissionCore(){try{if(!navigator.vibrate)return console.warn("⚠️ Vibration API not supported on this device (likely iOS)"),_debugVisible&&debugWarn("Vibration API not supported on this device"),void(window.vibrationEnabled=!1);navigator.vibrate(1)?(window.vibrationEnabled=!0,console.log("✅ Vibration enabled")):(console.warn("⚠️ Vibration API available but vibration failed"),window.vibrationEnabled=!1)}catch(e){console.error("Vibration permission error:",e),_debugVisible&&debugError("Vibration permission error:",e),window.vibrationEnabled=!1}}async function _requestNfcPermissionCore(){try{return!(!window.nfcEnabled||!_nfcReader)||(window.nfcError="",window.nfcStatus="starting","NDEFReader"in window?(window.nfcStatus="requesting-permission",_nfcAbortController=new AbortController,_nfcReader=new NDEFReader,_nfcReader.onreading=e=>{const n=e.serialNumber||"",o=new TextDecoder,t=[];for(const n of e.message.records){const e={recordType:n.recordType,mediaType:n.mediaType||null,id:n.id||null,data:null,raw:n.data};if("text"===n.recordType||"url"===n.recordType)e.data=o.decode(n.data);else if("mime"===n.recordType&&n.mediaType)try{const t=o.decode(n.data);n.mediaType.includes("json")?e.data=JSON.parse(t):e.data=t}catch(o){e.data=n.data}else e.data=n.data;t.push(e)}const a=getNfcTagAlias(n),i={serialNumber:n,alias:a,records:t};window.lastNfcMessage=i,window.lastNfcSerialNumber=n,window.lastNfcAlias=a,window.nfcStatus="tag-read",window.nfcError="","function"==typeof nfcRead&&nfcRead(i,n),console.log("NFC tag read — serial:",n,"records:",t.length),_debugVisible&&debug("NFC tag read: "+n)},_nfcReader.onreadingerror=e=>{console.warn("⚠️ NFC read error — tag may be incompatible or out of range"),window.nfcError="NFC read error. Make sure the tag is NDEF formatted and hold it near the phone NFC antenna.",_debugVisible&&debugWarn("NFC read error — tag incompatible or out of range")},await _nfcReader.scan({signal:_nfcAbortController.signal}),window.nfcEnabled=!0,window.nfcStatus="scanning",console.log("✅ NFC scanning active"),!0):(console.warn("⚠️ Web NFC API not supported on this device/browser (Android Chrome 89+ required)"),_debugVisible&&debugWarn("Web NFC not supported on this device/browser"),window.nfcEnabled=!1,window.nfcStatus="unsupported",window.nfcError=!1===window.isSecureContext?"NFC requires HTTPS. Serve this sketch from an HTTPS URL, not plain HTTP.":"Web NFC is not supported in this browser. Use Android Chrome 89+ over HTTPS.",!1))}catch(e){return"NotAllowedError"===e.name?(console.warn("⚠️ NFC permission denied by user"),window.nfcStatus="permission-denied",window.nfcError="NFC permission was denied. Reload and tap Allow if Chrome asks.",_debugVisible&&debugWarn("NFC permission denied")):"NotSupportedError"===e.name?(console.warn("⚠️ NFC not supported on this device"),window.nfcStatus="unsupported",window.nfcError="NFC is not supported on this device/browser, or this page is not using HTTPS.",_debugVisible&&debugWarn("NFC not supported on this device")):"SecurityError"===e.name?(console.warn("⚠️ NFC requires a secure HTTPS context"),window.nfcStatus="secure-context-required",window.nfcError="NFC requires HTTPS. Serve this sketch from an HTTPS URL, not plain HTTP.",_debugVisible&&debugWarn("NFC requires HTTPS")):(console.error("NFC permission error:",e),window.nfcStatus="error",window.nfcError=e&&e.message?e.message:"NFC could not start.",_debugVisible&&debugError("NFC error: "+e.message)),window.nfcEnabled=!1,_nfcReader=null,_nfcAbortController=null,!1}}async function _requestMotionPermissions(){await _requestMotionPermissionsCore(),_notifySketchReady()}async function _requestMicrophonePermissions(){await _requestMicrophonePermissionsCore(),_notifySketchReady()}async function _requestSoundOutput(){await _requestSoundOutputCore(),_notifySketchReady()}async function _requestSpeechPermission(){await _requestSpeechPermissionCore(),_notifySketchReady()}async function _requestVibrationPermission(){await _requestVibrationPermissionCore(),_notifySketchReady()}async function _requestNfcPermission(){const e=await _requestNfcPermissionCore();return _notifySketchReady(),e}function _notifySketchReady(){"function"==typeof userSetupComplete&&userSetupComplete(),window.dispatchEvent(new CustomEvent("permissionsReady",{detail:{sensors:window.sensorsEnabled,microphone:window.micEnabled,sound:window.soundEnabled,speech:window.speechEnabled,vibration:window.vibrationEnabled,nfc:window.nfcEnabled,gestures:window.gesturesLocked}}))}function _createPermissionButton(e,n,o){_removeExistingUI();let t=!1;const a=document.createElement("button");a.id="permissionButton",a.textContent=e,a.style.cssText="\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 20px 40px;\n font-size: 18px;\n font-weight: bold;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 12px;\n cursor: pointer;\n z-index: 999999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n box-shadow: 0 4px 15px rgba(0,0,0,0.2);\n transition: transform 0.2s ease;\n touch-action: manipulation;\n ";const i=document.createElement("div");i.id="permissionStatus",i.textContent=n,i.style.cssText="\n position: fixed;\n top: 60%;\n left: 50%;\n transform: translate(-50%, 0);\n color: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n z-index: 999998;\n display: none;\n ",a.addEventListener("mouseenter",()=>{a.style.transform="translate(-50%, -50%) scale(1.05)"}),a.addEventListener("mouseleave",()=>{a.style.transform="translate(-50%, -50%) scale(1)"});const r=async()=>{!t&&a.parentNode&&(t=!0,a.style.display="none",i.style.display="block",await o(),i.style.display="none",_removeExistingUI())};a.addEventListener("click",r),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),r()}),a.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),r()}),document.body.appendChild(a),document.body.appendChild(i)}function _createTapToEnable(e,n){_removeExistingUI();let o=!1;const t=document.createElement("div");t.id="tapOverlay",t.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n cursor: pointer;\n touch-action: manipulation;\n ";const a=document.createElement("div");a.textContent=e,a.style.cssText="\n color: white;\n font-size: 24px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n padding: 40px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-radius: 12px;\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(10px);\n ",t.appendChild(a);const i=async()=>{!o&&t.parentNode&&(o=!0,a.textContent="Enabling...",await n(),t.parentNode&&document.body.removeChild(t))};t.addEventListener("click",i),t.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()}),t.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),i()}),document.body.appendChild(t)}function _removeExistingUI(){const e=document.getElementById("permissionButton"),n=document.getElementById("permissionStatus"),o=document.getElementById("tapOverlay"),t=document.getElementById("permissionBanner");e&&e.remove(),n&&n.remove(),o&&o.remove(),t&&t.remove()}function _createCanvasToEnable(e,n){_removeExistingUI();let o=!1,t=null;e&&(t=setInterval(()=>{const n=document.querySelector("canvas");n&&"function"==typeof push&&(push(),fill(255,255,255,200),noStroke(),textAlign(CENTER,CENTER),textSize(.04*Math.min(n.width,n.height)),text(e,("undefined"!=typeof width?width:n.width)/2,.9*("undefined"!=typeof height?height:n.height)),pop())},50));const a=async e=>{o||(o=!0,t&&(clearInterval(t),t=null),document.removeEventListener("touchstart",a,!0),document.removeEventListener("mousedown",a,!0),await n())},i=()=>{const e=document.querySelector("canvas");e?(e.addEventListener("touchstart",a,{once:!0,capture:!0}),e.addEventListener("mousedown",a,{once:!0,capture:!0})):setTimeout(i,50)};i()}function _createBannerToEnable(e,n,o){_removeExistingUI();let t=!1;const a=document.createElement("div");a.id="permissionBanner";const i="top"===n;a.style.cssText=`\n position: fixed;\n ${i?"top: 0;":"bottom: 0;"}\n left: 0;\n width: 100%;\n padding: 16px 20px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n font-size: 16px;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n z-index: 999999;\n cursor: pointer;\n touch-action: manipulation;\n box-shadow: ${i?"0 2px 10px rgba(0,0,0,0.3)":"0 -2px 10px rgba(0,0,0,0.3)"};\n transition: opacity 0.3s ease, transform 0.3s ease;\n transform: translateY(${i?"-100%":"100%"});\n `,a.textContent=e,document.body.appendChild(a),requestAnimationFrame(()=>{requestAnimationFrame(()=>{a.style.transform="translateY(0)"})});const r=async()=>{!t&&a.parentNode&&(t=!0,a.textContent="Enabling...",a.style.pointerEvents="none",await o(),a.style.transform=`translateY(${i?"-100%":"100%"})`,a.style.opacity="0",setTimeout(()=>{a.parentNode&&a.remove()},300))};a.addEventListener("click",r),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),r()}),a.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),r()})}function _bindPermissionTo(e,n){let o=!1;const t=()=>{const a=document.querySelector(e);if(!a)return console.warn(`p5-phone: Element "${e}" not found. Retrying...`),void setTimeout(t,100);const i=async()=>{o||(o=!0,await n())};a.addEventListener("click",i),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()})};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}function _initializeGestureBlocking(){window.history.pushState(null,"",window.location.href),window.onpopstate=function(){window.history.pushState(null,"",window.location.href)},window.addEventListener("beforeunload",function(e){e.preventDefault(),e.returnValue=""}),_initializeEdgeSwipePrevention(),_initializeOtherGesturePrevention()}function _initializeEdgeSwipePrevention(){let e=0,n=0;document.addEventListener("touchstart",function(o){o.touches&&o.touches.length>0&&(e=o.touches[0].clientX,n=o.touches[0].clientY,(e<20||e>window.innerWidth-20)&&o.preventDefault())},{passive:!1,capture:!0}),document.addEventListener("touchmove",function(o){if(!o.touches||0===o.touches.length)return;let t=o.touches[0].clientX,a=o.touches[0].clientY,i=t-e,r=a-n;(e<20&&i>0||e>window.innerWidth-20&&i<0)&&(o.preventDefault(),o.stopPropagation()),0===window.pageYOffset&&r>0&&o.preventDefault(),!o.target||"CANVAS"!==o.target.tagName||document.getElementById("tapOverlay")||document.getElementById("permissionButton")||o.preventDefault()},{passive:!1,capture:!0})}function _initializeOtherGesturePrevention(){document.addEventListener("gesturestart",function(e){e.preventDefault()}),document.addEventListener("gesturechange",function(e){e.preventDefault()}),document.addEventListener("gestureend",function(e){e.preventDefault()});let e=0;document.addEventListener("touchend",function(n){if(n.target&&("tapOverlay"===n.target.id||n.target.closest("#tapOverlay")||"permissionButton"===n.target.id||"permissionStatus"===n.target.id||n.target.closest("#permissionButton")||n.target.closest("#permissionStatus")))return;const o=Date.now();o-e<=300&&n.preventDefault(),e=o},!1),window.oncontextmenu=function(e){return e.preventDefault(),e.stopPropagation(),!1}}function _initializeP5TouchOverrides(){let e=0;const n=()=>{e++;"undefined"!=typeof p5&&p5.instance||document.querySelector("canvas")||"function"==typeof window.setup&&"function"==typeof window.draw?_overrideP5Touch():e<50?setTimeout(n,100):console.warn("p5-phone: Could not detect p5.js setup completion. Touch overrides not applied.")};setTimeout(n,100)}function _overrideP5Touch(){const e=window.mousePressed||function(){},n=window.mouseDragged||function(){},o=window.mouseReleased||function(){};if(!_isP5v2){const e=window.touchStarted||function(){},n=window.touchMoved||function(){},o=window.touchEnded||function(){};window.touchStarted=function(n){return e(n),!1},window.touchMoved=function(e){return n(e),!1},window.touchEnded=function(e){return o(e),!1}}window.mousePressed=function(n){return e(n),!1},window.mouseDragged=function(e){return n(e),!1},window.mouseReleased=function(e){return o(e),!1}}document.addEventListener("DOMContentLoaded",function(){const e=document.getElementById("startButton"),n=document.getElementById("statusText");e&&n&&(console.warn("⚠️ Legacy HTML elements detected. Consider using the new API functions instead."),e.addEventListener("click",async()=>{e.classList.add("hidden"),n.classList.remove("hidden"),n.textContent="Requesting permissions...",await _requestMotionPermissions(),await _requestMicrophonePermissions(),n.classList.add("hidden")}),lockGestures())});let _debugPanel=null,_debugVisible=!1,_debugMessages=[];const MAX_DEBUG_MESSAGES=20;function showDebug(){_createDebugPanel(),_debugPanel.style.display="block",_debugVisible=!0,window._debugVisible=!0,_setupConsoleOverrides(),_displayEarlyErrors()}function hideDebug(){_debugPanel&&(_debugPanel.style.display="none",_debugVisible=!1)}function toggleDebug(){_debugVisible?hideDebug():showDebug()}function debug(...e){console.log(...e);_addDebugMessage(e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" "),"log")}function debugError(...e){(window._originalConsoleError||console.error).apply(console,e);_addDebugMessage(`❌ ERROR: ${e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" ")}`,"error")}function debugWarn(...e){(window._originalConsoleWarn||console.warn).apply(console,e);_addDebugMessage(`⚠️ WARNING: ${e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" ")}`,"warning")}function _addDebugMessage(e,n="log"){const o={text:`[${(new Date).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit",fractionalSecondDigits:3})}] ${e}`,type:n};_debugMessages.push(o),_debugMessages.length>20&&_debugMessages.shift(),_debugPanel&&_updateDebugDisplay()}function _setupConsoleOverrides(){window._consoleOverrideSet||(window._consoleOverrideSet=!0,"function"==typeof console.error&&(window._originalConsoleError=console.error),"function"==typeof console.warn&&(window._originalConsoleWarn=console.warn),console.error=function(...e){try{window._originalConsoleError.apply(console,e)}catch(e){}_debugVisible&&debugError(...e)},console.warn=function(...e){try{window._originalConsoleWarn.apply(console,e)}catch(e){}_debugVisible&&debugWarn(...e)})}function _displayEarlyErrors(){window._earlyErrors&&window._earlyErrors.length>0&&(debugError(`🚨 Found ${window._earlyErrors.length} early error(s):`),window._earlyErrors.forEach(e=>{debugError(e.message),e.stack&&debugError("Stack trace:",e.stack)}),window._earlyErrors=[])}function _createDebugPanel(){if(_debugPanel)return;_debugPanel=document.createElement("div"),_debugPanel.id="mobile-debug-panel",_debugPanel.innerHTML='\n <div id="mobile-debug-header">\n <span>Debug</span>\n <button id="mobile-debug-close">×</button>\n </div>\n <div id="mobile-debug-content"></div>\n ';const e=document.createElement("style");e.textContent="\n #mobile-debug-panel {\n position: fixed;\n top: 20px;\n right: 20px;\n width: 350px;\n max-width: calc(100vw - 40px);\n max-height: 400px;\n background: rgba(0, 0, 0, 0.9);\n color: #ffffff;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n z-index: 10000;\n display: none;\n }\n \n #mobile-debug-header {\n background: rgba(255, 255, 255, 0.1);\n padding: 8px 12px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2);\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-radius: 8px 8px 0 0;\n }\n \n #mobile-debug-header span {\n font-weight: bold;\n font-size: 13px;\n }\n \n #mobile-debug-close {\n background: none;\n border: none;\n color: #ffffff;\n font-size: 18px;\n cursor: pointer;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n #mobile-debug-close:hover {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n }\n \n #mobile-debug-content {\n padding: 12px;\n max-height: 340px;\n overflow-y: auto;\n word-wrap: break-word;\n line-height: 1.4;\n }\n \n .debug-message {\n margin-bottom: 4px;\n white-space: pre-wrap;\n }\n \n .debug-message.error {\n color: #ff6b6b;\n background: rgba(255, 107, 107, 0.1);\n padding: 4px;\n border-radius: 3px;\n border-left: 3px solid #ff6b6b;\n }\n \n .debug-message.warning {\n color: #ffd93d;\n background: rgba(255, 217, 61, 0.1);\n padding: 4px;\n border-radius: 3px;\n border-left: 3px solid #ffd93d;\n }\n \n .debug-timestamp {\n color: #888;\n font-size: 10px;\n }\n \n @media (max-width: 480px) {\n #mobile-debug-panel {\n width: calc(100vw - 20px);\n right: 10px;\n top: 10px;\n }\n }\n ",document.head.appendChild(e),document.body.appendChild(_debugPanel),document.getElementById("mobile-debug-close").onclick=hideDebug,_updateDebugDisplay()}function _updateDebugDisplay(){if(!_debugPanel)return;const e=document.getElementById("mobile-debug-content");e&&(e.innerHTML=_debugMessages.map(e=>"string"==typeof e?`<div class="debug-message">${e}</div>`:`<div class="debug-message ${e.type}">${e.text}</div>`).join(""),e.scrollTop=e.scrollHeight)}debug.clear=function(){_debugMessages=[],_debugPanel&&_updateDebugDisplay(),console.clear()},window.debug=debug,window.debugError=debugError,window.debugWarn=debugWarn,window.showDebug=showDebug,window.hideDebug=hideDebug,window.toggleDebug=toggleDebug,window.lockGestures=lockGestures,window.enableGyroTap=enableGyroTap,window.enableGyroButton=enableGyroButton,window.enableMicTap=enableMicTap,window.enableMicButton=enableMicButton,window.enableSoundTap=enableSoundTap,window.enableSoundButton=enableSoundButton,window.enableSpeechTap=enableSpeechTap,window.enableSpeechButton=enableSpeechButton,window.enableVibrationTap=enableVibrationTap,window.enableVibrationButton=enableVibrationButton,window.vibrate=vibrate,window.stopVibration=stopVibration,window.enableNfcTap=enableNfcTap,window.enableNfcButton=enableNfcButton,window.stopNfc=stopNfc,window.setNfcTagAlias=setNfcTagAlias,window.getNfcTagAlias=getNfcTagAlias,window.isNfcTag=isNfcTag,window.enableAllTap=enableAllTap,window.enableAllButton=enableAllButton,window.enableGyroCanvas=enableGyroCanvas,window.enableMicCanvas=enableMicCanvas,window.enableSoundCanvas=enableSoundCanvas,window.enableSpeechCanvas=enableSpeechCanvas,window.enableVibrationCanvas=enableVibrationCanvas,window.enableNfcCanvas=enableNfcCanvas,window.enableAllCanvas=enableAllCanvas,window.enableCameraCanvas=enableCameraCanvas,window.enableGyroBanner=enableGyroBanner,window.enableMicBanner=enableMicBanner,window.enableSoundBanner=enableSoundBanner,window.enableSpeechBanner=enableSpeechBanner,window.enableVibrationBanner=enableVibrationBanner,window.enableNfcBanner=enableNfcBanner,window.enableAllBanner=enableAllBanner,window.enableCameraBanner=enableCameraBanner,window.enableGyroOn=enableGyroOn,window.enableMicOn=enableMicOn,window.enableSoundOn=enableSoundOn,window.enableSpeechOn=enableSpeechOn,window.enableVibrationOn=enableVibrationOn,window.enableNfcOn=enableNfcOn,window.enableAllOn=enableAllOn,window.enableCameraOn=enableCameraOn;class PhoneCamera{constructor(e="user",n=!0,o="fitHeight"){this._active=e,this._mirror=n,this._mode=o,this._fixedWidth=640,this._fixedHeight=480,this._video=null,this._ready=!1,this._p5Instance=window,this._onReadyCallback=null,this._createCaptureRef=null,window._phoneCameras||(window._phoneCameras=[]),window._phoneCameras.push(this)}get ready(){return this._ready}get video(){return this._video}get videoElement(){return this._video?this._video.elt:null}get width(){if(!this._ready)return 0;return this.getDimensions().width}get height(){if(!this._ready)return 0;return this.getDimensions().height}get active(){return this._active}set active(e){"user"===e||"environment"===e?this._active!==e&&(this._active=e,this._ready&&this._switchCamera()):console.error('PhoneCamera: active must be "user" or "environment"')}get mirror(){return this._mirror}set mirror(e){this._mirror=!!e}get mode(){return this._mode}set mode(e){const n=["fitWidth","fitHeight","cover","contain","fixed"];n.includes(e)?this._mode=e:console.error("PhoneCamera: mode must be one of:",n.join(", "))}get fixedWidth(){return this._fixedWidth}set fixedWidth(e){this._fixedWidth=Math.max(1,e)}get fixedHeight(){return this._fixedHeight}set fixedHeight(e){this._fixedHeight=Math.max(1,e)}onReady(e){this._onReadyCallback=e,this._ready&&this._video&&this._video.elt&&this._video.elt.readyState>=2?e():this._video&&this._checkVideoReady()}_initializeCamera(){if(this._ready||this._video)return;const e={video:{facingMode:this._active},audio:!1};this._video=createCapture(e,()=>{this._ready=!0,this._video.hide(),console.log("✅ PhoneCamera ready"),this._checkVideoReady()}),this._video&&this._video.elt&&this._video.elt.addEventListener("loadeddata",()=>{this._ready=!0,this._checkVideoReady()})}_checkVideoReady(e=0){if(this._video&&this._video.elt&&this._video.elt.readyState>=2){if(this._onReadyCallback){const e=this._onReadyCallback;this._onReadyCallback=null,e()}}else e<100?setTimeout(()=>this._checkVideoReady(e+1),100):(console.warn("PhoneCamera: Video failed to reach ready state after 10 seconds"),_debugVisible&&debugWarn("PhoneCamera: Video not ready after timeout. Check camera permissions."))}_switchCamera(){if(!this._video)return;this._ready;this._ready=!1,this._video.remove();const e={video:{facingMode:this._active},audio:!1};this._video=createCapture(e,()=>{this._ready=!0,this._video.hide(),console.log(`✅ PhoneCamera switched to ${this._active} camera`)}),this._video&&this._video.elt&&this._video.elt.addEventListener("loadeddata",()=>{this._ready=!0})}remove(){this._video&&(this._video.remove(),this._video=null),this._ready=!1}getDimensions(){if(!this._ready||!this._video)return{x:0,y:0,width:0,height:0,scaleX:1,scaleY:1};const e=this._video.width,n=this._video.height,o="undefined"!=typeof width?width:window.innerWidth,t="undefined"!=typeof height?height:window.innerHeight;let a,i,r,s;if("fixed"===this._mode)a=this._fixedWidth,i=this._fixedHeight,r=(o-a)/2,s=(t-i)/2;else if("fitWidth"===this._mode)a=o,i=n/e*a,r=0,s=(t-i)/2;else if("fitHeight"===this._mode)i=t,a=e/n*i,r=(o-a)/2,s=0;else if("cover"===this._mode){const l=Math.max(o/e,t/n);a=e*l,i=n*l,r=(o-a)/2,s=(t-i)/2}else if("contain"===this._mode){const l=Math.min(o/e,t/n);a=e*l,i=n*l,r=(o-a)/2,s=(t-i)/2}return{x:r,y:s,width:a,height:i,scaleX:a/e,scaleY:i/n}}mapPoint(e,n){const o=this.getDimensions();let t=e*o.scaleX;const a=n*o.scaleY;this._mirror&&(t=o.width-t);return{x:t+o.x,y:a+o.y}}mapKeypoint(e){if(!e||void 0===e.x||void 0===e.y)return console.warn("PhoneCamera.mapKeypoint: invalid keypoint",e),e;const n=this.mapPoint(e.x,e.y);return{...e,x:n.x,y:n.y}}mapKeypoints(e){return Array.isArray(e)?e.map(e=>this.mapKeypoint(e)):(console.warn("PhoneCamera.mapKeypoints: expected array, got",typeof e),e)}mapBox(e){if(!e)return console.warn("PhoneCamera.mapBox: invalid box",e),e;const n=void 0!==e.x?e.x:e.xMin,o=void 0!==e.y?e.y:e.yMin,t=void 0!==e.width?e.width:e.xMax-e.xMin,a=void 0!==e.height?e.height:e.yMax-e.yMin,i=Number(n),r=Number(o),s=Number(t),l=Number(a);if(!(Number.isFinite(i)&&Number.isFinite(r)&&Number.isFinite(s)&&Number.isFinite(l)))return console.warn("PhoneCamera.mapBox: invalid box",e),e;const d=this.mapPoint(i,r),c=this.mapPoint(i+s,r+l),u=Math.min(d.x,c.x),p=Math.min(d.y,c.y),b=Math.abs(c.x-d.x),w=Math.abs(c.y-d.y);return{...e,x:u,y:p,width:b,height:w,xMin:u,yMin:p,xMax:u+b,yMax:p+w}}mapBoxes(e){return Array.isArray(e)?e.map(e=>this.mapBox(e)):(console.warn("PhoneCamera.mapBoxes: expected array, got",typeof e),e)}_draw(){if(!this._ready||!this._video)return;const e=this.getDimensions(),n="undefined"!=typeof width?width:window.innerWidth;this._drawDebugLogged||(console.log("_draw() params:",{x:e.x,y:e.y,width:e.width,height:e.height,canvasWidth:n,mirror:this._mirror}),this._drawDebugLogged=!0),push(),this._mirror?(translate(n,0),scale(-1,1),image(this._video,e.x,e.y,e.width,e.height)):image(this._video,e.x,e.y,e.width,e.height),pop()}}function createPhoneCamera(e="user",n=!0,o="fitHeight"){return new PhoneCamera(e,n,o)}function enableCameraButton(e="ENABLE CAMERA",n="Starting camera..."){_createPermissionButton(e,n,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via button")})}function enableCameraTap(e="Tap screen to enable camera"){navigator.permissions&&navigator.permissions.query?navigator.permissions.query({name:"camera"}).then(n=>{"granted"===n.state?(console.log("✅ Camera permission already granted - auto-starting"),_requestCameraPermission()):_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}).catch(()=>{_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}):_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}async function _requestCameraPermission(){try{if(void 0!==window._phoneCameras&&Array.isArray(window._phoneCameras))for(let e of window._phoneCameras)!e||e._ready||e._video||e._initializeCamera();"function"==typeof userCameraReady&&userCameraReady(),_notifySketchReady()}catch(e){console.error("Camera permission error:",e),_debugVisible&&debugError("Camera permission error:",e),_notifySketchReady()}}if(window.createPhoneCamera=createPhoneCamera,window.enableCameraButton=enableCameraButton,window.enableCameraTap=enableCameraTap,"undefined"!=typeof p5&&p5.prototype){const e=p5.prototype.image;p5.prototype.image=function(...n){if(n[0]instanceof PhoneCamera){n[0]._draw()}else e.apply(this,n)}}"undefined"!=typeof p5&&p5.prototype&&(p5.prototype.lockGestures=lockGestures,p5.prototype.enableGyroTap=enableGyroTap,p5.prototype.enableGyroButton=enableGyroButton,p5.prototype.enableMicTap=enableMicTap,p5.prototype.enableMicButton=enableMicButton,p5.prototype.enableSoundTap=enableSoundTap,p5.prototype.enableSoundButton=enableSoundButton,p5.prototype.enableSpeechTap=enableSpeechTap,p5.prototype.enableSpeechButton=enableSpeechButton,p5.prototype.enableVibrationTap=enableVibrationTap,p5.prototype.enableVibrationButton=enableVibrationButton,p5.prototype.vibrate=vibrate,p5.prototype.stopVibration=stopVibration,p5.prototype.enableNfcTap=enableNfcTap,p5.prototype.enableNfcButton=enableNfcButton,p5.prototype.stopNfc=stopNfc,p5.prototype.setNfcTagAlias=setNfcTagAlias,p5.prototype.getNfcTagAlias=getNfcTagAlias,p5.prototype.isNfcTag=isNfcTag,p5.prototype.enableAllTap=enableAllTap,p5.prototype.enableAllButton=enableAllButton,p5.prototype.enableGyroCanvas=enableGyroCanvas,p5.prototype.enableMicCanvas=enableMicCanvas,p5.prototype.enableSoundCanvas=enableSoundCanvas,p5.prototype.enableSpeechCanvas=enableSpeechCanvas,p5.prototype.enableVibrationCanvas=enableVibrationCanvas,p5.prototype.enableNfcCanvas=enableNfcCanvas,p5.prototype.enableAllCanvas=enableAllCanvas,p5.prototype.enableCameraCanvas=enableCameraCanvas,p5.prototype.enableGyroBanner=enableGyroBanner,p5.prototype.enableMicBanner=enableMicBanner,p5.prototype.enableSoundBanner=enableSoundBanner,p5.prototype.enableSpeechBanner=enableSpeechBanner,p5.prototype.enableVibrationBanner=enableVibrationBanner,p5.prototype.enableNfcBanner=enableNfcBanner,p5.prototype.enableAllBanner=enableAllBanner,p5.prototype.enableCameraBanner=enableCameraBanner,p5.prototype.enableGyroOn=enableGyroOn,p5.prototype.enableMicOn=enableMicOn,p5.prototype.enableSoundOn=enableSoundOn,p5.prototype.enableSpeechOn=enableSpeechOn,p5.prototype.enableVibrationOn=enableVibrationOn,p5.prototype.enableNfcOn=enableNfcOn,p5.prototype.enableAllOn=enableAllOn,p5.prototype.enableCameraOn=enableCameraOn,p5.prototype.createPhoneCamera=createPhoneCamera,p5.prototype.enableCameraButton=enableCameraButton,p5.prototype.enableCameraTap=enableCameraTap,p5.prototype.showDebug=showDebug,p5.prototype.hideDebug=hideDebug,p5.prototype.toggleDebug=toggleDebug,p5.prototype.debug=debug,p5.prototype.debugError=debugError,p5.prototype.debugWarn=debugWarn,console.log("✅ Mobile p5.js Permissions: p5.prototype functions registered")),"undefined"!=typeof p5&&"function"==typeof p5.registerAddon&&p5.registerAddon(function(e,n,o){n.lockGestures=lockGestures,n.enableGyroTap=enableGyroTap,n.enableGyroButton=enableGyroButton,n.enableMicTap=enableMicTap,n.enableMicButton=enableMicButton,n.enableSoundTap=enableSoundTap,n.enableSoundButton=enableSoundButton,n.enableSpeechTap=enableSpeechTap,n.enableSpeechButton=enableSpeechButton,n.enableVibrationTap=enableVibrationTap,n.enableVibrationButton=enableVibrationButton,n.vibrate=vibrate,n.stopVibration=stopVibration,n.enableNfcTap=enableNfcTap,n.enableNfcButton=enableNfcButton,n.stopNfc=stopNfc,n.setNfcTagAlias=setNfcTagAlias,n.getNfcTagAlias=getNfcTagAlias,n.isNfcTag=isNfcTag,n.enableAllTap=enableAllTap,n.enableAllButton=enableAllButton,n.enableGyroCanvas=enableGyroCanvas,n.enableMicCanvas=enableMicCanvas,n.enableSoundCanvas=enableSoundCanvas,n.enableSpeechCanvas=enableSpeechCanvas,n.enableVibrationCanvas=enableVibrationCanvas,n.enableNfcCanvas=enableNfcCanvas,n.enableAllCanvas=enableAllCanvas,n.enableCameraCanvas=enableCameraCanvas,n.enableGyroBanner=enableGyroBanner,n.enableMicBanner=enableMicBanner,n.enableSoundBanner=enableSoundBanner,n.enableSpeechBanner=enableSpeechBanner,n.enableVibrationBanner=enableVibrationBanner,n.enableNfcBanner=enableNfcBanner,n.enableAllBanner=enableAllBanner,n.enableCameraBanner=enableCameraBanner,n.enableGyroOn=enableGyroOn,n.enableMicOn=enableMicOn,n.enableSoundOn=enableSoundOn,n.enableSpeechOn=enableSpeechOn,n.enableVibrationOn=enableVibrationOn,n.enableNfcOn=enableNfcOn,n.enableAllOn=enableAllOn,n.enableCameraOn=enableCameraOn,n.createPhoneCamera=createPhoneCamera,n.enableCameraButton=enableCameraButton,n.enableCameraTap=enableCameraTap,n.showDebug=showDebug,n.hideDebug=hideDebug,n.toggleDebug=toggleDebug,n.debug=debug,n.debugError=debugError,n.debugWarn=debugWarn,console.log("✅ Mobile p5.js Permissions: registered as p5.js 2.0 addon")});
10
+ window._originalConsoleError=console.error,window._originalConsoleWarn=console.warn,window._debugErrorHandlersSet||(window._debugErrorHandlersSet=!0,window._earlyErrors=window._earlyErrors||[],window.addEventListener("error",function(e){const n=`${e.error?.message||e.message||"Unknown error"} (${e.filename?e.filename.split("/").pop():"unknown file"}:${e.lineno||"unknown line"})`;console.error("🚨 Error caught:",n),e.error?.stack&&console.error("Stack:",e.error.stack),window._earlyErrors.push({type:"error",message:"JavaScript Error: "+n,stack:e.error?.stack}),!1===window.SHOW_DEBUG||window._debugVisible||"function"==typeof showDebug&&showDebug(),window._debugVisible&&"function"==typeof debugError&&(debugError("JavaScript Error:",n),e.error?.stack&&debugError("Stack trace:",e.error.stack))}),window.addEventListener("unhandledrejection",function(e){const n=e.reason?.message||e.reason||"Unknown promise rejection";console.error("🚨 Promise rejection caught:",n),window._earlyErrors.push({type:"error",message:"Unhandled Promise Rejection: "+n}),window._debugVisible&&"function"==typeof debugError&&debugError("Unhandled Promise Rejection:",n)})),window.sensorsEnabled=!1,window.micEnabled=!1,window.soundEnabled=!1,window.gesturesLocked=!1,window.vibrationEnabled=!1,window.speechEnabled=!1,window.nfcEnabled=!1,window.nfcError="",window.nfcStatus="idle",window.nfcTagAliases={},window.lastNfcMessage=null,window.lastNfcSerialNumber=null,window.lastNfcAlias="";let _micInstance=null,_nfcReader=null,_nfcAbortController=null;const _p5MajorVersion="undefined"!=typeof p5&&p5.VERSION?parseInt(p5.VERSION.split(".")[0],10):1,_isP5v2=_p5MajorVersion>=2;function lockGestures(){window.gesturesLocked||(console.log("🔒 Locking mobile gestures..."),_initializeGestureBlocking(),_initializeP5TouchOverrides(),window.gesturesLocked=!0,console.log("✅ Mobile gestures locked"))}function enableGyroButton(e="ENABLE MOTION SENSORS",n="Requesting motion sensors..."){_createPermissionButton(e,n,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via button")})}function enableGyroTap(e="Tap screen to enable motion sensors"){_createTapToEnable(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via tap")})}function enableMicButton(e="ENABLE MICROPHONE",n="Requesting microphone access..."){_createPermissionButton(e,n,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via button")})}function enableMicTap(e="Tap screen to enable microphone"){_createTapToEnable(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via tap")})}function enableSoundButton(e="ENABLE SOUND",n="Enabling audio..."){_createPermissionButton(e,n,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via button")})}function enableSoundTap(e="Tap screen to enable sound"){_createTapToEnable(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via tap")})}function enableSpeechTap(e="Tap to enable speech recognition"){_createTapToEnable(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via tap")})}function enableSpeechButton(e="ENABLE SPEECH RECOGNITION",n="Enabling speech recognition..."){_createPermissionButton(e,n,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via button")})}function enableVibrationButton(e="ENABLE VIBRATION",n="Enabling vibration..."){_createPermissionButton(e,n,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via button")})}function enableVibrationTap(e="Tap screen to enable vibration"){_createTapToEnable(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via tap")})}function enableNfcButton(e="ENABLE NFC",n="Enabling NFC..."){_createPermissionButton(e,n,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via button")})}function enableNfcTap(e="Tap screen to enable NFC"){_createTapToEnable(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via tap")})}function enableAllButton(e="ENABLE MOTION & MICROPHONE",n="Requesting permissions..."){_createPermissionButton(e,n,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via button")})}function enableAllTap(e="Tap screen to enable motion sensors & microphone"){_createTapToEnable(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via tap")})}function enableGyroCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via canvas touch")})}function enableMicCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via canvas touch")})}function enableSoundCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via canvas touch")})}function enableSpeechCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via canvas touch")})}function enableVibrationCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via canvas touch")})}function enableNfcCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via canvas touch")})}function enableAllCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via canvas touch")})}function enableCameraCanvas(e="Touch to start"){_createCanvasToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via canvas touch")})}function enableGyroBanner(e="Tap to enable motion sensors",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via banner")})}function enableMicBanner(e="Tap to enable microphone",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via banner")})}function enableSoundBanner(e="Tap to enable sound",n="top"){_createBannerToEnable(e,n,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via banner")})}function enableSpeechBanner(e="Tap to enable speech recognition",n="top"){_createBannerToEnable(e,n,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via banner")})}function enableVibrationBanner(e="Tap to enable vibration",n="top"){_createBannerToEnable(e,n,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via banner")})}function enableNfcBanner(e="Tap to enable NFC",n="top"){_createBannerToEnable(e,n,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via banner")})}function enableAllBanner(e="Tap to enable sensors & microphone",n="top"){_createBannerToEnable(e,n,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via banner")})}function enableCameraBanner(e="Tap to enable camera",n="top"){_createBannerToEnable(e,n,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via banner")})}function enableGyroOn(e){_bindPermissionTo(e,async()=>{await _requestMotionPermissions(),console.log("✅ Gyroscope enabled via custom element")})}function enableMicOn(e){_bindPermissionTo(e,async()=>{await _requestMicrophonePermissions(),console.log("✅ Microphone enabled via custom element")})}function enableSoundOn(e){_bindPermissionTo(e,async()=>{await _requestSoundOutput(),console.log("✅ Sound output enabled via custom element")})}function enableSpeechOn(e){_bindPermissionTo(e,async()=>{await _requestSpeechPermission(),console.log("✅ Speech recognition enabled via custom element")})}function enableVibrationOn(e){_bindPermissionTo(e,async()=>{await _requestVibrationPermission(),console.log("✅ Vibration enabled via custom element")})}function enableNfcOn(e){_bindPermissionTo(e,async()=>{await _requestNfcPermission(),console.log("✅ NFC enabled via custom element")})}function enableAllOn(e){_bindPermissionTo(e,async()=>{await _requestMotionPermissionsCore(),await _requestMicrophonePermissionsCore(),_notifySketchReady(),console.log("✅ Motion sensors and microphone enabled via custom element")})}function enableCameraOn(e){_bindPermissionTo(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via custom element")})}function vibrate(e){return window.vibrationEnabled?navigator.vibrate?navigator.vibrate(e):(console.warn("⚠️ Vibration API not supported on this device"),!1):(console.warn("⚠️ Vibration not enabled. Call enableVibrationTap() or enableVibrationButton() first."),!1)}function stopVibration(){navigator.vibrate&&navigator.vibrate(0)}function stopNfc(){_nfcAbortController&&(_nfcAbortController.abort(),_nfcAbortController=null),_nfcReader=null,window.nfcEnabled=!1,window.nfcStatus="stopped",console.log("NFC scanning stopped")}function _normalizeNfcText(e){return null==e?"":String(e).trim()}function _normalizeNfcTagId(e){return _normalizeNfcText(e).toLowerCase()}function _nfcTextMatches(e,n){const o=_normalizeNfcText(e).toLowerCase(),t=_normalizeNfcText(n).toLowerCase();return""!==o&&o===t}function setNfcTagAlias(e,n){const o=_normalizeNfcTagId(e),t=_normalizeNfcText(n);return o?(t?window.nfcTagAliases[o]=t:delete window.nfcTagAliases[o],_normalizeNfcTagId(window.lastNfcSerialNumber)===o&&(window.lastNfcAlias=t,window.lastNfcMessage&&(window.lastNfcMessage.alias=t)),t):(console.warn("p5-phone: setNfcTagAlias() needs an NFC serial number"),"")}function getNfcTagAlias(e=window.lastNfcSerialNumber){const n=_normalizeNfcTagId(e);return n&&window.nfcTagAliases[n]||""}function isNfcTag(e,n=window.lastNfcSerialNumber){const o=_normalizeNfcTagId(n),t=_normalizeNfcText(e);return!(!o||!t)&&(o===_normalizeNfcTagId(t)||_nfcTextMatches(getNfcTagAlias(n),t))}async function _requestMotionPermissionsCore(){try{if("undefined"!=typeof DeviceOrientationEvent&&"function"==typeof DeviceOrientationEvent.requestPermission){const e=await DeviceOrientationEvent.requestPermission();if(console.log("Orientation permission:",e),"undefined"!=typeof DeviceMotionEvent&&"function"==typeof DeviceMotionEvent.requestPermission){const e=await DeviceMotionEvent.requestPermission();console.log("Motion permission:",e)}}window.sensorsEnabled=!0}catch(e){console.error("Motion sensor permission error:",e),_debugVisible&&debugError("Motion sensor permission error:",e),window.sensorsEnabled=!0}}async function _requestMicrophonePermissionsCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),"undefined"!=typeof mic&&mic&&mic.start?(mic.start(),_micInstance=mic,window.micEnabled=!0):console.warn("No microphone object found. Create one with: mic = new p5.AudioIn();")}catch(e){console.error("Microphone permission error:",e),_debugVisible&&debugError("Microphone permission error:",e)}}async function _requestSoundOutputCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),window.soundEnabled=!0}catch(e){console.error("Sound output error:",e),_debugVisible&&debugError("Sound output error:",e),window.soundEnabled=!0}}async function _requestSpeechPermissionCore(){try{"undefined"!=typeof userStartAudio&&await userStartAudio(),window.speechEnabled=!0}catch(e){console.error("Speech permission error:",e),_debugVisible&&debugError("Speech permission error:",e)}}async function _requestVibrationPermissionCore(){try{if(!navigator.vibrate)return console.warn("⚠️ Vibration API not supported on this device (likely iOS)"),_debugVisible&&debugWarn("Vibration API not supported on this device"),void(window.vibrationEnabled=!1);navigator.vibrate(1)?(window.vibrationEnabled=!0,console.log("✅ Vibration enabled")):(console.warn("⚠️ Vibration API available but vibration failed"),window.vibrationEnabled=!1)}catch(e){console.error("Vibration permission error:",e),_debugVisible&&debugError("Vibration permission error:",e),window.vibrationEnabled=!1}}async function _requestNfcPermissionCore(){try{return!(!window.nfcEnabled||!_nfcReader)||(window.nfcError="",window.nfcStatus="starting","NDEFReader"in window?(window.nfcStatus="requesting-permission",_nfcAbortController=new AbortController,_nfcReader=new NDEFReader,_nfcReader.onreading=e=>{const n=e.serialNumber||"",o=new TextDecoder,t=[];for(const n of e.message.records){const e={recordType:n.recordType,mediaType:n.mediaType||null,id:n.id||null,data:null,raw:n.data};if("text"===n.recordType||"url"===n.recordType)e.data=o.decode(n.data);else if("mime"===n.recordType&&n.mediaType)try{const t=o.decode(n.data);n.mediaType.includes("json")?e.data=JSON.parse(t):e.data=t}catch(o){e.data=n.data}else e.data=n.data;t.push(e)}const a=getNfcTagAlias(n),i={serialNumber:n,alias:a,records:t};window.lastNfcMessage=i,window.lastNfcSerialNumber=n,window.lastNfcAlias=a,window.nfcStatus="tag-read",window.nfcError="","function"==typeof nfcRead&&nfcRead(i,n),console.log("NFC tag read — serial:",n,"records:",t.length),_debugVisible&&debug("NFC tag read: "+n)},_nfcReader.onreadingerror=e=>{console.warn("⚠️ NFC read error — tag may be incompatible or out of range"),window.nfcError="NFC read error. Make sure the tag is NDEF formatted and hold it near the phone NFC antenna.",_debugVisible&&debugWarn("NFC read error — tag incompatible or out of range")},await _nfcReader.scan({signal:_nfcAbortController.signal}),window.nfcEnabled=!0,window.nfcStatus="scanning",console.log("✅ NFC scanning active"),!0):(console.warn("⚠️ Web NFC API not supported on this device/browser (Android Chrome 89+ required)"),_debugVisible&&debugWarn("Web NFC not supported on this device/browser"),window.nfcEnabled=!1,window.nfcStatus="unsupported",window.nfcError=!1===window.isSecureContext?"NFC requires HTTPS. Serve this sketch from an HTTPS URL, not plain HTTP.":"Web NFC is not supported in this browser. Use Android Chrome 89+ over HTTPS.",!1))}catch(e){return"NotAllowedError"===e.name?(console.warn("⚠️ NFC permission denied by user"),window.nfcStatus="permission-denied",window.nfcError="NFC permission was denied. Reload and tap Allow if Chrome asks.",_debugVisible&&debugWarn("NFC permission denied")):"NotSupportedError"===e.name?(console.warn("⚠️ NFC not supported on this device"),window.nfcStatus="unsupported",window.nfcError="NFC is not supported on this device/browser, or this page is not using HTTPS.",_debugVisible&&debugWarn("NFC not supported on this device")):"SecurityError"===e.name?(console.warn("⚠️ NFC requires a secure HTTPS context"),window.nfcStatus="secure-context-required",window.nfcError="NFC requires HTTPS. Serve this sketch from an HTTPS URL, not plain HTTP.",_debugVisible&&debugWarn("NFC requires HTTPS")):(console.error("NFC permission error:",e),window.nfcStatus="error",window.nfcError=e&&e.message?e.message:"NFC could not start.",_debugVisible&&debugError("NFC error: "+e.message)),window.nfcEnabled=!1,_nfcReader=null,_nfcAbortController=null,!1}}async function _requestMotionPermissions(){await _requestMotionPermissionsCore(),_notifySketchReady()}async function _requestMicrophonePermissions(){await _requestMicrophonePermissionsCore(),_notifySketchReady()}async function _requestSoundOutput(){await _requestSoundOutputCore(),_notifySketchReady()}async function _requestSpeechPermission(){await _requestSpeechPermissionCore(),_notifySketchReady()}async function _requestVibrationPermission(){await _requestVibrationPermissionCore(),_notifySketchReady()}async function _requestNfcPermission(){const e=await _requestNfcPermissionCore();return _notifySketchReady(),e}function _notifySketchReady(){"function"==typeof userSetupComplete&&userSetupComplete(),window.dispatchEvent(new CustomEvent("permissionsReady",{detail:{sensors:window.sensorsEnabled,microphone:window.micEnabled,sound:window.soundEnabled,speech:window.speechEnabled,vibration:window.vibrationEnabled,nfc:window.nfcEnabled,gestures:window.gesturesLocked}}))}function _createPermissionButton(e,n,o){_removeExistingUI();let t=!1;const a=document.createElement("button");a.id="permissionButton",a.textContent=e,a.style.cssText="\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 20px 40px;\n font-size: 18px;\n font-weight: bold;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 12px;\n cursor: pointer;\n z-index: 999999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n box-shadow: 0 4px 15px rgba(0,0,0,0.2);\n transition: transform 0.2s ease;\n touch-action: manipulation;\n ";const i=document.createElement("div");i.id="permissionStatus",i.textContent=n,i.style.cssText="\n position: fixed;\n top: 60%;\n left: 50%;\n transform: translate(-50%, 0);\n color: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n z-index: 999998;\n display: none;\n ",a.addEventListener("mouseenter",()=>{a.style.transform="translate(-50%, -50%) scale(1.05)"}),a.addEventListener("mouseleave",()=>{a.style.transform="translate(-50%, -50%) scale(1)"});const r=async()=>{!t&&a.parentNode&&(t=!0,a.style.display="none",i.style.display="block",await o(),i.style.display="none",_removeExistingUI())};a.addEventListener("click",r),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),r()}),a.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),r()}),document.body.appendChild(a),document.body.appendChild(i)}function _createTapToEnable(e,n){_removeExistingUI();let o=!1;const t=document.createElement("div");t.id="tapOverlay",t.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n cursor: pointer;\n touch-action: manipulation;\n ";const a=document.createElement("div");a.textContent=e,a.style.cssText="\n color: white;\n font-size: 24px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n padding: 40px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-radius: 12px;\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(10px);\n ",t.appendChild(a);const i=async()=>{!o&&t.parentNode&&(o=!0,a.textContent="Enabling...",await n(),t.parentNode&&document.body.removeChild(t))};t.addEventListener("click",i),t.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()}),t.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),i()}),document.body.appendChild(t)}function _removeExistingUI(){const e=document.getElementById("permissionButton"),n=document.getElementById("permissionStatus"),o=document.getElementById("tapOverlay"),t=document.getElementById("permissionBanner");e&&e.remove(),n&&n.remove(),o&&o.remove(),t&&t.remove()}function _createCanvasToEnable(e,n){_removeExistingUI();let o=!1,t=null;e&&(t=setInterval(()=>{const n=document.querySelector("canvas");n&&"function"==typeof push&&(push(),fill(255,255,255,200),noStroke(),textAlign(CENTER,CENTER),textSize(.04*Math.min(n.width,n.height)),text(e,("undefined"!=typeof width?width:n.width)/2,.9*("undefined"!=typeof height?height:n.height)),pop())},50));const a=async e=>{o||(o=!0,t&&(clearInterval(t),t=null),document.removeEventListener("touchstart",a,!0),document.removeEventListener("mousedown",a,!0),await n())},i=()=>{const e=document.querySelector("canvas");e?(e.addEventListener("touchstart",a,{once:!0,capture:!0}),e.addEventListener("mousedown",a,{once:!0,capture:!0})):setTimeout(i,50)};i()}function _createBannerToEnable(e,n,o){_removeExistingUI();let t=!1;const a=document.createElement("div");a.id="permissionBanner";const i="top"===n;a.style.cssText=`\n position: fixed;\n ${i?"top: 0;":"bottom: 0;"}\n left: 0;\n width: 100%;\n padding: 16px 20px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n font-size: 16px;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n text-align: center;\n z-index: 999999;\n cursor: pointer;\n touch-action: manipulation;\n box-shadow: ${i?"0 2px 10px rgba(0,0,0,0.3)":"0 -2px 10px rgba(0,0,0,0.3)"};\n transition: opacity 0.3s ease, transform 0.3s ease;\n transform: translateY(${i?"-100%":"100%"});\n `,a.textContent=e,document.body.appendChild(a),requestAnimationFrame(()=>{requestAnimationFrame(()=>{a.style.transform="translateY(0)"})});const r=async()=>{!t&&a.parentNode&&(t=!0,a.textContent="Enabling...",a.style.pointerEvents="none",await o(),a.style.transform=`translateY(${i?"-100%":"100%"})`,a.style.opacity="0",setTimeout(()=>{a.parentNode&&a.remove()},300))};a.addEventListener("click",r),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),r()}),a.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),r()})}function _bindPermissionTo(e,n){let o=!1;const t=()=>{const a=document.querySelector(e);if(!a)return console.warn(`p5-phone: Element "${e}" not found. Retrying...`),void setTimeout(t,100);const i=async()=>{o||(o=!0,await n())};a.addEventListener("click",i),a.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()})};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}function _initializeGestureBlocking(){window.history.pushState(null,"",window.location.href),window.onpopstate=function(){window.history.pushState(null,"",window.location.href)},window.addEventListener("beforeunload",function(e){e.preventDefault(),e.returnValue=""}),_initializeEdgeSwipePrevention(),_initializeOtherGesturePrevention()}function _initializeEdgeSwipePrevention(){let e=0,n=0;document.addEventListener("touchstart",function(o){o.touches&&o.touches.length>0&&(e=o.touches[0].clientX,n=o.touches[0].clientY,(e<20||e>window.innerWidth-20)&&o.preventDefault())},{passive:!1,capture:!0}),document.addEventListener("touchmove",function(o){if(!o.touches||0===o.touches.length)return;let t=o.touches[0].clientX,a=o.touches[0].clientY,i=t-e,r=a-n;(e<20&&i>0||e>window.innerWidth-20&&i<0)&&(o.preventDefault(),o.stopPropagation()),0===window.pageYOffset&&r>0&&o.preventDefault(),!o.target||"CANVAS"!==o.target.tagName||document.getElementById("tapOverlay")||document.getElementById("permissionButton")||o.preventDefault()},{passive:!1,capture:!0})}function _initializeOtherGesturePrevention(){document.addEventListener("gesturestart",function(e){e.preventDefault()}),document.addEventListener("gesturechange",function(e){e.preventDefault()}),document.addEventListener("gestureend",function(e){e.preventDefault()});let e=0;document.addEventListener("touchend",function(n){if(n.target&&("tapOverlay"===n.target.id||n.target.closest("#tapOverlay")||"permissionButton"===n.target.id||"permissionStatus"===n.target.id||n.target.closest("#permissionButton")||n.target.closest("#permissionStatus")))return;const o=Date.now();o-e<=300&&n.preventDefault(),e=o},!1),window.oncontextmenu=function(e){return e.preventDefault(),e.stopPropagation(),!1}}function _initializeP5TouchOverrides(){let e=0;const n=()=>{e++;"undefined"!=typeof p5&&p5.instance||document.querySelector("canvas")||"function"==typeof window.setup&&"function"==typeof window.draw?_overrideP5Touch():e<50?setTimeout(n,100):console.warn("p5-phone: Could not detect p5.js setup completion. Touch overrides not applied.")};setTimeout(n,100)}function _overrideP5Touch(){const e=window.mousePressed||function(){},n=window.mouseDragged||function(){},o=window.mouseReleased||function(){};if(!_isP5v2){const e=window.touchStarted||function(){},n=window.touchMoved||function(){},o=window.touchEnded||function(){};window.touchStarted=function(n){return e(n),!1},window.touchMoved=function(e){return n(e),!1},window.touchEnded=function(e){return o(e),!1}}window.mousePressed=function(n){return e(n),!1},window.mouseDragged=function(e){return n(e),!1},window.mouseReleased=function(e){return o(e),!1}}document.addEventListener("DOMContentLoaded",function(){const e=document.getElementById("startButton"),n=document.getElementById("statusText");e&&n&&(console.warn("⚠️ Legacy HTML elements detected. Consider using the new API functions instead."),e.addEventListener("click",async()=>{e.classList.add("hidden"),n.classList.remove("hidden"),n.textContent="Requesting permissions...",await _requestMotionPermissions(),await _requestMicrophonePermissions(),n.classList.add("hidden")}),lockGestures())});let _debugPanel=null,_debugVisible=!1,_debugMessages=[];const MAX_DEBUG_MESSAGES=20;function showDebug(){_createDebugPanel(),_debugPanel.style.display="block",_debugVisible=!0,window._debugVisible=!0,_setupConsoleOverrides(),_displayEarlyErrors()}function hideDebug(){_debugPanel&&(_debugPanel.style.display="none",_debugVisible=!1)}function toggleDebug(){_debugVisible?hideDebug():showDebug()}function debug(...e){console.log(...e);_addDebugMessage(e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" "),"log")}function debugError(...e){(window._originalConsoleError||console.error).apply(console,e);_addDebugMessage(`❌ ERROR: ${e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" ")}`,"error")}function debugWarn(...e){(window._originalConsoleWarn||console.warn).apply(console,e);_addDebugMessage(`⚠️ WARNING: ${e.map(e=>{if("object"==typeof e&&null!==e)try{return JSON.stringify(e,null,2)}catch(n){return String(e)}return String(e)}).join(" ")}`,"warning")}function _addDebugMessage(e,n="log"){const o={text:`[${(new Date).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit",fractionalSecondDigits:3})}] ${e}`,type:n};_debugMessages.push(o),_debugMessages.length>20&&_debugMessages.shift(),_debugPanel&&_updateDebugDisplay()}function _setupConsoleOverrides(){window._consoleOverrideSet||(window._consoleOverrideSet=!0,"function"==typeof console.error&&(window._originalConsoleError=console.error),"function"==typeof console.warn&&(window._originalConsoleWarn=console.warn),console.error=function(...e){try{window._originalConsoleError.apply(console,e)}catch(e){}_debugVisible&&debugError(...e)},console.warn=function(...e){try{window._originalConsoleWarn.apply(console,e)}catch(e){}_debugVisible&&debugWarn(...e)})}function _displayEarlyErrors(){window._earlyErrors&&window._earlyErrors.length>0&&(debugError(`🚨 Found ${window._earlyErrors.length} early error(s):`),window._earlyErrors.forEach(e=>{debugError(e.message),e.stack&&debugError("Stack trace:",e.stack)}),window._earlyErrors=[])}function _createDebugPanel(){if(_debugPanel)return;_debugPanel=document.createElement("div"),_debugPanel.id="mobile-debug-panel",_debugPanel.innerHTML='\n <div id="mobile-debug-header">\n <span>Debug</span>\n <button id="mobile-debug-close">×</button>\n </div>\n <div id="mobile-debug-content"></div>\n ';const e=document.createElement("style");e.textContent="\n #mobile-debug-panel {\n position: fixed;\n top: 20px;\n right: 20px;\n width: 350px;\n max-width: calc(100vw - 40px);\n max-height: 400px;\n background: rgba(0, 0, 0, 0.9);\n color: #ffffff;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n z-index: 10000;\n display: none;\n }\n \n #mobile-debug-header {\n background: rgba(255, 255, 255, 0.1);\n padding: 8px 12px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2);\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-radius: 8px 8px 0 0;\n }\n \n #mobile-debug-header span {\n font-weight: bold;\n font-size: 13px;\n }\n \n #mobile-debug-close {\n background: none;\n border: none;\n color: #ffffff;\n font-size: 18px;\n cursor: pointer;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n #mobile-debug-close:hover {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n }\n \n #mobile-debug-content {\n padding: 12px;\n max-height: 340px;\n overflow-y: auto;\n word-wrap: break-word;\n line-height: 1.4;\n }\n \n .debug-message {\n margin-bottom: 4px;\n white-space: pre-wrap;\n }\n \n .debug-message.error {\n color: #ff6b6b;\n background: rgba(255, 107, 107, 0.1);\n padding: 4px;\n border-radius: 3px;\n border-left: 3px solid #ff6b6b;\n }\n \n .debug-message.warning {\n color: #ffd93d;\n background: rgba(255, 217, 61, 0.1);\n padding: 4px;\n border-radius: 3px;\n border-left: 3px solid #ffd93d;\n }\n \n .debug-timestamp {\n color: #888;\n font-size: 10px;\n }\n \n @media (max-width: 480px) {\n #mobile-debug-panel {\n width: calc(100vw - 20px);\n right: 10px;\n top: 10px;\n }\n }\n ",document.head.appendChild(e),document.body.appendChild(_debugPanel),document.getElementById("mobile-debug-close").onclick=hideDebug,_updateDebugDisplay()}function _updateDebugDisplay(){if(!_debugPanel)return;const e=document.getElementById("mobile-debug-content");e&&(e.innerHTML=_debugMessages.map(e=>"string"==typeof e?`<div class="debug-message">${e}</div>`:`<div class="debug-message ${e.type}">${e.text}</div>`).join(""),e.scrollTop=e.scrollHeight)}debug.clear=function(){_debugMessages=[],_debugPanel&&_updateDebugDisplay(),console.clear()},window.debug=debug,window.debugError=debugError,window.debugWarn=debugWarn,window.showDebug=showDebug,window.hideDebug=hideDebug,window.toggleDebug=toggleDebug,window.lockGestures=lockGestures,window.enableGyroTap=enableGyroTap,window.enableGyroButton=enableGyroButton,window.enableSensorTap=enableGyroTap,window.enableSensorButton=enableGyroButton,window.enableMicTap=enableMicTap,window.enableMicButton=enableMicButton,window.enableSoundTap=enableSoundTap,window.enableSoundButton=enableSoundButton,window.enableSpeechTap=enableSpeechTap,window.enableSpeechButton=enableSpeechButton,window.enableVibrationTap=enableVibrationTap,window.enableVibrationButton=enableVibrationButton,window.vibrate=vibrate,window.stopVibration=stopVibration,window.enableNfcTap=enableNfcTap,window.enableNfcButton=enableNfcButton,window.stopNfc=stopNfc,window.setNfcTagAlias=setNfcTagAlias,window.getNfcTagAlias=getNfcTagAlias,window.isNfcTag=isNfcTag,window.enableAllTap=enableAllTap,window.enableAllButton=enableAllButton,window.enableGyroCanvas=enableGyroCanvas,window.enableSensorCanvas=enableGyroCanvas,window.enableMicCanvas=enableMicCanvas,window.enableSoundCanvas=enableSoundCanvas,window.enableSpeechCanvas=enableSpeechCanvas,window.enableVibrationCanvas=enableVibrationCanvas,window.enableNfcCanvas=enableNfcCanvas,window.enableAllCanvas=enableAllCanvas,window.enableCameraCanvas=enableCameraCanvas,window.enableGyroBanner=enableGyroBanner,window.enableSensorBanner=enableGyroBanner,window.enableMicBanner=enableMicBanner,window.enableSoundBanner=enableSoundBanner,window.enableSpeechBanner=enableSpeechBanner,window.enableVibrationBanner=enableVibrationBanner,window.enableNfcBanner=enableNfcBanner,window.enableAllBanner=enableAllBanner,window.enableCameraBanner=enableCameraBanner,window.enableGyroOn=enableGyroOn,window.enableSensorOn=enableGyroOn,window.enableMicOn=enableMicOn,window.enableSoundOn=enableSoundOn,window.enableSpeechOn=enableSpeechOn,window.enableVibrationOn=enableVibrationOn,window.enableNfcOn=enableNfcOn,window.enableAllOn=enableAllOn,window.enableCameraOn=enableCameraOn;class PhoneCamera{constructor(e="user",n=!0,o="fitHeight"){this._active=e,this._mirror=n,this._mode=o,this._fixedWidth=640,this._fixedHeight=480,this._video=null,this._ready=!1,this._p5Instance=window,this._onReadyCallback=null,this._createCaptureRef=null,window._phoneCameras||(window._phoneCameras=[]),window._phoneCameras.push(this)}get ready(){return this._ready}get video(){return this._video}get videoElement(){return this._video?this._video.elt:null}get width(){if(!this._ready)return 0;return this.getDimensions().width}get height(){if(!this._ready)return 0;return this.getDimensions().height}get active(){return this._active}set active(e){"user"===e||"environment"===e?this._active!==e&&(this._active=e,this._ready&&this._switchCamera()):console.error('PhoneCamera: active must be "user" or "environment"')}get mirror(){return this._mirror}set mirror(e){this._mirror=!!e}get mode(){return this._mode}set mode(e){const n=["fitWidth","fitHeight","cover","contain","fixed"];n.includes(e)?this._mode=e:console.error("PhoneCamera: mode must be one of:",n.join(", "))}get fixedWidth(){return this._fixedWidth}set fixedWidth(e){this._fixedWidth=Math.max(1,e)}get fixedHeight(){return this._fixedHeight}set fixedHeight(e){this._fixedHeight=Math.max(1,e)}onReady(e){this._onReadyCallback=e,this._ready&&this._video&&this._video.elt&&this._video.elt.readyState>=2?e():this._video&&this._checkVideoReady()}_initializeCamera(){if(this._ready||this._video)return;const e={video:{facingMode:this._active},audio:!1};this._video=createCapture(e,()=>{this._ready=!0,this._video.hide(),console.log("✅ PhoneCamera ready"),this._checkVideoReady()}),this._video&&this._video.elt&&this._video.elt.addEventListener("loadeddata",()=>{this._ready=!0,this._checkVideoReady()})}_checkVideoReady(e=0){if(this._video&&this._video.elt&&this._video.elt.readyState>=2){if(this._onReadyCallback){const e=this._onReadyCallback;this._onReadyCallback=null,e()}}else e<100?setTimeout(()=>this._checkVideoReady(e+1),100):(console.warn("PhoneCamera: Video failed to reach ready state after 10 seconds"),_debugVisible&&debugWarn("PhoneCamera: Video not ready after timeout. Check camera permissions."))}_switchCamera(){if(!this._video)return;this._ready;this._ready=!1,this._video.remove();const e={video:{facingMode:this._active},audio:!1};this._video=createCapture(e,()=>{this._ready=!0,this._video.hide(),console.log(`✅ PhoneCamera switched to ${this._active} camera`)}),this._video&&this._video.elt&&this._video.elt.addEventListener("loadeddata",()=>{this._ready=!0})}remove(){this._video&&(this._video.remove(),this._video=null),this._ready=!1}getDimensions(){if(!this._ready||!this._video)return{x:0,y:0,width:0,height:0,scaleX:1,scaleY:1};const e=this.videoElement,n=e&&e.videoWidth||this._video.width,o=e&&e.videoHeight||this._video.height;if(!n||!o)return{x:0,y:0,width:0,height:0,scaleX:1,scaleY:1};const t="undefined"!=typeof width?width:window.innerWidth,a="undefined"!=typeof height?height:window.innerHeight;let i,r,s,l;if("fixed"===this._mode)i=this._fixedWidth,r=this._fixedHeight,s=(t-i)/2,l=(a-r)/2;else if("fitWidth"===this._mode)i=t,r=o/n*i,s=0,l=(a-r)/2;else if("fitHeight"===this._mode)r=a,i=n/o*r,s=(t-i)/2,l=0;else if("cover"===this._mode){const e=Math.max(t/n,a/o);i=n*e,r=o*e,s=(t-i)/2,l=(a-r)/2}else if("contain"===this._mode){const e=Math.min(t/n,a/o);i=n*e,r=o*e,s=(t-i)/2,l=(a-r)/2}return{x:s,y:l,width:i,height:r,scaleX:i/n,scaleY:r/o}}mapPoint(e,n){const o=this.getDimensions();let t=e*o.scaleX;const a=n*o.scaleY;this._mirror&&(t=o.width-t);return{x:t+o.x,y:a+o.y}}mapKeypoint(e){if(!e||void 0===e.x||void 0===e.y)return console.warn("PhoneCamera.mapKeypoint: invalid keypoint",e),e;const n=this.mapPoint(e.x,e.y);return{...e,x:n.x,y:n.y}}mapKeypoints(e){return Array.isArray(e)?e.map(e=>this.mapKeypoint(e)):(console.warn("PhoneCamera.mapKeypoints: expected array, got",typeof e),e)}mapBox(e){if(!e)return console.warn("PhoneCamera.mapBox: invalid box",e),e;const n=void 0!==e.x?e.x:e.xMin,o=void 0!==e.y?e.y:e.yMin,t=void 0!==e.width?e.width:e.xMax-e.xMin,a=void 0!==e.height?e.height:e.yMax-e.yMin,i=Number(n),r=Number(o),s=Number(t),l=Number(a);if(!(Number.isFinite(i)&&Number.isFinite(r)&&Number.isFinite(s)&&Number.isFinite(l)))return console.warn("PhoneCamera.mapBox: invalid box",e),e;const d=this.mapPoint(i,r),c=this.mapPoint(i+s,r+l),u=Math.min(d.x,c.x),p=Math.min(d.y,c.y),b=Math.abs(c.x-d.x),h=Math.abs(c.y-d.y);return{...e,x:u,y:p,width:b,height:h,xMin:u,yMin:p,xMax:u+b,yMax:p+h}}mapBoxes(e){return Array.isArray(e)?e.map(e=>this.mapBox(e)):(console.warn("PhoneCamera.mapBoxes: expected array, got",typeof e),e)}_draw(e=null){const n=this.videoElement;if(!this._ready||!this._video||!n||n.readyState<2)return;const o=this.getDimensions(),t="undefined"!=typeof width?width:window.innerWidth;this._drawDebugLogged||(console.log("_draw() params:",{x:o.x,y:o.y,width:o.width,height:o.height,canvasWidth:t,mirror:this._mirror}),this._drawDebugLogged=!0);const a=e&&e.drawingContext||("undefined"!=typeof drawingContext?drawingContext:null);if(!a||"function"!=typeof a.drawImage)return;const i=e&&e.push?e.push.bind(e):"function"==typeof push?push:null,r=e&&e.pop?e.pop.bind(e):"function"==typeof pop?pop:null,s=e&&e.translate?e.translate.bind(e):"function"==typeof translate?translate:null,l=e&&e.scale?e.scale.bind(e):"function"==typeof scale?scale:null;i&&r&&s&&l&&(i(),this._mirror?(s(t,0),l(-1,1),a.drawImage(n,o.x,o.y,o.width,o.height)):a.drawImage(n,o.x,o.y,o.width,o.height),r())}}function createPhoneCamera(e="user",n=!0,o="fitHeight"){return new PhoneCamera(e,n,o)}function enableCameraButton(e="ENABLE CAMERA",n="Starting camera..."){_createPermissionButton(e,n,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via button")})}function enableCameraTap(e="Tap screen to enable camera"){navigator.permissions&&navigator.permissions.query?navigator.permissions.query({name:"camera"}).then(n=>{"granted"===n.state?(console.log("✅ Camera permission already granted - auto-starting"),_requestCameraPermission()):_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}).catch(()=>{_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}):_createTapToEnable(e,async()=>{await _requestCameraPermission(),console.log("✅ Camera enabled via tap")})}async function _requestCameraPermission(){try{if(void 0!==window._phoneCameras&&Array.isArray(window._phoneCameras))for(let e of window._phoneCameras)!e||e._ready||e._video||e._initializeCamera();"function"==typeof userCameraReady&&userCameraReady(),_notifySketchReady()}catch(e){console.error("Camera permission error:",e),_debugVisible&&debugError("Camera permission error:",e),_notifySketchReady()}}if(window.createPhoneCamera=createPhoneCamera,window.enableCameraButton=enableCameraButton,window.enableCameraTap=enableCameraTap,"undefined"!=typeof p5&&p5.prototype){const e=p5.prototype.image;p5.prototype.image=function(...n){if(n[0]instanceof PhoneCamera){n[0]._draw(this)}else e.apply(this,n)}}"undefined"!=typeof p5&&p5.prototype&&"function"!=typeof p5.registerAddon&&(p5.prototype.lockGestures=lockGestures,p5.prototype.enableGyroTap=enableGyroTap,p5.prototype.enableGyroButton=enableGyroButton,p5.prototype.enableSensorTap=enableGyroTap,p5.prototype.enableSensorButton=enableGyroButton,p5.prototype.enableMicTap=enableMicTap,p5.prototype.enableMicButton=enableMicButton,p5.prototype.enableSoundTap=enableSoundTap,p5.prototype.enableSoundButton=enableSoundButton,p5.prototype.enableSpeechTap=enableSpeechTap,p5.prototype.enableSpeechButton=enableSpeechButton,p5.prototype.enableVibrationTap=enableVibrationTap,p5.prototype.enableVibrationButton=enableVibrationButton,p5.prototype.vibrate=vibrate,p5.prototype.stopVibration=stopVibration,p5.prototype.enableNfcTap=enableNfcTap,p5.prototype.enableNfcButton=enableNfcButton,p5.prototype.stopNfc=stopNfc,p5.prototype.setNfcTagAlias=setNfcTagAlias,p5.prototype.getNfcTagAlias=getNfcTagAlias,p5.prototype.isNfcTag=isNfcTag,p5.prototype.enableAllTap=enableAllTap,p5.prototype.enableAllButton=enableAllButton,p5.prototype.enableGyroCanvas=enableGyroCanvas,p5.prototype.enableSensorCanvas=enableGyroCanvas,p5.prototype.enableMicCanvas=enableMicCanvas,p5.prototype.enableSoundCanvas=enableSoundCanvas,p5.prototype.enableSpeechCanvas=enableSpeechCanvas,p5.prototype.enableVibrationCanvas=enableVibrationCanvas,p5.prototype.enableNfcCanvas=enableNfcCanvas,p5.prototype.enableAllCanvas=enableAllCanvas,p5.prototype.enableCameraCanvas=enableCameraCanvas,p5.prototype.enableGyroBanner=enableGyroBanner,p5.prototype.enableSensorBanner=enableGyroBanner,p5.prototype.enableMicBanner=enableMicBanner,p5.prototype.enableSoundBanner=enableSoundBanner,p5.prototype.enableSpeechBanner=enableSpeechBanner,p5.prototype.enableVibrationBanner=enableVibrationBanner,p5.prototype.enableNfcBanner=enableNfcBanner,p5.prototype.enableAllBanner=enableAllBanner,p5.prototype.enableCameraBanner=enableCameraBanner,p5.prototype.enableGyroOn=enableGyroOn,p5.prototype.enableSensorOn=enableGyroOn,p5.prototype.enableMicOn=enableMicOn,p5.prototype.enableSoundOn=enableSoundOn,p5.prototype.enableSpeechOn=enableSpeechOn,p5.prototype.enableVibrationOn=enableVibrationOn,p5.prototype.enableNfcOn=enableNfcOn,p5.prototype.enableAllOn=enableAllOn,p5.prototype.enableCameraOn=enableCameraOn,p5.prototype.createPhoneCamera=createPhoneCamera,p5.prototype.enableCameraButton=enableCameraButton,p5.prototype.enableCameraTap=enableCameraTap,p5.prototype.showDebug=showDebug,p5.prototype.hideDebug=hideDebug,p5.prototype.toggleDebug=toggleDebug,p5.prototype.debug=debug,p5.prototype.debugError=debugError,p5.prototype.debugWarn=debugWarn,console.log("✅ Mobile p5.js Permissions: p5.prototype functions registered")),"undefined"!=typeof p5&&"function"==typeof p5.registerAddon&&p5.registerAddon(function(e,n,o){o.presetup=function(){this.lockGestures=lockGestures,this.enableGyroTap=enableGyroTap,this.enableGyroButton=enableGyroButton,this.enableSensorTap=enableGyroTap,this.enableSensorButton=enableGyroButton,this.enableMicTap=enableMicTap,this.enableMicButton=enableMicButton,this.enableSoundTap=enableSoundTap,this.enableSoundButton=enableSoundButton,this.enableSpeechTap=enableSpeechTap,this.enableSpeechButton=enableSpeechButton,this.enableVibrationTap=enableVibrationTap,this.enableVibrationButton=enableVibrationButton,this.vibrate=vibrate,this.stopVibration=stopVibration,this.enableNfcTap=enableNfcTap,this.enableNfcButton=enableNfcButton,this.stopNfc=stopNfc,this.setNfcTagAlias=setNfcTagAlias,this.getNfcTagAlias=getNfcTagAlias,this.isNfcTag=isNfcTag,this.enableAllTap=enableAllTap,this.enableAllButton=enableAllButton,this.enableGyroCanvas=enableGyroCanvas,this.enableSensorCanvas=enableGyroCanvas,this.enableMicCanvas=enableMicCanvas,this.enableSoundCanvas=enableSoundCanvas,this.enableSpeechCanvas=enableSpeechCanvas,this.enableVibrationCanvas=enableVibrationCanvas,this.enableNfcCanvas=enableNfcCanvas,this.enableAllCanvas=enableAllCanvas,this.enableCameraCanvas=enableCameraCanvas,this.enableGyroBanner=enableGyroBanner,this.enableSensorBanner=enableGyroBanner,this.enableMicBanner=enableMicBanner,this.enableSoundBanner=enableSoundBanner,this.enableSpeechBanner=enableSpeechBanner,this.enableVibrationBanner=enableVibrationBanner,this.enableNfcBanner=enableNfcBanner,this.enableAllBanner=enableAllBanner,this.enableCameraBanner=enableCameraBanner,this.enableGyroOn=enableGyroOn,this.enableSensorOn=enableGyroOn,this.enableMicOn=enableMicOn,this.enableSoundOn=enableSoundOn,this.enableSpeechOn=enableSpeechOn,this.enableVibrationOn=enableVibrationOn,this.enableNfcOn=enableNfcOn,this.enableAllOn=enableAllOn,this.enableCameraOn=enableCameraOn,this.createPhoneCamera=createPhoneCamera,this.enableCameraButton=enableCameraButton,this.enableCameraTap=enableCameraTap,this.showDebug=showDebug,this.hideDebug=hideDebug,this.toggleDebug=toggleDebug,this.debug=debug,this.debugError=debugError,this.debugWarn=debugWarn},console.log("✅ Mobile p5.js Permissions: registered as p5.js 2.0 addon")});
@@ -2,9 +2,10 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>P5.js Mobile - Microphone Level</title>
5
- <script src="https://cdn.jsdelivr.net/npm/p5@1.11.10/lib/p5.min.js"></script>
6
- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/addons/p5.sound.min.js"></script>
7
- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.1/dist/p5-phone.min.js"></script>
5
+ <script src="https://cdn.jsdelivr.net/npm/p5@2.2.3/lib/p5.js"></script>
6
+ <script src="https://cdn.jsdelivr.net/npm/p5.js-compatibility@0.2.0/src/preload.js"></script>
7
+ <script src="https://cdn.jsdelivr.net/npm/p5.sound@0.3.0/dist/p5.sound.min.js"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.3/dist/p5-phone.min.js"></script>
8
9
  <style>
9
10
  body {
10
11
  margin: 0;
@@ -14,6 +15,6 @@
14
15
  </style>
15
16
  </head>
16
17
  <body>
17
- <script src="sketch.js"></script>
18
+ <script src="sketch.js?v=20260602"></script>
18
19
  </body>
19
20
  </html>