@srsergio/taptapp-ar 1.0.7 → 1.0.8
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 +5 -43
- package/package.json +2 -5
- package/src/astro/ARScene.astro +0 -59
- package/src/astro/ARVideoTrigger.astro +0 -73
- package/src/astro/overlays/ErrorOverlay.astro +0 -40
- package/src/astro/overlays/LoadingOverlay.astro +0 -28
- package/src/astro/overlays/ScanningOverlay.astro +0 -119
- package/src/astro/scripts/ARScripts.astro +0 -118
- package/src/astro/styles/ARStyles.astro +0 -147
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# @srsergio/taptapp-ar
|
|
2
2
|
|
|
3
|
-
🚀 **TapTapp AR** is a high-performance Augmented Reality (AR) toolkit
|
|
3
|
+
🚀 **TapTapp AR** is a high-performance Augmented Reality (AR) compiler toolkit for **Node.js** and **Browser** environments. It provides an ultra-fast offline compiler for image targets.
|
|
4
4
|
|
|
5
|
-
Built
|
|
5
|
+
Built with performance in mind, this package features a **pure JavaScript offline compiler** that requires **no TensorFlow** for compilation, generating high-quality `.mind` files in record time.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## 🌟 Key Features
|
|
10
10
|
|
|
11
|
-
- 🚀 **Astro Native**: Optimized components for Astro's Islands architecture.
|
|
12
11
|
- 🖼️ **Ultra-Fast Offline Compiler**: Pure JavaScript compiler that generates `.mind` target files in **~1.3s per image**.
|
|
13
12
|
- ⚡ **Zero TensorFlow for Compilation**: The offline compiler uses optimized pure JS algorithms - no TensorFlow installation required.
|
|
14
13
|
- 🧵 **Multi-threaded Engine**: Truly parallel processing using Node.js `worker_threads` for bulk image compilation.
|
|
15
14
|
- 🚀 **Serverless Ready**: Lightweight compiler with minimal dependencies, perfect for Vercel, AWS Lambda, and Netlify.
|
|
15
|
+
- 📦 **Protocol V3 (Columnar Binary)**: Industry-leading performance with zero-copy loading and 80%+ smaller files.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -26,34 +26,6 @@ npm install @srsergio/taptapp-ar
|
|
|
26
26
|
|
|
27
27
|
> **Note:** TensorFlow is **NOT required** for the offline compiler. It only uses pure JavaScript.
|
|
28
28
|
|
|
29
|
-
For real-time AR tracking in the browser, TensorFlow.js is loaded automatically via CDN.
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 🚀 Astro Integration Guide
|
|
34
|
-
|
|
35
|
-
The easiest way to display AR content is using the `ARVideoTrigger` component.
|
|
36
|
-
|
|
37
|
-
### Usage
|
|
38
|
-
|
|
39
|
-
```astro
|
|
40
|
-
---
|
|
41
|
-
import ARVideoTrigger from '@srsergio/taptapp-ar/astro/ARVideoTrigger.astro';
|
|
42
|
-
|
|
43
|
-
const config = {
|
|
44
|
-
cardId: 'unique-id',
|
|
45
|
-
targetImageSrc: 'https://cdn.example.com/target.jpg',
|
|
46
|
-
targetMindSrc: 'https://cdn.example.com/targets.mind',
|
|
47
|
-
videoSrc: 'https://cdn.example.com/overlay.mp4',
|
|
48
|
-
videoWidth: 1280,
|
|
49
|
-
videoHeight: 720,
|
|
50
|
-
scale: 1.2,
|
|
51
|
-
};
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
<ARVideoTrigger config={config} />
|
|
55
|
-
```
|
|
56
|
-
|
|
57
29
|
---
|
|
58
30
|
|
|
59
31
|
## 🖼️ High-Performance Compiler (Protocol V3)
|
|
@@ -83,7 +55,7 @@ TaptApp AR features the industry's most advanced **pure JavaScript** offline com
|
|
|
83
55
|
Optimized for server-side compilation with multi-core parallelism:
|
|
84
56
|
|
|
85
57
|
```javascript
|
|
86
|
-
import { OfflineCompiler } from '@srsergio/taptapp-ar
|
|
58
|
+
import { OfflineCompiler } from '@srsergio/taptapp-ar';
|
|
87
59
|
|
|
88
60
|
const compiler = new OfflineCompiler();
|
|
89
61
|
|
|
@@ -100,22 +72,12 @@ const binaryBuffer = compiler.exportData(); // Yields a much smaller .mind file
|
|
|
100
72
|
### 🌐 Frontend (Zero-Latency Loading)
|
|
101
73
|
|
|
102
74
|
```javascript
|
|
103
|
-
import { OfflineCompiler } from '@srsergio/taptapp-ar
|
|
75
|
+
import { OfflineCompiler } from '@srsergio/taptapp-ar';
|
|
104
76
|
|
|
105
77
|
const compiler = new OfflineCompiler();
|
|
106
78
|
// Loading 127KB instead of 800KB saves bandwidth and CPU parsing time
|
|
107
79
|
compiler.importData(binaryBuffer);
|
|
108
80
|
```
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## ❓ Troubleshooting
|
|
112
|
-
|
|
113
|
-
| Issue | Solution |
|
|
114
|
-
| :--- | :--- |
|
|
115
|
-
| **Camera not starting** | Ensure your site is served via `HTTPS`. Browsers block camera access on insecure origins. |
|
|
116
|
-
| **Video not playing** | iOS Safari requires `muted` and `playsinline` attributes for autoplaying videos. Our components handle this by default. |
|
|
117
|
-
| **CORS errors** | Ensure that `targetImageSrc`, `targetMindSrc`, and `videoSrc` have CORS headers enabled (`Access-Control-Allow-Origin: *`). |
|
|
118
|
-
| **Memory Outage on Serverless** | Reduce the resolution of your target images. High-res images increase memory pressure during compilation. |
|
|
119
81
|
|
|
120
82
|
---
|
|
121
83
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@srsergio/taptapp-ar",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "AR
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"description": "AR Compiler for Node.js and Browser",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/srsergiolazaro/taptapp-ar.git"
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"types": "./dist/index.d.ts",
|
|
20
20
|
"import": "./dist/index.js"
|
|
21
21
|
},
|
|
22
|
-
"./astro/*": "./src/astro/*",
|
|
23
22
|
"./compiler/*": "./src/compiler/*"
|
|
24
23
|
},
|
|
25
24
|
"files": [
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
},
|
|
35
34
|
"peerDependencies": {
|
|
36
35
|
"aframe": ">=1.5.0",
|
|
37
|
-
"astro": ">=4.0.0",
|
|
38
36
|
"react": ">=18.0.0",
|
|
39
37
|
"react-dom": ">=18.0.0",
|
|
40
38
|
"three": ">=0.160.0"
|
|
@@ -48,7 +46,6 @@
|
|
|
48
46
|
"@types/react": "^18.3.3",
|
|
49
47
|
"@types/react-dom": "^18.3.0",
|
|
50
48
|
"@types/three": "^0.170.0",
|
|
51
|
-
"astro": "5.16.4",
|
|
52
49
|
"jimp": "^1.6.0",
|
|
53
50
|
"typescript": "^5.4.5",
|
|
54
51
|
"vitest": "^4.0.16"
|
package/src/astro/ARScene.astro
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { PropsConfig } from "../react/types";
|
|
3
|
-
interface Props {
|
|
4
|
-
config: PropsConfig;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const { config } = Astro.props;
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
<a-scene
|
|
11
|
-
mindar-image={`imageTargetSrc: ${config.targetMindSrc};uiLoading: #loading-overlay;uiScanning: #scanning-overlay;uiError: #error-overlay`}
|
|
12
|
-
color-space="sRGB"
|
|
13
|
-
renderer="colorManagement: true, physicallyCorrectLights"
|
|
14
|
-
vr-mode-ui="enabled: false"
|
|
15
|
-
device-orientation-permission-ui="enabled: false"
|
|
16
|
-
>
|
|
17
|
-
<a-assets>
|
|
18
|
-
<img id="target-image" crossorigin="anonymous" src={config.targetImageSrc} />
|
|
19
|
-
<video
|
|
20
|
-
id="ar-video"
|
|
21
|
-
src={config.videoSrc}
|
|
22
|
-
preload="auto"
|
|
23
|
-
loop
|
|
24
|
-
autoplay
|
|
25
|
-
playsinline
|
|
26
|
-
webkit-playsinline
|
|
27
|
-
muted
|
|
28
|
-
crossorigin="anonymous"
|
|
29
|
-
class="absolute opacity-0"
|
|
30
|
-
width="1"
|
|
31
|
-
height="1"></video></a-assets
|
|
32
|
-
>
|
|
33
|
-
<a-camera position="0 0 0" look-controls="enabled: false"></a-camera>
|
|
34
|
-
|
|
35
|
-
<a-entity mindar-image-target="targetIndex: 0">
|
|
36
|
-
<a-video
|
|
37
|
-
id="main-video"
|
|
38
|
-
src="#ar-video"
|
|
39
|
-
position="0 0 0"
|
|
40
|
-
opacity="1"
|
|
41
|
-
width={(config.videoWidth / config.videoHeight) * config.scale}
|
|
42
|
-
height={1 * config.scale}
|
|
43
|
-
rotation="0 0 0"
|
|
44
|
-
visible="true"
|
|
45
|
-
play-on-click
|
|
46
|
-
autoplay></a-video>
|
|
47
|
-
</a-entity>
|
|
48
|
-
</a-scene>
|
|
49
|
-
|
|
50
|
-
<style>
|
|
51
|
-
video {
|
|
52
|
-
width: 100% !important;
|
|
53
|
-
height: 100% !important;
|
|
54
|
-
object-fit: cover !important;
|
|
55
|
-
position: absolute !important;
|
|
56
|
-
top: 0 !important;
|
|
57
|
-
left: 0 !important;
|
|
58
|
-
}
|
|
59
|
-
</style>
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import ARStyles from "./styles/ARStyles.astro";
|
|
3
|
-
import LoadingOverlay from "./overlays/LoadingOverlay.astro";
|
|
4
|
-
import ScanningOverlay from "./overlays/ScanningOverlay.astro";
|
|
5
|
-
import ErrorOverlay from "./overlays/ErrorOverlay.astro";
|
|
6
|
-
import ARScene from "./ARScene.astro";
|
|
7
|
-
import ARScripts from "./scripts/ARScripts.astro";
|
|
8
|
-
import type { PropsConfig } from "../react/types";
|
|
9
|
-
interface Props {
|
|
10
|
-
config: PropsConfig;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const {config} = Astro.props ;
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
<!doctype html>
|
|
17
|
-
<html lang="es-PE">
|
|
18
|
-
<head>
|
|
19
|
-
<meta charset="UTF-8" />
|
|
20
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
21
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
22
|
-
<meta name="robots" content="index, follow" />
|
|
23
|
-
<link rel="canonical" href="https://go.taptapp.xyz" />
|
|
24
|
-
|
|
25
|
-
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
26
|
-
<link rel="icon" href="/favicon.svg" type="image/svg+xml" sizes="any" />
|
|
27
|
-
<meta name="theme-color" content="#3367D6" />
|
|
28
|
-
<meta
|
|
29
|
-
name="description"
|
|
30
|
-
content="Crea impacto duradero y genera confianza en tus clientes con la tarjeta digital TapTapp. Presenta tu información de manera clara y atractiva para conectar con el futuro."
|
|
31
|
-
/>
|
|
32
|
-
<meta name="keywords" content="tarjeta digital, identidad, futuro, confianza, clientes" />
|
|
33
|
-
<meta name="author" content="@srsergiolazaro" />
|
|
34
|
-
|
|
35
|
-
<meta property="og:title" content="TapTapp AR Experience" />
|
|
36
|
-
<meta
|
|
37
|
-
property="og:description"
|
|
38
|
-
content="Descubre nuestra experiencia de realidad aumentada y da vida a tu tarjeta digital TapTapp."
|
|
39
|
-
/>
|
|
40
|
-
<meta property="og:image" content="https://go.taptapp.xyz/Imgsocial.jpg" />
|
|
41
|
-
<meta property="og:url" content="https://go.taptapp.xyz" />
|
|
42
|
-
<link rel="manifest" href="/manifest.webmanifest" crossorigin="anonymous" />
|
|
43
|
-
|
|
44
|
-
<title>TapTapp AR Experience</title>
|
|
45
|
-
<script is:inline src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
|
|
46
|
-
<script is:inline src="https://r2-worker.sergiolazaromondargo.workers.dev/taptapp-ar.prod.js"
|
|
47
|
-
></script>
|
|
48
|
-
<link
|
|
49
|
-
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap"
|
|
50
|
-
rel="stylesheet"
|
|
51
|
-
/>
|
|
52
|
-
<ARStyles />
|
|
53
|
-
<ARScripts />
|
|
54
|
-
<style>
|
|
55
|
-
body {
|
|
56
|
-
font-family: "Montserrat", sans-serif;
|
|
57
|
-
margin: 0;
|
|
58
|
-
overflow: hidden;
|
|
59
|
-
}
|
|
60
|
-
@view-transition {
|
|
61
|
-
navigation: auto;
|
|
62
|
-
}
|
|
63
|
-
</style>
|
|
64
|
-
</head>
|
|
65
|
-
<body>
|
|
66
|
-
<!-- Custom UI Overlays -->
|
|
67
|
-
<LoadingOverlay />
|
|
68
|
-
<ScanningOverlay targetImage={config.targetImageSrc} />
|
|
69
|
-
<ErrorOverlay />
|
|
70
|
-
|
|
71
|
-
<ARScene config={config} />
|
|
72
|
-
</body>
|
|
73
|
-
</html>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<div id="error-overlay" class="custom-overlay hidden bg-gradient-to-br from-red-700 to-purple-700">
|
|
2
|
-
<div class="mb-5 text-5xl">⚠️</div>
|
|
3
|
-
<div class="font-semibold tracking-wide text-white/95 text-xl">No se pudo iniciar</div>
|
|
4
|
-
<div class="mt-3 max-w-[80%] text-center font-light text-white/75 text-sm">
|
|
5
|
-
Verifique los permisos de cámara o intente con otro dispositivo
|
|
6
|
-
</div>
|
|
7
|
-
<button
|
|
8
|
-
onclick="location.reload()"
|
|
9
|
-
class="mt-6 rounded-lg bg-blue-500 px-6 py-2.5 font-semibold text-white transition-all hover:bg-blue-600 hover:shadow-lg"
|
|
10
|
-
>
|
|
11
|
-
Reintentar
|
|
12
|
-
</button>
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
<style>
|
|
16
|
-
#error-overlay {
|
|
17
|
-
background: linear-gradient(135deg, #c0392b, #8e44ad);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.error-icon {
|
|
21
|
-
font-size: 50px;
|
|
22
|
-
margin-bottom: 20px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.retry-button {
|
|
26
|
-
margin-top: 20px;
|
|
27
|
-
padding: 10px 20px;
|
|
28
|
-
background-color: #3498db;
|
|
29
|
-
color: white;
|
|
30
|
-
border: none;
|
|
31
|
-
border-radius: 5px;
|
|
32
|
-
font-weight: 600;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
transition: background-color 0.3s ease;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.retry-button:hover {
|
|
38
|
-
background-color: #2980b9;
|
|
39
|
-
}
|
|
40
|
-
</style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<div id="loading-overlay" class="custom-overlay bg-gradient-to-br from-gray-800 to-gray-900">
|
|
2
|
-
<div class="loader"></div>
|
|
3
|
-
<div class="mt-5 font-semibold tracking-wide text-white/95 text-xl">Preparando...</div>
|
|
4
|
-
<div class="mt-3 max-w-[80%] text-center font-light text-white/75 text-sm">
|
|
5
|
-
Un momento mientras optimizamos su experiencia
|
|
6
|
-
</div>
|
|
7
|
-
</div>
|
|
8
|
-
|
|
9
|
-
<style>
|
|
10
|
-
.loader {
|
|
11
|
-
width: 60px;
|
|
12
|
-
height: 60px;
|
|
13
|
-
border: 5px solid rgba(255, 255, 255, 0.2);
|
|
14
|
-
border-top: 5px solid #3498db;
|
|
15
|
-
border-radius: 50%;
|
|
16
|
-
animation: spin 1s linear infinite;
|
|
17
|
-
margin-bottom: 20px;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@keyframes spin {
|
|
21
|
-
0% {
|
|
22
|
-
transform: rotate(0deg);
|
|
23
|
-
}
|
|
24
|
-
100% {
|
|
25
|
-
transform: rotate(360deg);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
</style>
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
targetImage?: string;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const { targetImage } = Astro.props;
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<div
|
|
10
|
-
id="scanning-overlay"
|
|
11
|
-
class="custom-overlay relative flex flex-col items-center justify-center"
|
|
12
|
-
>
|
|
13
|
-
<div class="scan-region relative mb-8 h-[300px] w-[300px] overflow-hidden">
|
|
14
|
-
<!-- Esquinas del recuadro de escaneo -->
|
|
15
|
-
<div class="corner top-left"></div>
|
|
16
|
-
<div class="corner top-right"></div>
|
|
17
|
-
<div class="corner bottom-left"></div>
|
|
18
|
-
<div class="corner bottom-right"></div>
|
|
19
|
-
|
|
20
|
-
<div class="absolute inset-0 p-6">
|
|
21
|
-
<img id="target-preview" src={targetImage} class="h-full w-full object-contain opacity-90" />
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
<div class="scan-animation"></div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div class="font-semibold tracking-wide text-white/95 text-2xl">Escaneando...</div>
|
|
28
|
-
<div class="mt-3 max-w-[80%] text-center font-light text-white/75 text-sm">
|
|
29
|
-
Centre el sticker dentro del marco
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<style>
|
|
34
|
-
.scan-region img {
|
|
35
|
-
width: 100%;
|
|
36
|
-
height: 100%;
|
|
37
|
-
object-fit: contain;
|
|
38
|
-
opacity: 0.7;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.scan-animation {
|
|
42
|
-
position: absolute;
|
|
43
|
-
top: 0;
|
|
44
|
-
left: 0;
|
|
45
|
-
width: 100%;
|
|
46
|
-
height: 2px;
|
|
47
|
-
background: linear-gradient(
|
|
48
|
-
90deg,
|
|
49
|
-
rgba(52, 152, 219, 0),
|
|
50
|
-
rgba(52, 152, 219, 0.8),
|
|
51
|
-
rgba(155, 89, 182, 0.8),
|
|
52
|
-
rgba(52, 152, 219, 0)
|
|
53
|
-
);
|
|
54
|
-
box-shadow:
|
|
55
|
-
0 0 10px rgba(52, 152, 219, 0.7),
|
|
56
|
-
0 0 20px rgba(155, 89, 182, 0.4);
|
|
57
|
-
animation: scan 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@keyframes scan {
|
|
61
|
-
0% {
|
|
62
|
-
transform: translateY(0);
|
|
63
|
-
opacity: 0.8;
|
|
64
|
-
}
|
|
65
|
-
15% {
|
|
66
|
-
opacity: 1;
|
|
67
|
-
}
|
|
68
|
-
50% {
|
|
69
|
-
transform: translateY(298px);
|
|
70
|
-
opacity: 1;
|
|
71
|
-
}
|
|
72
|
-
85% {
|
|
73
|
-
opacity: 0.8;
|
|
74
|
-
}
|
|
75
|
-
100% {
|
|
76
|
-
transform: translateY(0);
|
|
77
|
-
opacity: 0.8;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/* Estilos para las esquinas */
|
|
82
|
-
.corner {
|
|
83
|
-
position: absolute;
|
|
84
|
-
width: 24px;
|
|
85
|
-
height: 24px;
|
|
86
|
-
border-color: white;
|
|
87
|
-
border-style: solid;
|
|
88
|
-
opacity: 0.7;
|
|
89
|
-
z-index: 1;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.top-left {
|
|
93
|
-
top: 6px;
|
|
94
|
-
left: 6px;
|
|
95
|
-
border-width: 2px 0 0 2px;
|
|
96
|
-
border-top-left-radius: 6px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.top-right {
|
|
100
|
-
top: 6px;
|
|
101
|
-
right: 6px;
|
|
102
|
-
border-width: 2px 2px 0 0;
|
|
103
|
-
border-top-right-radius: 6px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.bottom-left {
|
|
107
|
-
bottom: 6px;
|
|
108
|
-
left: 6px;
|
|
109
|
-
border-width: 0 0 2px 2px;
|
|
110
|
-
border-bottom-left-radius: 6px;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.bottom-right {
|
|
114
|
-
bottom: 6px;
|
|
115
|
-
right: 6px;
|
|
116
|
-
border-width: 0 2px 2px 0;
|
|
117
|
-
border-bottom-right-radius: 6px;
|
|
118
|
-
}
|
|
119
|
-
</style>
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
<script is:inline>
|
|
2
|
-
// Lógica mejorada para reproducción de video
|
|
3
|
-
let started = false;
|
|
4
|
-
let playing = false;
|
|
5
|
-
|
|
6
|
-
window.addEventListener("click", async function () {
|
|
7
|
-
try {
|
|
8
|
-
let video = document.querySelector("#ar-video");
|
|
9
|
-
let avideo = document.querySelector("a-video");
|
|
10
|
-
|
|
11
|
-
if (!video || !avideo) {
|
|
12
|
-
console.error("Elementos de video no encontrados");
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (!started) {
|
|
17
|
-
await video.play();
|
|
18
|
-
avideo.setAttribute("opacity", 1);
|
|
19
|
-
started = true;
|
|
20
|
-
playing = true;
|
|
21
|
-
} else {
|
|
22
|
-
if (playing) {
|
|
23
|
-
video.pause();
|
|
24
|
-
playing = false;
|
|
25
|
-
} else {
|
|
26
|
-
await video.play();
|
|
27
|
-
playing = true;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.error("Error en la reproducción del video:", error);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<script is:inline>
|
|
37
|
-
document.addEventListener("DOMContentLoaded", function () {
|
|
38
|
-
const scene = document.querySelector("a-scene");
|
|
39
|
-
const errorOverlay = document.getElementById("error-overlay");
|
|
40
|
-
const scanningOverlay = document.getElementById("scanning-overlay");
|
|
41
|
-
const videoEl = document.querySelector("#ar-video");
|
|
42
|
-
const mainVideo = document.querySelector("#main-video");
|
|
43
|
-
const targetImage = document.querySelector("#target-image");
|
|
44
|
-
|
|
45
|
-
if (!scene || !errorOverlay || !scanningOverlay || !videoEl || !mainVideo || !targetImage) {
|
|
46
|
-
console.error("Elementos críticos no encontrados");
|
|
47
|
-
if (errorOverlay) errorOverlay.classList.remove("hidden");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Verificación de recursos
|
|
52
|
-
targetImage.addEventListener("error", () => {
|
|
53
|
-
console.error("Error al cargar la imagen objetivo");
|
|
54
|
-
errorOverlay.classList.remove("hidden");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
videoEl.addEventListener("error", () => {
|
|
58
|
-
console.error("Error al cargar el video");
|
|
59
|
-
errorOverlay.classList.remove("hidden");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Gestión mejorada de errores AR
|
|
63
|
-
scene.addEventListener("arError", (event) => {
|
|
64
|
-
console.error("Error AR:", event);
|
|
65
|
-
errorOverlay.classList.remove("hidden");
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Verificar si MindAR está disponible
|
|
69
|
-
if (!window.MINDAR || !window.MINDAR.IMAGE) {
|
|
70
|
-
console.error("MindAR no está disponible");
|
|
71
|
-
errorOverlay.classList.remove("hidden");
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Manejo de eventos de target
|
|
76
|
-
const targetEntity = document.querySelector("a-entity[mindar-image-target]");
|
|
77
|
-
|
|
78
|
-
targetEntity.addEventListener("targetFound", () => {
|
|
79
|
-
console.log("¡Objetivo encontrado!");
|
|
80
|
-
scanningOverlay.classList.add("hidden");
|
|
81
|
-
|
|
82
|
-
// Hacer visible el video
|
|
83
|
-
mainVideo.setAttribute("opacity", "1");
|
|
84
|
-
|
|
85
|
-
// Intentar reproducir
|
|
86
|
-
videoEl.play().catch((err) => {
|
|
87
|
-
console.error("Error reproduciendo video:", err);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
targetEntity.addEventListener("targetLost", () => {
|
|
92
|
-
console.log("Objetivo perdido");
|
|
93
|
-
scanningOverlay.classList.remove("hidden");
|
|
94
|
-
mainVideo.setAttribute("opacity", "0");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Función para aplicar estilos adaptativos
|
|
98
|
-
function applyVideoStyles() {
|
|
99
|
-
// Estilos del elemento video HTML
|
|
100
|
-
if (videoEl) {
|
|
101
|
-
videoEl.style.width = "100%";
|
|
102
|
-
videoEl.style.height = "100%";
|
|
103
|
-
videoEl.style.objectFit = "contain";
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Aplicar estilos al inicio y cuando cambie la orientación
|
|
108
|
-
applyVideoStyles();
|
|
109
|
-
window.addEventListener("resize", applyVideoStyles);
|
|
110
|
-
|
|
111
|
-
// Manejar toques para dispositivos móviles
|
|
112
|
-
document.addEventListener("touchstart", () => {
|
|
113
|
-
if (videoEl.paused && mainVideo.getAttribute("opacity") === "1") {
|
|
114
|
-
videoEl.play().catch((e) => console.log("Error en touchstart:", e));
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
</script>
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
<style is:global>
|
|
2
|
-
/* Estilos globales básicos de A-Frame */
|
|
3
|
-
.a-enter-vr,
|
|
4
|
-
.a-enter-vr-button {
|
|
5
|
-
display: none !important;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
body,
|
|
9
|
-
a-scene {
|
|
10
|
-
background-color: transparent !important;
|
|
11
|
-
font-family: "Montserrat", sans-serif;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.a-canvas {
|
|
15
|
-
background-color: transparent !important;
|
|
16
|
-
width: 100% !important;
|
|
17
|
-
height: 100% !important;
|
|
18
|
-
position: absolute !important;
|
|
19
|
-
top: 0 !important;
|
|
20
|
-
left: 0 !important;
|
|
21
|
-
right: 0 !important;
|
|
22
|
-
bottom: 0 !important;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* Clase base compartida para overlays */
|
|
26
|
-
.custom-overlay {
|
|
27
|
-
position: fixed;
|
|
28
|
-
top: 0;
|
|
29
|
-
left: 0;
|
|
30
|
-
width: 100%;
|
|
31
|
-
height: 100%;
|
|
32
|
-
display: flex;
|
|
33
|
-
flex-direction: column;
|
|
34
|
-
justify-content: center;
|
|
35
|
-
align-items: center;
|
|
36
|
-
z-index: 999;
|
|
37
|
-
color: white;
|
|
38
|
-
text-align: center;
|
|
39
|
-
transition: opacity 0.5s ease;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.custom-overlay.hidden {
|
|
43
|
-
display: none;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/* Texto compartido */
|
|
47
|
-
.status-text {
|
|
48
|
-
font-size: 18px;
|
|
49
|
-
font-weight: 600;
|
|
50
|
-
margin-top: 20px;
|
|
51
|
-
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.instruction-text {
|
|
55
|
-
font-size: 14px;
|
|
56
|
-
max-width: 80%;
|
|
57
|
-
margin-top: 10px;
|
|
58
|
-
opacity: 0.8;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/* Estilos para las pantallas de UI personalizadas */
|
|
62
|
-
.custom-overlay {
|
|
63
|
-
position: fixed;
|
|
64
|
-
top: 0;
|
|
65
|
-
left: 0;
|
|
66
|
-
width: 100%;
|
|
67
|
-
height: 100%;
|
|
68
|
-
display: flex;
|
|
69
|
-
flex-direction: column;
|
|
70
|
-
justify-content: center;
|
|
71
|
-
align-items: center;
|
|
72
|
-
z-index: 999;
|
|
73
|
-
background-color: rgba(0, 0, 0, 0);
|
|
74
|
-
color: white;
|
|
75
|
-
text-align: center;
|
|
76
|
-
transition: opacity 0.5s ease;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.custom-overlay.hidden {
|
|
80
|
-
display: none;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/* Pantalla de carga */
|
|
84
|
-
#loading-overlay {
|
|
85
|
-
background: linear-gradient(135deg, #2c3e50, #1a1a2e);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.loader {
|
|
89
|
-
width: 60px;
|
|
90
|
-
height: 60px;
|
|
91
|
-
border: 5px solid rgba(255, 255, 255, 0.2);
|
|
92
|
-
border-top: 5px solid #3498db;
|
|
93
|
-
border-radius: 50%;
|
|
94
|
-
animation: spin 1s linear infinite;
|
|
95
|
-
margin-bottom: 20px;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@keyframes spin {
|
|
99
|
-
0% {
|
|
100
|
-
transform: rotate(0deg);
|
|
101
|
-
}
|
|
102
|
-
100% {
|
|
103
|
-
transform: rotate(360deg);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* Pantalla de error */
|
|
108
|
-
#error-overlay {
|
|
109
|
-
background: linear-gradient(135deg, #c0392b, #8e44ad);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.error-icon {
|
|
113
|
-
font-size: 50px;
|
|
114
|
-
margin-bottom: 20px;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/* Pantalla de escaneo */
|
|
118
|
-
#scanning-overlay {
|
|
119
|
-
background-color: rgba(0, 0, 0, 0);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/* Botón para reintentar */
|
|
123
|
-
.retry-button {
|
|
124
|
-
margin-top: 20px;
|
|
125
|
-
padding: 10px 20px;
|
|
126
|
-
background-color: #3498db;
|
|
127
|
-
color: white;
|
|
128
|
-
border: none;
|
|
129
|
-
border-radius: 5px;
|
|
130
|
-
font-weight: 600;
|
|
131
|
-
cursor: pointer;
|
|
132
|
-
transition: background-color 0.3s ease;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.retry-button:hover {
|
|
136
|
-
background-color: #2980b9;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
video {
|
|
140
|
-
width: 100% !important;
|
|
141
|
-
height: 100% !important;
|
|
142
|
-
object-fit: cover !important;
|
|
143
|
-
position: absolute !important;
|
|
144
|
-
top: 0 !important;
|
|
145
|
-
left: 0 !important;
|
|
146
|
-
}
|
|
147
|
-
</style>
|