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,210 @@
1
+ // Sound Visualizer
2
+ // Demonstrates microphone input for audio-reactive visuals
3
+
4
+ let mic;
5
+ let particles = [];
6
+ let levelHistory = [];
7
+ let maxHistoryLength = 100;
8
+
9
+ function setup() {
10
+ createCanvas(windowWidth, windowHeight);
11
+
12
+ // Create microphone input
13
+ mic = new p5.AudioIn();
14
+
15
+ // Initialize particles
16
+ for (let i = 0; i < 50; i++) {
17
+ particles.push(createParticle());
18
+ }
19
+
20
+ colorMode(HSB, 360, 100, 100, 1);
21
+ }
22
+
23
+ function draw() {
24
+ background(0, 0, 10, 0.1);
25
+
26
+ if (window.micEnabled) {
27
+ drawVisualizer();
28
+ } else {
29
+ showWaitingScreen();
30
+ }
31
+ }
32
+
33
+ function drawVisualizer() {
34
+ let level = mic.getLevel();
35
+
36
+ // Store level history for waveform
37
+ levelHistory.push(level);
38
+ if (levelHistory.length > maxHistoryLength) {
39
+ levelHistory.shift();
40
+ }
41
+
42
+ // Central circle that responds to audio
43
+ let centerSize = map(level, 0, 1, 50, 300);
44
+ let hue = (millis() * 0.1) % 360;
45
+
46
+ // Draw central responsive circle
47
+ push();
48
+ translate(width/2, height/2);
49
+
50
+ // Outer glow
51
+ for (let i = 0; i < 5; i++) {
52
+ let alpha = map(i, 0, 4, 0.3, 0.05);
53
+ fill(hue, 80, 100, alpha);
54
+ noStroke();
55
+ circle(0, 0, centerSize + i * 20);
56
+ }
57
+
58
+ // Core circle
59
+ fill(hue, 100, 100, 0.8);
60
+ circle(0, 0, centerSize);
61
+
62
+ // Inner details
63
+ fill(hue + 180, 80, 100, 0.5);
64
+ circle(0, 0, centerSize * 0.6);
65
+
66
+ pop();
67
+
68
+ // Update and draw particles
69
+ for (let particle of particles) {
70
+ updateParticle(particle, level);
71
+ drawParticle(particle);
72
+ }
73
+
74
+ // Draw waveform
75
+ drawWaveform();
76
+
77
+ // Draw level meter
78
+ drawLevelMeter(level);
79
+
80
+ // Instructions
81
+ fill(0, 0, 100, 0.7);
82
+ textAlign(CENTER, BOTTOM);
83
+ textSize(16);
84
+ text("Make some noise!", width/2, height - 20);
85
+ }
86
+
87
+ function createParticle() {
88
+ return {
89
+ x: random(width),
90
+ y: random(height),
91
+ vx: random(-2, 2),
92
+ vy: random(-2, 2),
93
+ size: random(5, 15),
94
+ hue: random(360),
95
+ life: 1.0
96
+ };
97
+ }
98
+
99
+ function updateParticle(particle, audioLevel) {
100
+ // Move particle
101
+ particle.x += particle.vx;
102
+ particle.y += particle.vy;
103
+
104
+ // Audio influence
105
+ let audioForce = audioLevel * 10;
106
+ let centerX = width / 2;
107
+ let centerY = height / 2;
108
+
109
+ // Pull towards center when loud
110
+ if (audioLevel > 0.1) {
111
+ let dx = centerX - particle.x;
112
+ let dy = centerY - particle.y;
113
+ let distance = sqrt(dx * dx + dy * dy);
114
+
115
+ if (distance > 0) {
116
+ particle.vx += (dx / distance) * audioForce * 0.02;
117
+ particle.vy += (dy / distance) * audioForce * 0.02;
118
+ }
119
+ }
120
+
121
+ // Bounce off edges
122
+ if (particle.x < 0 || particle.x > width) {
123
+ particle.vx *= -0.8;
124
+ particle.x = constrain(particle.x, 0, width);
125
+ }
126
+
127
+ if (particle.y < 0 || particle.y > height) {
128
+ particle.vy *= -0.8;
129
+ particle.y = constrain(particle.y, 0, height);
130
+ }
131
+
132
+ // Apply friction
133
+ particle.vx *= 0.98;
134
+ particle.vy *= 0.98;
135
+
136
+ // Update size based on audio
137
+ particle.targetSize = map(audioLevel, 0, 1, 5, 25);
138
+ particle.size = lerp(particle.size, particle.targetSize, 0.1);
139
+ }
140
+
141
+ function drawParticle(particle) {
142
+ push();
143
+ translate(particle.x, particle.y);
144
+
145
+ let alpha = map(particle.size, 5, 25, 0.3, 0.8);
146
+ fill(particle.hue, 80, 100, alpha);
147
+ noStroke();
148
+
149
+ circle(0, 0, particle.size);
150
+
151
+ // Inner highlight
152
+ fill(particle.hue, 40, 100, alpha * 0.5);
153
+ circle(0, 0, particle.size * 0.5);
154
+
155
+ pop();
156
+ }
157
+
158
+ function drawWaveform() {
159
+ if (levelHistory.length < 2) return;
160
+
161
+ stroke(0, 0, 100, 0.6);
162
+ strokeWeight(2);
163
+ noFill();
164
+
165
+ beginShape();
166
+ for (let i = 0; i < levelHistory.length; i++) {
167
+ let x = map(i, 0, levelHistory.length - 1, 0, width);
168
+ let y = map(levelHistory[i], 0, 1, height - 50, height - 150);
169
+ vertex(x, y);
170
+ }
171
+ endShape();
172
+ }
173
+
174
+ function drawLevelMeter(level) {
175
+ // Level meter on the side
176
+ let meterHeight = 200;
177
+ let meterWidth = 20;
178
+ let meterX = width - 40;
179
+ let meterY = height/2 - meterHeight/2;
180
+
181
+ // Background
182
+ fill(0, 0, 0, 0.3);
183
+ rect(meterX, meterY, meterWidth, meterHeight);
184
+
185
+ // Level bar
186
+ let levelHeight = map(level, 0, 1, 0, meterHeight);
187
+ let levelHue = map(level, 0, 1, 120, 0); // Green to red
188
+
189
+ fill(levelHue, 80, 100, 0.8);
190
+ rect(meterX, meterY + meterHeight - levelHeight, meterWidth, levelHeight);
191
+
192
+ // Level text
193
+ fill(0, 0, 100);
194
+ textAlign(CENTER, CENTER);
195
+ textSize(12);
196
+ text("MIC", meterX + meterWidth/2, meterY - 20);
197
+ }
198
+
199
+ function showWaitingScreen() {
200
+ fill(0, 0, 100, 0.7);
201
+ textAlign(CENTER, CENTER);
202
+ textSize(24);
203
+ text("Waiting for microphone...", width/2, height/2);
204
+ textSize(16);
205
+ text("Allow microphone access to continue", width/2, height/2 + 40);
206
+ }
207
+
208
+ function windowResized() {
209
+ resizeCanvas(windowWidth, windowHeight);
210
+ }
@@ -0,0 +1,25 @@
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, user-scalable=no">
6
+ <title>Slider vs Touch Angle - Mobile p5 Permissions</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ overflow: hidden;
12
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
13
+ }
14
+
15
+ canvas {
16
+ display: block;
17
+ }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/mobile-p5-permissions@1.4.4/dist/p5.mobile-permissions.min.js"></script>
23
+ <script src="sketch.js"></script>
24
+ </body>
25
+ </html>
@@ -0,0 +1,429 @@
1
+ // Slider vs Touch Angle Comparison
2
+ // Shows traditional float slider UI vs two-touch angle measurement
3
+
4
+ // Color scheme - using proper p5.js colors
5
+ let backgroundColor, sliderColor, touchColor;
6
+
7
+ // Slider properties
8
+ let sliderValue = 0.5; // Current slider value (0.0-1.0)
9
+ let sliderMin = 0.0;
10
+ let sliderMax = 1.0;
11
+ let sliderX, sliderY;
12
+ let sliderWidth = 300;
13
+ let sliderHeight = 40;
14
+ let isDraggingSlider = false;
15
+
16
+ // Touch angle measurement
17
+ let touchAngle = 0.0; // Angle in degrees
18
+ let normalizedAngle = 0.0; // Normalized to 0.0-1.0 (0-360 degrees)
19
+
20
+ // Layout properties
21
+ let topSectionHeight;
22
+ let bottomSectionHeight;
23
+ let dividerY;
24
+ let currentOrientation = 'portrait';
25
+
26
+ function setup() {
27
+ createCanvas(windowWidth, windowHeight);
28
+
29
+ // Initialize colors properly
30
+ backgroundColor = color(44, 62, 80); // Dark blue-gray
31
+ sliderColor = color(52, 152, 219); // Blue
32
+ touchColor = color(231, 76, 60); // Red
33
+
34
+ // Only call lockGestures if it exists
35
+ if (typeof lockGestures === 'function') {
36
+ lockGestures();
37
+ }
38
+
39
+ // Calculate layout
40
+ updateLayout();
41
+
42
+ textAlign(CENTER, CENTER);
43
+ noStroke();
44
+
45
+ console.log('Slider vs Angle ready!');
46
+ }
47
+
48
+ function draw() {
49
+ background(backgroundColor);
50
+
51
+ // Update orientation
52
+ currentOrientation = (width > height) ? 'landscape' : 'portrait';
53
+
54
+ // Calculate touch angle for bottom section
55
+ calculateTouchAngle();
56
+
57
+ // Draw divider line
58
+ stroke(255, 255, 255, 100);
59
+ strokeWeight(2);
60
+ line(0, dividerY, width, dividerY);
61
+ noStroke();
62
+
63
+ // Draw top section - Traditional Float Slider UI
64
+ drawTopSection();
65
+
66
+ // Draw bottom section - Touch Angle Interaction
67
+ drawBottomSection();
68
+ }
69
+
70
+ function drawTopSection() {
71
+ // Section title
72
+ fill(255, 255, 255);
73
+ textSize(24);
74
+ if (currentOrientation === 'landscape') {
75
+ textAlign(LEFT, CENTER);
76
+ text('TRADITIONAL UI', 30, 40);
77
+ } else {
78
+ textAlign(CENTER, CENTER);
79
+ text('TRADITIONAL UI', width / 2, 40);
80
+ }
81
+
82
+ // Draw slider
83
+ drawSlider();
84
+
85
+ // Draw value bar visualization
86
+ drawValueBar(sliderValue, topSectionHeight / 2 + 80, sliderColor);
87
+
88
+ // Draw slider value text
89
+ fill(255, 255, 255);
90
+ textSize(20);
91
+ let angleFromSlider = sliderValue * 360;
92
+ let valueText = 'Slider angle: ' + angleFromSlider.toFixed(0) + '°';
93
+ if (currentOrientation === 'landscape') {
94
+ textAlign(LEFT, CENTER);
95
+ text(valueText, 30, topSectionHeight - 40);
96
+ } else {
97
+ textAlign(CENTER, CENTER);
98
+ text(valueText, width / 2, topSectionHeight - 40);
99
+ }
100
+ }
101
+
102
+ function drawBottomSection() {
103
+ // Section title
104
+ fill(255, 255, 255);
105
+ textSize(24);
106
+ if (currentOrientation === 'landscape') {
107
+ textAlign(LEFT, CENTER);
108
+ text('MOBILE INTERACTION', 30, dividerY + 40);
109
+ } else {
110
+ textAlign(CENTER, CENTER);
111
+ text('MOBILE INTERACTION', width / 2, dividerY + 40);
112
+ }
113
+
114
+ // Instructions
115
+ fill(255, 255, 255, 200);
116
+ textSize(18);
117
+ let instructionText = getTouchInstructions();
118
+ if (currentOrientation === 'landscape') {
119
+ textAlign(LEFT, CENTER);
120
+ text(instructionText, 30, dividerY + 80);
121
+ } else {
122
+ textAlign(CENTER, CENTER);
123
+ text(instructionText, width / 2, dividerY + 80);
124
+ }
125
+
126
+ // Draw value bar for angle
127
+ drawValueBar(normalizedAngle, dividerY + (bottomSectionHeight / 2) + 40, touchColor);
128
+
129
+ // Draw touch angle visualization
130
+ drawTouchAngleVisualization();
131
+
132
+ // Draw angle value text
133
+ fill(255, 255, 255);
134
+ textSize(20);
135
+ let angleText = 'Touch angle: ' + touchAngle.toFixed(0) + '°';
136
+ if (currentOrientation === 'landscape') {
137
+ textAlign(LEFT, CENTER);
138
+ text(angleText, 30, height - 40);
139
+ } else {
140
+ textAlign(CENTER, CENTER);
141
+ text(angleText, width / 2, height - 40);
142
+ }
143
+ }
144
+
145
+ function getTouchInstructions() {
146
+ let bottomTouches = getBottomTouches();
147
+ if (bottomTouches.length === 0) {
148
+ return 'Place two fingers to measure angle!';
149
+ } else if (bottomTouches.length === 1) {
150
+ return 'Add a second finger!';
151
+ } else if (bottomTouches.length === 2) {
152
+ return 'Rotate fingers to change angle!';
153
+ } else {
154
+ return 'Too many fingers - use only 2!';
155
+ }
156
+ }
157
+
158
+ function drawSlider() {
159
+ // Position slider in center of top section
160
+ sliderY = topSectionHeight / 2 - sliderHeight / 2;
161
+
162
+ if (currentOrientation === 'landscape') {
163
+ sliderX = width / 2 - sliderWidth / 2 + 50; // Offset right to avoid left text
164
+ } else {
165
+ sliderX = width / 2 - sliderWidth / 2;
166
+ }
167
+
168
+ // Slider track (background)
169
+ fill(255, 255, 255, 100);
170
+ rect(sliderX, sliderY, sliderWidth, sliderHeight, sliderHeight / 2);
171
+
172
+ // Calculate slider handle position
173
+ let handleX = map(sliderValue, sliderMin, sliderMax, sliderX + 20, sliderX + sliderWidth - 20);
174
+
175
+ // Slider fill (shows progress)
176
+ fill(sliderColor);
177
+ rect(sliderX, sliderY, handleX - sliderX + 20, sliderHeight, sliderHeight / 2);
178
+
179
+ // Slider handle shadow
180
+ fill(0, 0, 0, 50);
181
+ circle(handleX + 2, sliderY + sliderHeight / 2 + 2, 35);
182
+
183
+ // Slider handle
184
+ fill(255, 255, 255);
185
+ if (isDraggingSlider) {
186
+ fill(255, 255, 0); // Yellow when dragging
187
+ }
188
+ circle(handleX, sliderY + sliderHeight / 2, 35);
189
+
190
+ // Handle indicator
191
+ fill(sliderColor);
192
+ circle(handleX, sliderY + sliderHeight / 2, 15);
193
+ }
194
+
195
+ function drawValueBar(value, yPos, barColor) {
196
+ // Draw a horizontal bar representing the value (0.0-1.0)
197
+ let barWidth = min(300, width - 120);
198
+ let barHeight = 30;
199
+ let barX = width / 2 - barWidth / 2;
200
+
201
+ if (currentOrientation === 'landscape') {
202
+ barX = width / 2 - barWidth / 2 + 25; // Slight offset for landscape
203
+ }
204
+
205
+ // Background bar
206
+ fill(255, 255, 255, 100);
207
+ rect(barX, yPos - barHeight / 2, barWidth, barHeight, barHeight / 2);
208
+
209
+ // Value fill
210
+ let fillWidth = value * barWidth;
211
+ fill(barColor);
212
+ rect(barX, yPos - barHeight / 2, fillWidth, barHeight, barHeight / 2);
213
+
214
+ // Value text on bar (showing degrees)
215
+ fill(255, 255, 255);
216
+ textAlign(CENTER, CENTER);
217
+ textSize(16);
218
+ text((value * 360).toFixed(0) + '°', barX + barWidth / 2, yPos);
219
+ }
220
+
221
+ function drawTouchAngleVisualization() {
222
+ let bottomTouches = getBottomTouches();
223
+
224
+ if (bottomTouches.length >= 2) {
225
+ // Draw angle visualization between first two touches
226
+ let touch1 = bottomTouches[0];
227
+ let touch2 = bottomTouches[1];
228
+
229
+ // Connection line
230
+ stroke(touchColor);
231
+ strokeWeight(3);
232
+ line(touch1.x, touch1.y, touch2.x, touch2.y);
233
+
234
+ // Calculate midpoint for angle arc
235
+ let midX = (touch1.x + touch2.x) / 2;
236
+ let midY = (touch1.y + touch2.y) / 2;
237
+
238
+ // Draw angle arc
239
+ stroke(255, 255, 0); // Yellow for angle indicator
240
+ strokeWeight(2);
241
+ noFill();
242
+ let arcRadius = 60;
243
+
244
+ // Calculate angle from horizontal (right direction = 0°)
245
+ let angleRad = atan2(touch2.y - touch1.y, touch2.x - touch1.x);
246
+
247
+ // Draw reference line (horizontal)
248
+ stroke(255, 255, 255, 100);
249
+ strokeWeight(1);
250
+ line(midX - 40, midY, midX + 40, midY);
251
+
252
+ // Draw angle arc from horizontal to the line
253
+ stroke(255, 255, 0);
254
+ strokeWeight(2);
255
+ if (angleRad >= 0) {
256
+ arc(midX, midY, arcRadius, arcRadius, 0, angleRad);
257
+ } else {
258
+ arc(midX, midY, arcRadius, arcRadius, angleRad, 0);
259
+ }
260
+
261
+ // Touch points
262
+ fill(touchColor);
263
+ noStroke();
264
+ circle(touch1.x, touch1.y, 40);
265
+ circle(touch2.x, touch2.y, 40);
266
+
267
+ // Touch numbers
268
+ fill(255, 255, 255);
269
+ textAlign(CENTER, CENTER);
270
+ textSize(18);
271
+ text('1', touch1.x, touch1.y);
272
+ text('2', touch2.x, touch2.y);
273
+
274
+ // Angle text near midpoint
275
+ fill(0, 0, 0, 150);
276
+ let angleText = Math.round(touchAngle) + '°';
277
+ textSize(14);
278
+ let textW = textWidth(angleText) + 10;
279
+ rect(midX - textW / 2, midY - 35, textW, 20, 5);
280
+
281
+ // Angle text
282
+ fill(255, 255, 0);
283
+ text(angleText, midX, midY - 25);
284
+
285
+ } else {
286
+ // Draw all touches in bottom section
287
+ for (let i = 0; i < bottomTouches.length; i++) {
288
+ let touch = bottomTouches[i];
289
+ fill(touchColor);
290
+ noStroke();
291
+ circle(touch.x, touch.y, 40);
292
+
293
+ fill(255, 255, 255);
294
+ textAlign(CENTER, CENTER);
295
+ textSize(18);
296
+ text(i + 1, touch.x, touch.y);
297
+ }
298
+ }
299
+ }
300
+
301
+ function getBottomTouches() {
302
+ let bottomTouches = [];
303
+ if (touches && touches.length > 0) {
304
+ for (let touch of touches) {
305
+ if (touch && typeof touch.x === 'number' && typeof touch.y === 'number' && touch.y > dividerY) {
306
+ bottomTouches.push(touch);
307
+ }
308
+ }
309
+ }
310
+ return bottomTouches;
311
+ }
312
+
313
+ function calculateTouchAngle() {
314
+ let bottomTouches = getBottomTouches();
315
+
316
+ if (bottomTouches.length >= 2) {
317
+ let touch1 = bottomTouches[0];
318
+ let touch2 = bottomTouches[1];
319
+
320
+ // Calculate angle in radians, then convert to degrees
321
+ let angleRad = atan2(touch2.y - touch1.y, touch2.x - touch1.x);
322
+ touchAngle = degrees(angleRad);
323
+
324
+ // Normalize to 0-360 degrees
325
+ if (touchAngle < 0) {
326
+ touchAngle += 360;
327
+ }
328
+
329
+ // Normalize to 0.0-1.0 range
330
+ normalizedAngle = touchAngle / 360.0;
331
+ } else {
332
+ touchAngle = 0.0;
333
+ normalizedAngle = 0.0;
334
+ }
335
+ }
336
+
337
+ function isSliderPressed(x, y) {
338
+ return x >= sliderX &&
339
+ x <= sliderX + sliderWidth &&
340
+ y >= sliderY - 20 &&
341
+ y <= sliderY + sliderHeight + 20 &&
342
+ y < dividerY;
343
+ }
344
+
345
+ function updateSliderValueFromTouch(x) {
346
+ let newValue = map(x, sliderX, sliderX + sliderWidth, sliderMin, sliderMax);
347
+ newValue = constrain(newValue, sliderMin, sliderMax);
348
+ sliderValue = newValue;
349
+
350
+ console.log('Slider angle:', (sliderValue * 360).toFixed(1) + '°');
351
+ }
352
+
353
+ // Handle touch interaction for mobile
354
+ function touchStarted() {
355
+ // Handle slider interaction only for touches in top section
356
+ if (touches && touches.length >= 1) {
357
+ for (let touch of touches) {
358
+ if (touch && touch.y < dividerY && isSliderPressed(touch.x, touch.y)) {
359
+ isDraggingSlider = true;
360
+ updateSliderValueFromTouch(touch.x);
361
+ break;
362
+ }
363
+ }
364
+ }
365
+ return false; // Always prevent default
366
+ }
367
+
368
+ function touchMoved() {
369
+ // Update slider if dragging and touch is in top section
370
+ if (isDraggingSlider && touches && touches.length >= 1) {
371
+ for (let touch of touches) {
372
+ if (touch && touch.y < dividerY) {
373
+ updateSliderValueFromTouch(touch.x);
374
+ break;
375
+ }
376
+ }
377
+ }
378
+ return false; // Always prevent default
379
+ }
380
+
381
+ function touchEnded() {
382
+ // Check if any touches remain in slider area
383
+ if (isDraggingSlider) {
384
+ let sliderTouchExists = false;
385
+ if (touches && touches.length > 0) {
386
+ for (let touch of touches) {
387
+ if (touch && touch.y < dividerY && isSliderPressed(touch.x, touch.y)) {
388
+ sliderTouchExists = true;
389
+ break;
390
+ }
391
+ }
392
+ }
393
+ if (!sliderTouchExists) {
394
+ isDraggingSlider = false;
395
+ }
396
+ }
397
+ return false; // Always prevent default
398
+ }
399
+
400
+ // Handle mouse interaction for desktop testing
401
+ function mousePressed() {
402
+ if (isSliderPressed(mouseX, mouseY)) {
403
+ isDraggingSlider = true;
404
+ updateSliderValueFromTouch(mouseX);
405
+ return false;
406
+ }
407
+ }
408
+
409
+ function mouseDragged() {
410
+ if (isDraggingSlider) {
411
+ updateSliderValueFromTouch(mouseX);
412
+ return false;
413
+ }
414
+ }
415
+
416
+ function mouseReleased() {
417
+ isDraggingSlider = false;
418
+ }
419
+
420
+ function updateLayout() {
421
+ topSectionHeight = height * 0.5;
422
+ bottomSectionHeight = height * 0.5;
423
+ dividerY = height * 0.5;
424
+ }
425
+
426
+ function windowResized() {
427
+ resizeCanvas(windowWidth, windowHeight);
428
+ updateLayout();
429
+ }
@@ -0,0 +1,25 @@
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, user-scalable=no">
6
+ <title>Slider vs Touch Distance - Mobile p5 Permissions</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ overflow: hidden;
12
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
13
+ }
14
+
15
+ canvas {
16
+ display: block;
17
+ }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/mobile-p5-permissions@1.4.4/dist/p5.mobile-permissions.min.js"></script>
23
+ <script src="sketch.js"></script>
24
+ </body>
25
+ </html>