ReactVision: Eskiu across an AR stack
The setup
ReactVision builds ViroCore, the native AR/VR rendering
engine behind @reactvision/react-viro on iOS, Android, Meta
Quest, and visionOS. It is a large, long-lived C++ codebase, on the order
of 2,200+ files and ~23 MB of engine source, split across
the parts you'd expect of a real-time renderer:
| Subsystem | Scale |
|---|---|
| Renderer | ~800 files |
| Physics | ~480 files |
| Scene graph | ~110 files |
| Image / texture, materials, lighting, text, particles | the rest |
It ships to phones and headsets, where memory is the scarce resource: every texture buffer, scene-graph node, and per-frame allocation counts. The hot, memory-sensitive paths (image and texture preprocessing, the scene graph, physics) are exactly the kind of native code where how you allocate decides the footprint.
Why Eskiu fit
The team didn't want to rewrite the engine, and didn't want to trade C++'s control for a language with a garbage collector or a heavy runtime. Eskiu's shape matched the constraints:
- Native, no runtime. Compiles to native code through LLVM, with no collector and nothing to embed, so the binary footprint stays predictable.
- Memory you account for.
alloc<T>(N)/free(ptr)live in the source. A migrated component's allocation pattern is explicit and auditable, not hidden behind a framework. - C ABI in and out. Eskiu speaks the C ABI directly and links as a plain native object. A module drops into the existing C++ engine, called from it and calling back into it, without rewriting the host.
- Modern where it helps. Sum types with
match, async/await, templates: current-language ergonomics without giving up the systems layer.
The approach
Selective, not a rewrite: take one memory-sensitive C++ component, re-implement it as an explicit Eskiu module, and link it in over the C ABI. The surrounding engine doesn't change; it sees the same symbols. Each migrated module is small enough to audit and measure on its own, so the footprint win is attributable. On the modules moved so far: ≈85% less memory.
Web AR tracking: tinyvio, ported whole
tinyvio is ReactVision's monocular visual-inertial tracker: FAST
corners, pyramidal Lucas-Kanade flow, two-view initialisation, pose solving,
sliding-window bundle adjustment, plane detection, relocalisation and anchors. It
is the engine @reactvision/viro-web-renderer loads for AR in the
browser, compiled to WebAssembly, and since 2026-10-20 the one in production is
written in Eskiu. Its whole engine, about 9,000 lines of C++, is now
about 7,400 lines of Eskiu that implement the same SLAM C API, so the existing
embind layer builds the drop-in web engine from it unchanged.
The port computes the same bits as the C++. A recording is replayed through the C API on both engines, and every pose, map point, tracked feature and plane is compared after every frame, with no tolerance. Perturbed replays (dark, shifted and dropped frames, gyro spikes, other configurations) drive the tracker into relocalisation and back, and each module is also checked on its own, about 440,000 cases with no difference.
| Where | C++ against Eskiu |
|---|---|
| macOS (arm64) | identical |
| WebAssembly (Node) | identical, and identical to native |
| iOS simulator | identical |
| Android emulator (NDK) | identical |
| The web engine's own smoke test | passes with the same output |
Speed is the same: 1.36 s against 1.35 s natively for a 275-frame capture, 1.89 s
each in Node. The WebAssembly module is 311 KB against 266 KB. Matching to the bit
took care in two places a C++ build never shows: libc++'s sort leaves tied
elements in an order the standard does not fix, so Eskiu's <sort>
now uses the same algorithms, and clang merges sin and
cos of one angle into one call that rounds differently on Apple
platforms, which the port reproduces.
Object detection: one core for iOS and Android
@reactvision/react-viro-onnx runs YOLOE object detection for
ViroObjectDetector. Its session caching, the decoding of the model's
300 proposals, non-maximum suppression and class names were written twice, in
Objective-C++ and in Java. They are now one Eskiu core over the
onnx package: iOS calls it through a
C header as a static xcframework, and Android through JNI entry points written in
Eskiu itself, with no C glue. The core matches a Python reference of the old
post-processing byte for byte, and does on the iOS simulator and an Android
emulator within the rounding of their ONNX Runtime versions.
Both are in production: ViroReact's web AR runs on the Eskiu tinyvio, and
react-viro-onnx detects objects with the Eskiu core on iOS and Android.
So the same language that boots a bare-metal ARM64 kernel also drops a memory-tight module into a C++ rendering engine, runs AR tracking in the browser bit for bit, and replaces native code written twice with code written once. One language across the stack, used where it pays off.
eskiu