Skip to content

Releases: ReactVision/viro

v2.57.2

Choose a tag to compare

@doranteseduardo doranteseduardo released this 29 Jun 20:46

v2.57.2 — 16 KB page-size alignment (completion)

This release completes the 16 KB memory-page alignment work started in previous releases,
unblocking Google Play / Meta Quest Store submission for Android 15+ devices.

Highlights

  • All bundled native libraries are now 16 KB-page aligned. v2.57.0 aligned
    libopenxr_loader.so, but the prebuilt libc++_shared.so inside the renderer
    AAR was still 4 KB-aligned (2**12) and kept failing the requirement. Because
    it's a prebuilt copied verbatim from the NDK sysroot, the
    -Wl,-z,max-page-size=16384 linker flag (which already aligns everything Viro
    compiles) can't touch it — and NDK r21–r26 ship it at 4 KB. The renderer's
    Android NDK was bumped from r25 → r27 (27.1.12297006), whose
    libc++_shared.so is 16 KB-aligned, and the prebuilt AARs
    (viro_renderer-release.aar, react_viro-release.aar) were regenerated.

Notes

  • Every 64-bit (arm64-v8a) library now reports ≥ 16 KB segment alignment —
    most at 16 KB (2**14), with libvrapi.so / libgvr*.so at 64 KB (2**16).
    Verified with Google's check_elf_alignment.sh (0 unaligned).
  • ELF segment alignment is one half of the requirement; ensure the consuming app
    also packages each .so uncompressed and 16 KB-aligned in the APK/AAB
    (AGP 8.2+ handles this automatically).
  • Pairs with @reactvision/virocore 2.57.2.

See CHANGELOG.md for full detail.

v2.57.1

Choose a tag to compare

@doranteseduardo doranteseduardo released this 28 Jun 01:18

v2.57.1 — Mixed Reality on Meta Quest

This release brings Viro's AR component API to Meta Quest 3 / 3S through the
OpenXR renderer — no new API to learn. The same ViroARScene you ship on phones
now runs in passthrough mixed reality on Quest.

Highlights

  • Mixed Reality scenes on Quest. Pass a ViroARScene to ViroXRSceneNavigator
    and it runs on phones (ARCore) and Quest (OpenXR). onAnchorFound,
    ViroARPlane, and ViroARPlaneSelector fire from the room's floors, walls,
    ceilings, and tables, with passthrough enabled automatically.

  • Object detection on Quest. ViroObjectDetector now runs on Quest 3 / 3S,
    driven by the Meta Passthrough Camera API. v1 emits labels + normalized boxes.

  • Passthrough styling. New setPassthroughStyle(viewTag, { opacity, edgeColor })
    tunes passthrough opacity and edge-highlight colour at runtime.

  • Reliability fixes. Passthrough no longer renders a black background, and an
    initial passthroughEnabled prop is honored even when set before the renderer
    initializes.

Upgrade notes

  • Permissions (Quest). The Expo plugin now declares
    horizonos.permission.USE_ANCHOR_API (room planes) and
    horizonos.permission.HEADSET_CAMERA (object-detection camera). Both are
    runtime-granted — request them in-app or adb shell pm grant <pkg> <perm>.
  • Room planes require Space Setup. Plane data comes from the Quest room model;
    run Space Setup on the headset first, or no plane anchors are produced.
  • MR scenes: set hdrEnabled={false} on ViroXRSceneNavigator for now — the
    HDR post-process path forces an opaque composite that hides passthrough. (A fix
    to lift this restriction is planned.)
  • Object detection on Quest is Horizon OS v74+ and emits labels + 2D boxes
    only (no worldPosition / screenBoundingBox yet).

See CHANGELOG.md for the full list of changes, and
docs/QUEST_SETUP.md for setup details.

v2.57.0

Choose a tag to compare

@doranteseduardo doranteseduardo released this 24 Jun 02:33

ReactVision ViroReact v2.57.0

This release adds on-device object detection, improves AR depth accuracy on iOS, fixes layered glTF/GLB animation playback, aligns the OpenXR loader to the Android 16 KB page-size requirement, and adds Expo SDK 56 support.

ViroObjectDetector

A new component that runs YOLOE object detection through ONNX Runtime on the device. It works only in AR: it shares the camera feed of the enclosing ViroARSceneNavigator rather than opening a camera of its own. Detections are reported through onDetection with a label, confidence, and normalized bounding box.

Each detection also includes a screenBoundingBox in density-independent points, aligned to the on-screen camera preview, so it maps directly onto an absolutely-positioned overlay without extra math. Detection and the 2D overlay work the same on iOS and Android. The 3D worldPosition raycast is currently iOS only.

Inference runs in the companion package @reactvision/react-viro-onnx, which uses the NNAPI execution provider with FP16 on Android. The detector has no built-in inference path: if the provider is not installed, it produces no detections and calls onError.

npm install @reactvision/react-viro @reactvision/react-viro-onnx
{ "expo": { "plugins": ["@reactvision/react-viro", "@reactvision/react-viro-onnx"] } }

Setup, model bundling, and the coordinate system are documented in docs/ViroObjectDetector.md.

AR depth on iOS

Depth points are now read directly from the AR depth map instead of being approximated, and the monocular depth model is warmed up before its first use. This removes the inaccurate and late depth values that previously showed up on the first frames and improves occlusion and hit-testing on devices without LiDAR.

ViroARScene gains an onDepthReady event on iOS and Android. It fires once, when AR depth first becomes available, so you can wait for it before enabling features that depend on depth.

Layered GLB animations (VIRO-5741)

glTF/GLB skeletal clips that mixed STEP and LINEAR interpolation, or whose channels used several independent time-grids, were being dropped or flattened and froze instead of playing. This is common in Blender exports with layered animations. The loader now resamples all of a skin's channels onto one common time-grid and merges each joint's channels into a single index-aligned keyframe animation, with a per-frame density cap so skinning cost stays bounded on large clips. These animations now play to the end.

OpenXR loader 16 KB page-size alignment

The bundled OpenXR loader library, libopenxr_loader.so, is now aligned to a 16 KB page size (the loader was updated from 1.1.38 to 1.1.49). This native .so previously used 4 KB alignment, which fails the 16 KB memory-page requirement for Android 15 and later and blocks Google Play and Meta Quest Store submission. Apps that do not use XR are not affected.

Expo SDK 56

The config plugin and prebuilt artifacts build against Expo 56 and React Native's new architecture.

Other fixes

  • VR controller input works again after moving the VR event listener to the new architecture.
  • onDrag in StudioSceneNavigator now fires.
  • visionOS-only sources are excluded from the iOS CocoaPods build, which fixes compile errors in iOS-only targets.

Experimental

  • Initial visionOS renderer: a Metal-based renderer and driver, the React Native bindings, and the renderer bridge. This is still in progress and not ready for production.

Upgrading

npm install @reactvision/react-viro@2.57.0
# For ViroObjectDetector:
npm install @reactvision/react-viro-onnx
npx expo prebuild

There are no breaking API changes. If you use ViroObjectDetector, bundle your .onnx model into the native project as described in the component docs. Note that expo prebuild --clean removes manually placed assets.

Full changelog: see CHANGELOG.md in viro and virocore.

v2.56.0

Choose a tag to compare

@doranteseduardo doranteseduardo released this 05 Jun 01:13
770e808

Release Notes — v2.56.0

What's new

Dynamic mesh node

VRODynamicMeshNode lets you update geometry every frame without recreating the node or triggering GPU reallocation. This unlocks a class of apps that wasn't practical before: procedural terrain, marching cubes in AR, CPU skinning of custom formats, and output from external simulation engines. The vertex buffers (positions, normals, UVs, colors) are updated in place using an orphan + sub-data path on OpenGL, keeping frame time flat even at 60 fps.


Virtual game controller

Two new native components — ViroVirtualJoystick and ViroVirtualButton — bring on-screen game controls to AR apps with sub-2 ms input latency. Touch events are handled entirely at the native layer and written to a shared state registry that your C++ game loop reads every frame, with no JS bridge round-trips in the hot path. Both components also fire JS callbacks (onStickChange, onPressIn, onPressOut) so you can drive UI reactions from the same input.

<ViroVirtualJoystick
  controllerId="p1"
  stickSide="left"
  radius={60}
  onStickChange={(e) => move(e.nativeEvent.x, e.nativeEvent.y)}
/>
<ViroVirtualButton controllerId="p1" button="A" size={52} />

PCM audio streaming

StreamingAudioManager opens a real-time audio path where you push raw PCM samples as they are produced, rather than loading a complete file. The API is the same on iOS and Android:

StreamingAudioManager.create('voice');
StreamingAudioManager.beginStreaming('voice', 24000, 1);
StreamingAudioManager.play('voice');

// from your audio producer loop:
StreamingAudioManager.pushSamples('voice', base64Float32PCM);

Useful for TTS output, procedural sound synthesis, physics-driven audio, and any embedded engine that generates audio samples at runtime.


AR World Mesh — public subscriber API

The AR world mesh is now a general-purpose multi-consumer provider. Any part of your app can subscribe to receive the full mesh geometry (vertices, indices, confidence) along with a source tag that tells you whether the data came from LiDAR, the monocular depth model, or ARKit plane anchors.

This release also adds:

  • Plane fallback — devices without LiDAR or the Depth API now get a mesh built from detected AR planes, so the feature degrades gracefully instead of producing nothing.
  • Per-consumer decimation — each subscriber can cap its triangle budget independently, so a physics engine and a nav-mesh consumer can coexist without fighting over resolution.
  • Async physics — Bullet BVH construction runs on a background thread, preventing the ARKit frame drops that appeared when processing large meshes on the render thread.
  • Full Android support — ARCore depth mode is now activated automatically when world mesh is enabled, and plane mesh generation is implemented end-to-end on Android.

Game loop

ViroGameLoop and the useGameLoop / useFixedUpdate hooks give you a proper per-frame callback with both variable-dt and deterministic fixed-step modes. Fixed-step mode is useful for physics engines and networked simulations that require ticks at an exact frequency.

<ViroGameLoop
  onUpdate={({ dt, elapsed }) => { /* variable, every frame */ }}
  fixedHz={30}
  onFixedUpdate={({ dt }) => { /* deterministic, 30 times/s */ }}
/>

ViroGameLoopUtils provides setPosition, setRotation, and setScale that write directly to the native node, bypassing React's reconciler for zero-overhead transforms from inside the loop.


Improvements

Monocular depth — new metric model, better occlusion

The monocular depth estimator has been upgraded to Depth Anything V2 (metric, indoor), a model trained on indoor scenes that outputs depth in meters. Compared to the previous model, occlusion triggers more reliably and at the correct distances for typical indoor AR use.

The pipeline also received several quality improvements: temporal confidence synthesis to avoid upgrading hit-tests on unstable depth pixels, in-place GPU texture updates that eliminate a per-frame allocation, correct handling of all four device orientations, and adaptive thermal throttling to prevent overheating during extended sessions.

Two new props on ViroARSceneNavigator let you tune the estimator at runtime:

Prop Default Description
monocularDepthScale 1.0 Multiplies all depth values before occlusion. Lower values make occlusion trigger sooner.
monocularDepthTargetFPS 5 Inference rate. Raise for smoother occlusion; lower to reduce thermal load.

Bug fixes

  • SIGABRT on Android 14+ (API 34) — a hard crash in the ARCore anchor handling path has been resolved. The crash occurred when NewStringUTF received a non-Modified-UTF-8 anchor ID, which became common on Android 14.

  • Quest Store submission rejected due to forced landscape orientation — the Viro Android plugin was unconditionally setting landscape orientation on MainActivity, which caused Quest Store validation failures for non-Quest apps and overrode the orientation set in app.json. The override now applies only to Quest apps.


Upgrade notes

No breaking changes. All new components and hooks are additive. StreamingAudioManager, ViroVirtualJoystick, ViroVirtualButton, ViroGameLoop, and the useGameLoop family are available as named exports from @reactvision/react-viro.

The setUpdateCallback on VROARWorldMesh is retained but deprecated in favor of the new subscribe / unsubscribe API.

v2.55.0

Choose a tag to compare

@doranteseduardo doranteseduardo released this 10 May 20:37
acb0c5e

This release adds first-class Meta Horizon OS support, a new ReactVision Studio integration layer, and a cross-reality JS routing component that lets a single app target phones, tablets and Meta Quest from one React surface. It also ships three Android / iOS stability fixes that unblock the latest Android ABI and resolve two regressions reported by the community.


Highlights

Meta Horizon OS support

VR scenes run natively on Meta Quest 3 / Quest Pro / Quest 2 / Quest 1 via a new OpenXR backend in virocore. The integration is end-to-end and has been device-validated at 90 Hz on Quest 3:

  • Dual-Activity architecture. The same APK ships an Android phone / tablet panel (MainActivity) and an exclusive VR Activity (VRActivity, emitted automatically by the Expo plugin when xRMode: ["QUEST"] is set). Consumers don't have to manage the switch — mount <ViroXRSceneNavigator> and entering/exiting VR is handled for you (see Cross-reality JS layer below).

  • Two simultaneous pointers. Right and left controllers (or tracked hands) each get an independent cyan laser line, hover state, and click resolution. Either side can be controller-tracked or hand-tracked; right is the single-pointer fallback when only one is available.

  • Full input set. Touch controllers (triggers, grips, A/B/X/Y, menu, thumbsticks, haptics), XR_EXT_hand_tracking joints, and XR_FB_hand_tracking_aim for fingertip-aimed pointing. Pinch-to-click and grip-to-grab are detected per hand. B and Menu buttons exit VR; returning from the Quest system menu relaunches automatically, explicit exitVRScene() calls don't.

  • Stable hover and click on small UI targets. Pose hysteresis and a 75 ms hover grace window absorb natural OpenXR aim jitter, so hover state doesn't oscillate and trigger pulls land on first try.

  • Passthrough + recenter. VRModuleOpenXR.setPassthroughEnabled(viewTag, …) and recenterTracking(viewTag) for in-app control.

  • Full lighting pipeline. HDR, PBR, bloom, shadows — all validated at 90 Hz with App=5–6 ms frame time on Quest 3.

  • Fast Refresh works inside VR. Metro Fast Refresh, timers, and requestAnimationFrame keep working when the headset is on, just like in the 2D panel.

  • questAppId plugin option. Sideloaded builds no longer show the system "App Name Unavailable" overlay.

Cross-reality JS layer

Three additions to @reactvision/react-viro collapse the multi-platform story into a one-liner for downstream apps.

  • ViroXRSceneNavigator — auto-detects the platform and mounts the right navigator: ViroVRSceneNavigator on Meta Quest, ViroARSceneNavigator on iOS / non-Quest Android. Pass a single shared scene, or per-platform scenes:

    // Shared scene
    <ViroXRSceneNavigator initialScene={{ scene: MyScene }} />
    
    // Per-platform scenes
    <ViroXRSceneNavigator
      arInitialScene={{ scene: MyARScene }}
      vrInitialScene={{ scene: MyVRScene }}
    />
  • Platform guards on the existing navigators. ViroARSceneNavigator short-circuits with a clean fallback when mounted on Quest instead of trying to start an AR session; ViroVRSceneNavigator does the same on non-Quest Android instead of falling through to the deprecated Google Cardboard split-screen renderer. Both expose an override prop (questFallback / nonQuestFallback) for custom UIs (e.g. a "Launch VR" launcher button).

  • isQuest and hasOpenXRSupport — runtime-detected booleans exported from the package root. Detection is hardware-ID based (Build.MANUFACTURER, BRAND, MODEL via Platform.constants), not module-presence based, so a single APK that bundles Quest support does not misidentify regular phones as Quest.

Multi-pointer hooks

Two helpers for apps that want simple aggregated state without writing the per-source bookkeeping themselves.

import {
  useAnySourceHover,
  useAnySourcePressed,
} from "@reactvision/react-viro";

function MyButton() {
  const [hovered, onHover] = useAnySourceHover();
  const [pressed, onClickState] = useAnySourcePressed();
  return (
    <ViroNode onHover={onHover} onClickState={onClickState} onClick={fire}>
      <ViroQuad
        scale={pressed ? [0.95, 0.95, 0.95] : [1, 1, 1]}
        materials={[hovered ? "btnHover" : "btnIdle"]}
      />
    </ViroNode>
  );
}

Both hooks return [bool, handler] and deduplicate per source ID so a second pointer crossing an already-hovered node does not produce spurious enter/exit toggles in JS state. Apps that do care which specific pointer fired the event (drag-to-controller, single-handed gestures) read source directly from the raw callback.

StudioSceneNavigator

Drop-in component for ReactVision Studio scenes. Fetches a Studio-authored scene by UUID via rvGetScene(sceneId) — auth is the project's API key, wired through the Expo plugin (rvProjectId in app.json):

import { StudioSceneNavigator } from "@reactvision/react-viro";

<StudioSceneNavigator sceneId="abc-123-uuid" style={StyleSheet.absoluteFill} />;

What it renders, end to end:

  • 3D models (GLB / VRX), images, video, and text from the scene's asset registry
  • Per-asset placement (position / rotation / scale) and physics bodies
  • Scene functions: NAVIGATION (push to another scene), ALERT, ANIMATION
  • Collision bindings (asset-pair triggered functions)
  • Animation registry (Studio-authored keyframes pushed into ViroAnimations)
  • Material configs with optional shader modifiers — animated time uniform for animated presets, _rf_vpw / _rf_vph viewport uniforms for screen-space effects, and auto-flagged requiresCameraTexture when the shader samples the camera feed
  • Image-tracking targets and the Viro360Image / Viro360Video background
  • Physics world configs

StudioSceneNavigator is fully cross-reality on Quest — the same sceneId mounts the scene in AR on phones / tablets and in VR on headset, with no consumer-side branching.

Underlying API surface

StudioSceneNavigator is powered by two new endpoints in the ReactVision Cloud Anchor SDK (libreactvisioncca, shipped inside virocore):

  • getScene(sceneId, callback) — returns the full scene response (metadata, assets, animations, collision bindings, scene functions, project info).
  • getSceneAssets(sceneId, callback) — asset-list-only variant for clients that already have scene metadata cached.

Both are exposed to JS via ViroARSceneNavigator.rvGetScene(sceneId) and rvGetSceneAssets(sceneId), and authenticate with the project API key wired through the Expo plugin. Existing Cloud Anchor / Geospatial endpoints are unchanged.


Fixes

  • 16 KB .so page alignment for libvrapi.so (Issue A). The Android 2025 ABI requires all shipped .so files to align to 16 KB pages. libvrapi.so is now repackaged with -Wl,-z,max-page-size=16384, resolving load failures on devices with the new page size.

  • ViroARImageMarker children fixed-on-screen after re-detection (Android, GitHub #465). Models parented to an image marker no longer pin to screen coordinates after the target was lost and re-acquired in v2.54.0. Markers re-anchor cleanly to the detected world pose every time, including subsequent re-detection.

  • iOS ViroPortalScene portal-tree stability (GitHub #452). Continued portal-render-pass hardening on top of the v2.54.0 fix:

    • Portal stencil silhouette no longer drops transparent entry fragments before alpha discard runs.
    • 360° background inside a portal is no longer overwritten by the AR camera background drawn afterwards.
    • The interior of a portal hole no longer reveals the portal interior when the user is outside a nested exit-frame portal.
    • AR occlusion is disabled inside the portal interior so virtual content is no longer discarded by depth-based occlusion when nested.

Compatibility

  • React Native 0.83, Expo 54 + Expo 55 for AR / non-Quest paths (unchanged from 2.54.0).
  • Android Gradle Plugin 8.7+ is required for 16 KB-aligned APKs. Minimum SDK unchanged (24).
  • Meta Quest support requires React Native ≥ 0.83 / Expo ≥ 55. ViroXRSceneNavigator throws an actionable JS error if the runtime is below the threshold. AR continues to work on the Expo 54 + RN 0.79 baseline.
  • Meta Quest support also requires the Quest variant of the Viro Android package — ReactViroPackage(ReactViroPackage.ViroPlatform.QUEST) in MainApplication.kt, plus xRMode: ["QUEST"] in the Expo plugin config. Both are emitted automatically by expo prebuild when the plugin is configured.
  • Recommended install path: Expo Dev Client. Bare React Native is not tested for this release. It should work but will need a substantial amount of manual wiring — MainApplication.kt package registration, the VRActivity Android Activity declaration with the correct intent filter and Quest hardware features, the xRMode Quest manifest features, and iOS Podfile configuration. The Expo plugin generates all of these automatically. Bare RN support will be revisited in a follow-up release.
  • iOS and non-Quest Android code paths are unchanged. Existing apps upgrade with no code changes.

Migration

No breaking JS API changes. Existing ViroARSceneNavigator and ViroVRSceneNavigator usage continues to work. New cross-reality apps should mount <ViroXRSceneNavigator> and wire its onExitViro prop to take the panel back to wherever VR was launched from (e.g. navigation.goBack()). B / Menu buttons exit VR automatically; exitVRScene() from @reactvision/react-viro is only needed for programmatic in-scene exits.

v2.54.0

Choose a tag to compare

@doranteseduardo doranteseduardo released this 02 Apr 03:03
9572a17

React Viro — v2.54.0 Release Notes

Release date: March 31, 2026


What's New

Semantic Masking

Virtual objects can now react to what the camera sees in the real world. A material can be configured to appear only on specific surfaces — for example, render a cloud effect exclusively on pixels classified as sky, or hide a character wherever a person is detected. Eleven real-world categories are supported: sky, building, tree, road, sidewalk, terrain, structure, object, vehicle, person, and water. Available on both Android and iOS.

iOS setup: Semantic masking on iOS requires the ARCore Semantics pod. Add includeSemantics: true to your Expo plugin config in app.json to have it included automatically. If you are already using provider: "arcore" or includeARCore: true, the pod is already included and no extra config is needed.

["@reactvision/react-viro", {
  "ios": {
    "includeSemantics": true
  }
}]

Animated GLB Models

3D models in GLB/glTF format with embedded animations now play correctly. This covers the three main animation systems used by artists — skeletal rigs (character movement), morph targets (facial expressions, blend shapes), and skinning (soft-body deformation). No extra configuration is needed; animations embedded in the file are automatically available.

Permission Helpers

Two new utility functions make it easier to handle camera and location permissions:

  • requestRequiredPermissions(permissions?) — prompts the user for the specified permissions. Pass a list to request only what your feature needs ("camera", "microphone", "storage", "location"), or call with no arguments to request all four at once.
  • checkPermissions(permissions?) — reads the current permission status without prompting the user. Useful for checking what has already been granted before deciding whether to ask.

Expo 54 & 55 Support

The package is now compatible with both Expo SDK 54 and Expo SDK 55.


Bug Fixes

Android — App crash on launch (Android 15 / 16)

Apps were crashing immediately on launch on devices running Android 15 or 16 due to a new 16 KB memory page-size requirement introduced by Google. All native libraries have been rebuilt to comply with the new standard.

Android — App crash after returning from background

A combination of three separate issues caused a guaranteed crash whenever the operating system suspended the app and reclaimed GPU memory. On resume, the app attempted to use GPU resources that no longer existed. All three root causes have been fixed; the app now recovers cleanly from background suspension.

Android — ViroARImageMarker detection callback not firing

The onAnchorFound callback on ViroARImageMarker was never called on Android, making it impossible to respond to image detection events in JavaScript. The native event bridge has been corrected.

Android — Model texture overlaying the screen during video recording

When recording AR scenes, the 3D model's texture was incorrectly rendered over the entire screen instead of just the model. This was caused by a stale GPU state cache when switching between the display and recording graphics contexts. The cache is now correctly reset on each context switch.

iOS — Portal scene interior not rendering (#452)

On iOS, looking through a ViroPortalScene showed only the camera feed — none of the 3D content inside the portal was visible. This was caused by leftover GPU stencil state from the previous frame that prevented interior content from passing the render test. The stencil state is now correctly reset each frame.

iOS — EAS cloud build failure (Podfile syntax error) (#441)

iOS builds through Expo Application Services (EAS) were failing with a CocoaPods syntax error in the generated Podfile. The Expo plugin now generates a valid Podfile in all build environments.


Summary

Area Change
New feature Semantic masking for materials (Android + iOS)
New feature Animated GLB — skeletal, morph targets, skinning
New feature requestRequiredPermissions utility
New feature checkPermissions utility
Platform Expo 54 & 55 support
Fix — Android Crash on launch on Android 15 / 16 (16 KB page size)
Fix — Android Crash after returning from background
Fix — Android ViroARImageMarker onAnchorFound never fired
Fix — Android Model texture overlay during video recording
Fix — iOS Portal scene interior content not rendering (#452)
Fix — iOS EAS cloud build Podfile syntax error (#441)

v2.53.1

Choose a tag to compare

@doranteseduardo doranteseduardo released this 12 Mar 00:34

Hotfix: In MALI GPU devices, the camera texture may get frozen while switching AR scenes.

v2.53.0

Choose a tag to compare

@doranteseduardo doranteseduardo released this 11 Mar 00:34

@reactvision/react-viro v2.53.0 — Release Notes

⚠️ Breaking Changes

ViroARSceneNavigatorprovider replaces cloudAnchorProvider and geospatialAnchorProvider

The two separate props are merged into a single provider prop that controls both backends simultaneously. provider defaults to "reactvision" so the prop can be omitted entirely in most cases.

Before:

<ViroARSceneNavigator
  cloudAnchorProvider="reactvision"
  geospatialAnchorProvider="reactvision"
  initialScene={{ scene: MyARScene }}
/>

After:

// defaults to "reactvision" — prop can be omitted
<ViroARSceneNavigator initialScene={{ scene: MyARScene }} />

// Or to override:
<ViroARSceneNavigator provider="arcore" initialScene={{ scene: MyARScene }} />

ViroCloudAnchorProvider and ViroGeospatialAnchorProvider are now deprecated aliases for the new ViroProvider type. They still compile with a deprecation warning.

Expo plugin (withViro) — provider replaces cloudAnchorProvider and geospatialAnchorProvider

Before:

["@reactvision/react-viro", {
  "cloudAnchorProvider": "reactvision",
  "geospatialAnchorProvider": "reactvision",
  "rvApiKey": "...",
  "rvProjectId": "..."
}]

After:

["@reactvision/react-viro", {
  "provider": "reactvision",
  "rvApiKey": "...",
  "rvProjectId": "..."
}]

ViroARPlaneSelector requires manual anchor wiring

The component no longer self-discovers planes. You must now forward ViroARScene anchor events to it via a ref:

const selectorRef = useRef<ViroARPlaneSelector>(null);

<ViroARScene
  anchorDetectionTypes={["PlanesHorizontal", "PlanesVertical"]}
  onAnchorFound={(a)   => selectorRef.current?.handleAnchorFound(a)}
  onAnchorUpdated={(a) => selectorRef.current?.handleAnchorUpdated(a)}
  onAnchorRemoved={(a) => a && selectorRef.current?.handleAnchorRemoved(a)}
>
  <ViroARPlaneSelector ref={selectorRef} alignment="Both" onPlaneSelected={...}>
    <MyContent />
  </ViroARPlaneSelector>
</ViroARScene>

What's new

ReactVision Cloud Anchors (RVCA)

Place persistent AR content that other users can find — no Google Cloud account required. RVCA is a proprietary closed-source SDK; its implementation is not part of the open-source ViroCore or react-viro distribution.

The "reactvision" provider routes hostCloudAnchor / resolveCloudAnchor through the ReactVision platform. The existing hostCloudAnchor, resolveCloudAnchor, and onCloudAnchorStateChange API is unchanged.

  • Hosting: scan your environment briefly, then call hostCloudAnchor. Returns an error immediately if the environment has not been sufficiently observed — no silent fallback.
  • Resolving: the SDK matches the live camera feed against stored anchor data and returns a pose once a confident localisation is established. Cross-platform (iOS host → Android resolve and vice versa) is fully supported.
  • TTL: hostCloudAnchor accepts a ttlDays parameter (1–365) to control anchor expiry on the backend.
  • GPS tagging: set the device location before hosting to embed GPS coordinates as anchor metadata. Enables proximity search via rvFindNearbyCloudAnchors.

8 new methods on arSceneNavigator for full CRUD and analytics on cloud anchors:

Method Description
rvGetCloudAnchor(anchorId) Fetch a single anchor record
rvListCloudAnchors(limit, offset) Paginated list of all project anchors
rvUpdateCloudAnchor(id, name, desc, isPublic) Rename / re-describe an anchor
rvDeleteCloudAnchor(anchorId) Permanently delete an anchor and its assets
rvFindNearbyCloudAnchors(lat, lng, radius, limit) GPS proximity search
rvAttachAssetToCloudAnchor(id, url, size, name, type, userId) Attach a hosted file
rvRemoveAssetFromCloudAnchor(anchorId, assetId) Remove an attached asset
rvTrackCloudAnchorResolution(...) Record resolve analytics manually

ReactVision Geospatial Anchor Management

5 new management methods for GPS-tagged anchors (backed by the proprietary RVCA SDK):

Method Description
rvListGeospatialAnchors(limit, offset) Paginated list
rvGetGeospatialAnchor(anchorId) Fetch a single geospatial anchor
rvFindNearbyGeospatialAnchors(lat, lng, radius, limit) GPS proximity search
rvUpdateGeospatialAnchor(id, sceneAssetId, sceneId, name) Update metadata
rvDeleteGeospatialAnchor(anchorId) Permanently delete

createGeospatialAnchor, createTerrainAnchor, and createRooftopAnchor are now supported with provider="reactvision". No VPS, no ARCore Geospatial API, and no ARCore pods are required.

Asset upload:

rvUploadAsset(assetType, filename, data, appUserId) — uploads a file to ReactVision storage and returns a URL and asset ID. Supported assetType values: "3d-model", "image", "video", "audio". The returned asset ID can be linked to a geospatial anchor via rvUpdateGeospatialAnchor or to a cloud anchor via rvAttachAssetToCloudAnchor.

New geospatial utilities

  • gpsToArWorld(devicePose, lat, lng, alt) — converts a GPS coordinate to an AR world-space [x, y, z] offset from the device's current geospatial pose.
  • latLngToMercator(lat, lng) — converts a GPS coordinate to a metric 2D position. Building block for gpsToArWorld and custom geo math.

Both are exported from @reactvision/react-viro.

New ViroProvider type

Canonical union type "none" | "arcore" | "reactvision" exported from the package. Replaces the deprecated ViroCloudAnchorProvider and ViroGeospatialAnchorProvider types.

Shader modifier system — major expansion

Shader modifiers now support the full range of custom GPU effects:

  • Custom textures — declare uniform sampler2D in modifier code and pass textures via materialUniforms. Swap them at runtime with updateShaderUniform.
  • Vertex → fragment data — use the new varyings field to pass typed values from a Geometry modifier to a Surface or Fragment modifier (e.g. displacement amount driving roughness).
  • Scene depth access — set requiresSceneDepth: true on a fragment modifier to receive scene_depth_texture automatically. Enables soft particles, contact glow, and intersection effects.
  • Live camera feed on geometry — set requiresCameraTexture: true to sample the AR camera on any surface. Platform differences (samplerExternalOES vs sampler2D) handled invisibly. Enables magnifying glass, portal, refraction, and warp effects.
  • Deterministic ordering — modifiers now have a priority field so engine internals never override your effects regardless of attachment order.

AR plane detection improvements

  • Plane detection now defaults to both horizontal and vertical — no need to set anchorDetectionTypes explicitly.
  • Objects placed via ViroARPlaneSelector now appear at the exact tap point, not the plane centre.
  • onPlaneSelected receives the tap position as a third argument: (plane, tapPosition?) => void.
  • New props: onPlaneRemoved, hideOverlayOnSelection, material.
  • useActualShape now defaults to true — polygon boundary used instead of bounding rect.
  • New public method handleAnchorRemoved on ViroARPlaneSelector for use in the onAnchorRemoved callback.

Depth sensor access

ViroARSceneNavigator has three new props for apps that need depth data without full occlusion:

  • depthEnabled — activates LiDAR / monocular depth / ARCore Depth for DepthPoint hit tests.
  • depthDebugEnabled — overlays the depth map on the camera feed.
  • preferMonocularDepth (iOS only) — forces monocular depth even on LiDAR devices.

Bug fixes

  • Models with washed-out / overexposed colours — GLB and other 3D assets appeared too bright due to an emissive colour value being incorrectly added to all materials. Fixed.
  • iOS video recording silent failurestartVideoRecording / stopVideoRecording were broken on iOS 17+ with the New Architecture. Multiple AVAssetWriter and AVAudioSession issues fixed; recording now falls back to video-only if audio fails.
  • Android crash when closing a scene with physics — null pointer dereference on scene close for physics-enabled nodes. Fixed.
  • Android New Architecture dev menu error — "You should not use ReactNativeHost directly" error on startup. Fixed.
  • Ghost planes in ViroARPlaneSelector — pre-allocated slot index mapping was non-deterministic causing planes to appear in wrong positions or persist after removal. Fully rewritten.
  • Selected plane disappeared immediately on tap — opacity logic inversion fixed.
  • Children rendered on every plane slot — children now rendered once, only on the selected plane.
  • onPlaneDetected return value ignored — returning false from onPlaneDetected previously had no effect. Now correctly prevents the plane from being added to the visible set.
  • Removed planes not cleaned up — disappeared planes were never removed from internal state, accumulating over time. handleAnchorRemoved now deletes the entry and resets selection if needed.
  • Plane updates silently dropped for large surfaces — ARKit update threshold logic was AND instead of OR; large planes (floors, walls) rarely updated. Fixed.
  • Rapid plane updates dropped on initial detection — fixed 100 ms throttle replaced with adaptive rate (33 ms for first 20 updates, 66 ms thereafter).

v2.52.1

Choose a tag to compare

@doranteseduardo doranteseduardo released this 16 Feb 22:43
c0acb32

What's Changed

Full Changelog: v2.52.0...v2.52.1

v2.52.0 - Shader System & Memory Improvements

Choose a tag to compare

@doranteseduardo doranteseduardo released this 09 Feb 20:30
390da91

Summary

This release adds shader customization support for iOS and Android, fixes critical memory leaks, and improves AR depth functionality.

Key Features

Shader System (New)

  • Cross-platform shader support
  • Real-time shader customization for iOS and Android
  • Shader propagation down node trees
  • Standardized fragment output
  • Texture and animation support in shaders
  • Optimized material sharing for better performance

AR & Depth Improvements

  • Depth-based AR hit testing
  • Monocular depth fallback for non-LiDAR devices
  • Fixed depth frame alignment issues

Critical Bug Fixes

  • iOS Memory Leaks (Critical): Fixed all memory leaks on iOS platform
  • Material Overflow: Fixed cloned materials array overflow crashes
  • Portal Crashes: Fixed crashes when unmounting portals on iOS
  • Gravity Type Crash: Fixed Android crash (gravity now uses 3D vector [x, y, z] instead of number)
  • VRX Asset Loading: Fixed VRX asset loading issues on iOS
  • hitResultId: Fixed availability in AR hit tests

Other Improvements

  • Performance throttle to prevent system overload
  • Refactored thread lock implementation
  • Removed debug logs from production code
  • Improved TypeScript type definitions