Por qué este motor
No es una lista de funciones, sino el puñado de decisiones que cambian lo que puedes construir, y por qué importan en la práctica.
Un solo modelo, en todas partes
El editor, el reproductor web, la app del móvil y el servidor ejecutan la misma escena: los mismos objetos, los mismos componentes, el mismo comportamiento.
No hay paso de exportación, ni un «formato de ejecución» aparte, ni una segunda implementación que se desvíe de la primera. Lo que colocaste en el editor es lo que corre, y un fallo que ves en el reproductor se reproduce en todas partes.
La consecuencia práctica es aburrida y valiosa: las cosas no cambian de significado al publicar.
Los grafos se convierten en código, no en un intérprete
En la mayoría de las herramientas, un grafo visual es un dato que algo recorre en ejecución, nodo a nodo, en cada fotograma. Aquí se compila a un script normal, una vez, y ese script es lo que corre.
| Velocidad | un grafo cuesta lo mismo que el código escrito a mano, porque es código |
| Inspeccionable | abre el panel de código y lee exactamente en qué se convirtió tu grafo |
| Componible | un grafo puede llamar a un script y un script a un grafo, porque por debajo son lo mismo |
Así que no hay un techo en el que tengas que abandonar la herramienta visual y reescribirlo todo en código. Añades un script junto al grafo que ya tienes.
Los materiales son grafos hasta el fondo
Los tipos de material integrados no son un conjunto cerrado con un editor de nodos atornillado. Son puntos dentro del mismo sistema que usa un grafo propio, así que un material en grafo no es más lento, ni un ciudadano de segunda, ni está limitado a la web: el mismo grafo compila para el navegador y para el renderizador nativo de un móvil.
Y lo que no usas no cuesta nada. Los extras físicos que se quedan en sus valores por defecto se pliegan en tiempo de compilación, así que un material con la opción de ser vidrio es exactamente igual de barato que uno sin ella.
Funciona como una hoja de cálculo
Esta es la decisión sobre la que se apoya todo lo demás, y lo más fácil es explicarla con una analogía.
En una hoja de cálculo cambias una celda y solo se recalculan las fórmulas que usan esa celda. Nadie recalcula la hoja entera, y nunca pulsas un botón de «actualizar».
La escena funciona exactamente así. Cambia el color de un objeto y lo único que reacciona es lo que estaba leyendo el color. No el objeto: el color.
cambio material.color
│
├─ el renderizador repinta esa superficie
├─ el campo del inspector que lo muestra se actualiza
├─ el cambio se pone en cola para tus colaboradores
└─ …y no se ejecuta nada más
Qué te da eso
Nada sondea y nada se rerenderiza por si acaso. No hay una pasada por fotograma que compare el mundo con una copia de sí mismo para averiguar qué se ha movido. Un fotograma hace el trabajo que exigen los cambios, y una escena quieta no cuesta casi nada.
Las escenas grandes siguen respondiendo mientras las editas. Una línea de tiempo con veinte mil keyframes no se redibuja porque uno se haya movido: un panel puede depender de «los keyframes han cambiado» sin suscribirse a cada keyframe de la lista. Esa distinción es lo que mantiene usables los proyectos grandes.
Cargar no necesita código de carga. Un sistema pide un recurso y no recibe nada si aún no ha llegado; cuando llega, el sistema simplemente se vuelve a ejecutar. Nadie escribe callbacks, ni sondea una bandera de «listo», ni maneja dos veces el caso de «todavía no cargado».
Un único flujo de cambios alimenta todo. El renderizador, el inspector, deshacer, tus colaboradores, el sandbox de scripts y la simulación física leen las mismas actualizaciones, que es por lo que no pueden separarse ni discrepar sobre lo que contiene la escena. Deshacer no es un camino especial: es un cambio más pasando por la misma tubería.
No puedes olvidarte de avisar al motor. No hay «marcar como sucio», ni «refrescar», ni invalidación manual que recordar. Escribir el valor es la notificación.
Actualizar un valor lo fusiona con lo que ya hay en vez de reemplazarlo, así que todo lo que estaba mirando sigue enganchado a lo mismo que miraba. Suena a detalle de implementación; es la diferencia entre una animación fluida y unos fotogramas por segundo que se hunden según crece tu escena.
No es una función del framework: es el sustrato
La reactividad es un paquete propio, y el mismo está a tu disposición. Un panel de plugin, una extensión de componente y el propio inspector del editor están escritos contra él, así que una extensión que escribas se actualiza exactamente por el mismo motivo que los paneles integrados.
import { signal, computed, effect, batch } from '@was/signals';
const score = signal(0);
const label = computed(() => `Score: ${score.value}`);
effect(() => render(label.value)); // se reejecuta solo cuando se mueve la puntuación
batch(() => { score.value += 1; score.value += 1; }); // una actualización, no dos
Merece la pena nombrar tres propiedades, porque la mayoría de los sistemas reactivos tienen una o dos:
| De grano fino | las dependencias se siguen por valor leído, no por componente. Nada se rerenderiza «por si acaso». |
| Profunda | un árbol de objeto entero se vuelve reactivo, así que vigilar position.y no es vigilar el objeto |
| Barata de depender | puedes depender de que algo cambió sin leerlo, que es lo que evita que una lista enorme se rerenderice cuando se mueve un elemento |
Lo último suena arcano y es la razón por la que una línea de tiempo de veinte mil keyframes sigue siendo editable.
Validación que no te cuesta un fotograma
Cada componente se describe con un esquema, y los esquemas normalmente significan un impuesto: algo recorre una descripción en ejecución, campo a campo, cada vez que llegan datos.
Aquí el esquema se compila una vez a código para esa forma exacta. No hay recorrido. La diferencia no es académica: medido con el propio banco de pruebas de este proyecto:
| Análisis | Añadido al bundle | |
|---|---|---|
| La biblioteca habitual (zod) | 94,7 ns por operación | +267 KB minificados, +61 KB con gzip |
| Esta (svdt) | 5,0 ns por operación | nada: ya está ahí |
Unas diecinueve veces más rápido, y nada extra que descarguen tus visitantes.
Importa porque aquí la validación no es un suceso raro: corre en cada cambio que cruza entre el editor, el sandbox de scripts, la simulación física y tus colaboradores. Un coste por campo que parece insignificante se convierte en el presupuesto de animación cuando ocurre miles de veces por segundo.
Es el mismo paquete que tu propio plugin puede importar para sus propios datos. → Los paquetes compartidos
El trabajo pesado se queda fuera del fotograma
Dos cosas que normalmente atascan una página de navegador se sacan de ella:
- Tus scripts corren aislados de la página, así que un bucle lento no puede congelar el renderizado.
- La física corre junto al fotograma, no dentro de él.
Una escena sigue respondiendo mientras está ocupada, en lugar de perder fotogramas cuando tu lógica se pone interesante.
El runtime se niega a trabajar hasta que lo necesita
Esta es la parte que se manifiesta como tiempo de carga para tus visitantes.
La física no arranca, ni se descarga, a menos que una escena la necesite de verdad. Un decorado sin partes móviles nunca paga por el simulador, y eso son megabytes que tus visitantes no esperan. La comprobación está viva: una pelota creada a mitad de sesión levanta la física por su cuenta.
Diez mil copias cuestan más o menos una. La hierba, las multitudes, los escombros y las partículas se dibujan en una sola llamada. Su disposición se genera a partir de una semilla en vez de guardarse, así que no cuesta nada en el archivo, nada en la red, y se ve idéntica para cada participante.
Nada a nivel de partícula se sincroniza jamás. Los mismos ajustes producen el mismo efecto en todas partes, así que un efecto elaborado sale gratis en multijugador.
Un solo vocabulario para el comportamiento
Eventos, grafos de patch y scripts oyen los mismos disparadores: on-click significa lo mismo
en los tres. Aprendes un juego de nombres y luego eliges cuánto código quieres escribir.
Eso también significa que puedes empezar una interacción como evento, ascenderla a patch cuando necesite una condición, y pasarte a un script cuando necesite lógica de verdad, sin volver a aprender nada.
Construido para más de una persona
La colaboración no es una función atornillada encima: un space es un mundo vivo compartido por todos los que están dentro, así que las ediciones aparecen según ocurren y deshacer funciona por persona.
La misma maquinaria sincroniza el editor, el sandbox de scripts y la simulación física, que es por lo que no pueden discrepar sobre lo que contiene la escena.
Corre donde tu público ya está
Un proyecto publicado se abre desde un enlace, en un navegador, sin nada que instalar. De eso va la WebAR: sin tienda de aplicaciones, sin descarga, sin «instala primero nuestra app» entre tu visitante y lo que has hecho.
A partir de ahí, el mismo proyecto llega más lejos sin reconstruirse:
| Dónde | Cómo llega ahí |
|---|---|
| Cualquier navegador de móvil | el enlace publicado, o un código QR: nada que instalar |
| App Clip de iOS | se abre desde un enlace, un QR o NFC, sin instalar desde la App Store |
| La app nativa | un renderizador nativo — ver abajo |
| Navegadores de visores | el mismo enlace publicado: el runtime habla WebXR |
| Gafas y visores AR | una capa XR nativa para XREAL One, Quest 3 y PICO 4 — ver abajo |
| Visores vía Unity | el SDK de Unity — XREAL, PICO, Apple Vision Pro, HoloLens 2, Magic Leap 2, Rokid |
Alguien apunta la cámara a un código y tu experiencia se abre: sin tienda, sin cuenta, sin esperas. Apple limita el tamaño de un clip, así que mantén ligera la primera escena y carga el resto una vez esté en marcha.
Los móviles funcionan de serie. Los paquetes específicos de cada dispositivo —pipelines de renderizado, perfiles de mando, plantillas de despliegue— se conceden por cuenta. → Plataformas soportadas
En un móvil, velocidad de renderizado nativa
En un navegador tienes WebGL: rápido y con techo. La app nativa no renderiza a través de un navegador en absoluto: usa un renderizador nativo tanto en iOS como en Android, hablando directamente con Metal y Vulkan.
Así que el mismo proyecto obtiene el presupuesto gráfico de una app nativa —sombras en tiempo real, materiales más pesados, más cosas en pantalla— sin que tengas que mantener una segunda versión. Tus materiales compilan para ese renderizador igual que para la web, que es lo que hace que «el mismo proyecto» sea cierto y no una aspiración.
Usa la compilación web por alcance, y la app para los proyectos que necesiten el presupuesto de fotograma.
Gafas, de forma nativa
Una capa XR nativa pone el propio runtime de AR Clip en unas gafas: el mismo proyecto, la misma escena, renderizada en el dispositivo y no en un navegador.
Está construida como una única interfaz con backends de fabricante intercambiables, así que un dispositivo es un backend y no una bifurcación del runtime, y no pasa por Unity:
| Dispositivo | A través de | Qué funciona ahí |
|---|---|---|
| XREAL One | el SDK del fabricante | pantalla, seguimiento de cabeza, cámara, grabación de sesión |
| Meta Quest 3 | OpenXR | pantalla, seguimiento, mandos, seguimiento de manos, grabación de sesión |
| PICO 4 | OpenXR | lo mismo, con la cámara desactivada |
Un backend declara lo que realmente admite en vez de fingir. PICO aquí no tiene paso de cámara, así que una escena que necesite el mundo real detrás pertenece a XREAL o a Quest; una que no lo necesite corre en las tres.
Venga por donde venga un visitante, es la misma escena con los mismos componentes y el mismo comportamiento. No estás manteniendo una versión web y una versión para visor.
Y es ampliable en los sitios que importan
Tus propios pasos y disparadores se pueden registrar desde una aplicación. El editor admite plugins que añaden paneles, generan escenas o aportan clases de componente enteramente nuevas. El catálogo de nodos tiene una salida de emergencia para el único caso que no cubre.
Todas las tablas de componentes, disparadores, pasos y nodos de este sitio se generan desde el propio motor. Cuando el motor gana un nodo, la referencia gana una fila: nadie tiene que acordarse de actualizarla.
Siguiente: Objetos y escenas — el modelo completo.