MindAR es una librería de Realidad Aumentada web open source (JS puro, TensorFlow.js + WebGL + Web Workers) que soporta Image Tracking y Face Tracking. Este estudio documenta de forma extensa en casos de uso (con código completo): image con A-Frame y Three.js, face + React, casos avanzados (UI, audio, dual) y las 4 arquitecturas de despliegue. Integra todo el conocimiento del OKF (3 repos, análisis de 15 repos, proyectos AR y 4 skills de despliegue).
mindar-minimal (image/face · A-Frame/Three.js · React · video · UI · 4 despliegues)
Anclar contenido 3D/video a imágenes físicas. CDN: mindar-image.prod.js + mindar-image-aframe.prod.js.
<head> — 3 scripts: SDK image + A-Frame + extensión image-aframe
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-image.prod.js"></script>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-image-aframe.prod.js"></script>
<a-scene mindar-image="imageTargetSrc: ./targets/card.mind; uiLoading: no; uiScanning: no; uiError: no"
vr-mode-ui="enabled: false" renderer="colorManagement: true, physicallyCorrectLights"
device-orientation-permission-ui="enabled: false">
<a-assets>
<img id="card" src="./card.png"/>
<a-asset-item id="avatarModel" src="./softmind/scene.gltf"></a-asset-item>
<video id="video" src="./video.mp4" playsinline webkit-playsinline muted loop></video>
</a-assets>
<a-camera position="0 0 0" look-controls="enabled: false"></a-camera>
<a-entity mindar-image-target="targetIndex: 0">
<a-plane src="#card" position="0 0 0" height="0.552" width="1"></a-plane>
<a-gltf-model src="#avatarModel" position="0 0 0.1" scale="0.005 0.005 0.005"
animation="property: position; to: 0 0.1 0.1; dur: 1000; loop: true; dir: alternate"></a-gltf-model>
<a-video src="#video" position="0 0 0.05" width="0.8" height="0.45"></a-video>
</a-entity>
</a-scene>
mindar-image-target se ancla al marcador detectado; los hijos (a-plane, a-gltf-model, a-video) se posicionan sobre él en coordenadas relativas.<a-scene mindar-image="imageTargetSrc: ./targets/multi.mind">
<a-entity mindar-image-target="targetIndex: 0">
<a-box color="red" position="0 0 0" scale="0.5 0.5 0.5"></a-box>
</a-entity>
<a-entity mindar-image-target="targetIndex: 1">
<a-sphere color="blue" position="0 0 0" radius="0.3"></a-sphere>
</a-entity>
</a-scene>
.mind puede contener varias imágenes; cada targetIndex enlaza el contenido a un marcador distinto (tarjetas, posters, museos).<script type="importmap">
{"imports":{"mind-ar":"https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-image-three.prod.js",
"three":"https://unpkg.com/three@0.140.0/build/three.module.js"}}
</script>
<script type="module">
import {MindARThree} from 'mind-ar';
const mindarThree = new MindARThree({container: document.body, imageTargetSrc: './targets/card.mind'});
const {renderer, scene, camera} = mindarThree;
const geo = new THREE.PlaneGeometry(1, 0.552);
const mat = new THREE.MeshBasicMaterial({color: '#f6ad55'});
scene.add(new THREE.Mesh(geo, mat));
await mindarThree.start();
renderer.setAnimationLoop(() => renderer.render(scene, camera));
</script>
MindARThree expone renderer/scene/camera; añades mallas con Three.js puro (geometría procedural, animaciones, luces) y setAnimationLoop renderiza. Base de casos tipo preplanter-ar (planta procedural).<a-entity mindar-image-target="targetIndex: 0">
<a-video src="#video" position="0 0 0.05" width="0.9" height="0.5" sound="on: true" autoplay></a-video>
</a-entity>
const ok = video.canPlayType('video/webm; codecs="vp9"') !== '';
video.src = ok ? 'v.webm' : 'v.mp4';Superponer contenido sobre el rostro (mediapipe face mesh, 468 puntos) y embeker MindAR en React con ciclo de vida correcto.
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-face.prod.js"></script>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-face-aframe.prod.js"></script>
<a-scene mindar-face="uiScanning: no" vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false">
<a-camera active="false" position="0 0 0"></a-camera>
<a-entity mindar-face-target>
<!-- anchorIndex 10 = puente de la nariz (para gafas) -->
<a-entity mindar-face-target="anchorIndex: 10" position="0 0 0.05">
<a-box position="-0.075 0 0" width="0.15" height="0.05" depth="0.02" color="black"></a-box>
<a-box position="0.075 0 0" width="0.15" height="0.05" depth="0.02" color="black"></a-box>
</a-entity>
</a-entity>
</a-scene>
mindar-face detecta la cara y mindar-face-target expone anclas (anchorIndex) por zona facial (10 = nariz, 4 = ojo…). El contenido se posiciona relativo a la ancla.// mindar-face-three.prod.js (import map con "three")
const mindarThree = new MindARThree({
container: document.body,
filterMinCF: 0.002, filterBeta: 0.1, // estabilización (reduce jitter)
});
const {renderer, scene, camera} = mindarThree;
// malla del face mesh (468 puntos) y superponer accesorios…
await mindarThree.start();
renderer.setAnimationLoop(() => renderer.render(scene, camera));
import {useEffect, useRef} from 'react';
function Viewer() {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
el.setAttribute('mindar-image', 'imageTargetSrc: /targets/card.mind');
return () => { // cleanup: detener cámara + liberar WebGL (SPA)
const c = el.components['mindar-image'].controller;
c.stop(); renderer.dispose?.();
};
}, []);
return <a-scene ref={ref} mindar-image=""></a-scene>;
}
controller.stop() + renderer.dispose()) es crítico al navegar fuera de la pestaña AR en una SPA.useEffect(() => {
const mindarThree = new MindARThree({container: el, imageTargetSrc: '/targets/card.mind'});
mindarThree.start();
el.appendChild(mindarThree.renderer.domElement);
return () => { mindarThree.stop(); }; // libera cámara y WebGL
}, []);
Pulir la experiencia AR y producir targets sin escribir código.
<!-- En el a-scene se apunta el overlay custom -->
<a-scene mindar-image="imageTargetSrc: ./targets/card.mind; uiScanning: #mi-overlay; uiLoading: no; uiError: no">
/* CSS: oculta el overlay nativo de MindAR */
.mindar-ui-overlay { display: none !important; }
<!-- HTML propio -->
<div id="mi-overlay" class="overlay-custom"><div class="spinner"></div><p>Apunta la cámara al marcador</p></div>
uiScanning apunta a un elemento propio; con !important se oculta el overlay nativo. Base del custom-ui.html de la doc oficial (usado en AR Membrillal).const target = document.querySelector('[mindar-image-target]');
const audio = document.querySelector('#narracion');
target.addEventListener('targetFound', () => {
audio.play(); status.textContent = '🎯 ¡Contenido encontrado!';
});
target.addEventListener('targetLost', () => {
audio.pause(); status.textContent = '🔍 Buscando el marcador…';
});
targetFound/targetLost permiten disparar audio, animaciones o UI cuando el marcador aparece/desaparece (patrón del browser-ar-runtime).function cambiarModo(modo) {
if (modo === 'image') { escenaImagen.style.display = 'block'; escenaRostro.style.display = 'none'; }
else { escenaImagen.style.display = 'none'; escenaRostro.style.display = 'block'; }
}
1. Compilador en el navegador → https://hiukim.github.io/mind-ar-js-doc/tools/compile
(subes una imagen → obtienes el .mind + el marcador imprimible)
2. MindAR Studio → https://studio.mindar.org (face tracking sin código, export estático)
3. Pictarize → https://pictarize.com (image tracking sin código, hosting)
4. Por CLI: npm install mind-ar-js y usar el compilador de la doc
.mind es un descriptor de features de la imagen; se genera con el compilador (web o CLI) y se referencia en imageTargetSrc.Cómo publicar una experiencia MindAR según el contexto (skills OKF despliegue-ar-*).
# Paquete standalone: HTML + SDK + .mind + assets todo embebido
cd experiencia
python -m http.server 8080 # abre http://localhost:8080 (necesita webcam)
# pip install flask — el portátil sirve y los celulares entran por IP local
from flask import Flask, send_from_directory
app = Flask(__name__, static_folder='experiencia')
@app.route('/')
def home(): return send_from_directory('experiencia', 'index.html')
app.run(host='0.0.0.0', port=8282) # celular: http://<ip-del-portatil>:8282
host='0.0.0.0' para acceso por IP local en el mismo WiFi.# Subir a gerardoesquivia.com (cPanel/FTPS), GitHub Pages u otro hosting.
# El celular accede por URL pública desde cualquier lugar.
# Ruta: /mindar/ → https://gerardoesquivia.com/mindar/
# Clave: CDN de MindAR o SDK local; rutas relativas para .mind + assets.
# assets/videos locales + librerías del motor desde CDN (o viceversa). Requiere internet parcial.
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/dist/mindar-image.prod.js"></script> # CDN
<video src="/assets/video.mp4"></video> # local
El token 🟠 recorre: compilar target → image → face → React → contenido → desplegar. Clic reinicia.
| Script / concepto | Qué hace |
|---|---|
mindar-image.prod.js + -aframe | SDK image tracking + extensión A-Frame |
mindar-face.prod.js + -aframe | SDK face tracking (mediapipe face mesh) |
mindar-image-three.prod.js | Integración Three.js directa (import map) |
.mind + targetIndex | Target compilado + índice del marcador |
mindar-image-target / mindar-face-target | Entidad anclada al marcador / rostro |
anchorIndex | Zona facial de anclaje (10 = nariz) |
targetFound / targetLost | Eventos de detección (audio/UI) |
uiScanning / .mindar-ui-overlay | Overlay custom / nativo |
MindARThree · controller.stop() | Three.js puro · cleanup React |
C:\Users\TUF\Documents\librerías\local\mind-ar-js\; para Arq 3/4 CDN. Docs: https://hiukim.github.io/mind-ar-js-doc/. Compilador: .../tools/compile.