p5-phone 1.7.0 → 1.9.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.
- package/README.md +133 -9
- package/dist/p5-phone.js +291 -18
- package/dist/p5-phone.min.js +1 -1
- package/examples/Phone Sensor Examples/microphone/01_mic_level/index.html +1 -1
- package/examples/Phone Sensor Examples/microphone/01_mic_level/sketch.js +3 -3
- package/examples/Phone Sensor Examples/microphone/02_speech_recognition/README.md +1 -1
- package/examples/Phone Sensor Examples/microphone/02_speech_recognition/index.html +1 -1
- package/examples/Phone Sensor Examples/microphone/02_speech_recognition/sketch.js +2 -2
- package/examples/Phone Sensor Examples/movement/01_orientation_basic/index.html +2 -1
- package/examples/Phone Sensor Examples/movement/01_orientation_basic/sketch.js +3 -3
- package/examples/Phone Sensor Examples/movement/02_rotational_velocity/index.html +2 -1
- package/examples/Phone Sensor Examples/movement/02_rotational_velocity/sketch.js +3 -3
- package/examples/Phone Sensor Examples/movement/03_acceleration/index.html +2 -1
- package/examples/Phone Sensor Examples/movement/03_acceleration/sketch.js +3 -3
- package/examples/Phone Sensor Examples/nfc/01_nfc_read/index.html +29 -0
- package/examples/Phone Sensor Examples/nfc/01_nfc_read/sketch.js +60 -0
- package/examples/Phone Sensor Examples/sound/01_dual_audio/index.html +2 -1
- package/examples/Phone Sensor Examples/sound/01_dual_audio/sketch.js +5 -5
- package/examples/Phone Sensor Examples/sound/02_volume_touches/index.html +2 -1
- package/examples/Phone Sensor Examples/sound/02_volume_touches/sketch.js +7 -7
- package/examples/Phone Sensor Examples/touch/01_touch_basic/index.html +2 -1
- package/examples/Phone Sensor Examples/touch/01_touch_basic/sketch.js +4 -4
- package/examples/Phone Sensor Examples/touch/02_touch_zones/index.html +2 -1
- package/examples/Phone Sensor Examples/touch/02_touch_zones/sketch.js +3 -3
- package/examples/Phone Sensor Examples/touch/03_touch_count/index.html +2 -1
- package/examples/Phone Sensor Examples/touch/03_touch_count/sketch.js +3 -3
- package/examples/Phone Sensor Examples/touch/04_touch_distance/index.html +2 -1
- package/examples/Phone Sensor Examples/touch/04_touch_distance/sketch.js +3 -3
- package/examples/Phone Sensor Examples/touch/05_touch_angle/index.html +2 -1
- package/examples/Phone Sensor Examples/touch/05_touch_angle/sketch.js +3 -3
- package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/index.html +2 -1
- package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/sketch.js +3 -3
- package/examples/Phone Sensor Examples - Minimal/microphone/01_mic_level/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/movement/01_orientation_basic/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/movement/02_rotational_velocity/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/movement/03_acceleration/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/sound/01_sound_basic/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/sound/02_sound_amplitude/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/sketch.js +2 -2
- package/examples/Phone Sensor Examples - Minimal/vibration/01_haptic_feedback/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/vibration/01_haptic_feedback/sketch.js +2 -2
- package/examples/Phone and Gif/collision/index.html +1 -1
- package/examples/Phone and Gif/collision/sketch.js +3 -3
- package/examples/Phone and Gif/fetch/index.html +1 -1
- package/examples/Phone and Gif/fetch/sketch.js +3 -3
- package/examples/Phone and Gif/fly/index.html +1 -1
- package/examples/Phone and Gif/roll/index.html +1 -1
- package/examples/Phone and Gif/roll/sketch.js +3 -3
- package/examples/UIStyles/banner-style/index.html +1 -0
- package/examples/UIStyles/canvas-style/index.html +1 -0
- package/examples/UIStyles/custom-element/index.html +1 -0
- package/examples/UXcompare/button-vs-movement/index.html +2 -1
- package/examples/UXcompare/button-vs-orientation/index.html +2 -1
- package/examples/UXcompare/button-vs-shake/index.html +2 -1
- package/examples/UXcompare/gyroscope-demo/index.html +2 -1
- package/examples/UXcompare/microphone-demo/index.html +2 -1
- package/examples/UXcompare/slider-vs-angle/index.html +2 -1
- package/examples/UXcompare/slider-vs-angle/sketch.js +3 -3
- package/examples/UXcompare/slider-vs-distance/index.html +2 -1
- package/examples/UXcompare/slider-vs-distance/sketch.js +3 -3
- package/examples/UXcompare/slider-vs-microphone/index.html +2 -1
- package/examples/UXcompare/slider-vs-microphone/sketch.js +3 -3
- package/examples/UXcompare/slider-vs-touches/index.html +2 -1
- package/examples/UXcompare/slider-vs-touches/sketch.js +3 -3
- package/examples/UXcompare/sliders-vs-acceleration/index.html +2 -1
- package/examples/UXcompare/sliders-vs-acceleration/sketch.js +3 -3
- package/examples/UXcompare/sliders-vs-rotation/index.html +2 -1
- package/examples/UXcompare/sliders-vs-rotation/sketch.js +3 -3
- package/examples/blankTemplate/index.html +2 -1
- package/examples/blankTemplate/sketch.js +2 -2
- package/examples/homepage/index.html +10 -9
- package/examples/ml5/Gaze_detector_class/index.html +2 -1
- package/examples/ml5/PHONE_BodyPose_two_points/index.html +2 -1
- package/examples/ml5/PHONE_FaceMesh_two_points/index.html +2 -1
- package/examples/ml5/PHONE_HandPose_two_points/index.html +2 -1
- package/package.json +1 -1
- package/src/p5-phone.js +291 -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
|
-
- [`
|
|
22
|
-
- [`
|
|
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,32 @@ 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
|
+
| NFC Tag Reading (Android only) | ✅ | ✅ |
|
|
62
|
+
| Debug console | ✅ | ✅ |
|
|
63
|
+
| lockGestures() | ✅ | ✅ |
|
|
64
|
+
| `touchStarted()` / `touchEnded()` | ✅ | ❌ Use `mousePressed()` / `mouseReleased()` |
|
|
65
|
+
| `p5.registerAddon()` | ❌ | ✅ (auto-detected) |
|
|
66
|
+
|
|
67
|
+
**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.
|
|
68
|
+
|
|
69
|
+
p5-phone automatically detects the p5.js version and adjusts its internal touch override behavior accordingly. No configuration needed.
|
|
70
|
+
|
|
48
71
|
## Table of Contents
|
|
49
72
|
|
|
50
73
|
- [Link for Interactive Examples](#link-for-interactive-examples)
|
|
51
74
|
- [Browser Compatibility](#browser-compatibility)
|
|
75
|
+
- [p5.js Version Compatibility](#p5js-version-compatibility)
|
|
52
76
|
- [CDN (Recommended)](#cdn-recommended)
|
|
53
77
|
- [Basic Setup](#basic-setup)
|
|
54
78
|
- [Index HTML](#index-html)
|
|
@@ -63,6 +87,7 @@ This library simplifies access to the following p5.js mobile sensor and audio co
|
|
|
63
87
|
- [Speech Recognition Activation](#speech-recognition-activation)
|
|
64
88
|
- [Combined Activation](#combined-activation)
|
|
65
89
|
- [Vibration Motor (Android Only)](#vibration-motor-android-only)
|
|
90
|
+
- [NFC Tag Reading (Android Only)](#nfc-tag-reading-android-only)
|
|
66
91
|
- [PhoneCamera (ML5 Integration)](#phonecamera-ml5-integration)
|
|
67
92
|
- [Debug System](#debug-system)
|
|
68
93
|
- [Permission UI Styles](#permission-ui-styles)
|
|
@@ -77,10 +102,10 @@ This library simplifies access to the following p5.js mobile sensor and audio co
|
|
|
77
102
|
|
|
78
103
|
```html
|
|
79
104
|
<!-- Minified version (recommended) -->
|
|
80
|
-
<script src="https://cdn.jsdelivr.net/npm/p5-phone@1.
|
|
105
|
+
<script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.0/dist/p5-phone.min.js"></script>
|
|
81
106
|
|
|
82
107
|
<!-- Development version (larger, with comments) -->
|
|
83
|
-
<!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.
|
|
108
|
+
<!-- <script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.0/dist/p5-phone.js"></script> -->
|
|
84
109
|
```
|
|
85
110
|
|
|
86
111
|
### Basic Setup
|
|
@@ -106,9 +131,10 @@ This library simplifies access to the following p5.js mobile sensor and audio co
|
|
|
106
131
|
|
|
107
132
|
<!-- Load p5.js library -->
|
|
108
133
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.10/p5.min.js"></script>
|
|
134
|
+
<!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
|
|
109
135
|
|
|
110
136
|
<!-- Load p5-phone library -->
|
|
111
|
-
<script src="https://cdn.jsdelivr.net/npm/p5-phone@1.
|
|
137
|
+
<script src="https://cdn.jsdelivr.net/npm/p5-phone@1.9.0/dist/p5-phone.min.js"></script>
|
|
112
138
|
|
|
113
139
|
</head>
|
|
114
140
|
<body>
|
|
@@ -173,11 +199,12 @@ function draw() {
|
|
|
173
199
|
}
|
|
174
200
|
|
|
175
201
|
// Prevent default touch behavior (optional but recommended)
|
|
176
|
-
|
|
202
|
+
// Use mousePressed/mouseReleased — works in both p5.js 1.x and 2.0
|
|
203
|
+
function mousePressed() {
|
|
177
204
|
return false;
|
|
178
205
|
}
|
|
179
206
|
|
|
180
|
-
function
|
|
207
|
+
function mouseReleased() {
|
|
181
208
|
return false;
|
|
182
209
|
}
|
|
183
210
|
```
|
|
@@ -277,6 +304,7 @@ this.enableGyroTap('Tap to start');
|
|
|
277
304
|
- `window.soundEnabled` - Boolean indicating if sound output is active
|
|
278
305
|
- `window.speechEnabled` - Boolean indicating if speech recognition is active
|
|
279
306
|
- `window.vibrationEnabled` - Boolean indicating if vibration is available (Android only)
|
|
307
|
+
- `window.nfcEnabled` - Boolean indicating if NFC scanning is active (Android only)
|
|
280
308
|
|
|
281
309
|
**Usage:**
|
|
282
310
|
```javascript
|
|
@@ -301,6 +329,11 @@ function draw() {
|
|
|
301
329
|
// Safe to use vibration (Android only)
|
|
302
330
|
vibrate(50);
|
|
303
331
|
}
|
|
332
|
+
|
|
333
|
+
if (window.nfcEnabled) {
|
|
334
|
+
// NFC scanning is active (Android only)
|
|
335
|
+
// Tag data arrives via nfcRead() callback
|
|
336
|
+
}
|
|
304
337
|
}
|
|
305
338
|
|
|
306
339
|
// You can also use them for conditional UI
|
|
@@ -580,7 +613,7 @@ function mousePressed() {
|
|
|
580
613
|
}
|
|
581
614
|
|
|
582
615
|
// Touch zones with different haptic patterns
|
|
583
|
-
function
|
|
616
|
+
function mousePressed() {
|
|
584
617
|
if (window.vibrationEnabled) {
|
|
585
618
|
if (mouseX < width/2) {
|
|
586
619
|
vibrate(50); // Left side - short pulse
|
|
@@ -613,6 +646,94 @@ function gameOver() {
|
|
|
613
646
|
- Don't overuse - vibration can quickly drain battery
|
|
614
647
|
- Test on Android devices as iOS doesn't support vibration
|
|
615
648
|
|
|
649
|
+
### NFC Tag Reading (Android Only)
|
|
650
|
+
|
|
651
|
+
**Purpose:** Read NFC (Near Field Communication) tags using the Web NFC API. Ideal for interactive installations, scavenger hunts, or any sketch that responds to physical NFC tags.
|
|
652
|
+
|
|
653
|
+
**⚠️ Platform Support:**
|
|
654
|
+
- ✅ **Android** - Chrome 89+ and Samsung Internet 15+
|
|
655
|
+
- ❌ **iOS** - Not supported (Web NFC API not available on iOS)
|
|
656
|
+
- Requires **HTTPS** — NFC is blocked on insecure origins
|
|
657
|
+
|
|
658
|
+
**Important:** The Web NFC API requires user activation (a tap or click) before scanning can begin — the same pattern used by all other p5-phone permission functions. On unsupported devices/browsers, `window.nfcEnabled` will be `false` and calls will be safely ignored with console warnings.
|
|
659
|
+
|
|
660
|
+
**Commands:**
|
|
661
|
+
- `enableNfcTap(message)` - Tap anywhere on screen to enable NFC scanning
|
|
662
|
+
- `enableNfcButton(text)` - Creates a button with custom text to enable NFC
|
|
663
|
+
- `stopNfc()` - Stop NFC scanning
|
|
664
|
+
|
|
665
|
+
**Status Variables:**
|
|
666
|
+
- `window.nfcEnabled` - Boolean indicating if NFC scanning is active
|
|
667
|
+
- `window.lastNfcMessage` - Object containing the most recently read tag's data
|
|
668
|
+
- `window.lastNfcSerialNumber` - Serial number string of the most recently read tag
|
|
669
|
+
|
|
670
|
+
**User Callback:**
|
|
671
|
+
|
|
672
|
+
Define an `nfcRead()` function in your sketch to receive tag data when a tag is scanned:
|
|
673
|
+
|
|
674
|
+
```javascript
|
|
675
|
+
function nfcRead(message, serialNumber) {
|
|
676
|
+
// message.serialNumber — tag serial number
|
|
677
|
+
// message.records — array of NDEF records, each with:
|
|
678
|
+
// .recordType — 'text', 'url', 'mime', etc.
|
|
679
|
+
// .data — decoded content (string for text/url, object for JSON, raw for others)
|
|
680
|
+
// .mediaType — MIME type (for 'mime' records)
|
|
681
|
+
// .id — record id (if present)
|
|
682
|
+
// .raw — original DataView
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
**Usage:**
|
|
687
|
+
```javascript
|
|
688
|
+
let tagText = 'No tag scanned yet';
|
|
689
|
+
|
|
690
|
+
function setup() {
|
|
691
|
+
createCanvas(windowWidth, windowHeight);
|
|
692
|
+
lockGestures();
|
|
693
|
+
enableNfcTap('Tap to enable NFC');
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function draw() {
|
|
697
|
+
background(220);
|
|
698
|
+
textAlign(CENTER, CENTER);
|
|
699
|
+
textSize(20);
|
|
700
|
+
|
|
701
|
+
if (!window.nfcEnabled) {
|
|
702
|
+
text('NFC not active', width / 2, height / 2);
|
|
703
|
+
} else {
|
|
704
|
+
text(tagText, width / 2, height / 2);
|
|
705
|
+
text('Hold an NFC tag near your phone', width / 2, height / 2 + 40);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function nfcRead(message, serialNumber) {
|
|
710
|
+
tagText = 'Tag: ' + serialNumber;
|
|
711
|
+
for (let record of message.records) {
|
|
712
|
+
if (record.recordType === 'text' || record.recordType === 'url') {
|
|
713
|
+
tagText += '\n' + record.data;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
**Record Types:**
|
|
720
|
+
|
|
721
|
+
NFC tags contain NDEF records. The most common types are:
|
|
722
|
+
|
|
723
|
+
| Record Type | `record.data` Contains | Example |
|
|
724
|
+
|-------------|----------------------|----------|
|
|
725
|
+
| `text` | Decoded string | `"Hello World"` |
|
|
726
|
+
| `url` | Decoded URL string | `"https://example.com"` |
|
|
727
|
+
| `mime` | Decoded string or parsed JSON | `{ id: 42 }` |
|
|
728
|
+
| other | Raw `DataView` | Binary data |
|
|
729
|
+
|
|
730
|
+
**Best Practices:**
|
|
731
|
+
- Always check `window.nfcEnabled` before relying on NFC features
|
|
732
|
+
- Use the `nfcRead()` callback for real-time tag processing
|
|
733
|
+
- Use `window.lastNfcMessage` in `draw()` for displaying the most recent tag
|
|
734
|
+
- Test on Android devices with Chrome — NFC is not available on iOS or desktop browsers
|
|
735
|
+
- Tags must be NDEF-formatted to be read by the Web NFC API
|
|
736
|
+
|
|
616
737
|
### Speech Recognition Activation
|
|
617
738
|
|
|
618
739
|
**Purpose:** Enable the Web Speech API for voice input and speech-to-text in mobile browsers.
|
|
@@ -899,6 +1020,7 @@ The canvas displays a centered message until the user taps. Great for "full-scre
|
|
|
899
1020
|
- `enableSensorCanvas(message)`
|
|
900
1021
|
- `enableMicCanvas(message)`
|
|
901
1022
|
- `enableSpeechCanvas(message)`
|
|
1023
|
+
- `enableNfcCanvas(message)`
|
|
902
1024
|
- `enableAllCanvas(message)`
|
|
903
1025
|
- `enableCameraCanvas(message)`
|
|
904
1026
|
|
|
@@ -925,6 +1047,7 @@ A styled banner slides in from the top of the screen with an animated entrance.
|
|
|
925
1047
|
- `enableSensorBanner(message)`
|
|
926
1048
|
- `enableMicBanner(message)`
|
|
927
1049
|
- `enableSpeechBanner(message)`
|
|
1050
|
+
- `enableNfcBanner(message)`
|
|
928
1051
|
- `enableAllBanner(message)`
|
|
929
1052
|
- `enableCameraBanner(message)`
|
|
930
1053
|
|
|
@@ -952,6 +1075,7 @@ Bind the permission activation to any existing HTML element on the page using a
|
|
|
952
1075
|
- `enableSensorOn(selector)`
|
|
953
1076
|
- `enableMicOn(selector)`
|
|
954
1077
|
- `enableSpeechOn(selector)`
|
|
1078
|
+
- `enableNfcOn(selector)`
|
|
955
1079
|
- `enableAllOn(selector)`
|
|
956
1080
|
- `enableCameraOn(selector)`
|
|
957
1081
|
|
package/dist/p5-phone.js
CHANGED
|
@@ -87,9 +87,20 @@ window.soundEnabled = false;
|
|
|
87
87
|
window.gesturesLocked = false;
|
|
88
88
|
window.vibrationEnabled = false;
|
|
89
89
|
window.speechEnabled = false;
|
|
90
|
+
window.nfcEnabled = false;
|
|
91
|
+
window.lastNfcMessage = null;
|
|
92
|
+
window.lastNfcSerialNumber = null;
|
|
90
93
|
|
|
91
94
|
// Internal state
|
|
92
95
|
let _micInstance = null;
|
|
96
|
+
let _nfcReader = null;
|
|
97
|
+
let _nfcAbortController = null;
|
|
98
|
+
|
|
99
|
+
// p5.js version detection (1.x vs 2.x)
|
|
100
|
+
const _p5MajorVersion = (typeof p5 !== 'undefined' && p5.VERSION)
|
|
101
|
+
? parseInt(p5.VERSION.split('.')[0], 10)
|
|
102
|
+
: 1; // Default to 1 if p5 not loaded yet
|
|
103
|
+
const _isP5v2 = _p5MajorVersion >= 2;
|
|
93
104
|
|
|
94
105
|
// =========================================
|
|
95
106
|
// PUBLIC API - CALL THESE FROM YOUR P5 SKETCH
|
|
@@ -229,6 +240,30 @@ function enableVibrationTap(message = 'Tap screen to enable vibration') {
|
|
|
229
240
|
});
|
|
230
241
|
}
|
|
231
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Enable NFC tag reading with a button interface
|
|
245
|
+
* Creates a start button that user must click
|
|
246
|
+
* Note: Web NFC is supported on Android Chrome 89+ only, not iOS
|
|
247
|
+
*/
|
|
248
|
+
function enableNfcButton(buttonText = 'ENABLE NFC', statusText = 'Enabling NFC...') {
|
|
249
|
+
_createPermissionButton(buttonText, statusText, async () => {
|
|
250
|
+
await _requestNfcPermission();
|
|
251
|
+
console.log('✅ NFC enabled via button');
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Enable NFC tag reading with tap-to-start
|
|
257
|
+
* User taps anywhere on screen to enable
|
|
258
|
+
* Note: Web NFC is supported on Android Chrome 89+ only, not iOS
|
|
259
|
+
*/
|
|
260
|
+
function enableNfcTap(message = 'Tap screen to enable NFC') {
|
|
261
|
+
_createTapToEnable(message, async () => {
|
|
262
|
+
await _requestNfcPermission();
|
|
263
|
+
console.log('✅ NFC enabled via tap');
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
232
267
|
/**
|
|
233
268
|
* Enable both motion sensors and microphone with a button interface
|
|
234
269
|
* Creates a start button that user must click to enable both
|
|
@@ -312,6 +347,16 @@ function enableVibrationCanvas(message = 'Touch to start') {
|
|
|
312
347
|
});
|
|
313
348
|
}
|
|
314
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Enable NFC on first canvas touch
|
|
352
|
+
*/
|
|
353
|
+
function enableNfcCanvas(message = 'Touch to start') {
|
|
354
|
+
_createCanvasToEnable(message, async () => {
|
|
355
|
+
await _requestNfcPermission();
|
|
356
|
+
console.log('✅ NFC enabled via canvas touch');
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
315
360
|
/**
|
|
316
361
|
* Enable both motion sensors and microphone on first canvas touch
|
|
317
362
|
*/
|
|
@@ -379,6 +424,13 @@ function enableVibrationBanner(message = 'Tap to enable vibration', position = '
|
|
|
379
424
|
});
|
|
380
425
|
}
|
|
381
426
|
|
|
427
|
+
function enableNfcBanner(message = 'Tap to enable NFC', position = 'top') {
|
|
428
|
+
_createBannerToEnable(message, position, async () => {
|
|
429
|
+
await _requestNfcPermission();
|
|
430
|
+
console.log('✅ NFC enabled via banner');
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
382
434
|
function enableAllBanner(message = 'Tap to enable sensors & microphone', position = 'top') {
|
|
383
435
|
_createBannerToEnable(message, position, async () => {
|
|
384
436
|
await _requestMotionPermissionsCore();
|
|
@@ -439,6 +491,13 @@ function enableVibrationOn(selector) {
|
|
|
439
491
|
});
|
|
440
492
|
}
|
|
441
493
|
|
|
494
|
+
function enableNfcOn(selector) {
|
|
495
|
+
_bindPermissionTo(selector, async () => {
|
|
496
|
+
await _requestNfcPermission();
|
|
497
|
+
console.log('✅ NFC enabled via custom element');
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
442
501
|
function enableAllOn(selector) {
|
|
443
502
|
_bindPermissionTo(selector, async () => {
|
|
444
503
|
await _requestMotionPermissionsCore();
|
|
@@ -488,6 +547,19 @@ function stopVibration() {
|
|
|
488
547
|
}
|
|
489
548
|
}
|
|
490
549
|
|
|
550
|
+
/**
|
|
551
|
+
* Stop NFC scanning
|
|
552
|
+
*/
|
|
553
|
+
function stopNfc() {
|
|
554
|
+
if (_nfcAbortController) {
|
|
555
|
+
_nfcAbortController.abort();
|
|
556
|
+
_nfcAbortController = null;
|
|
557
|
+
}
|
|
558
|
+
_nfcReader = null;
|
|
559
|
+
window.nfcEnabled = false;
|
|
560
|
+
console.log('NFC scanning stopped');
|
|
561
|
+
}
|
|
562
|
+
|
|
491
563
|
// =========================================
|
|
492
564
|
// INTERNAL PERMISSION HANDLERS
|
|
493
565
|
// =========================================
|
|
@@ -613,6 +685,102 @@ async function _requestVibrationPermissionCore() {
|
|
|
613
685
|
}
|
|
614
686
|
}
|
|
615
687
|
|
|
688
|
+
async function _requestNfcPermissionCore() {
|
|
689
|
+
try {
|
|
690
|
+
// Check if Web NFC API is supported
|
|
691
|
+
if (!('NDEFReader' in window)) {
|
|
692
|
+
console.warn('⚠️ Web NFC API not supported on this device/browser (Android Chrome 89+ required)');
|
|
693
|
+
if (_debugVisible) {
|
|
694
|
+
debugWarn('Web NFC not supported on this device/browser');
|
|
695
|
+
}
|
|
696
|
+
window.nfcEnabled = false;
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
_nfcAbortController = new AbortController();
|
|
701
|
+
_nfcReader = new NDEFReader();
|
|
702
|
+
|
|
703
|
+
_nfcReader.onreading = (event) => {
|
|
704
|
+
const serialNumber = event.serialNumber || '';
|
|
705
|
+
const decoder = new TextDecoder();
|
|
706
|
+
const records = [];
|
|
707
|
+
|
|
708
|
+
for (const record of event.message.records) {
|
|
709
|
+
const entry = {
|
|
710
|
+
recordType: record.recordType,
|
|
711
|
+
mediaType: record.mediaType || null,
|
|
712
|
+
id: record.id || null,
|
|
713
|
+
data: null,
|
|
714
|
+
raw: record.data
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
if (record.recordType === 'text' || record.recordType === 'url') {
|
|
718
|
+
entry.data = decoder.decode(record.data);
|
|
719
|
+
} else if (record.recordType === 'mime' && record.mediaType) {
|
|
720
|
+
try {
|
|
721
|
+
const text = decoder.decode(record.data);
|
|
722
|
+
if (record.mediaType.includes('json')) {
|
|
723
|
+
entry.data = JSON.parse(text);
|
|
724
|
+
} else {
|
|
725
|
+
entry.data = text;
|
|
726
|
+
}
|
|
727
|
+
} catch (e) {
|
|
728
|
+
entry.data = record.data;
|
|
729
|
+
}
|
|
730
|
+
} else {
|
|
731
|
+
entry.data = record.data;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
records.push(entry);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const message = { serialNumber: serialNumber, records: records };
|
|
738
|
+
window.lastNfcMessage = message;
|
|
739
|
+
window.lastNfcSerialNumber = serialNumber;
|
|
740
|
+
|
|
741
|
+
// Call user-defined callback if it exists
|
|
742
|
+
if (typeof nfcRead === 'function') {
|
|
743
|
+
nfcRead(message, serialNumber);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
console.log('NFC tag read — serial:', serialNumber, 'records:', records.length);
|
|
747
|
+
if (_debugVisible) {
|
|
748
|
+
debug('NFC tag read: ' + serialNumber);
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
_nfcReader.onreadingerror = (event) => {
|
|
753
|
+
console.warn('⚠️ NFC read error — tag may be incompatible or out of range');
|
|
754
|
+
if (_debugVisible) {
|
|
755
|
+
debugWarn('NFC read error — tag incompatible or out of range');
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
await _nfcReader.scan({ signal: _nfcAbortController.signal });
|
|
760
|
+
window.nfcEnabled = true;
|
|
761
|
+
console.log('✅ NFC scanning active');
|
|
762
|
+
|
|
763
|
+
} catch (error) {
|
|
764
|
+
if (error.name === 'NotAllowedError') {
|
|
765
|
+
console.warn('⚠️ NFC permission denied by user');
|
|
766
|
+
if (_debugVisible) {
|
|
767
|
+
debugWarn('NFC permission denied');
|
|
768
|
+
}
|
|
769
|
+
} else if (error.name === 'NotSupportedError') {
|
|
770
|
+
console.warn('⚠️ NFC not supported on this device');
|
|
771
|
+
if (_debugVisible) {
|
|
772
|
+
debugWarn('NFC not supported on this device');
|
|
773
|
+
}
|
|
774
|
+
} else {
|
|
775
|
+
console.error('NFC permission error:', error);
|
|
776
|
+
if (_debugVisible) {
|
|
777
|
+
debugError('NFC error: ' + error.message);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
window.nfcEnabled = false;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
616
784
|
// Wrapped versions that notify the sketch (used by single-permission functions)
|
|
617
785
|
async function _requestMotionPermissions() {
|
|
618
786
|
await _requestMotionPermissionsCore();
|
|
@@ -639,6 +807,11 @@ async function _requestVibrationPermission() {
|
|
|
639
807
|
_notifySketchReady();
|
|
640
808
|
}
|
|
641
809
|
|
|
810
|
+
async function _requestNfcPermission() {
|
|
811
|
+
await _requestNfcPermissionCore();
|
|
812
|
+
_notifySketchReady();
|
|
813
|
+
}
|
|
814
|
+
|
|
642
815
|
function _notifySketchReady() {
|
|
643
816
|
// Call userSetupComplete if it exists
|
|
644
817
|
if (typeof userSetupComplete === 'function') {
|
|
@@ -653,6 +826,7 @@ function _notifySketchReady() {
|
|
|
653
826
|
sound: window.soundEnabled,
|
|
654
827
|
speech: window.speechEnabled,
|
|
655
828
|
vibration: window.vibrationEnabled,
|
|
829
|
+
nfc: window.nfcEnabled,
|
|
656
830
|
gestures: window.gesturesLocked
|
|
657
831
|
}
|
|
658
832
|
}));
|
|
@@ -1141,29 +1315,37 @@ function _initializeP5TouchOverrides() {
|
|
|
1141
1315
|
}
|
|
1142
1316
|
|
|
1143
1317
|
function _overrideP5Touch() {
|
|
1144
|
-
const origTouchStarted = window.touchStarted || function() {};
|
|
1145
|
-
const origTouchMoved = window.touchMoved || function() {};
|
|
1146
|
-
const origTouchEnded = window.touchEnded || function() {};
|
|
1147
1318
|
const origMousePressed = window.mousePressed || function() {};
|
|
1148
1319
|
const origMouseDragged = window.mouseDragged || function() {};
|
|
1149
1320
|
const origMouseReleased = window.mouseReleased || function() {};
|
|
1150
1321
|
|
|
1151
|
-
//
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
origTouchMoved(
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1322
|
+
// In p5.js 2.0, touch and mouse are unified via Pointer API.
|
|
1323
|
+
// mousePressed/mouseDragged/mouseReleased fire for ALL pointer types (mouse + touch).
|
|
1324
|
+
// In p5.js 1.x, touchStarted/touchMoved/touchEnded are separate from mouse callbacks.
|
|
1325
|
+
// We wrap both sets for 1.x, and only mouse callbacks for 2.0.
|
|
1326
|
+
if (!_isP5v2) {
|
|
1327
|
+
// p5.js 1.x: also wrap touch-specific callbacks
|
|
1328
|
+
const origTouchStarted = window.touchStarted || function() {};
|
|
1329
|
+
const origTouchMoved = window.touchMoved || function() {};
|
|
1330
|
+
const origTouchEnded = window.touchEnded || function() {};
|
|
1331
|
+
|
|
1332
|
+
window.touchStarted = function(e) {
|
|
1333
|
+
origTouchStarted(e);
|
|
1334
|
+
return false;
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
window.touchMoved = function(e) {
|
|
1338
|
+
origTouchMoved(e);
|
|
1339
|
+
return false;
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
window.touchEnded = function(e) {
|
|
1343
|
+
origTouchEnded(e);
|
|
1344
|
+
return false;
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1166
1347
|
|
|
1348
|
+
// Mouse callbacks — work in both 1.x and 2.0
|
|
1167
1349
|
window.mousePressed = function(e) {
|
|
1168
1350
|
origMousePressed(e);
|
|
1169
1351
|
return false;
|
|
@@ -1389,6 +1571,9 @@ window.enableVibrationTap = enableVibrationTap;
|
|
|
1389
1571
|
window.enableVibrationButton = enableVibrationButton;
|
|
1390
1572
|
window.vibrate = vibrate;
|
|
1391
1573
|
window.stopVibration = stopVibration;
|
|
1574
|
+
window.enableNfcTap = enableNfcTap;
|
|
1575
|
+
window.enableNfcButton = enableNfcButton;
|
|
1576
|
+
window.stopNfc = stopNfc;
|
|
1392
1577
|
window.enableAllTap = enableAllTap;
|
|
1393
1578
|
window.enableAllButton = enableAllButton;
|
|
1394
1579
|
|
|
@@ -1398,6 +1583,7 @@ window.enableMicCanvas = enableMicCanvas;
|
|
|
1398
1583
|
window.enableSoundCanvas = enableSoundCanvas;
|
|
1399
1584
|
window.enableSpeechCanvas = enableSpeechCanvas;
|
|
1400
1585
|
window.enableVibrationCanvas = enableVibrationCanvas;
|
|
1586
|
+
window.enableNfcCanvas = enableNfcCanvas;
|
|
1401
1587
|
window.enableAllCanvas = enableAllCanvas;
|
|
1402
1588
|
window.enableCameraCanvas = enableCameraCanvas;
|
|
1403
1589
|
|
|
@@ -1407,6 +1593,7 @@ window.enableMicBanner = enableMicBanner;
|
|
|
1407
1593
|
window.enableSoundBanner = enableSoundBanner;
|
|
1408
1594
|
window.enableSpeechBanner = enableSpeechBanner;
|
|
1409
1595
|
window.enableVibrationBanner = enableVibrationBanner;
|
|
1596
|
+
window.enableNfcBanner = enableNfcBanner;
|
|
1410
1597
|
window.enableAllBanner = enableAllBanner;
|
|
1411
1598
|
window.enableCameraBanner = enableCameraBanner;
|
|
1412
1599
|
|
|
@@ -1416,6 +1603,7 @@ window.enableMicOn = enableMicOn;
|
|
|
1416
1603
|
window.enableSoundOn = enableSoundOn;
|
|
1417
1604
|
window.enableSpeechOn = enableSpeechOn;
|
|
1418
1605
|
window.enableVibrationOn = enableVibrationOn;
|
|
1606
|
+
window.enableNfcOn = enableNfcOn;
|
|
1419
1607
|
window.enableAllOn = enableAllOn;
|
|
1420
1608
|
window.enableCameraOn = enableCameraOn;
|
|
1421
1609
|
|
|
@@ -2171,6 +2359,9 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2171
2359
|
p5.prototype.enableVibrationButton = enableVibrationButton;
|
|
2172
2360
|
p5.prototype.vibrate = vibrate;
|
|
2173
2361
|
p5.prototype.stopVibration = stopVibration;
|
|
2362
|
+
p5.prototype.enableNfcTap = enableNfcTap;
|
|
2363
|
+
p5.prototype.enableNfcButton = enableNfcButton;
|
|
2364
|
+
p5.prototype.stopNfc = stopNfc;
|
|
2174
2365
|
p5.prototype.enableAllTap = enableAllTap;
|
|
2175
2366
|
p5.prototype.enableAllButton = enableAllButton;
|
|
2176
2367
|
|
|
@@ -2180,6 +2371,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2180
2371
|
p5.prototype.enableSoundCanvas = enableSoundCanvas;
|
|
2181
2372
|
p5.prototype.enableSpeechCanvas = enableSpeechCanvas;
|
|
2182
2373
|
p5.prototype.enableVibrationCanvas = enableVibrationCanvas;
|
|
2374
|
+
p5.prototype.enableNfcCanvas = enableNfcCanvas;
|
|
2183
2375
|
p5.prototype.enableAllCanvas = enableAllCanvas;
|
|
2184
2376
|
p5.prototype.enableCameraCanvas = enableCameraCanvas;
|
|
2185
2377
|
|
|
@@ -2189,6 +2381,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2189
2381
|
p5.prototype.enableSoundBanner = enableSoundBanner;
|
|
2190
2382
|
p5.prototype.enableSpeechBanner = enableSpeechBanner;
|
|
2191
2383
|
p5.prototype.enableVibrationBanner = enableVibrationBanner;
|
|
2384
|
+
p5.prototype.enableNfcBanner = enableNfcBanner;
|
|
2192
2385
|
p5.prototype.enableAllBanner = enableAllBanner;
|
|
2193
2386
|
p5.prototype.enableCameraBanner = enableCameraBanner;
|
|
2194
2387
|
|
|
@@ -2198,6 +2391,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2198
2391
|
p5.prototype.enableSoundOn = enableSoundOn;
|
|
2199
2392
|
p5.prototype.enableSpeechOn = enableSpeechOn;
|
|
2200
2393
|
p5.prototype.enableVibrationOn = enableVibrationOn;
|
|
2394
|
+
p5.prototype.enableNfcOn = enableNfcOn;
|
|
2201
2395
|
p5.prototype.enableAllOn = enableAllOn;
|
|
2202
2396
|
p5.prototype.enableCameraOn = enableCameraOn;
|
|
2203
2397
|
|
|
@@ -2215,4 +2409,83 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2215
2409
|
p5.prototype.debugWarn = debugWarn;
|
|
2216
2410
|
|
|
2217
2411
|
console.log('✅ Mobile p5.js Permissions: p5.prototype functions registered');
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// =========================================
|
|
2415
|
+
// P5.JS 2.0 ADDON REGISTRATION
|
|
2416
|
+
// =========================================
|
|
2417
|
+
|
|
2418
|
+
/**
|
|
2419
|
+
* Register as a p5.js 2.0 addon via p5.registerAddon().
|
|
2420
|
+
* This provides the modern lifecycle integration for p5.js 2.0+
|
|
2421
|
+
* while the p5.prototype block above handles 1.x compatibility.
|
|
2422
|
+
*/
|
|
2423
|
+
if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
|
|
2424
|
+
p5.registerAddon(function(p5, fn, lifecycles) {
|
|
2425
|
+
// Register all public functions on the prototype (fn === p5.prototype)
|
|
2426
|
+
// Core permission functions
|
|
2427
|
+
fn.lockGestures = lockGestures;
|
|
2428
|
+
fn.enableGyroTap = enableGyroTap;
|
|
2429
|
+
fn.enableGyroButton = enableGyroButton;
|
|
2430
|
+
fn.enableMicTap = enableMicTap;
|
|
2431
|
+
fn.enableMicButton = enableMicButton;
|
|
2432
|
+
fn.enableSoundTap = enableSoundTap;
|
|
2433
|
+
fn.enableSoundButton = enableSoundButton;
|
|
2434
|
+
fn.enableSpeechTap = enableSpeechTap;
|
|
2435
|
+
fn.enableSpeechButton = enableSpeechButton;
|
|
2436
|
+
fn.enableVibrationTap = enableVibrationTap;
|
|
2437
|
+
fn.enableVibrationButton = enableVibrationButton;
|
|
2438
|
+
fn.vibrate = vibrate;
|
|
2439
|
+
fn.stopVibration = stopVibration;
|
|
2440
|
+
fn.enableNfcTap = enableNfcTap;
|
|
2441
|
+
fn.enableNfcButton = enableNfcButton;
|
|
2442
|
+
fn.stopNfc = stopNfc;
|
|
2443
|
+
fn.enableAllTap = enableAllTap;
|
|
2444
|
+
fn.enableAllButton = enableAllButton;
|
|
2445
|
+
|
|
2446
|
+
// Canvas-first-touch style
|
|
2447
|
+
fn.enableGyroCanvas = enableGyroCanvas;
|
|
2448
|
+
fn.enableMicCanvas = enableMicCanvas;
|
|
2449
|
+
fn.enableSoundCanvas = enableSoundCanvas;
|
|
2450
|
+
fn.enableSpeechCanvas = enableSpeechCanvas;
|
|
2451
|
+
fn.enableVibrationCanvas = enableVibrationCanvas;
|
|
2452
|
+
fn.enableNfcCanvas = enableNfcCanvas;
|
|
2453
|
+
fn.enableAllCanvas = enableAllCanvas;
|
|
2454
|
+
fn.enableCameraCanvas = enableCameraCanvas;
|
|
2455
|
+
|
|
2456
|
+
// Banner style
|
|
2457
|
+
fn.enableGyroBanner = enableGyroBanner;
|
|
2458
|
+
fn.enableMicBanner = enableMicBanner;
|
|
2459
|
+
fn.enableSoundBanner = enableSoundBanner;
|
|
2460
|
+
fn.enableSpeechBanner = enableSpeechBanner;
|
|
2461
|
+
fn.enableVibrationBanner = enableVibrationBanner;
|
|
2462
|
+
fn.enableNfcBanner = enableNfcBanner;
|
|
2463
|
+
fn.enableAllBanner = enableAllBanner;
|
|
2464
|
+
fn.enableCameraBanner = enableCameraBanner;
|
|
2465
|
+
|
|
2466
|
+
// Custom element binding
|
|
2467
|
+
fn.enableGyroOn = enableGyroOn;
|
|
2468
|
+
fn.enableMicOn = enableMicOn;
|
|
2469
|
+
fn.enableSoundOn = enableSoundOn;
|
|
2470
|
+
fn.enableSpeechOn = enableSpeechOn;
|
|
2471
|
+
fn.enableVibrationOn = enableVibrationOn;
|
|
2472
|
+
fn.enableNfcOn = enableNfcOn;
|
|
2473
|
+
fn.enableAllOn = enableAllOn;
|
|
2474
|
+
fn.enableCameraOn = enableCameraOn;
|
|
2475
|
+
|
|
2476
|
+
// Camera functions
|
|
2477
|
+
fn.createPhoneCamera = createPhoneCamera;
|
|
2478
|
+
fn.enableCameraButton = enableCameraButton;
|
|
2479
|
+
fn.enableCameraTap = enableCameraTap;
|
|
2480
|
+
|
|
2481
|
+
// Debug functions
|
|
2482
|
+
fn.showDebug = showDebug;
|
|
2483
|
+
fn.hideDebug = hideDebug;
|
|
2484
|
+
fn.toggleDebug = toggleDebug;
|
|
2485
|
+
fn.debug = debug;
|
|
2486
|
+
fn.debugError = debugError;
|
|
2487
|
+
fn.debugWarn = debugWarn;
|
|
2488
|
+
|
|
2489
|
+
console.log('✅ Mobile p5.js Permissions: registered as p5.js 2.0 addon');
|
|
2490
|
+
});
|
|
2218
2491
|
}
|