p5-phone 1.4.4

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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +509 -0
  3. package/dist/p5-phone.js +1062 -0
  4. package/dist/p5-phone.min.js +10 -0
  5. package/examples/Phone Sensor Examples/microphone/01_mic_level/index.html +19 -0
  6. package/examples/Phone Sensor Examples/microphone/01_mic_level/sketch.js +117 -0
  7. package/examples/Phone Sensor Examples/movement/01_orientation_basic/index.html +28 -0
  8. package/examples/Phone Sensor Examples/movement/01_orientation_basic/sketch.js +123 -0
  9. package/examples/Phone Sensor Examples/movement/02_rotational_velocity/index.html +28 -0
  10. package/examples/Phone Sensor Examples/movement/02_rotational_velocity/sketch.js +144 -0
  11. package/examples/Phone Sensor Examples/movement/03_acceleration/index.html +28 -0
  12. package/examples/Phone Sensor Examples/movement/03_acceleration/sketch.js +87 -0
  13. package/examples/Phone Sensor Examples/sound/01_dual_audio/index.html +31 -0
  14. package/examples/Phone Sensor Examples/sound/01_dual_audio/sketch.js +225 -0
  15. package/examples/Phone Sensor Examples/sound/01_dual_audio/tracks/audio1.mp3 +0 -0
  16. package/examples/Phone Sensor Examples/sound/01_dual_audio/tracks/audio2.mp3 +0 -0
  17. package/examples/Phone Sensor Examples/sound/02_volume_touches/index.html +31 -0
  18. package/examples/Phone Sensor Examples/sound/02_volume_touches/sketch.js +269 -0
  19. package/examples/Phone Sensor Examples/sound/02_volume_touches/tracks/audio1.mp3 +0 -0
  20. package/examples/Phone Sensor Examples/touch/01_touch_basic/index.html +28 -0
  21. package/examples/Phone Sensor Examples/touch/01_touch_basic/sketch.js +94 -0
  22. package/examples/Phone Sensor Examples/touch/02_touch_zones/index.html +28 -0
  23. package/examples/Phone Sensor Examples/touch/02_touch_zones/sketch.js +220 -0
  24. package/examples/Phone Sensor Examples/touch/03_touch_count/index.html +28 -0
  25. package/examples/Phone Sensor Examples/touch/03_touch_count/sketch.js +93 -0
  26. package/examples/Phone Sensor Examples/touch/04_touch_distance/index.html +28 -0
  27. package/examples/Phone Sensor Examples/touch/04_touch_distance/sketch.js +120 -0
  28. package/examples/Phone Sensor Examples/touch/05_touch_angle/index.html +28 -0
  29. package/examples/Phone Sensor Examples/touch/05_touch_angle/sketch.js +117 -0
  30. package/examples/Phone Sensor Examples - Minimal/microphone/01_mic_level/index.html +19 -0
  31. package/examples/Phone Sensor Examples - Minimal/microphone/01_mic_level/sketch.js +72 -0
  32. package/examples/Phone Sensor Examples - Minimal/movement/01_orientation_basic/index.html +18 -0
  33. package/examples/Phone Sensor Examples - Minimal/movement/01_orientation_basic/sketch.js +51 -0
  34. package/examples/Phone Sensor Examples - Minimal/movement/02_rotational_velocity/index.html +18 -0
  35. package/examples/Phone Sensor Examples - Minimal/movement/02_rotational_velocity/sketch.js +70 -0
  36. package/examples/Phone Sensor Examples - Minimal/movement/03_acceleration/index.html +18 -0
  37. package/examples/Phone Sensor Examples - Minimal/movement/03_acceleration/sketch.js +83 -0
  38. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/index.html +19 -0
  39. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/sketch.js +96 -0
  40. package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/tracks/audio1.mp3 +0 -0
  41. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/index.html +19 -0
  42. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/sketch.js +118 -0
  43. package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/tracks/audio1.mp3 +0 -0
  44. package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/index.html +18 -0
  45. package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/sketch.js +58 -0
  46. package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/index.html +18 -0
  47. package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/sketch.js +78 -0
  48. package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/index.html +18 -0
  49. package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/sketch.js +64 -0
  50. package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/index.html +18 -0
  51. package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/sketch.js +69 -0
  52. package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/index.html +18 -0
  53. package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/sketch.js +85 -0
  54. package/examples/Phone and Gif/collision/README.md +31 -0
  55. Gif/collision/gifs/spaceSuit2.png +0 -0
  56. package/examples/Phone and Gif/collision/index.html +19 -0
  57. package/examples/Phone and Gif/collision/sketch.js +226 -0
  58. Gif/fetch/gifs/corgiswimflip.gif +0 -0
  59. package/examples/Phone and Gif/fetch/index.html +18 -0
  60. package/examples/Phone and Gif/fetch/sketch.js +139 -0
  61. Gif/fly/gifs/comparison.gif +0 -0
  62. package/examples/Phone and Gif/fly/index.html +18 -0
  63. package/examples/Phone and Gif/fly/sketch.js +103 -0
  64. Gif/roll/gifs/how-penciles-are-made.gif +0 -0
  65. package/examples/Phone and Gif/roll/index.html +18 -0
  66. package/examples/Phone and Gif/roll/sketch.js +121 -0
  67. package/examples/UXcompare/button-vs-movement/index.html +45 -0
  68. package/examples/UXcompare/button-vs-movement/sketch.js +355 -0
  69. package/examples/UXcompare/button-vs-orientation/index.html +25 -0
  70. package/examples/UXcompare/button-vs-orientation/sketch.js +317 -0
  71. package/examples/UXcompare/button-vs-shake/index.html +45 -0
  72. package/examples/UXcompare/button-vs-shake/sketch.js +320 -0
  73. package/examples/UXcompare/gyroscope-demo/index.html +78 -0
  74. package/examples/UXcompare/gyroscope-demo/sketch.js +166 -0
  75. package/examples/UXcompare/index.html +419 -0
  76. package/examples/UXcompare/microphone-demo/index.html +79 -0
  77. package/examples/UXcompare/microphone-demo/sketch.js +210 -0
  78. package/examples/UXcompare/slider-vs-angle/index.html +25 -0
  79. package/examples/UXcompare/slider-vs-angle/sketch.js +429 -0
  80. package/examples/UXcompare/slider-vs-distance/index.html +25 -0
  81. package/examples/UXcompare/slider-vs-distance/sketch.js +401 -0
  82. package/examples/UXcompare/slider-vs-microphone/index.html +26 -0
  83. package/examples/UXcompare/slider-vs-microphone/sketch.js +336 -0
  84. package/examples/UXcompare/slider-vs-touches/index.html +25 -0
  85. package/examples/UXcompare/slider-vs-touches/sketch.js +376 -0
  86. package/examples/UXcompare/sliders-vs-acceleration/index.html +25 -0
  87. package/examples/UXcompare/sliders-vs-acceleration/sketch.js +361 -0
  88. package/examples/UXcompare/sliders-vs-rotation/index.html +25 -0
  89. package/examples/UXcompare/sliders-vs-rotation/sketch.js +375 -0
  90. package/examples/blankTemplate/index.html +31 -0
  91. package/examples/blankTemplate/sketch.js +55 -0
  92. package/examples/homepage/index.html +506 -0
  93. package/package.json +73 -0
  94. package/src/p5-phone.js +1062 -0
  95. package/src/permissionMic.js +240 -0
  96. package/src/permissionsGesture.js +213 -0
  97. package/src/permissionsGyro.js +246 -0
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
6
+ <meta name="apple-mobile-web-app-capable" content="yes">
7
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
8
+ <title>Button vs Shake Comparison</title>
9
+
10
+ <style>
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ -webkit-user-select: none;
16
+ user-select: none;
17
+ -webkit-tap-highlight-color: transparent;
18
+ -webkit-touch-callout: none;
19
+ }
20
+
21
+ html, body {
22
+ width: 100%;
23
+ height: 100%;
24
+ overflow: hidden;
25
+ position: fixed;
26
+ touch-action: none;
27
+ background: #000;
28
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
29
+ }
30
+
31
+ canvas {
32
+ display: block;
33
+ position: fixed;
34
+ left: 0;
35
+ top: 0;
36
+ }
37
+ </style>
38
+
39
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
40
+ <script src="https://cdn.jsdelivr.net/npm/mobile-p5-permissions@1.4.4/dist/p5.mobile-permissions.min.js"></script>
41
+ </head>
42
+ <body>
43
+ <script src="sketch.js"></script>
44
+ </body>
45
+ </html>
@@ -0,0 +1,320 @@
1
+ // Button vs Shake Comparison
2
+ // Shows traditional button UI vs mobile device shake interaction
3
+
4
+ // Color states
5
+ let isBlueBackground = true; // true = blue, false = orange
6
+ let buttonColor1 = '#3498db'; // Blue
7
+ let buttonColor2 = '#e67e22'; // Orange
8
+
9
+ // Counters
10
+ let buttonClickCount = 0;
11
+ let shakeCount = 0;
12
+
13
+ // Button properties
14
+ let buttonWidth = 200;
15
+ let buttonHeight = 60;
16
+ let buttonX, buttonY;
17
+
18
+ // Slider properties
19
+ let sliderX, sliderY;
20
+ let sliderWidth = 200;
21
+ let sliderHeight = 20;
22
+ let sliderValue = 100; // Default shake threshold (higher = less sensitive)
23
+ let sliderMin = 30;
24
+ let sliderMax = 150;
25
+ let isDraggingSlider = false;
26
+
27
+ // Simple shake debounce
28
+ let lastShakeFrame = 0;
29
+
30
+ // Layout properties
31
+ let topSectionHeight;
32
+ let bottomSectionHeight;
33
+ let dividerY;
34
+
35
+ function setup() {
36
+ createCanvas(windowWidth, windowHeight);
37
+
38
+ // Enable gesture locking and motion sensors
39
+ lockGestures();
40
+ enableGyroTap('Tap to enable shake detection');
41
+
42
+ // Calculate layout for portrait orientation
43
+ topSectionHeight = height * 0.5;
44
+ bottomSectionHeight = height * 0.5;
45
+ dividerY = height * 0.5;
46
+
47
+ // Position button in top section
48
+ buttonX = width / 2 - buttonWidth / 2;
49
+ buttonY = topSectionHeight / 2 - buttonHeight / 2;
50
+
51
+ // Position slider in bottom section
52
+ sliderX = width / 2 - sliderWidth / 2;
53
+ sliderY = height - 120;
54
+
55
+ // Set initial shake threshold (higher value = less sensitive)
56
+ setShakeThreshold(sliderValue);
57
+
58
+ textAlign(CENTER, CENTER);
59
+ }
60
+
61
+ function draw() {
62
+ // Set background color based on current state
63
+ if (isBlueBackground) {
64
+ background(buttonColor1);
65
+ } else {
66
+ background(buttonColor2);
67
+ }
68
+
69
+ // Draw divider line
70
+ stroke(255, 255, 255, 100);
71
+ strokeWeight(2);
72
+ line(0, dividerY, width, dividerY);
73
+
74
+ // Draw top section - Traditional Button UI
75
+ drawTopSection();
76
+
77
+ // Draw bottom section - Shake Interaction
78
+ drawBottomSection();
79
+ }
80
+
81
+ function drawTopSection() {
82
+ // Section title
83
+ fill(255);
84
+ textSize(24);
85
+ text('TRADITIONAL UI', width / 2, 40);
86
+
87
+ // Draw button
88
+ drawButton();
89
+
90
+ // Draw counter
91
+ textSize(20);
92
+ text('Button pressed: ' + buttonClickCount + ' times', width / 2, buttonY + buttonHeight + 40);
93
+ }
94
+
95
+ function drawBottomSection() {
96
+ // Section title
97
+ fill(255);
98
+ textSize(24);
99
+ text('MOBILE INTERACTION', width / 2, dividerY + 40);
100
+
101
+ // Instructions or shake indicator
102
+ textSize(18);
103
+ if (window.sensorsEnabled) {
104
+ text('Shake your device!', width / 2, dividerY + 80);
105
+ } else {
106
+ text('Enable motion sensors first', width / 2, dividerY + 80);
107
+ }
108
+
109
+ // Draw shake visualization
110
+ if (window.sensorsEnabled) {
111
+ drawShakeIndicator();
112
+ }
113
+
114
+ // Draw shake threshold slider
115
+ drawSlider();
116
+
117
+ // Draw counter
118
+ textSize(20);
119
+ text('Device shaken: ' + shakeCount + ' times', width / 2, height - 30);
120
+ }
121
+
122
+ function drawButton() {
123
+ // Button shadow
124
+ fill(0, 0, 0, 50);
125
+ noStroke();
126
+ rect(buttonX + 3, buttonY + 3, buttonWidth, buttonHeight, 8);
127
+
128
+ // Button background
129
+ if (isBlueBackground) {
130
+ fill(255, 255, 255, 200);
131
+ } else {
132
+ fill(255, 255, 255, 200);
133
+ }
134
+
135
+ // Check if button is being pressed
136
+ if (isButtonPressed()) {
137
+ fill(255, 255, 255, 255); // Brighter when pressed
138
+ }
139
+
140
+ rect(buttonX, buttonY, buttonWidth, buttonHeight, 8);
141
+
142
+ // Button text
143
+ fill(0);
144
+ textSize(18);
145
+ text('TOGGLE COLOR', width / 2, buttonY + buttonHeight / 2);
146
+ }
147
+
148
+ function drawShakeIndicator() {
149
+ // Simple shake visualization - concentric circles
150
+ let centerX = width / 2;
151
+ let centerY = dividerY + (bottomSectionHeight / 2) - 20;
152
+
153
+ // Get motion intensity for visualization
154
+ let motionIntensity = 0;
155
+ if (typeof accelerationX !== 'undefined') {
156
+ motionIntensity = abs(accelerationX) + abs(accelerationY) + abs(accelerationZ);
157
+ motionIntensity = constrain(motionIntensity, 0, 10);
158
+ }
159
+
160
+ // Draw concentric circles that respond to motion
161
+ noFill();
162
+ stroke(255, 150);
163
+ strokeWeight(2);
164
+
165
+ for (let i = 1; i <= 3; i++) {
166
+ let radius = 30 + (i * 20) + (motionIntensity * 2);
167
+ circle(centerX, centerY, radius);
168
+ }
169
+
170
+ // Center dot
171
+ fill(255);
172
+ noStroke();
173
+ circle(centerX, centerY, 10);
174
+ }
175
+
176
+ function drawSlider() {
177
+ // Slider label
178
+ fill(255);
179
+ textSize(16);
180
+ text('Shake Sensitivity: ' + sliderValue, width / 2, sliderY - 25);
181
+
182
+ // Slider track (background)
183
+ fill(255, 255, 255, 100);
184
+ noStroke();
185
+ rect(sliderX, sliderY, sliderWidth, sliderHeight, sliderHeight / 2);
186
+
187
+ // Calculate slider handle position
188
+ let handleX = map(sliderValue, sliderMin, sliderMax, sliderX, sliderX + sliderWidth - 20);
189
+
190
+ // Slider handle
191
+ fill(255);
192
+ if (isDraggingSlider) {
193
+ fill(255, 255, 0); // Yellow when dragging
194
+ }
195
+
196
+ // Handle shadow
197
+ fill(0, 0, 0, 50);
198
+ circle(handleX + 12, sliderY + sliderHeight / 2 + 2, 24);
199
+
200
+ // Handle
201
+ if (isDraggingSlider) {
202
+ fill(255, 255, 0);
203
+ } else {
204
+ fill(255);
205
+ }
206
+ circle(handleX + 10, sliderY + sliderHeight / 2, 24);
207
+
208
+ // Handle indicator
209
+ fill(0);
210
+ circle(handleX + 10, sliderY + sliderHeight / 2, 8);
211
+ }
212
+
213
+ function isButtonPressed() {
214
+ return mouseIsPressed &&
215
+ mouseX >= buttonX &&
216
+ mouseX <= buttonX + buttonWidth &&
217
+ mouseY >= buttonY &&
218
+ mouseY <= buttonY + buttonHeight;
219
+ }
220
+
221
+ function isSliderPressed() {
222
+ let handleX = map(sliderValue, sliderMin, sliderMax, sliderX, sliderX + sliderWidth - 20);
223
+ return mouseX >= handleX &&
224
+ mouseX <= handleX + 20 &&
225
+ mouseY >= sliderY - 10 &&
226
+ mouseY <= sliderY + sliderHeight + 10;
227
+ }
228
+
229
+ // Handle button clicks
230
+ function mousePressed() {
231
+ // Check button press
232
+ if (mouseX >= buttonX &&
233
+ mouseX <= buttonX + buttonWidth &&
234
+ mouseY >= buttonY &&
235
+ mouseY <= buttonY + buttonHeight) {
236
+
237
+ // Toggle background color
238
+ isBlueBackground = !isBlueBackground;
239
+
240
+ // Increment counter
241
+ buttonClickCount++;
242
+
243
+ console.log('Button clicked! Count:', buttonClickCount);
244
+
245
+ return false; // Prevent default
246
+ }
247
+
248
+ // Check slider press
249
+ if (isSliderPressed()) {
250
+ isDraggingSlider = true;
251
+ updateSliderValue();
252
+ return false;
253
+ }
254
+ }
255
+
256
+ function mouseDragged() {
257
+ if (isDraggingSlider) {
258
+ updateSliderValue();
259
+ return false;
260
+ }
261
+ }
262
+
263
+ function mouseReleased() {
264
+ isDraggingSlider = false;
265
+ }
266
+
267
+ function updateSliderValue() {
268
+ // Calculate new slider value based on mouse position
269
+ let newValue = map(mouseX, sliderX, sliderX + sliderWidth, sliderMin, sliderMax);
270
+ newValue = constrain(newValue, sliderMin, sliderMax);
271
+ sliderValue = round(newValue);
272
+
273
+ // Update shake threshold
274
+ setShakeThreshold(sliderValue);
275
+
276
+ console.log('Shake threshold set to:', sliderValue);
277
+ }
278
+
279
+ // Handle device shake (built-in p5.js function)
280
+ function deviceShaken() {
281
+ // Only respond if motion sensors are enabled
282
+ if (window.sensorsEnabled) {
283
+ // Simple debounce - ignore if shake happened in last 10 frames (about 1/6 second)
284
+ if (frameCount - lastShakeFrame > 10) {
285
+ // Toggle background color
286
+ isBlueBackground = !isBlueBackground;
287
+
288
+ // Increment counter
289
+ shakeCount++;
290
+
291
+ // Update last shake frame
292
+ lastShakeFrame = frameCount;
293
+
294
+ console.log('Device shaken! Count:', shakeCount);
295
+ }
296
+ }
297
+ }
298
+
299
+ // Handle screen rotation
300
+ function windowResized() {
301
+ resizeCanvas(windowWidth, windowHeight);
302
+
303
+ // Recalculate layout
304
+ topSectionHeight = height * 0.5;
305
+ bottomSectionHeight = height * 0.5;
306
+ dividerY = height * 0.5;
307
+
308
+ // Reposition button
309
+ buttonX = width / 2 - buttonWidth / 2;
310
+ buttonY = topSectionHeight / 2 - buttonHeight / 2;
311
+
312
+ // Reposition slider
313
+ sliderX = width / 2 - sliderWidth / 2;
314
+ sliderY = height - 120;
315
+ }
316
+
317
+ // Called when permissions are ready
318
+ function userSetupComplete() {
319
+ console.log('Motion sensors enabled! You can now shake the device.');
320
+ }
@@ -0,0 +1,78 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
6
+ <meta name="apple-mobile-web-app-capable" content="yes">
7
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
8
+ <title>Tilt Ball Game</title>
9
+
10
+ <style>
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ -webkit-user-select: none;
16
+ user-select: none;
17
+ -webkit-tap-highlight-color: transparent;
18
+ -webkit-touch-callout: none;
19
+ }
20
+
21
+ html, body {
22
+ width: 100%;
23
+ height: 100%;
24
+ overflow: hidden;
25
+ position: fixed;
26
+ touch-action: none;
27
+ background: #000;
28
+ }
29
+
30
+ canvas {
31
+ display: block;
32
+ position: fixed;
33
+ left: 0;
34
+ top: 0;
35
+ }
36
+
37
+ #startButton {
38
+ position: fixed;
39
+ top: 50%;
40
+ left: 50%;
41
+ transform: translate(-50%, -50%);
42
+ padding: 40px 60px;
43
+ font-size: 24px;
44
+ font-weight: bold;
45
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
46
+ color: white;
47
+ border: none;
48
+ border-radius: 20px;
49
+ cursor: pointer;
50
+ z-index: 10000;
51
+ }
52
+
53
+ #statusText {
54
+ position: fixed;
55
+ top: 60%;
56
+ left: 50%;
57
+ transform: translate(-50%, 0);
58
+ color: white;
59
+ font-family: Arial, sans-serif;
60
+ text-align: center;
61
+ z-index: 9999;
62
+ }
63
+
64
+ .hidden {
65
+ display: none;
66
+ }
67
+ </style>
68
+
69
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
70
+ <script src="https://cdn.jsdelivr.net/npm/mobile-p5-permissions@1.4.4/dist/p5.mobile-permissions.min.js"></script>
71
+ </head>
72
+ <body>
73
+ <button id="startButton">START GAME</button>
74
+ <div id="statusText" class="hidden">Requesting motion sensors...</div>
75
+
76
+ <script src="sketch.js"></script>
77
+ </body>
78
+ </html>
@@ -0,0 +1,166 @@
1
+ // Tilt Ball Game
2
+ // Demonstrates gyroscope and accelerometer input
3
+
4
+ let ball;
5
+ let targets = [];
6
+ let score = 0;
7
+ let gameStarted = false;
8
+
9
+ function setup() {
10
+ createCanvas(windowWidth, windowHeight);
11
+
12
+ // Initialize ball
13
+ ball = {
14
+ x: width / 2,
15
+ y: height / 2,
16
+ vx: 0,
17
+ vy: 0,
18
+ size: 30
19
+ };
20
+
21
+ // Create initial targets
22
+ createTargets();
23
+ }
24
+
25
+ function draw() {
26
+ background(20, 30, 50);
27
+
28
+ if (window.sensorsEnabled) {
29
+ gameStarted = true;
30
+ updateGame();
31
+ } else {
32
+ showWaitingScreen();
33
+ }
34
+ }
35
+
36
+ function updateGame() {
37
+ // Apply tilt forces to ball
38
+ let tiltX = rotationY || 0;
39
+ let tiltY = rotationX || 0;
40
+
41
+ // Scale the tilt input
42
+ ball.vx += tiltX * 0.3;
43
+ ball.vy += tiltY * 0.3;
44
+
45
+ // Apply friction
46
+ ball.vx *= 0.95;
47
+ ball.vy *= 0.95;
48
+
49
+ // Update ball position
50
+ ball.x += ball.vx;
51
+ ball.y += ball.vy;
52
+
53
+ // Bounce off walls
54
+ if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
55
+ ball.vx *= -0.8;
56
+ ball.x = constrain(ball.x, ball.size/2, width - ball.size/2);
57
+ }
58
+
59
+ if (ball.y < ball.size/2 || ball.y > height - ball.size/2) {
60
+ ball.vy *= -0.8;
61
+ ball.y = constrain(ball.y, ball.size/2, height - ball.size/2);
62
+ }
63
+
64
+ // Draw targets
65
+ for (let i = targets.length - 1; i >= 0; i--) {
66
+ let target = targets[i];
67
+
68
+ // Animate target
69
+ target.pulse += 0.1;
70
+ let pulseSize = target.size + sin(target.pulse) * 5;
71
+
72
+ fill(target.color[0], target.color[1], target.color[2], 150);
73
+ circle(target.x, target.y, pulseSize);
74
+
75
+ // Check collision with ball
76
+ let distance = dist(ball.x, ball.y, target.x, target.y);
77
+ if (distance < (ball.size + target.size) / 2) {
78
+ // Target hit!
79
+ score++;
80
+ targets.splice(i, 1);
81
+
82
+ // Create new target
83
+ if (targets.length < 3) {
84
+ createTarget();
85
+ }
86
+ }
87
+ }
88
+
89
+ // Draw ball
90
+ fill(255, 200, 100);
91
+ stroke(255, 255, 150);
92
+ strokeWeight(2);
93
+ circle(ball.x, ball.y, ball.size);
94
+
95
+ // Draw trail
96
+ fill(255, 200, 100, 50);
97
+ noStroke();
98
+ circle(ball.x - ball.vx * 2, ball.y - ball.vy * 2, ball.size * 0.8);
99
+ circle(ball.x - ball.vx * 4, ball.y - ball.vy * 4, ball.size * 0.6);
100
+
101
+ // Draw UI
102
+ drawUI();
103
+ }
104
+
105
+ function createTargets() {
106
+ targets = [];
107
+ for (let i = 0; i < 3; i++) {
108
+ createTarget();
109
+ }
110
+ }
111
+
112
+ function createTarget() {
113
+ let target = {
114
+ x: random(50, width - 50),
115
+ y: random(50, height - 50),
116
+ size: random(40, 80),
117
+ color: [random(100, 255), random(100, 255), random(100, 255)],
118
+ pulse: random(TWO_PI)
119
+ };
120
+
121
+ // Make sure target isn't too close to ball
122
+ while (dist(target.x, target.y, ball.x, ball.y) < 100) {
123
+ target.x = random(50, width - 50);
124
+ target.y = random(50, height - 50);
125
+ }
126
+
127
+ targets.push(target);
128
+ }
129
+
130
+ function drawUI() {
131
+ // Score
132
+ fill(255);
133
+ textAlign(LEFT, TOP);
134
+ textSize(24);
135
+ text("Score: " + score, 20, 20);
136
+
137
+ // Instructions
138
+ textAlign(CENTER, BOTTOM);
139
+ textSize(14);
140
+ text("Tilt your device to move the ball", width/2, height - 20);
141
+
142
+ // Tilt indicator
143
+ if (window.sensorsEnabled) {
144
+ textAlign(RIGHT, TOP);
145
+ textSize(12);
146
+ text("Tilt X: " + (rotationY || 0).toFixed(1), width - 20, 20);
147
+ text("Tilt Y: " + (rotationX || 0).toFixed(1), width - 20, 40);
148
+ }
149
+ }
150
+
151
+ function showWaitingScreen() {
152
+ fill(255, 150);
153
+ textAlign(CENTER, CENTER);
154
+ textSize(24);
155
+ text("Waiting for motion sensors...", width/2, height/2);
156
+ textSize(16);
157
+ text("Make sure to allow permissions!", width/2, height/2 + 40);
158
+ }
159
+
160
+ function windowResized() {
161
+ resizeCanvas(windowWidth, windowHeight);
162
+
163
+ // Keep ball in bounds
164
+ ball.x = constrain(ball.x, ball.size/2, width - ball.size/2);
165
+ ball.y = constrain(ball.y, ball.size/2, height - ball.size/2);
166
+ }