Skip to content

Releases: ReactVision/viro

v2.54.0

02 Apr 03:03
9572a17

Choose a tag to compare

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

12 Mar 00:34

Choose a tag to compare

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

v2.53.0

11 Mar 00:34

Choose a tag to compare

@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

16 Feb 22:43
c0acb32

Choose a tag to compare

What's Changed

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

v2.52.0 - Shader System & Memory Improvements

09 Feb 20:30
390da91

Choose a tag to compare

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

v2.51.0

01 Feb 20:59
190295a

Choose a tag to compare

What's Changed

  • Merge develop → main (AR stability + depth estimation for non-LiDAR) by @doranteseduardo in #428

Full Changelog: v2.50.1...v2.51.0

v2.50.1

24 Dec 03:58
f6bbb89

Choose a tag to compare

What's Changed

Full Changelog: v2.50.0...v2.50.1

v2.50.0

09 Dec 00:54

Choose a tag to compare

ReactVision 2.50.0 Release Notes

New Features

All features from ViroCore 2.50.0 are included, plus React Native specific bug fixes.


Cloud Anchors

Cross-platform AR anchor sharing between iOS and Android devices.

  • Cross-Platform: Share anchors between iOS and Android devices
  • Persistent: Anchors can be stored for 1-365 days
  • Accurate: Sub-centimeter accuracy in good conditions
  • Scalable: Supports multiple concurrent users
<ViroARSceneNavigator cloudAnchorProvider="arcore">
  {/* Use sceneNavigator.hostCloudAnchor() and resolveCloudAnchor() */}
</ViroARSceneNavigator>

API Highlights:

  • hostCloudAnchor(anchorId, ttlDays) - Upload anchor to Google's servers
  • resolveCloudAnchor(cloudAnchorId) - Retrieve anchor on another device
  • cancelCloudAnchorOperations() - Cancel pending operations

Geospatial API

Location-based AR with GPS coordinates using Google's ARCore Geospatial API.

  • Earth Tracking: Track device position using GPS and Visual Positioning System (VPS)
  • Three Anchor Types: WGS84 (absolute altitude), Terrain (relative to ground), and Rooftop (relative to buildings)
  • VPS Availability Check: Verify if enhanced positioning is available at a location
<ViroARSceneNavigator geospatialAnchorProvider="arcore">
  {/* Use createGeospatialAnchor(), createTerrainAnchor(), createRooftopAnchor() */}
</ViroARSceneNavigator>

API Highlights:

  • createGeospatialAnchor(lat, lng, altitude, quaternion) - WGS84 anchor
  • createTerrainAnchor(lat, lng, altitudeAboveTerrain, quaternion) - Ground-relative anchor
  • createRooftopAnchor(lat, lng, altitudeAboveRooftop, quaternion) - Building-relative anchor
  • getCameraGeospatialPose() - Get current location with accuracy metrics
  • checkVPSAvailability(lat, lng) - Check VPS support at location

Scene Semantics

ML-based scene understanding with 12 semantic labels.

  • 12 Semantic Labels: sky, building, tree, road, sidewalk, terrain, structure, object, vehicle, person, water, unlabeled
  • Real-time Processing: Per-frame label fractions
  • Use Cases: Outdoor detection, environment-aware content, safety warnings
// Enable via cloudAnchorProvider or geospatialAnchorProvider
// Use getSemanticLabelFractions() for environment detection

const { fractions } = await arSceneNavigator.getSemanticLabelFractions();
if (fractions.sky > 0.1) {
  console.log("User is outdoors!");
}

Depth Occlusion

Visual occlusion behind real-world objects for realistic AR blending.

  • Three Modes: Disabled, DepthBased, PeopleOnly
  • Realistic Blending: Virtual objects hidden behind real surfaces
  • People Segmentation: Option to only occlude behind detected people
<ViroARSceneNavigator occlusionMode="depthBased">
  {/* Virtual content properly occluded behind real surfaces */}
</ViroARSceneNavigator>

Occlusion Modes:

  • "disabled" - No occlusion (virtual objects always on top)
  • "depthBased" - Use depth data to occlude behind real surfaces
  • "peopleOnly" - Only occlude behind detected people

Extended glTF Support

Expanded glTF 2.0 support with 17 additional features for improved 3D model compatibility.

Core Geometry & Materials

  1. Non-indexed geometry support - Primitives without index buffers
  2. LINE_LOOP primitive type - Converted to line strip with closing segment
  3. TRIANGLE_FAN primitive type - Converted to individual triangles
  4. Mipmap filter modes - Proper separation of min/mip filtering
  5. Alpha masking (MASK mode) - With alphaCutoff support
  6. Emissive materials - emissiveFactor and emissiveTexture
  7. STEP animation interpolation - Discrete keyframe transitions
  8. Sparse accessor support - Override specific buffer values

Camera & Scene

  1. Perspective cameras - FOV, near/far planes, aspect ratio
  2. Orthographic cameras - xmag, ymag, clipping planes
  3. Default scene selection - Respects model.defaultScene

Lighting (KHR_lights_punctual)

  1. Directional lights - Color, intensity
  2. Point lights - Color, intensity, range/attenuation
  3. Spot lights - Color, intensity, range, inner/outer cone angles

Material Extensions

  1. KHR_materials_unlit - Constant/unlit lighting model
  2. Normal texture scale - Controls bump intensity
  3. Occlusion texture strength - Controls AO influence

Bug Fixes

Memory Leak Fix

  • Enhanced memory safety across 8 Java modules through Fabric architecture migration
  • Fixed null reference issues in prop application during React Native's pre-attachment phase
  • Improved stability during AR session transitions and low-end device scenarios
  • Migrated 30 methods to use Fabric's UIBlock pattern for safer memory management

Affected Modules:

  • ARSceneModule
  • ARSceneNavigatorModule
  • CameraModule
  • ControllerModule
  • NodeModule
  • SceneModule
  • SceneNavigatorModule
  • VRT3DSceneNavigatorModule

onClick iOS Fix

  • Fixed ViroText onClick event handling on iOS
  • Resolved issue where onClick prop was incorrectly passed to native code, interfering with event delegation
  • Fixes GitHub issue #272

AR Image Marker Fix

  • Improved ARImageMarker lifecycle management with proper weak reference patterns
  • Prevents retain cycles and memory leaks during image target tracking
  • Proper cleanup via removeARImageTarget() when updating targets

Setup

Expo Projects

{
  "expo": {
    "plugins": [
      [
        "@reactvision/react-viro",
        {
          "googleCloudApiKey": "YOUR_API_KEY",
          "cloudAnchorProvider": "arcore",
          "geospatialAnchorProvider": "arcore",
          "android": {
            "xRMode": ["AR"]
          }
        }
      ]
    ]
  }
}

Then rebuild:

npx expo prebuild --clean
npx expo run:ios
# or
npx expo run:android

Bare React Native Projects

iOS - Podfile:

use_frameworks! :linkage => :dynamic

pod 'ARCore/CloudAnchors', '~> 1.51.0'
pod 'ARCore/Geospatial', '~> 1.51.0'
pod 'ARCore/Semantics', '~> 1.51.0'

iOS - Info.plist:

<key>GARAPIKey</key>
<string>YOUR_GOOGLE_CLOUD_API_KEY</string>

Android - AndroidManifest.xml:

<meta-data
    android:name="com.google.android.ar.API_KEY"
    android:value="YOUR_GOOGLE_CLOUD_API_KEY" />

Requirements

  • iOS: iOS 12.0+, ARKit-capable device
  • Android: Android 7.0+ (API 24), ARCore-supported device
  • Google Cloud: Valid API key with ARCore API enabled
  • Depth Features: LiDAR (iOS) or ToF sensor/ARCore Depth API (Android)

v2.44.2

22 Nov 00:42

Choose a tag to compare

This is a minor patch update that removes some layers in the Android side to get 1:1 plane detection compared with direct ARCore implementations.

See at v2.44.1 for more details.

v2.44.1

19 Nov 23:07
d530ccb

Choose a tag to compare

Release Notes – v2.44.1

AR Plane Detection & Selection – Major Update

ViroARPlaneSelector – Complete Rewrite

Accurate Plane Shape Rendering

  • Planes now render using their actual geometric boundaries from ARKit/ARCore (via boundary vertices).
  • Automatic fallback to rectangular visualisation when vertex data is not available.
  • New useActualShape property to control rendering mode (default: true).

Map-Based Plane Tracking

  • Replaced array-based tracking with Map<string, ViroARPlaneType> for reliable and deterministic plane handling.
  • Plane identification now uses anchorId, eliminating index-based race conditions.
  • Improved stability for both plane selection and update cycles.

Multi-Alignment Detection

  • Added new alignment mode: "Both" for concurrent horizontal and vertical plane detection.
  • 25 detectors per alignment type for broader and more consistent scene coverage.
  • Enhanced scene understanding through simultaneous multi-plane detection.

Plane Classification Support (iOS)

  • ARKit plane classification now exposed, including: Wall, Floor, Ceiling, Table, Seat, Door, Window.
  • Classification data is included in all plane update callbacks.
  • Enables semantic placement and surface-specific logic.

Enhanced Properties & Callbacks

  • onPlaneDetected?: (updateMap) => boolean — Validate planes before adding them.
  • disableClickSelection?: boolean — Enables visual-only mode.
  • useActualShape?: boolean — Controls shape rendering behaviour.

Visual Improvements

  • Updated material to a bright, translucent blue (rgba(0, 122, 255, 0.5)) for improved visibility.
  • cullMode: "None" enabled for better Android rendering compatibility.
  • Corrected alpha blending and depth buffer behaviour.

ViroARPlane Improvements

Improved Vertex Handling

  • More accurate 3D-to-2D vertex conversion for shape mapping.
  • Unified coordinate system handling across iOS and Android.
  • Corrected rotation logic for horizontal and vertical surfaces.

Enhanced Anchor Data

  • Plane anchors now provide full metadata: position, rotation, scale, centre, and dimensions.
  • Classification and vertex data included in all callbacks.
  • Consistent and reliable anchorId tracking throughout the plane lifecycle.

Architecture & Performance

16KB Page Size Support

  • Full compatibility with modern Android devices using 16KB memory pages.

Breaking Changes

Removed Properties (ViroARPlaneSelector)

  • maxPlanes removed (replaced by dynamic 25-detector-per-alignment behaviour).
  • ViroCommonProps and ViroObjectProps removed from type definitions.
    • These properties were previously documented but non-functional.
    • The component now exposes only explicit, fully supported props.

Internal State Refactor

  • Internal state has been migrated from an array to a Map.
    • (This affects only direct internal state access and does not impact typical usage.)