Estudio de MindAR — Casos de Estudio

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).

Resumen con para qué y cómo, listo para pegar en tu OKF/Obsidian (el agente lo implementa sin gastar tokens).
🤖 Skill de implementación: mindar-minimal (image/face · A-Frame/Three.js · React · video · UI · 4 despliegues)

1 · Image Tracking (A-Frame y Three.js)

Anclar contenido 3D/video a imágenes físicas. CDN: mindar-image.prod.js + mindar-image-aframe.prod.js.

1.1 · Básico: marcador → modelo 3D (GLTF) + video A-Frame

<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>
🔁 Cómo funciona: mindar-image-target se ancla al marcador detectado; los hijos (a-plane, a-gltf-model, a-video) se posicionan sobre él en coordenadas relativas.

1.2 · Multi-targets (varios marcadores independientes) A-Frame

<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>
🔁 Cómo funciona: un solo .mind puede contener varias imágenes; cada targetIndex enlaza el contenido a un marcador distinto (tarjetas, posters, museos).

1.3 · Three.js puro (MindARThree, sin A-Frame) Three.js

<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>
🔁 Cómo funciona: 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).

1.4 · Video anclado al marcador (overlay de póster) Video

<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>
💡 Nota OKF (AR Membrillal): para videos transparentes, verificar si el navegador soporta WebM con canal alfa; si no (Safari iOS), alternar a MP4:
const ok = video.canPlayType('video/webm; codecs="vp9"') !== '';
video.src = ok ? 'v.webm' : 'v.mp4';

2 · Face Tracking y React

Superponer contenido sobre el rostro (mediapipe face mesh, 468 puntos) y embeker MindAR en React con ciclo de vida correcto.

2.1 · Probador de gafas (face target + ancla) A-Frame

<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>
🔁 Cómo funciona: 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.

2.2 · Face mesh con Three.js puro Three.js

// 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));
🔁 Cómo funciona: expone los 468 puntos 3D del face mesh (mediapipe) para anclar mallas, sombreros o efectos 2D sobre la cara.

2.3 · React + A-Frame (mindar-viewer) React

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>;
}
🔁 Cómo funciona: se envuelve la inicialización imperativa en hooks. El cleanup (controller.stop() + renderer.dispose()) es crítico al navegar fuera de la pestaña AR en una SPA.

2.4 · React + Three.js (mindar-three-viewer) React

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
}, []);
🔁 Cómo funciona: versión Three.js pura (sin A-Frame) con control granular de animaciones y luces; el cleanup evita que la cámara siga activa al desmontar.

3 · Casos Avanzados (UI, audio, dual, sin código)

Pulir la experiencia AR y producir targets sin escribir código.

3.1 · UI de escaneo personalizada (overlay premium) UI

<!-- 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>
🔁 Cómo funciona: 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).

3.2 · Audio y estado interactivo (targetFound / targetLost) Audio

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…';
});
🔁 Cómo funciona: los eventos targetFound/targetLost permiten disparar audio, animaciones o UI cuando el marcador aparece/desaparece (patrón del browser-ar-runtime).

3.3 · Arquitectura dual Image + Face (modos conmutable) Dual

function cambiarModo(modo) {
  if (modo === 'image') { escenaImagen.style.display = 'block'; escenaRostro.style.display = 'none'; }
  else { escenaImagen.style.display = 'none'; escenaRostro.style.display = 'block'; }
}
🔁 Cómo funciona: cargar ambos SDK (image + face) y conmutar visibilidad entre escenas. Patrón del browser-ar-runtime (7 targets + face filters, usado en 30+ instituciones culturales).

3.4 · Producción de targets sin código Tools

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
🔁 Cómo funciona: el .mind es un descriptor de features de la imagen; se genera con el compilador (web o CLI) y se referencia en imageTargetSrc.

4 · Despliegue — 4 Arquitecturas

Cómo publicar una experiencia MindAR según el contexto (skills OKF despliegue-ar-*).

4.1 · Arq 1 — 100% local (sin internet) Offline

# Paquete standalone: HTML + SDK + .mind + assets todo embebido
cd experiencia
python -m http.server 8080   # abre http://localhost:8080 (necesita webcam)
Cuándo: ferias sin conectividad, demo en un solo equipo, respaldo offline. Clave: SDK y assets locales (no CDN).

4.2 · Arq 2 — WiFi local (portátil = servidor) ⭐ educación Aula

# 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
Cuándo: aula sin internet, taller con celulares. Clave: host='0.0.0.0' para acceso por IP local en el mismo WiFi.

4.3 · Arq 3 — Hosting (internet obligatorio) ⭐ distribución Producción

# 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.
Cuándo: proyecto terminado, portafolio, distribución global.

4.4 · Arq 4 — Híbrida (local + CDN) Transición

# 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
Cuándo: transición, prototipos, cuando no se puede empaquetar todo. Clave: decidir qué va local (pesado/propietario) y qué va CDN (librerías).

5 · Grafo animado — del marcador a la publicación

El token 🟠 recorre: compilar target → image → face → React → contenido → desplegar. Clic reinicia.

Iniciando…

6 · Referencia y regla de librerías

Script / conceptoQué hace
mindar-image.prod.js + -aframeSDK image tracking + extensión A-Frame
mindar-face.prod.js + -aframeSDK face tracking (mediapipe face mesh)
mindar-image-three.prod.jsIntegración Three.js directa (import map)
.mind + targetIndexTarget compilado + índice del marcador
mindar-image-target / mindar-face-targetEntidad anclada al marcador / rostro
anchorIndexZona facial de anclaje (10 = nariz)
targetFound / targetLostEventos de detección (audio/UI)
uiScanning / .mindar-ui-overlayOverlay custom / nativo
MindARThree · controller.stop()Three.js puro · cleanup React
📦 Regla de librerías (local primero): para Arq 1/2 usar el SDK descargado desde 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.