p5-phone 1.8.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 +102 -3
- package/dist/p5-phone.js +186 -0
- 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/02_speech_recognition/index.html +1 -1
- package/examples/Phone Sensor Examples/movement/01_orientation_basic/index.html +1 -1
- package/examples/Phone Sensor Examples/movement/02_rotational_velocity/index.html +1 -1
- package/examples/Phone Sensor Examples/movement/03_acceleration/index.html +1 -1
- 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 +1 -1
- package/examples/Phone Sensor Examples/sound/02_volume_touches/index.html +1 -1
- package/examples/Phone Sensor Examples/touch/01_touch_basic/index.html +1 -1
- package/examples/Phone Sensor Examples/touch/02_touch_zones/index.html +1 -1
- package/examples/Phone Sensor Examples/touch/03_touch_count/index.html +1 -1
- package/examples/Phone Sensor Examples/touch/04_touch_distance/index.html +1 -1
- package/examples/Phone Sensor Examples/touch/05_touch_angle/index.html +1 -1
- package/examples/Phone Sensor Examples/vibration/01_haptic_feedback/index.html +1 -1
- 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/02_sound_amplitude/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/01_touch_basic/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/02_touch_zones/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/03_touch_count/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/04_touch_distance/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/touch/05_touch_angle/index.html +1 -1
- package/examples/Phone Sensor Examples - Minimal/vibration/01_haptic_feedback/index.html +1 -1
- package/examples/Phone and Gif/collision/index.html +1 -1
- package/examples/Phone and Gif/fetch/index.html +1 -1
- package/examples/Phone and Gif/fly/index.html +1 -1
- package/examples/Phone and Gif/roll/index.html +1 -1
- package/examples/UXcompare/button-vs-movement/index.html +1 -1
- package/examples/UXcompare/button-vs-orientation/index.html +1 -1
- package/examples/UXcompare/button-vs-shake/index.html +1 -1
- package/examples/UXcompare/gyroscope-demo/index.html +1 -1
- package/examples/UXcompare/microphone-demo/index.html +1 -1
- package/examples/UXcompare/slider-vs-angle/index.html +1 -1
- package/examples/UXcompare/slider-vs-distance/index.html +1 -1
- package/examples/UXcompare/slider-vs-microphone/index.html +1 -1
- package/examples/UXcompare/slider-vs-touches/index.html +1 -1
- package/examples/UXcompare/sliders-vs-acceleration/index.html +1 -1
- package/examples/UXcompare/sliders-vs-rotation/index.html +1 -1
- package/examples/blankTemplate/index.html +1 -1
- package/examples/homepage/index.html +5 -5
- package/examples/ml5/Gaze_detector_class/index.html +1 -1
- package/examples/ml5/PHONE_BodyPose_two_points/index.html +1 -1
- package/examples/ml5/PHONE_FaceMesh_two_points/index.html +1 -1
- package/examples/ml5/PHONE_HandPose_two_points/index.html +1 -1
- package/package.json +1 -1
- package/src/p5-phone.js +186 -0
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ p5-phone supports both **p5.js 1.x** and **p5.js 2.0+**.
|
|
|
58
58
|
| Microphone / Speech / Sound | ✅ | ✅ |
|
|
59
59
|
| Camera (PhoneCamera) | ✅ | ✅ |
|
|
60
60
|
| Vibration | ✅ | ✅ |
|
|
61
|
+
| NFC Tag Reading (Android only) | ✅ | ✅ |
|
|
61
62
|
| Debug console | ✅ | ✅ |
|
|
62
63
|
| lockGestures() | ✅ | ✅ |
|
|
63
64
|
| `touchStarted()` / `touchEnded()` | ✅ | ❌ Use `mousePressed()` / `mouseReleased()` |
|
|
@@ -86,6 +87,7 @@ p5-phone automatically detects the p5.js version and adjusts its internal touch
|
|
|
86
87
|
- [Speech Recognition Activation](#speech-recognition-activation)
|
|
87
88
|
- [Combined Activation](#combined-activation)
|
|
88
89
|
- [Vibration Motor (Android Only)](#vibration-motor-android-only)
|
|
90
|
+
- [NFC Tag Reading (Android Only)](#nfc-tag-reading-android-only)
|
|
89
91
|
- [PhoneCamera (ML5 Integration)](#phonecamera-ml5-integration)
|
|
90
92
|
- [Debug System](#debug-system)
|
|
91
93
|
- [Permission UI Styles](#permission-ui-styles)
|
|
@@ -100,10 +102,10 @@ p5-phone automatically detects the p5.js version and adjusts its internal touch
|
|
|
100
102
|
|
|
101
103
|
```html
|
|
102
104
|
<!-- Minified version (recommended) -->
|
|
103
|
-
<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>
|
|
104
106
|
|
|
105
107
|
<!-- Development version (larger, with comments) -->
|
|
106
|
-
<!-- <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> -->
|
|
107
109
|
```
|
|
108
110
|
|
|
109
111
|
### Basic Setup
|
|
@@ -132,7 +134,7 @@ p5-phone automatically detects the p5.js version and adjusts its internal touch
|
|
|
132
134
|
<!-- For p5.js 2.0: <script src="https://cdn.jsdelivr.net/npm/p5@2/lib/p5.min.js"></script> -->
|
|
133
135
|
|
|
134
136
|
<!-- Load p5-phone library -->
|
|
135
|
-
<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>
|
|
136
138
|
|
|
137
139
|
</head>
|
|
138
140
|
<body>
|
|
@@ -302,6 +304,7 @@ this.enableGyroTap('Tap to start');
|
|
|
302
304
|
- `window.soundEnabled` - Boolean indicating if sound output is active
|
|
303
305
|
- `window.speechEnabled` - Boolean indicating if speech recognition is active
|
|
304
306
|
- `window.vibrationEnabled` - Boolean indicating if vibration is available (Android only)
|
|
307
|
+
- `window.nfcEnabled` - Boolean indicating if NFC scanning is active (Android only)
|
|
305
308
|
|
|
306
309
|
**Usage:**
|
|
307
310
|
```javascript
|
|
@@ -326,6 +329,11 @@ function draw() {
|
|
|
326
329
|
// Safe to use vibration (Android only)
|
|
327
330
|
vibrate(50);
|
|
328
331
|
}
|
|
332
|
+
|
|
333
|
+
if (window.nfcEnabled) {
|
|
334
|
+
// NFC scanning is active (Android only)
|
|
335
|
+
// Tag data arrives via nfcRead() callback
|
|
336
|
+
}
|
|
329
337
|
}
|
|
330
338
|
|
|
331
339
|
// You can also use them for conditional UI
|
|
@@ -638,6 +646,94 @@ function gameOver() {
|
|
|
638
646
|
- Don't overuse - vibration can quickly drain battery
|
|
639
647
|
- Test on Android devices as iOS doesn't support vibration
|
|
640
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
|
+
|
|
641
737
|
### Speech Recognition Activation
|
|
642
738
|
|
|
643
739
|
**Purpose:** Enable the Web Speech API for voice input and speech-to-text in mobile browsers.
|
|
@@ -924,6 +1020,7 @@ The canvas displays a centered message until the user taps. Great for "full-scre
|
|
|
924
1020
|
- `enableSensorCanvas(message)`
|
|
925
1021
|
- `enableMicCanvas(message)`
|
|
926
1022
|
- `enableSpeechCanvas(message)`
|
|
1023
|
+
- `enableNfcCanvas(message)`
|
|
927
1024
|
- `enableAllCanvas(message)`
|
|
928
1025
|
- `enableCameraCanvas(message)`
|
|
929
1026
|
|
|
@@ -950,6 +1047,7 @@ A styled banner slides in from the top of the screen with an animated entrance.
|
|
|
950
1047
|
- `enableSensorBanner(message)`
|
|
951
1048
|
- `enableMicBanner(message)`
|
|
952
1049
|
- `enableSpeechBanner(message)`
|
|
1050
|
+
- `enableNfcBanner(message)`
|
|
953
1051
|
- `enableAllBanner(message)`
|
|
954
1052
|
- `enableCameraBanner(message)`
|
|
955
1053
|
|
|
@@ -977,6 +1075,7 @@ Bind the permission activation to any existing HTML element on the page using a
|
|
|
977
1075
|
- `enableSensorOn(selector)`
|
|
978
1076
|
- `enableMicOn(selector)`
|
|
979
1077
|
- `enableSpeechOn(selector)`
|
|
1078
|
+
- `enableNfcOn(selector)`
|
|
980
1079
|
- `enableAllOn(selector)`
|
|
981
1080
|
- `enableCameraOn(selector)`
|
|
982
1081
|
|
package/dist/p5-phone.js
CHANGED
|
@@ -87,9 +87,14 @@ 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;
|
|
93
98
|
|
|
94
99
|
// p5.js version detection (1.x vs 2.x)
|
|
95
100
|
const _p5MajorVersion = (typeof p5 !== 'undefined' && p5.VERSION)
|
|
@@ -235,6 +240,30 @@ function enableVibrationTap(message = 'Tap screen to enable vibration') {
|
|
|
235
240
|
});
|
|
236
241
|
}
|
|
237
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
|
+
|
|
238
267
|
/**
|
|
239
268
|
* Enable both motion sensors and microphone with a button interface
|
|
240
269
|
* Creates a start button that user must click to enable both
|
|
@@ -318,6 +347,16 @@ function enableVibrationCanvas(message = 'Touch to start') {
|
|
|
318
347
|
});
|
|
319
348
|
}
|
|
320
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
|
+
|
|
321
360
|
/**
|
|
322
361
|
* Enable both motion sensors and microphone on first canvas touch
|
|
323
362
|
*/
|
|
@@ -385,6 +424,13 @@ function enableVibrationBanner(message = 'Tap to enable vibration', position = '
|
|
|
385
424
|
});
|
|
386
425
|
}
|
|
387
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
|
+
|
|
388
434
|
function enableAllBanner(message = 'Tap to enable sensors & microphone', position = 'top') {
|
|
389
435
|
_createBannerToEnable(message, position, async () => {
|
|
390
436
|
await _requestMotionPermissionsCore();
|
|
@@ -445,6 +491,13 @@ function enableVibrationOn(selector) {
|
|
|
445
491
|
});
|
|
446
492
|
}
|
|
447
493
|
|
|
494
|
+
function enableNfcOn(selector) {
|
|
495
|
+
_bindPermissionTo(selector, async () => {
|
|
496
|
+
await _requestNfcPermission();
|
|
497
|
+
console.log('✅ NFC enabled via custom element');
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
448
501
|
function enableAllOn(selector) {
|
|
449
502
|
_bindPermissionTo(selector, async () => {
|
|
450
503
|
await _requestMotionPermissionsCore();
|
|
@@ -494,6 +547,19 @@ function stopVibration() {
|
|
|
494
547
|
}
|
|
495
548
|
}
|
|
496
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
|
+
|
|
497
563
|
// =========================================
|
|
498
564
|
// INTERNAL PERMISSION HANDLERS
|
|
499
565
|
// =========================================
|
|
@@ -619,6 +685,102 @@ async function _requestVibrationPermissionCore() {
|
|
|
619
685
|
}
|
|
620
686
|
}
|
|
621
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
|
+
|
|
622
784
|
// Wrapped versions that notify the sketch (used by single-permission functions)
|
|
623
785
|
async function _requestMotionPermissions() {
|
|
624
786
|
await _requestMotionPermissionsCore();
|
|
@@ -645,6 +807,11 @@ async function _requestVibrationPermission() {
|
|
|
645
807
|
_notifySketchReady();
|
|
646
808
|
}
|
|
647
809
|
|
|
810
|
+
async function _requestNfcPermission() {
|
|
811
|
+
await _requestNfcPermissionCore();
|
|
812
|
+
_notifySketchReady();
|
|
813
|
+
}
|
|
814
|
+
|
|
648
815
|
function _notifySketchReady() {
|
|
649
816
|
// Call userSetupComplete if it exists
|
|
650
817
|
if (typeof userSetupComplete === 'function') {
|
|
@@ -659,6 +826,7 @@ function _notifySketchReady() {
|
|
|
659
826
|
sound: window.soundEnabled,
|
|
660
827
|
speech: window.speechEnabled,
|
|
661
828
|
vibration: window.vibrationEnabled,
|
|
829
|
+
nfc: window.nfcEnabled,
|
|
662
830
|
gestures: window.gesturesLocked
|
|
663
831
|
}
|
|
664
832
|
}));
|
|
@@ -1403,6 +1571,9 @@ window.enableVibrationTap = enableVibrationTap;
|
|
|
1403
1571
|
window.enableVibrationButton = enableVibrationButton;
|
|
1404
1572
|
window.vibrate = vibrate;
|
|
1405
1573
|
window.stopVibration = stopVibration;
|
|
1574
|
+
window.enableNfcTap = enableNfcTap;
|
|
1575
|
+
window.enableNfcButton = enableNfcButton;
|
|
1576
|
+
window.stopNfc = stopNfc;
|
|
1406
1577
|
window.enableAllTap = enableAllTap;
|
|
1407
1578
|
window.enableAllButton = enableAllButton;
|
|
1408
1579
|
|
|
@@ -1412,6 +1583,7 @@ window.enableMicCanvas = enableMicCanvas;
|
|
|
1412
1583
|
window.enableSoundCanvas = enableSoundCanvas;
|
|
1413
1584
|
window.enableSpeechCanvas = enableSpeechCanvas;
|
|
1414
1585
|
window.enableVibrationCanvas = enableVibrationCanvas;
|
|
1586
|
+
window.enableNfcCanvas = enableNfcCanvas;
|
|
1415
1587
|
window.enableAllCanvas = enableAllCanvas;
|
|
1416
1588
|
window.enableCameraCanvas = enableCameraCanvas;
|
|
1417
1589
|
|
|
@@ -1421,6 +1593,7 @@ window.enableMicBanner = enableMicBanner;
|
|
|
1421
1593
|
window.enableSoundBanner = enableSoundBanner;
|
|
1422
1594
|
window.enableSpeechBanner = enableSpeechBanner;
|
|
1423
1595
|
window.enableVibrationBanner = enableVibrationBanner;
|
|
1596
|
+
window.enableNfcBanner = enableNfcBanner;
|
|
1424
1597
|
window.enableAllBanner = enableAllBanner;
|
|
1425
1598
|
window.enableCameraBanner = enableCameraBanner;
|
|
1426
1599
|
|
|
@@ -1430,6 +1603,7 @@ window.enableMicOn = enableMicOn;
|
|
|
1430
1603
|
window.enableSoundOn = enableSoundOn;
|
|
1431
1604
|
window.enableSpeechOn = enableSpeechOn;
|
|
1432
1605
|
window.enableVibrationOn = enableVibrationOn;
|
|
1606
|
+
window.enableNfcOn = enableNfcOn;
|
|
1433
1607
|
window.enableAllOn = enableAllOn;
|
|
1434
1608
|
window.enableCameraOn = enableCameraOn;
|
|
1435
1609
|
|
|
@@ -2185,6 +2359,9 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2185
2359
|
p5.prototype.enableVibrationButton = enableVibrationButton;
|
|
2186
2360
|
p5.prototype.vibrate = vibrate;
|
|
2187
2361
|
p5.prototype.stopVibration = stopVibration;
|
|
2362
|
+
p5.prototype.enableNfcTap = enableNfcTap;
|
|
2363
|
+
p5.prototype.enableNfcButton = enableNfcButton;
|
|
2364
|
+
p5.prototype.stopNfc = stopNfc;
|
|
2188
2365
|
p5.prototype.enableAllTap = enableAllTap;
|
|
2189
2366
|
p5.prototype.enableAllButton = enableAllButton;
|
|
2190
2367
|
|
|
@@ -2194,6 +2371,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2194
2371
|
p5.prototype.enableSoundCanvas = enableSoundCanvas;
|
|
2195
2372
|
p5.prototype.enableSpeechCanvas = enableSpeechCanvas;
|
|
2196
2373
|
p5.prototype.enableVibrationCanvas = enableVibrationCanvas;
|
|
2374
|
+
p5.prototype.enableNfcCanvas = enableNfcCanvas;
|
|
2197
2375
|
p5.prototype.enableAllCanvas = enableAllCanvas;
|
|
2198
2376
|
p5.prototype.enableCameraCanvas = enableCameraCanvas;
|
|
2199
2377
|
|
|
@@ -2203,6 +2381,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2203
2381
|
p5.prototype.enableSoundBanner = enableSoundBanner;
|
|
2204
2382
|
p5.prototype.enableSpeechBanner = enableSpeechBanner;
|
|
2205
2383
|
p5.prototype.enableVibrationBanner = enableVibrationBanner;
|
|
2384
|
+
p5.prototype.enableNfcBanner = enableNfcBanner;
|
|
2206
2385
|
p5.prototype.enableAllBanner = enableAllBanner;
|
|
2207
2386
|
p5.prototype.enableCameraBanner = enableCameraBanner;
|
|
2208
2387
|
|
|
@@ -2212,6 +2391,7 @@ if (typeof p5 !== 'undefined' && p5.prototype) {
|
|
|
2212
2391
|
p5.prototype.enableSoundOn = enableSoundOn;
|
|
2213
2392
|
p5.prototype.enableSpeechOn = enableSpeechOn;
|
|
2214
2393
|
p5.prototype.enableVibrationOn = enableVibrationOn;
|
|
2394
|
+
p5.prototype.enableNfcOn = enableNfcOn;
|
|
2215
2395
|
p5.prototype.enableAllOn = enableAllOn;
|
|
2216
2396
|
p5.prototype.enableCameraOn = enableCameraOn;
|
|
2217
2397
|
|
|
@@ -2257,6 +2437,9 @@ if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
|
|
|
2257
2437
|
fn.enableVibrationButton = enableVibrationButton;
|
|
2258
2438
|
fn.vibrate = vibrate;
|
|
2259
2439
|
fn.stopVibration = stopVibration;
|
|
2440
|
+
fn.enableNfcTap = enableNfcTap;
|
|
2441
|
+
fn.enableNfcButton = enableNfcButton;
|
|
2442
|
+
fn.stopNfc = stopNfc;
|
|
2260
2443
|
fn.enableAllTap = enableAllTap;
|
|
2261
2444
|
fn.enableAllButton = enableAllButton;
|
|
2262
2445
|
|
|
@@ -2266,6 +2449,7 @@ if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
|
|
|
2266
2449
|
fn.enableSoundCanvas = enableSoundCanvas;
|
|
2267
2450
|
fn.enableSpeechCanvas = enableSpeechCanvas;
|
|
2268
2451
|
fn.enableVibrationCanvas = enableVibrationCanvas;
|
|
2452
|
+
fn.enableNfcCanvas = enableNfcCanvas;
|
|
2269
2453
|
fn.enableAllCanvas = enableAllCanvas;
|
|
2270
2454
|
fn.enableCameraCanvas = enableCameraCanvas;
|
|
2271
2455
|
|
|
@@ -2275,6 +2459,7 @@ if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
|
|
|
2275
2459
|
fn.enableSoundBanner = enableSoundBanner;
|
|
2276
2460
|
fn.enableSpeechBanner = enableSpeechBanner;
|
|
2277
2461
|
fn.enableVibrationBanner = enableVibrationBanner;
|
|
2462
|
+
fn.enableNfcBanner = enableNfcBanner;
|
|
2278
2463
|
fn.enableAllBanner = enableAllBanner;
|
|
2279
2464
|
fn.enableCameraBanner = enableCameraBanner;
|
|
2280
2465
|
|
|
@@ -2284,6 +2469,7 @@ if (typeof p5 !== 'undefined' && typeof p5.registerAddon === 'function') {
|
|
|
2284
2469
|
fn.enableSoundOn = enableSoundOn;
|
|
2285
2470
|
fn.enableSpeechOn = enableSpeechOn;
|
|
2286
2471
|
fn.enableVibrationOn = enableVibrationOn;
|
|
2472
|
+
fn.enableNfcOn = enableNfcOn;
|
|
2287
2473
|
fn.enableAllOn = enableAllOn;
|
|
2288
2474
|
fn.enableCameraOn = enableCameraOn;
|
|
2289
2475
|
|