ReactVision: Eskiu a lo largo de un stack de AR
El contexto
ReactVision desarrolla ViroCore, el motor nativo de renderizado
AR/VR detrás de @reactvision/react-viro en iOS, Android, Meta
Quest y visionOS. Es una base de código C++ grande y de larga vida, del orden
de 2,200+ archivos y ~23 MB de código del motor, repartida entre
las partes que esperarías de un renderizador en tiempo real:
| Subsistema | Escala |
|---|---|
| Renderizador | ~800 archivos |
| Física | ~480 archivos |
| Grafo de escena | ~110 archivos |
| Imagen / textura, materiales, iluminación, texto, partículas | el resto |
Se distribuye a teléfonos y visores, donde la memoria es el recurso escaso: cada buffer de textura, nodo del grafo de escena y asignación por frame cuenta. Las rutas críticas y sensibles a la memoria (preprocesamiento de imagen y textura, el grafo de escena, la física) son justo el tipo de código nativo donde la forma de asignar memoria decide el footprint.
Por qué encajó Eskiu
El equipo no quería reescribir el motor, ni cambiar el control de C++ por un lenguaje con recolector de basura o un runtime pesado. El perfil de Eskiu encajaba con esas restricciones:
- Nativo, sin runtime. Compila a código nativo vía LLVM, sin recolector y sin nada que embeber, así que el footprint del binario se mantiene predecible.
- Memoria que administras.
alloc<T>(N)/free(ptr)viven en el código. El patrón de asignación de un componente migrado es explícito y auditable, no oculto tras un framework. - ABI de C en ambos sentidos. Eskiu habla el ABI de C directamente y enlaza como un objeto nativo plano. Un módulo entra en el motor C++ existente, llamado desde él y llamándolo de vuelta, sin reescribir el host.
- Moderno donde ayuda. Tipos suma con
match, async/await, templates: ergonomía de lenguaje actual sin renunciar a la capa de sistemas.
El enfoque
Selectivo, no una reescritura: tomas un componente C++ sensible a la memoria, lo reimplementas como un módulo Eskiu explícito y lo enlazas por el ABI de C. El motor de alrededor no cambia; ve los mismos símbolos. Cada módulo migrado es lo bastante chico para auditarse y medirse por sí solo, así que la ganancia de footprint es atribuible. En los módulos movidos hasta ahora: ≈85% menos memoria.
Tracking de AR en la web: tinyvio, portado completo
tinyvio es el tracker visual-inercial monocular de ReactVision:
esquinas FAST, flujo óptico Lucas-Kanade piramidal, inicialización con dos vistas,
cálculo de pose, bundle adjustment de ventana deslizante, detección de planos,
relocalización y anclas. Es el motor que @reactvision/viro-web-renderer
carga para AR en el navegador, compilado a WebAssembly, y desde el 2026-10-20 el que
está en producción está escrito en Eskiu. Todo el motor, unas 9,000
líneas de C++, ahora son unas 7,400 líneas de Eskiu que implementan la misma API de
C de SLAM, así que la capa de embind que ya existía construye con ellas el motor web
sin cambios.
El port calcula los mismos bits que el C++. Una grabación se reproduce por la API de C en los dos motores, y cada pose, punto de mapa, feature rastreado y plano se compara después de cada cuadro, sin tolerancia. Reproducciones perturbadas (cuadros oscuros, desplazados o perdidos, picos de giroscopio, otras configuraciones) llevan al tracker a relocalizar y volver, y cada módulo se revisa también por separado: unos 440,000 casos sin una sola diferencia.
| Dónde | C++ contra Eskiu |
|---|---|
| macOS (arm64) | idéntico |
| WebAssembly (Node) | idéntico, e idéntico al nativo |
| Simulador de iOS | idéntico |
| Emulador de Android (NDK) | idéntico |
| El smoke test del propio motor web | pasa con la misma salida |
La velocidad es la misma: 1.36 s contra 1.35 s en nativo para una captura de 275
cuadros, 1.89 s cada uno en Node. El módulo de WebAssembly pesa 311 KB contra 266 KB.
Igualar cada bit pidió cuidado en dos lugares que un build de C++ nunca muestra: el
sort de libc++ deja los empates en un orden que el estándar no fija, así que el
<sort> de Eskiu ahora usa los mismos algoritmos; y clang junta
sin y cos de un mismo ángulo en una sola llamada que en
plataformas de Apple redondea distinto, y el port la reproduce.
Detección de objetos: un núcleo para iOS y Android
@reactvision/react-viro-onnx hace la detección de objetos YOLOE de
ViroObjectDetector. El caché de sesiones, la decodificación de las 300
propuestas del modelo, la supresión de no máximos y los nombres de clase estaban
escritos dos veces, en Objective-C++ y en Java. Ahora son un solo núcleo en Eskiu
sobre el paquete onnx: iOS lo llama
por un header de C como xcframework estático, y Android por funciones JNI escritas
en el propio Eskiu, sin pegamento en C. El núcleo coincide byte por byte con una
referencia en Python del post-procesamiento anterior, y en el simulador de iOS y un
emulador de Android coincide dentro del redondeo de sus versiones de ONNX Runtime.
Los dos están en producción: el AR web de ViroReact corre sobre el tinyvio en Eskiu, y
react-viro-onnx detecta objetos con el núcleo en Eskiu en iOS y Android.
Así que el mismo lenguaje que arranca un kernel ARM64 bare-metal también mete un módulo ajustado en memoria dentro de un motor de renderizado C++, corre tracking de AR en el navegador bit por bit y reemplaza código nativo escrito dos veces por código escrito una vez. Un solo lenguaje a lo largo del stack, usado donde de verdad rinde.
eskiu