Releases: ReactVision/viro
v2.54.0
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
Hotfix: In MALI GPU devices, the camera texture may get frozen while switching AR scenes.
v2.53.0
@reactvision/react-viro v2.53.0 — Release Notes
⚠️ Breaking Changes
ViroARSceneNavigator — provider 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:
hostCloudAnchoraccepts attlDaysparameter (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 forgpsToArWorldand 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 sampler2Din modifier code and pass textures viamaterialUniforms. Swap them at runtime withupdateShaderUniform. - Vertex → fragment data — use the new
varyingsfield 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: trueon a fragment modifier to receivescene_depth_textureautomatically. Enables soft particles, contact glow, and intersection effects. - Live camera feed on geometry — set
requiresCameraTexture: trueto sample the AR camera on any surface. Platform differences (samplerExternalOESvssampler2D) handled invisibly. Enables magnifying glass, portal, refraction, and warp effects. - Deterministic ordering — modifiers now have a
priorityfield 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
anchorDetectionTypesexplicitly. - Objects placed via
ViroARPlaneSelectornow appear at the exact tap point, not the plane centre. onPlaneSelectedreceives the tap position as a third argument:(plane, tapPosition?) => void.- New props:
onPlaneRemoved,hideOverlayOnSelection,material. useActualShapenow defaults totrue— polygon boundary used instead of bounding rect.- New public method
handleAnchorRemovedonViroARPlaneSelectorfor use in theonAnchorRemovedcallback.
Depth sensor access
ViroARSceneNavigator has three new props for apps that need depth data without full occlusion:
depthEnabled— activates LiDAR / monocular depth / ARCore Depth forDepthPointhit 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 failure —
startVideoRecording/stopVideoRecordingwere broken on iOS 17+ with the New Architecture. MultipleAVAssetWriterandAVAudioSessionissues 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.
onPlaneDetectedreturn value ignored — returningfalsefromonPlaneDetectedpreviously 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.
handleAnchorRemovednow 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
What's Changed
- Fix ARCORE crashes and depth issues. by @doranteseduardo in #439
Full Changelog: v2.52.0...v2.52.1
v2.52.0 - Shader System & Memory Improvements
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
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
What's Changed
- Update README.md by @oliedis in #414
- Weak Linking for ARcore Pods by @doranteseduardo in #417
Full Changelog: v2.50.0...v2.50.1
v2.50.0
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 serversresolveCloudAnchor(cloudAnchorId)- Retrieve anchor on another devicecancelCloudAnchorOperations()- 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 anchorcreateTerrainAnchor(lat, lng, altitudeAboveTerrain, quaternion)- Ground-relative anchorcreateRooftopAnchor(lat, lng, altitudeAboveRooftop, quaternion)- Building-relative anchorgetCameraGeospatialPose()- Get current location with accuracy metricscheckVPSAvailability(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
- Non-indexed geometry support - Primitives without index buffers
- LINE_LOOP primitive type - Converted to line strip with closing segment
- TRIANGLE_FAN primitive type - Converted to individual triangles
- Mipmap filter modes - Proper separation of min/mip filtering
- Alpha masking (MASK mode) - With alphaCutoff support
- Emissive materials - emissiveFactor and emissiveTexture
- STEP animation interpolation - Discrete keyframe transitions
- Sparse accessor support - Override specific buffer values
Camera & Scene
- Perspective cameras - FOV, near/far planes, aspect ratio
- Orthographic cameras - xmag, ymag, clipping planes
- Default scene selection - Respects model.defaultScene
Lighting (KHR_lights_punctual)
- Directional lights - Color, intensity
- Point lights - Color, intensity, range/attenuation
- Spot lights - Color, intensity, range, inner/outer cone angles
Material Extensions
- KHR_materials_unlit - Constant/unlit lighting model
- Normal texture scale - Controls bump intensity
- 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
UIBlockpattern 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:androidBare 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
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
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
useActualShapeproperty 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
anchorIdtracking 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)
maxPlanesremoved (replaced by dynamic 25-detector-per-alignment behaviour).ViroCommonPropsandViroObjectPropsremoved 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.)