p5-phone 1.7.0 → 1.8.0

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 (68) hide show
  1. package/README.md +34 -9
  2. package/dist/p5-phone.js +105 -18
  3. package/dist/p5-phone.min.js +1 -1
  4. package/examples/Phone Sensor Examples/microphone/01_mic_level/sketch.js +3 -3
  5. package/examples/Phone Sensor Examples/microphone/02_speech_recognition/README.md +1 -1
  6. package/examples/Phone Sensor Examples/microphone/02_speech_recognition/sketch.js +2 -2
  7. package/examples/Phone Sensor Examples/movement/01_orientation_basic/index.html +1 -0
  8. package/examples/Phone Sensor Examples/movement/01_orientation_basic/sketch.js +3 -3
  9. package/examples/Phone Sensor Examples/movement/02_rotational_velocity/index.html +1 -0
  10. package/examples/Phone Sensor Examples/movement/02_rotational_velocity/sketch.js +3 -3
  11. package/examples/Phone Sensor Examples/movement/03_acceleration/index.html +1 -0
  12. package/examples/Phone Sensor Examples/movement/03_acceleration/sketch.js +3 -3
  13. package/examples/Phone Sensor Examples/sound/01_dual_audio/index.html +1 -0
  14. package/examples/Phone Sensor Examples/sound/01_dual_audio/sketch.js +5 -5
  15. package/examples/Phone Sensor Examples/sound/02_volume_touches/index.html +1 -0
  16. package/examples/Phone Sensor Examples/sound/02_volume_touches/sketch.js +7 -7
  17. package/examples/Phone Sensor Examples/touch/01_touch_basic/index.html +1 -0
  18. package/examples/Phone Sensor Examples/touch/01_touch_basic/sketch.js +4 -4
  19. package/examples/Phone Sensor Examples/touch/02_touch_zones/index.html +1 -0
  20. package/examples/Phone Sensor Examples/touch/02_touch_zones/sketch.js +3 -3
  21. package/examples/Phone Sensor Examples/touch/03_touch_count/index.html +1 -0
  22. package/examples/Phone Sensor Examples/touch/03_touch_count/sketch.js +3 -3
  23. package/examples/Phone Sensor Examples/touch/04_touch_distance/index.html +1 -0
  24. package/examples/Phone Sensor Examples/touch/04_touch_distance/sketch.js +3 -3
  25. package/examples/Phone Sensor Examples/touch/05_touch_angle/index.html +1 -0
  26. package/examples/Phone Sensor Examples/touch/05_touch_angle/sketch.js +3 -3
  27. package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/index.html +1 -0
  28. package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/sketch.js +3 -3
  29. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/sketch.js +2 -2
  30. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/sketch.js +2 -2
  31. package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/sketch.js +2 -2
  32. package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/sketch.js +2 -2
  33. package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/sketch.js +2 -2
  34. package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/sketch.js +2 -2
  35. package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/sketch.js +2 -2
  36. package/examples/Phone Sensor Examples - Minimal/vibration/01_haptic_feedback/sketch.js +2 -2
  37. package/examples/Phone and Gif/collision/sketch.js +3 -3
  38. package/examples/Phone and Gif/fetch/sketch.js +3 -3
  39. package/examples/Phone and Gif/roll/sketch.js +3 -3
  40. package/examples/UIStyles/banner-style/index.html +1 -0
  41. package/examples/UIStyles/canvas-style/index.html +1 -0
  42. package/examples/UIStyles/custom-element/index.html +1 -0
  43. package/examples/UXcompare/button-vs-movement/index.html +1 -0
  44. package/examples/UXcompare/button-vs-orientation/index.html +1 -0
  45. package/examples/UXcompare/button-vs-shake/index.html +1 -0
  46. package/examples/UXcompare/gyroscope-demo/index.html +1 -0
  47. package/examples/UXcompare/microphone-demo/index.html +1 -0
  48. package/examples/UXcompare/slider-vs-angle/index.html +1 -0
  49. package/examples/UXcompare/slider-vs-angle/sketch.js +3 -3
  50. package/examples/UXcompare/slider-vs-distance/index.html +1 -0
  51. package/examples/UXcompare/slider-vs-distance/sketch.js +3 -3
  52. package/examples/UXcompare/slider-vs-microphone/index.html +1 -0
  53. package/examples/UXcompare/slider-vs-microphone/sketch.js +3 -3
  54. package/examples/UXcompare/slider-vs-touches/index.html +1 -0
  55. package/examples/UXcompare/slider-vs-touches/sketch.js +3 -3
  56. package/examples/UXcompare/sliders-vs-acceleration/index.html +1 -0
  57. package/examples/UXcompare/sliders-vs-acceleration/sketch.js +3 -3
  58. package/examples/UXcompare/sliders-vs-rotation/index.html +1 -0
  59. package/examples/UXcompare/sliders-vs-rotation/sketch.js +3 -3
  60. package/examples/blankTemplate/index.html +1 -0
  61. package/examples/blankTemplate/sketch.js +2 -2
  62. package/examples/homepage/index.html +5 -4
  63. package/examples/ml5/Gaze_detector_class/index.html +1 -0
  64. package/examples/ml5/PHONE_BodyPose_two_points/index.html +1 -0
  65. package/examples/ml5/PHONE_FaceMesh_two_points/index.html +1 -0
  66. package/examples/ml5/PHONE_HandPose_two_points/index.html +1 -0
  67. package/package.json +1 -1
  68. package/src/p5-phone.js +105 -18
package/README.md CHANGED
@@ -17,9 +17,11 @@ That's where this library comes in:
17
17
 
18
18
  This library simplifies access to the following p5.js mobile sensor and audio commands:
19
19
 
20
- **Touch Events:**
21
- - [`touchStarted()`](https://p5js.org/reference/p5/touchStarted/) - Called when a touch begins
22
- - [`touchEnded()`](https://p5js.org/reference/p5/touchEnded/) - Called when a touch ends
20
+ **Touch/Pointer Events:**
21
+ - [`mousePressed()`](https://p5js.org/reference/p5/mousePressed/) - Called when a press/touch begins (works for both mouse and touch in p5.js 1.x and 2.0)
22
+ - [`mouseReleased()`](https://p5js.org/reference/p5/mouseReleased/) - Called when a press/touch ends (works for both mouse and touch in p5.js 1.x and 2.0)
23
+ - [`touchStarted()`](https://p5js.org/reference/p5/touchStarted/) - Called when a touch begins (p5.js 1.x only)
24
+ - [`touchEnded()`](https://p5js.org/reference/p5/touchEnded/) - Called when a touch ends (p5.js 1.x only)
23
25
 
24
26
  **Device Motion & Orientation:**
25
27
  - [`rotationX`](https://p5js.org/reference/p5/rotationX/) - Device tilt forward/backward
@@ -45,10 +47,31 @@ This library simplifies access to the following p5.js mobile sensor and audio co
45
47
  - Safari 13+
46
48
  - Firefox 75+
47
49
 
50
+ ## p5.js Version Compatibility
51
+
52
+ p5-phone supports both **p5.js 1.x** and **p5.js 2.0+**.
53
+
54
+ | Feature | p5.js 1.x | p5.js 2.0+ |
55
+ |---------|-----------|------------|
56
+ | Permission UI (Tap/Button/Canvas/Banner/Custom) | ✅ | ✅ |
57
+ | Motion sensors (rotationX/Y/Z, accelerationX/Y/Z) | ✅ | ✅ |
58
+ | Microphone / Speech / Sound | ✅ | ✅ |
59
+ | Camera (PhoneCamera) | ✅ | ✅ |
60
+ | Vibration | ✅ | ✅ |
61
+ | Debug console | ✅ | ✅ |
62
+ | lockGestures() | ✅ | ✅ |
63
+ | `touchStarted()` / `touchEnded()` | ✅ | ❌ Use `mousePressed()` / `mouseReleased()` |
64
+ | `p5.registerAddon()` | ❌ | ✅ (auto-detected) |
65
+
66
+ **Key change in p5.js 2.0:** Touch-specific callbacks (`touchStarted`, `touchMoved`, `touchEnded`) are no longer dispatched. The unified Pointer API routes all input (mouse + touch) through `mousePressed()`, `mouseDragged()`, and `mouseReleased()`. These mouse callbacks work in **both** p5.js 1.x and 2.0, so use them for forward-compatible code.
67
+
68
+ p5-phone automatically detects the p5.js version and adjusts its internal touch override behavior accordingly. No configuration needed.
69
+
48
70
  ## Table of Contents
49
71
 
50
72
  - [Link for Interactive Examples](#link-for-interactive-examples)
51
73
  - [Browser Compatibility](#browser-compatibility)
74
+ - [p5.js Version Compatibility](#p5js-version-compatibility)
52
75
  - [CDN (Recommended)](#cdn-recommended)
53
76
  - [Basic Setup](#basic-setup)
54
77
  - [Index HTML](#index-html)
@@ -77,10 +100,10 @@ This library simplifies access to the following p5.js mobile sensor and audio co
77
100
 
78
101
  ```html
79
102
  <!-- Minified version (recommended) -->
80
- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.7.0/dist/p5-phone.min.js"></script>
103
+ <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.8.0/dist/p5-phone.min.js"></script>
81
104
 
82
105
  <!-- Development version (larger, with comments) -->
83
- <!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.7.0/dist/p5-phone.js"></script> -->
106
+ <!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.8.0/dist/p5-phone.js"></script> -->
84
107
  ```
85
108
 
86
109
  ### Basic Setup
@@ -106,9 +129,10 @@ This library simplifies access to the following p5.js mobile sensor and audio co
106
129
 
107
130
  <!-- Load p5.js library -->
108
131
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
132
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
109
133
 
110
134
  <!-- Load p5-phone library -->
111
- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.7.0/dist/p5-phone.min.js"></script>
135
+ <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.8.0/dist/p5-phone.min.js"></script>
112
136
 
113
137
  </head>
114
138
  <body>
@@ -173,11 +197,12 @@ function draw() {
173
197
  }
174
198
 
175
199
  // Prevent default touch behavior (optional but recommended)
176
- function touchStarted() {
200
+ // Use mousePressed/mouseReleased — works in both p5.js 1.x and 2.0
201
+ function mousePressed() {
177
202
  return false;
178
203
  }
179
204
 
180
- function touchEnded() {
205
+ function mouseReleased() {
181
206
  return false;
182
207
  }
183
208
  ```
@@ -580,7 +605,7 @@ function mousePressed() {
580
605
  }
581
606
 
582
607
  // Touch zones with different haptic patterns
583
- function touchStarted() {
608
+ function mousePressed() {
584
609
  if (window.vibrationEnabled) {
585
610
  if (mouseX < width/2) {
586
611
  vibrate(50); // Left side - short pulse
package/dist/p5-phone.js CHANGED
@@ -91,6 +91,12 @@ window.speechEnabled = false;
91
91
  // Internal state
92
92
  let _micInstance = null;
93
93
 
94
+ // p5.js version detection (1.x vs 2.x)
95
+ const _p5MajorVersion = (typeof p5 !== 'undefined' && p5.VERSION)
96
+ ? parseInt(p5.VERSION.split('.')[0], 10)
97
+ : 1; // Default to 1 if p5 not loaded yet
98
+ const _isP5v2 = _p5MajorVersion >= 2;
99
+
94
100
  // =========================================
95
101
  // PUBLIC API - CALL THESE FROM YOUR P5 SKETCH
96
102
  // =========================================
@@ -1141,29 +1147,37 @@ function _initializeP5TouchOverrides() {
1141
1147
  }
1142
1148
 
1143
1149
  function _overrideP5Touch() {
1144
- const origTouchStarted = window.touchStarted || function() {};
1145
- const origTouchMoved = window.touchMoved || function() {};
1146
- const origTouchEnded = window.touchEnded || function() {};
1147
1150
  const origMousePressed = window.mousePressed || function() {};
1148
1151
  const origMouseDragged = window.mouseDragged || function() {};
1149
1152
  const origMouseReleased = window.mouseReleased || function() {};
1150
1153
 
1151
- // Ensure all touch functions return false to prevent default behaviors
1152
- window.touchStarted = function(e) {
1153
- origTouchStarted(e);
1154
- return false;
1155
- };
1156
-
1157
- window.touchMoved = function(e) {
1158
- origTouchMoved(e);
1159
- return false;
1160
- };
1161
-
1162
- window.touchEnded = function(e) {
1163
- origTouchEnded(e);
1164
- return false;
1165
- };
1154
+ // In p5.js 2.0, touch and mouse are unified via Pointer API.
1155
+ // mousePressed/mouseDragged/mouseReleased fire for ALL pointer types (mouse + touch).
1156
+ // In p5.js 1.x, touchStarted/touchMoved/touchEnded are separate from mouse callbacks.
1157
+ // We wrap both sets for 1.x, and only mouse callbacks for 2.0.
1158
+ if (!_isP5v2) {
1159
+ // p5.js 1.x: also wrap touch-specific callbacks
1160
+ const origTouchStarted = window.touchStarted || function() {};
1161
+ const origTouchMoved = window.touchMoved || function() {};
1162
+ const origTouchEnded = window.touchEnded || function() {};
1163
+
1164
+ window.touchStarted = function(e) {
1165
+ origTouchStarted(e);
1166
+ return false;
1167
+ };
1168
+
1169
+ window.touchMoved = function(e) {
1170
+ origTouchMoved(e);
1171
+ return false;
1172
+ };
1173
+
1174
+ window.touchEnded = function(e) {
1175
+ origTouchEnded(e);
1176
+ return false;
1177
+ };
1178
+ }
1166
1179
 
1180
+ // Mouse callbacks — work in both 1.x and 2.0
1167
1181
  window.mousePressed = function(e) {
1168
1182
  origMousePressed(e);
1169
1183
  return false;
@@ -2215,4 +2229,77 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
2215
2229
  p5.prototype.debugWarn = debugWarn;
2216
2230
 
2217
2231
  console.log('✅ Mobile p5.js Permissions: p5.prototype functions registered');
2232
+ }
2233
+
2234
+ // =========================================
2235
+ // P5.JS 2.0 ADDON REGISTRATION
2236
+ // =========================================
2237
+
2238
+ /**
2239
+ * Register as a p5.js 2.0 addon via p5.registerAddon().
2240
+ * This provides the modern lifecycle integration for p5.js 2.0+
2241
+ * while the p5.prototype block above handles 1.x compatibility.
2242
+ */
2243
+ if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
2244
+ p5.registerAddon(function(p5, fn, lifecycles) {
2245
+ // Register all public functions on the prototype (fn === p5.prototype)
2246
+ // Core permission functions
2247
+ fn.lockGestures = lockGestures;
2248
+ fn.enableGyroTap = enableGyroTap;
2249
+ fn.enableGyroButton = enableGyroButton;
2250
+ fn.enableMicTap = enableMicTap;
2251
+ fn.enableMicButton = enableMicButton;
2252
+ fn.enableSoundTap = enableSoundTap;
2253
+ fn.enableSoundButton = enableSoundButton;
2254
+ fn.enableSpeechTap = enableSpeechTap;
2255
+ fn.enableSpeechButton = enableSpeechButton;
2256
+ fn.enableVibrationTap = enableVibrationTap;
2257
+ fn.enableVibrationButton = enableVibrationButton;
2258
+ fn.vibrate = vibrate;
2259
+ fn.stopVibration = stopVibration;
2260
+ fn.enableAllTap = enableAllTap;
2261
+ fn.enableAllButton = enableAllButton;
2262
+
2263
+ // Canvas-first-touch style
2264
+ fn.enableGyroCanvas = enableGyroCanvas;
2265
+ fn.enableMicCanvas = enableMicCanvas;
2266
+ fn.enableSoundCanvas = enableSoundCanvas;
2267
+ fn.enableSpeechCanvas = enableSpeechCanvas;
2268
+ fn.enableVibrationCanvas = enableVibrationCanvas;
2269
+ fn.enableAllCanvas = enableAllCanvas;
2270
+ fn.enableCameraCanvas = enableCameraCanvas;
2271
+
2272
+ // Banner style
2273
+ fn.enableGyroBanner = enableGyroBanner;
2274
+ fn.enableMicBanner = enableMicBanner;
2275
+ fn.enableSoundBanner = enableSoundBanner;
2276
+ fn.enableSpeechBanner = enableSpeechBanner;
2277
+ fn.enableVibrationBanner = enableVibrationBanner;
2278
+ fn.enableAllBanner = enableAllBanner;
2279
+ fn.enableCameraBanner = enableCameraBanner;
2280
+
2281
+ // Custom element binding
2282
+ fn.enableGyroOn = enableGyroOn;
2283
+ fn.enableMicOn = enableMicOn;
2284
+ fn.enableSoundOn = enableSoundOn;
2285
+ fn.enableSpeechOn = enableSpeechOn;
2286
+ fn.enableVibrationOn = enableVibrationOn;
2287
+ fn.enableAllOn = enableAllOn;
2288
+ fn.enableCameraOn = enableCameraOn;
2289
+
2290
+ // Camera functions
2291
+ fn.createPhoneCamera = createPhoneCamera;
2292
+ fn.enableCameraButton = enableCameraButton;
2293
+ fn.enableCameraTap = enableCameraTap;
2294
+
2295
+ // Debug functions
2296
+ fn.showDebug = showDebug;
2297
+ fn.hideDebug = hideDebug;
2298
+ fn.toggleDebug = toggleDebug;
2299
+ fn.debug = debug;
2300
+ fn.debugError = debugError;
2301
+ fn.debugWarn = debugWarn;
2302
+
2303
+ console.log('✅ Mobile p5.js Permissions: registered as p5.js 2.0 addon');
2304
+ });
2218
2305
  }
@@ -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;let _micInstance=null;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 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 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 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 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)}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 _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()}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,gestures:window.gesturesLocked}}))}function _createPermissionButton(e,n,o){_removeExistingUI();const t=document.createElement("button");t.id="permissionButton",t.textContent=e,t.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 ",t.addEventListener("mouseenter",()=>{t.style.transform="translate(-50%, -50%) scale(1.05)"}),t.addEventListener("mouseleave",()=>{t.style.transform="translate(-50%, -50%) scale(1)"});const a=async()=>{t.parentNode&&(t.style.display="none",i.style.display="block",await o(),i.style.display="none",_removeExistingUI())};t.addEventListener("click",a),t.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),a()}),t.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),a()}),document.body.appendChild(t),document.body.appendChild(i)}function _createTapToEnable(e,n){_removeExistingUI();const o=document.createElement("div");o.id="tapOverlay",o.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 t=document.createElement("div");t.textContent=e,t.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 ",o.appendChild(t);const i=async()=>{o.parentNode&&(t.textContent="Enabling...",await n(),o.parentNode&&document.body.removeChild(o))};o.addEventListener("click",i),o.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()}),o.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),i()}),document.body.appendChild(o)}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 i=async e=>{o||(o=!0,t&&(clearInterval(t),t=null),document.removeEventListener("touchstart",i,!0),document.removeEventListener("mousedown",i,!0),await n())},a=()=>{const e=document.querySelector("canvas");e?(e.addEventListener("touchstart",i,{once:!0,capture:!0}),e.addEventListener("mousedown",i,{once:!0,capture:!0})):setTimeout(a,50)};a()}function _createBannerToEnable(e,n,o){_removeExistingUI();const t=document.createElement("div");t.id="permissionBanner";const i="top"===n;t.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 `,t.textContent=e,document.body.appendChild(t),requestAnimationFrame(()=>{requestAnimationFrame(()=>{t.style.transform="translateY(0)"})});const a=async()=>{t.parentNode&&(t.textContent="Enabling...",t.style.pointerEvents="none",await o(),t.style.transform=`translateY(${i?"-100%":"100%"})`,t.style.opacity="0",setTimeout(()=>{t.parentNode&&t.remove()},300))};t.addEventListener("click",a),t.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),a()}),t.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),a()})}function _bindPermissionTo(e,n){let o=!1;const t=()=>{const i=document.querySelector(e);if(!i)return console.warn(`p5-phone: Element "${e}" not found. Retrying...`),void setTimeout(t,100);const a=async()=>{o||(o=!0,await n())};i.addEventListener("click",a),i.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),a()})};"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,i=o.touches[0].clientY,a=t-e,r=i-n;(e<20&&a>0||e>window.innerWidth-20&&a<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.touchStarted||function(){},n=window.touchMoved||function(){},o=window.touchEnded||function(){},t=window.mousePressed||function(){},i=window.mouseDragged||function(){},a=window.mouseReleased||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(e){return t(e),!1},window.mouseDragged=function(e){return i(e),!1},window.mouseReleased=function(e){return a(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.enableAllTap=enableAllTap,window.enableAllButton=enableAllButton,window.enableGyroCanvas=enableGyroCanvas,window.enableMicCanvas=enableMicCanvas,window.enableSoundCanvas=enableSoundCanvas,window.enableSpeechCanvas=enableSpeechCanvas,window.enableVibrationCanvas=enableVibrationCanvas,window.enableAllCanvas=enableAllCanvas,window.enableCameraCanvas=enableCameraCanvas,window.enableGyroBanner=enableGyroBanner,window.enableMicBanner=enableMicBanner,window.enableSoundBanner=enableSoundBanner,window.enableSpeechBanner=enableSpeechBanner,window.enableVibrationBanner=enableVibrationBanner,window.enableAllBanner=enableAllBanner,window.enableCameraBanner=enableCameraBanner,window.enableGyroOn=enableGyroOn,window.enableMicOn=enableMicOn,window.enableSoundOn=enableSoundOn,window.enableSpeechOn=enableSpeechOn,window.enableVibrationOn=enableVibrationOn,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 i,a,r,s;if("fixed"===this._mode)i=this._fixedWidth,a=this._fixedHeight,r=(o-i)/2,s=(t-a)/2;else if("fitWidth"===this._mode)i=o,a=n/e*i,r=0,s=(t-a)/2;else if("fitHeight"===this._mode)a=t,i=e/n*a,r=(o-i)/2,s=0;else if("cover"===this._mode){const d=Math.max(o/e,t/n);i=e*d,a=n*d,r=(o-i)/2,s=(t-a)/2}else if("contain"===this._mode){const d=Math.min(o/e,t/n);i=e*d,a=n*d,r=(o-i)/2,s=(t-a)/2}return{x:r,y:s,width:i,height:a,scaleX:i/e,scaleY:a/n}}mapPoint(e,n){const o=this.getDimensions();let t=e*o.scaleX;const i=n*o.scaleY;this._mirror&&(t=o.width-t);return{x:t+o.x,y:i+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)}_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.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.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.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.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"));
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;let _micInstance=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 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 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 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 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)}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 _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()}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,gestures:window.gesturesLocked}}))}function _createPermissionButton(e,n,o){_removeExistingUI();const t=document.createElement("button");t.id="permissionButton",t.textContent=e,t.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 a=document.createElement("div");a.id="permissionStatus",a.textContent=n,a.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 ",t.addEventListener("mouseenter",()=>{t.style.transform="translate(-50%, -50%) scale(1.05)"}),t.addEventListener("mouseleave",()=>{t.style.transform="translate(-50%, -50%) scale(1)"});const i=async()=>{t.parentNode&&(t.style.display="none",a.style.display="block",await o(),a.style.display="none",_removeExistingUI())};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),document.body.appendChild(a)}function _createTapToEnable(e,n){_removeExistingUI();const o=document.createElement("div");o.id="tapOverlay",o.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 t=document.createElement("div");t.textContent=e,t.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 ",o.appendChild(t);const a=async()=>{o.parentNode&&(t.textContent="Enabling...",await n(),o.parentNode&&document.body.removeChild(o))};o.addEventListener("click",a),o.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),a()}),o.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),a()}),document.body.appendChild(o)}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();const t=document.createElement("div");t.id="permissionBanner";const a="top"===n;t.style.cssText=`\n position: fixed;\n ${a?"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: ${a?"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(${a?"-100%":"100%"});\n `,t.textContent=e,document.body.appendChild(t),requestAnimationFrame(()=>{requestAnimationFrame(()=>{t.style.transform="translateY(0)"})});const i=async()=>{t.parentNode&&(t.textContent="Enabling...",t.style.pointerEvents="none",await o(),t.style.transform=`translateY(${a?"-100%":"100%"})`,t.style.opacity="0",setTimeout(()=>{t.parentNode&&t.remove()},300))};t.addEventListener("click",i),t.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),i()}),t.addEventListener("pointerup",function(e){e.preventDefault(),e.stopPropagation(),i()})}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.enableAllTap=enableAllTap,window.enableAllButton=enableAllButton,window.enableGyroCanvas=enableGyroCanvas,window.enableMicCanvas=enableMicCanvas,window.enableSoundCanvas=enableSoundCanvas,window.enableSpeechCanvas=enableSpeechCanvas,window.enableVibrationCanvas=enableVibrationCanvas,window.enableAllCanvas=enableAllCanvas,window.enableCameraCanvas=enableCameraCanvas,window.enableGyroBanner=enableGyroBanner,window.enableMicBanner=enableMicBanner,window.enableSoundBanner=enableSoundBanner,window.enableSpeechBanner=enableSpeechBanner,window.enableVibrationBanner=enableVibrationBanner,window.enableAllBanner=enableAllBanner,window.enableCameraBanner=enableCameraBanner,window.enableGyroOn=enableGyroOn,window.enableMicOn=enableMicOn,window.enableSoundOn=enableSoundOn,window.enableSpeechOn=enableSpeechOn,window.enableVibrationOn=enableVibrationOn,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)}_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.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.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.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.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.enableAllTap=enableAllTap,n.enableAllButton=enableAllButton,n.enableGyroCanvas=enableGyroCanvas,n.enableMicCanvas=enableMicCanvas,n.enableSoundCanvas=enableSoundCanvas,n.enableSpeechCanvas=enableSpeechCanvas,n.enableVibrationCanvas=enableVibrationCanvas,n.enableAllCanvas=enableAllCanvas,n.enableCameraCanvas=enableCameraCanvas,n.enableGyroBanner=enableGyroBanner,n.enableMicBanner=enableMicBanner,n.enableSoundBanner=enableSoundBanner,n.enableSpeechBanner=enableSpeechBanner,n.enableVibrationBanner=enableVibrationBanner,n.enableAllBanner=enableAllBanner,n.enableCameraBanner=enableCameraBanner,n.enableGyroOn=enableGyroOn,n.enableMicOn=enableMicOn,n.enableSoundOn=enableSoundOn,n.enableSpeechOn=enableSpeechOn,n.enableVibrationOn=enableVibrationOn,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")});
@@ -99,18 +99,18 @@ function draw()
99
99
  }
100
100
 
101
101
  // ==============================================
102
- // TOUCH EVENT FUNCTIONS
102
+ // INPUT EVENT FUNCTIONS
103
103
  // ==============================================
104
104
 
105
105
  // This function runs when a new touch begins
106
- function touchStarted()
106
+ function mousePressed()
107
107
  {
108
108
  // Touch positions will be updated in draw() function
109
109
  return false;
110
110
  }
111
111
 
112
112
  // This function runs when a touch ends
113
- function touchEnded()
113
+ function mouseReleased()
114
114
  {
115
115
  // Touch positions will be updated in draw() function
116
116
  return false;
@@ -74,7 +74,7 @@ speechRec.interimResults = false; // Only final results
74
74
  speechRec.onResult = showResult;
75
75
 
76
76
  // Touch-to-talk pattern
77
- function touchStarted() {
77
+ function mousePressed() {
78
78
  if (speechRec && window.speechEnabled) {
79
79
  speechRec.start();
80
80
  }
@@ -71,7 +71,7 @@ function showResult() {
71
71
  }
72
72
 
73
73
  // Touch started - start listening
74
- function touchStarted() {
74
+ function mousePressed() {
75
75
  if (speechRec && window.speechEnabled && !isListening) {
76
76
  isListening = true;
77
77
  speechRec.start();
@@ -81,7 +81,7 @@ function touchStarted() {
81
81
  }
82
82
 
83
83
  // Touch ended - stop listening
84
- function touchEnded() {
84
+ function mouseReleased() {
85
85
  if (speechRec && isListening) {
86
86
  isListening = false;
87
87
  // Don't call stop - just let it process what was said
@@ -16,6 +16,7 @@
16
16
 
17
17
  <!-- Load p5.js library -->
18
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
19
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
19
20
 
20
21
  <!-- Load the mobile p5.js permissions library -->
21
22
  <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.6.4/dist/p5-phone.js"></script>
@@ -106,17 +106,17 @@ function draw()
106
106
  }
107
107
 
108
108
  // ==============================================
109
- // TOUCH EVENT FUNCTIONS
109
+ // INPUT EVENT FUNCTIONS
110
110
  // ==============================================
111
111
  // Note: Touch events are handled by enableGyroTap for permissions
112
112
 
113
- function touchStarted()
113
+ function mousePressed()
114
114
  {
115
115
  // Permission handling is done by enableGyroTap
116
116
  return false;
117
117
  }
118
118
 
119
- function touchEnded()
119
+ function mouseReleased()
120
120
  {
121
121
  return false;
122
122
  }
@@ -16,6 +16,7 @@
16
16
 
17
17
  <!-- Load p5.js library -->
18
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
19
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
19
20
 
20
21
  <!-- Load the mobile p5.js permissions library -->
21
22
  <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.6.4/dist/p5-phone.js"></script>
@@ -127,17 +127,17 @@ function draw()
127
127
  }
128
128
 
129
129
  // ==============================================
130
- // TOUCH EVENT FUNCTIONS
130
+ // INPUT EVENT FUNCTIONS
131
131
  // ==============================================
132
132
  // Note: Touch events are handled by enableGyroTap for permissions
133
133
 
134
- function touchStarted()
134
+ function mousePressed()
135
135
  {
136
136
  // Permission handling is done by enableGyroTap
137
137
  return false;
138
138
  }
139
139
 
140
- function touchEnded()
140
+ function mouseReleased()
141
141
  {
142
142
  return false;
143
143
  }
@@ -16,6 +16,7 @@
16
16
 
17
17
  <!-- Load p5.js library -->
18
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
19
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
19
20
 
20
21
  <!-- Load the mobile p5.js permissions library -->
21
22
  <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.6.4/dist/p5-phone.js"></script>
@@ -69,18 +69,18 @@ function draw()
69
69
  }
70
70
 
71
71
  // ==============================================
72
- // TOUCH EVENT FUNCTIONS
72
+ // INPUT EVENT FUNCTIONS
73
73
  // ==============================================
74
74
 
75
75
  // This function runs when a new touch begins
76
- function touchStarted()
76
+ function mousePressed()
77
77
  {
78
78
  // Touch positions will be updated in draw() function
79
79
  return false;
80
80
  }
81
81
 
82
82
  // This function runs when a touch ends
83
- function touchEnded()
83
+ function mouseReleased()
84
84
  {
85
85
  // Touch positions will be updated in draw() function
86
86
  return false;
@@ -16,6 +16,7 @@
16
16
 
17
17
  <!-- Load p5.js library -->
18
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
19
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
19
20
 
20
21
  <!-- Load p5.sound library for audio -->
21
22
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/addons/p5.sound.min.js"></script>
@@ -167,12 +167,12 @@ function drawVisualizers()
167
167
  }
168
168
 
169
169
  // ==============================================
170
- // TOUCH EVENT FUNCTIONS
170
+ // INPUT EVENT FUNCTIONS
171
171
  // ==============================================
172
172
 
173
- // touchStarted() runs when a touch begins
173
+ // mousePressed() runs when a touch begins
174
174
  // This function starts playing audio based on which zone is touched
175
- function touchStarted()
175
+ function mousePressed()
176
176
  {
177
177
  // Only process if sound system is enabled
178
178
  if (!window.soundEnabled)
@@ -207,9 +207,9 @@ function touchStarted()
207
207
  return false;
208
208
  }
209
209
 
210
- // touchEnded() runs when a touch is released
210
+ // mouseReleased() runs when a touch is released
211
211
  // This function stops the audio when touch is released
212
- function touchEnded()
212
+ function mouseReleased()
213
213
  {
214
214
  // Only process if sound system is enabled
215
215
  if (window.soundEnabled)
@@ -16,6 +16,7 @@
16
16
 
17
17
  <!-- Load p5.js library -->
18
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
19
+ <!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
19
20
 
20
21
  <!-- Load p5.sound library for audio -->
21
22
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/addons/p5.sound.min.js"></script>