@srsergio/taptapp-ar 1.0.95 → 1.0.97
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 +53 -151
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/react/TaptappAR.js +20 -6
- package/dist/react/types.d.ts +1 -1
- package/dist/react/use-ar.d.ts +2 -1
- package/dist/react/use-ar.js +52 -45
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/track.d.ts +170 -0
- package/dist/runtime/track.js +381 -0
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/react/TaptappAR.tsx +31 -6
- package/src/react/types.ts +1 -1
- package/src/react/use-ar.ts +59 -49
- package/src/runtime/index.ts +2 -1
- package/src/runtime/track.ts +623 -0
- package/dist/runtime/simple-ar.d.ts +0 -86
- package/dist/runtime/simple-ar.js +0 -323
- package/src/runtime/simple-ar.ts +0 -399
package/README.md
CHANGED
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
- **Dynamic Scale Filtering (LOD)**: Runtime matching engine skips irrelevant octaves based on estimated scale.
|
|
39
39
|
- **4-bit Packed Tracking Data**: Grayscale images are compressed to 4-bit depth, slashing file size.
|
|
40
40
|
- **64-bit LSH Descriptors**: Optimized Locality Sensitive Hashing with XOR folding support.
|
|
41
|
-
- 🧵 **
|
|
41
|
+
- 🧵 **HD Precision Tracking**: Default resolution upgraded to **1280x960 (HD)** for superior sharpness on modern displays.
|
|
42
|
+
- ⚡ **Zero-Config JIT Compilation**: No need for offline tools. Just pass an image URL and the engine compiles it on the fly.
|
|
42
43
|
- 📏 **Virtualized Scale Range**: Stable tracking from **20% (distant targets)** to **1000% (close-up)** using a single high-res keyframe.
|
|
43
44
|
- ⚡ **Immediate AR Detection**: Optimized "warm-up" period (15 frames) with relaxed inlier thresholds (6 pts) for instant tracking lock.
|
|
44
|
-
- 📦 **Framework Agnostic**: Includes wrappers for **A-Frame**, **Three.js**, and a raw **Controller
|
|
45
|
+
- 📦 **Framework Agnostic**: Includes wrappers for **React**, **A-Frame**, **Three.js**, and a raw **Controller**.
|
|
45
46
|
- 📉 **Ultra-Compact Files**: Output `.taar` files are now **~100KB** (vs ~380KB+ previously).
|
|
46
47
|
|
|
47
48
|
---
|
|
@@ -80,183 +81,84 @@ The latest version has been rigorously tested with an adaptive stress test (`rob
|
|
|
80
81
|
|
|
81
82
|
---
|
|
82
83
|
|
|
83
|
-
## 🖼️ Compiler Usage (
|
|
84
|
+
## 🖼️ Compiler Usage (Automatic / JIT)
|
|
84
85
|
|
|
85
|
-
The
|
|
86
|
+
The new **TapTapp AR** engine handles compilation automatically in the browser (Just-In-Time). You likely **don't need** to use the offline compiler manually anymore.
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
import { OfflineCompiler } from '@srsergio/taptapp-ar';
|
|
88
|
+
Simply pass your image URL to the tracker, and it will compile it on the fly:
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
```typescript
|
|
91
|
+
// No compilation step needed!
|
|
92
|
+
const tracker = await startTracking({
|
|
93
|
+
targetSrc: './my-image.jpg' // Using a JPG/PNG directly
|
|
94
|
+
});
|
|
95
|
+
```
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
// Input: { width, height, data: Uint8Array }
|
|
94
|
-
await compiler.compileImageTargets(
|
|
95
|
-
[{ width, height, data: grayscaleUint8Array }],
|
|
96
|
-
(progress) => console.log(`Compiling: ${progress}%`)
|
|
97
|
-
);
|
|
97
|
+
However, if you still want to pre-compile for faster startup on low-end devices:
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
```javascript
|
|
100
|
+
import { OfflineCompiler } from '@srsergio/taptapp-ar';
|
|
101
|
+
// ... same compiler code as before ...
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
---
|
|
104
105
|
|
|
105
106
|
## 🎥 Runtime Usage (AR Tracking)
|
|
106
107
|
|
|
107
|
-
### 1.
|
|
108
|
-
The easiest way to use TapTapp AR in a web app:
|
|
108
|
+
### 1. The Easy Way: React Component ⚛️
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
|
|
112
|
-
<script src="path/to/@srsergio/taptapp-ar/dist/index.js"></script>
|
|
110
|
+
The simplest, zero-config way to add AR to your app:
|
|
113
111
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<a-entity taar-image-target="targetIndex: 0">
|
|
117
|
-
<a-plane position="0 0 0" height="0.552" width="1"></a-plane>
|
|
118
|
-
</a-entity>
|
|
119
|
-
</a-scene>
|
|
120
|
-
```
|
|
112
|
+
```tsx
|
|
113
|
+
import { TaptappAR } from '@srsergio/taptapp-ar/react';
|
|
121
114
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const {renderer, scene, camera} = taarThree;
|
|
134
|
-
|
|
135
|
-
const anchor = taarThree.addAnchor(0);
|
|
136
|
-
// Add your 3D models to anchor.group
|
|
137
|
-
|
|
138
|
-
await taarThree.start();
|
|
139
|
-
renderer.setAnimationLoop(() => {
|
|
140
|
-
renderer.render(scene, camera);
|
|
141
|
-
});
|
|
115
|
+
export const MyARScene = () => (
|
|
116
|
+
<TaptappAR
|
|
117
|
+
config={{
|
|
118
|
+
targetImageSrc: "https://example.com/target.jpg", // Direct Image URL
|
|
119
|
+
videoSrc: "https://example.com/overlay.mp4", // Content to show
|
|
120
|
+
scale: 1.2
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
142
124
|
```
|
|
143
125
|
|
|
144
|
-
###
|
|
145
|
-
The `Controller` is the core engine of TapTapp AR. You can use it to build your own AR components or integrate tracking into custom 3D engines.
|
|
126
|
+
### 2. The Powerful Way: `startTracking` API
|
|
146
127
|
|
|
147
|
-
|
|
148
|
-
| Property | Default | Description |
|
|
149
|
-
| :--- | :--- | :--- |
|
|
150
|
-
| `inputWidth` | **Required** | The width of the video or image source. |
|
|
151
|
-
| `inputHeight` | **Required** | The height of the video or image source. |
|
|
152
|
-
| `maxTrack` | `1` | Max number of images to track simultaneously. |
|
|
153
|
-
| `warmupTolerance` | `5` | Frames of consistent detection needed to "lock" a target. |
|
|
154
|
-
| `missTolerance` | `5` | Frames of missed detection before considering the target "lost". |
|
|
155
|
-
| `filterMinCF` | `0.001` | Min cutoff frequency for the OneEuroFilter (reduces jitter). |
|
|
156
|
-
| `filterBeta` | `1000` | Filter beta parameter (higher = more responsive, lower = smoother). |
|
|
157
|
-
| `onUpdate` | `null` | Callback for tracking events (Found, Lost, ProcessDone). |
|
|
158
|
-
| `debugMode` | `false` | If true, returns extra debug data (cropped images, feature points). |
|
|
159
|
-
| `worker` | `null` | Pass a custom worker instance if using a specialized environment. |
|
|
160
|
-
|
|
161
|
-
#### 🚀 Example: Tracking a Video Stream
|
|
162
|
-
Ideal for real-time AR apps in the browser:
|
|
128
|
+
For vanilla JS or custom integrations, use the new high-level API:
|
|
163
129
|
|
|
164
|
-
```
|
|
165
|
-
import {
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
console.log(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
130
|
+
```typescript
|
|
131
|
+
import { startTracking } from '@srsergio/taptapp-ar';
|
|
132
|
+
|
|
133
|
+
const tracker = await startTracking({
|
|
134
|
+
targetSrc: './assets/target.jpg', // No .taar needed!
|
|
135
|
+
container: document.getElementById('ar-container'),
|
|
136
|
+
overlay: document.getElementById('overlay-element'),
|
|
137
|
+
|
|
138
|
+
// Optional callbacks
|
|
139
|
+
callbacks: {
|
|
140
|
+
onFound: () => console.log("Target Found! 🎯"),
|
|
141
|
+
onLost: () => console.log("Target Lost 👋"),
|
|
142
|
+
onUpdate: (data) => {
|
|
143
|
+
console.log("Stability:", data.avgStability);
|
|
144
|
+
}
|
|
179
145
|
}
|
|
180
|
-
}
|
|
181
146
|
});
|
|
182
147
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// OR multiple targets from different .taar files
|
|
187
|
-
await controller.addImageTargets(['./target1.taar', './target2.taar', './target3.taar']);
|
|
188
|
-
controller.processVideo(videoElement); // Starts the internal RAF loop
|
|
148
|
+
// Stop later
|
|
149
|
+
// tracker.stop();
|
|
189
150
|
```
|
|
190
151
|
|
|
191
|
-
|
|
192
|
-
Use this for "Snap and Detect" features without a continuous video loop:
|
|
193
|
-
|
|
194
|
-
```javascript
|
|
195
|
-
const controller = new Controller({ inputWidth: 1024, inputHeight: 1024 });
|
|
196
|
-
await controller.addImageTargets('./targets.taar');
|
|
197
|
-
|
|
198
|
-
// 1. Detect features in a static image
|
|
199
|
-
const { featurePoints } = await controller.detect(canvasElement);
|
|
200
|
-
|
|
201
|
-
// 2. Attempt to match against a specific target index
|
|
202
|
-
const { targetIndex, modelViewTransform } = await controller.match(featurePoints, 0);
|
|
203
|
-
|
|
204
|
-
if (targetIndex !== -1) {
|
|
205
|
-
// Found a match! Use modelViewTransform for initial pose estimation
|
|
206
|
-
}
|
|
207
|
-
```
|
|
152
|
+
### 3. Advanced Integration (Three.js / A-Frame)
|
|
208
153
|
|
|
209
|
-
|
|
210
|
-
The **simplest way** to use AR—no Three.js, no A-Frame. Just overlay an image on the tracked target.
|
|
154
|
+
We still provide wrappers for 3D engines if you need to render complex 3D models instead of DOM overlays.
|
|
211
155
|
|
|
156
|
+
#### Three.js Adapter
|
|
212
157
|
```javascript
|
|
213
|
-
import {
|
|
214
|
-
|
|
215
|
-
const ar = new SimpleAR({
|
|
216
|
-
container: document.getElementById('ar-container'),
|
|
217
|
-
targetSrc: './my-target.taar', // Single URL or array: ['./a.taar', './b.taar']
|
|
218
|
-
overlay: document.getElementById('my-overlay'),
|
|
219
|
-
onFound: ({ targetIndex }) => console.log(`Target ${targetIndex} detected! 🎯`),
|
|
220
|
-
onLost: ({ targetIndex }) => console.log(`Target ${targetIndex} lost 👋`)
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
await ar.start();
|
|
224
|
-
|
|
225
|
-
// When done:
|
|
226
|
-
ar.stop();
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
#### 📁 Minimal HTML
|
|
230
|
-
```html
|
|
231
|
-
<div id="ar-container" style="width: 100vw; height: 100vh;">
|
|
232
|
-
<img id="my-overlay" src="./overlay.png"
|
|
233
|
-
style="opacity: 0; z-index: 1; width: 200px; transition: opacity 0.3s;" />
|
|
234
|
-
</div>
|
|
235
|
-
|
|
236
|
-
<script type="module">
|
|
237
|
-
import { SimpleAR } from '@srsergio/taptapp-ar';
|
|
238
|
-
|
|
239
|
-
const ar = new SimpleAR({
|
|
240
|
-
container: document.getElementById('ar-container'),
|
|
241
|
-
targetSrc: './targets.taar',
|
|
242
|
-
overlay: document.getElementById('my-overlay'),
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
ar.start();
|
|
246
|
-
</script>
|
|
158
|
+
import { TaarThree } from '@srsergio/taptapp-ar';
|
|
159
|
+
// ... (standard Three.js integration)
|
|
247
160
|
```
|
|
248
161
|
|
|
249
|
-
#### ⚙️ SimpleAR Options
|
|
250
|
-
| Option | Required | Description |
|
|
251
|
-
| :--- | :--- | :--- |
|
|
252
|
-
| `container` | ✅ | DOM element where video + overlay render |
|
|
253
|
-
| `targetSrc` | ✅ | URL to your `.taar` file |
|
|
254
|
-
| `overlay` | ✅ | DOM element to position on the target |
|
|
255
|
-
| `onFound` | ❌ | Callback when target is detected |
|
|
256
|
-
| `onLost` | ❌ | Callback when target is lost |
|
|
257
|
-
| `onUpdate` | ❌ | Called each frame with `{ targetIndex, worldMatrix }` |
|
|
258
|
-
| `cameraConfig` | ❌ | Camera constraints (default: `{ facingMode: 'environment', width: 1280, height: 720 }`) |
|
|
259
|
-
|
|
260
162
|
---
|
|
261
163
|
|
|
262
164
|
## 🏗️ Protocol V11 (Nanite Virtualized Format)
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export * from "./react/TaptappAR.js";
|
|
|
3
3
|
export * from "./react/use-ar.js";
|
|
4
4
|
export * from "./compiler/offline-compiler.js";
|
|
5
5
|
export { Controller } from "./runtime/controller.js";
|
|
6
|
-
export {
|
|
6
|
+
export { createTracker, startTracking } from "./runtime/track.js";
|
|
7
7
|
export * as protocol from "./core/protocol.js";
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export * from "./react/TaptappAR.js";
|
|
|
3
3
|
export * from "./react/use-ar.js";
|
|
4
4
|
export * from "./compiler/offline-compiler.js";
|
|
5
5
|
export { Controller } from "./runtime/controller.js";
|
|
6
|
-
export {
|
|
6
|
+
export { createTracker, startTracking } from "./runtime/track.js";
|
|
7
7
|
export * as protocol from "./core/protocol.js";
|
package/dist/react/TaptappAR.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { useAR } from "./use-ar.js";
|
|
4
4
|
export const TaptappAR = ({ config, className = "", showScanningOverlay = true, showErrorOverlay = true }) => {
|
|
5
|
-
const { containerRef, overlayRef, status, toggleVideo, trackedPoints } = useAR(config);
|
|
5
|
+
const { containerRef, overlayRef, status, toggleVideo, trackedPoints, error } = useAR(config);
|
|
6
6
|
// Simple heuristic to determine if it's a video or image
|
|
7
7
|
// based on the presence of videoSrc and common extensions
|
|
8
8
|
const isVideo = useMemo(() => {
|
|
@@ -12,7 +12,7 @@ export const TaptappAR = ({ config, className = "", showScanningOverlay = true,
|
|
|
12
12
|
const url = config.videoSrc.toLowerCase().split('?')[0];
|
|
13
13
|
return videoExtensions.some(ext => url.endsWith(ext)) || config.videoSrc.includes('video');
|
|
14
14
|
}, [config.videoSrc]);
|
|
15
|
-
return (_jsxs("div", { className: `taptapp-ar-wrapper ${className} ${status}`, style: { position: 'relative', width: '100%', height: '100%', overflow: 'hidden' }, children: [showScanningOverlay && status === "scanning" && (_jsx("div", { className: "taptapp-ar-overlay taptapp-ar-scanning", children: _jsxs("div", { className: "scanning-content", children: [_jsxs("div", { className: "scanning-frame", children: [_jsx("img", { className: "target-preview", src: config.targetImageSrc, alt: "Target", crossOrigin: "anonymous" }), _jsx("div", { className: "scanning-line" })] }), _jsx("p", { className: "scanning-text", children: "Apunta a la imagen para comenzar" })] }) })), showErrorOverlay && status === "error" && (_jsx("div", { className: "taptapp-ar-overlay taptapp-ar-error", children: _jsxs("div", { className: "error-content", children: [_jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), _jsx("p", { className: "error-title", children: "No se pudo iniciar AR" }), _jsx("p", { className: "error-text", children: "Verifica los permisos de
|
|
15
|
+
return (_jsxs("div", { className: `taptapp-ar-wrapper ${className} ${status}`, style: { position: 'relative', width: '100%', height: '100%', overflow: 'hidden' }, children: [showScanningOverlay && status === "scanning" && (_jsx("div", { className: "taptapp-ar-overlay taptapp-ar-scanning", children: _jsxs("div", { className: "scanning-content", children: [_jsxs("div", { className: "scanning-frame", children: [_jsx("img", { className: "target-preview", src: config.targetImageSrc, alt: "Target", crossOrigin: "anonymous" }), _jsx("div", { className: "scanning-line" })] }), _jsx("p", { className: "scanning-text", children: "Apunta a la imagen para comenzar" })] }) })), status === "compiling" && (_jsx("div", { className: "taptapp-ar-overlay taptapp-ar-compiling", style: { background: 'rgba(0,0,0,0.9)' }, children: _jsxs("div", { className: "scanning-content", children: [_jsx("div", { className: "loading-spinner" }), _jsx("p", { className: "scanning-text", style: { marginTop: '20px' }, children: "Preparando motor AR..." }), _jsx("p", { style: { fontSize: '0.8rem', opacity: 0.6 }, children: "Compilando imagen de referencia" })] }) })), showErrorOverlay && status === "error" && (_jsx("div", { className: "taptapp-ar-overlay taptapp-ar-error", children: _jsxs("div", { className: "error-content", children: [_jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), _jsx("p", { className: "error-title", children: "No se pudo iniciar AR" }), _jsx("p", { className: "error-text", children: error || "Verifica los permisos de cámara" }), _jsx("button", { className: "retry-btn", onClick: () => window.location.reload(), children: "Reintentar" })] }) })), _jsx("div", { ref: containerRef, className: "taptapp-ar-container", onClick: toggleVideo, style: { width: '100%', height: '100%' }, children: isVideo ? (_jsx("video", { ref: overlayRef, className: "taptapp-ar-overlay-element", src: config.videoSrc, preload: "auto", loop: true, playsInline: true, muted: true, crossOrigin: "anonymous" })) : (_jsx("img", { ref: overlayRef, className: "taptapp-ar-overlay-element", src: config.videoSrc || config.targetImageSrc, crossOrigin: "anonymous", alt: "AR Overlay" })) }), trackedPoints.length > 0 && (_jsx("div", { className: "taptapp-ar-points-overlay", style: { opacity: status === "tracking" ? 1 : 0.6 }, children: trackedPoints
|
|
16
16
|
.map((point, i) => {
|
|
17
17
|
// 🚀 Reflex visualization of the engine's new sensitivity
|
|
18
18
|
const isStable = point.stability > 0.3 && point.reliability > 0.2;
|
|
@@ -89,6 +89,17 @@ export const TaptappAR = ({ config, className = "", showScanningOverlay = true,
|
|
|
89
89
|
font-weight: 500;
|
|
90
90
|
letter-spacing: 0.5px;
|
|
91
91
|
}
|
|
92
|
+
.loading-spinner {
|
|
93
|
+
width: 40px;
|
|
94
|
+
height: 40px;
|
|
95
|
+
border: 3px solid rgba(255,255,255,0.1);
|
|
96
|
+
border-radius: 50%;
|
|
97
|
+
border-top-color: #00e5ff;
|
|
98
|
+
animation: spin 1s ease-in-out infinite;
|
|
99
|
+
}
|
|
100
|
+
@keyframes spin {
|
|
101
|
+
to { transform: rotate(360deg); }
|
|
102
|
+
}
|
|
92
103
|
.error-icon { font-size: 3rem; margin-bottom: 10px; }
|
|
93
104
|
.error-title { font-size: 1.2rem; font-weight: bold; margin: 0; }
|
|
94
105
|
.error-text { opacity: 0.8; margin: 5px 0 20px; }
|
|
@@ -104,12 +115,15 @@ export const TaptappAR = ({ config, className = "", showScanningOverlay = true,
|
|
|
104
115
|
}
|
|
105
116
|
.retry-btn:active { transform: scale(0.95); }
|
|
106
117
|
.taptapp-ar-overlay-element {
|
|
107
|
-
display:
|
|
108
|
-
|
|
118
|
+
display: none; /* Controlled by tracker */
|
|
119
|
+
position: absolute;
|
|
120
|
+
top: 0;
|
|
121
|
+
left: 0;
|
|
122
|
+
width: auto;
|
|
109
123
|
height: auto;
|
|
110
|
-
opacity: 0;
|
|
111
124
|
pointer-events: none;
|
|
112
|
-
|
|
125
|
+
z-index: 10;
|
|
126
|
+
/* Will be positioned via matrix3d by track.ts */
|
|
113
127
|
}
|
|
114
128
|
.taptapp-ar-points-overlay {
|
|
115
129
|
position: absolute;
|
package/dist/react/types.d.ts
CHANGED
package/dist/react/use-ar.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ARConfig } from "./types.js";
|
|
2
|
-
export type ARStatus = "scanning" | "tracking" | "error";
|
|
2
|
+
export type ARStatus = "compiling" | "scanning" | "tracking" | "error";
|
|
3
3
|
export interface TrackedPoint {
|
|
4
4
|
x: number;
|
|
5
5
|
y: number;
|
|
@@ -13,5 +13,6 @@ export interface UseARReturn {
|
|
|
13
13
|
isPlaying: boolean;
|
|
14
14
|
toggleVideo: () => Promise<void>;
|
|
15
15
|
trackedPoints: TrackedPoint[];
|
|
16
|
+
error: string | null;
|
|
16
17
|
}
|
|
17
18
|
export declare const useAR: (config: ARConfig) => UseARReturn;
|
package/dist/react/use-ar.js
CHANGED
|
@@ -5,6 +5,7 @@ export const useAR = (config) => {
|
|
|
5
5
|
const [status, setStatus] = useState("scanning");
|
|
6
6
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
7
7
|
const [trackedPoints, setTrackedPoints] = useState([]);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
8
9
|
const arInstanceRef = useRef(null);
|
|
9
10
|
const toggleVideo = useCallback(async () => {
|
|
10
11
|
const overlay = overlayRef.current;
|
|
@@ -31,65 +32,70 @@ export const useAR = (config) => {
|
|
|
31
32
|
const initAR = async () => {
|
|
32
33
|
try {
|
|
33
34
|
// Safe hybrid import for SSR + Speed
|
|
34
|
-
const {
|
|
35
|
+
const { createTracker } = await import("../runtime/track.js");
|
|
35
36
|
if (!isMounted)
|
|
36
37
|
return;
|
|
37
|
-
|
|
38
|
+
setStatus("compiling");
|
|
39
|
+
const instance = await createTracker({
|
|
38
40
|
container: containerRef.current,
|
|
39
|
-
targetSrc: config.targetTaarSrc,
|
|
41
|
+
targetSrc: config.targetTaarSrc || config.targetImageSrc,
|
|
40
42
|
overlay: overlayRef.current,
|
|
41
43
|
scale: config.scale,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
onFound: async ({ targetIndex }) => {
|
|
56
|
-
console.log(`🎯 Target ${targetIndex} detected!`);
|
|
57
|
-
if (!isMounted)
|
|
58
|
-
return;
|
|
59
|
-
setStatus("tracking");
|
|
60
|
-
const overlay = overlayRef.current;
|
|
61
|
-
if (overlay instanceof HTMLVideoElement) {
|
|
62
|
-
try {
|
|
63
|
-
await overlay.play();
|
|
64
|
-
setIsPlaying(true);
|
|
44
|
+
debugMode: false,
|
|
45
|
+
callbacks: {
|
|
46
|
+
onUpdate: (data) => {
|
|
47
|
+
const { screenCoords, reliabilities, stabilities } = data;
|
|
48
|
+
if (screenCoords && reliabilities && stabilities) {
|
|
49
|
+
const points = screenCoords.map((p, i) => ({
|
|
50
|
+
x: p.x,
|
|
51
|
+
y: p.y,
|
|
52
|
+
reliability: reliabilities[i],
|
|
53
|
+
stability: stabilities[i]
|
|
54
|
+
}));
|
|
55
|
+
setTrackedPoints(points);
|
|
65
56
|
}
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
},
|
|
58
|
+
onFound: async ({ targetIndex }) => {
|
|
59
|
+
console.log(`🎯 Target ${targetIndex} detected!`);
|
|
60
|
+
if (!isMounted)
|
|
61
|
+
return;
|
|
62
|
+
setStatus("tracking");
|
|
63
|
+
const overlay = overlayRef.current;
|
|
64
|
+
if (overlay instanceof HTMLVideoElement) {
|
|
65
|
+
try {
|
|
66
|
+
await overlay.play();
|
|
67
|
+
setIsPlaying(true);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.warn("Auto-play blocked:", err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
onLost: ({ targetIndex }) => {
|
|
75
|
+
console.log(`👋 Target ${targetIndex} lost`);
|
|
76
|
+
if (!isMounted)
|
|
77
|
+
return;
|
|
78
|
+
setStatus("scanning");
|
|
79
|
+
setTrackedPoints([]);
|
|
80
|
+
const overlay = overlayRef.current;
|
|
81
|
+
if (overlay instanceof HTMLVideoElement) {
|
|
82
|
+
overlay.pause();
|
|
83
|
+
setIsPlaying(false);
|
|
68
84
|
}
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
onLost: ({ targetIndex }) => {
|
|
72
|
-
console.log(`👋 Target ${targetIndex} lost`);
|
|
73
|
-
if (!isMounted)
|
|
74
|
-
return;
|
|
75
|
-
setStatus("scanning");
|
|
76
|
-
setTrackedPoints([]);
|
|
77
|
-
const overlay = overlayRef.current;
|
|
78
|
-
if (overlay instanceof HTMLVideoElement) {
|
|
79
|
-
overlay.pause();
|
|
80
|
-
setIsPlaying(false);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
});
|
|
84
88
|
arInstanceRef.current = instance;
|
|
85
|
-
await instance.
|
|
89
|
+
await instance.startCamera();
|
|
86
90
|
if (isMounted)
|
|
87
91
|
setStatus("scanning");
|
|
88
92
|
}
|
|
89
93
|
catch (err) {
|
|
90
|
-
console.error("
|
|
91
|
-
if (isMounted)
|
|
94
|
+
console.error("❌ [TapTapp AR] Error durante la inicialización:", err);
|
|
95
|
+
if (isMounted) {
|
|
96
|
+
setError(err.message || String(err));
|
|
92
97
|
setStatus("error");
|
|
98
|
+
}
|
|
93
99
|
}
|
|
94
100
|
};
|
|
95
101
|
initAR();
|
|
@@ -98,13 +104,14 @@ export const useAR = (config) => {
|
|
|
98
104
|
arInstanceRef.current?.stop();
|
|
99
105
|
arInstanceRef.current = null;
|
|
100
106
|
};
|
|
101
|
-
}, [config.targetTaarSrc, config.scale]);
|
|
107
|
+
}, [config.targetTaarSrc, config.targetImageSrc, config.scale]);
|
|
102
108
|
return {
|
|
103
109
|
containerRef,
|
|
104
110
|
overlayRef,
|
|
105
111
|
status,
|
|
106
112
|
isPlaying,
|
|
107
113
|
toggleVideo,
|
|
108
|
-
trackedPoints
|
|
114
|
+
trackedPoints,
|
|
115
|
+
error
|
|
109
116
|
};
|
|
110
117
|
};
|
package/dist/runtime/index.d.ts
CHANGED
package/dist/runtime/index.js
CHANGED