Repository navigation
v3.1.0
v3.1.0
Advanced VPS arrives: scan a place with the phone, then find it again and pin content to it, matched on the device or on the GPU server. Scans can carry the device's depth, so blank walls reconstruct. The world mesh now fuses depth across frames into a room that persists, and Meta Quest gets a headset-native Studio experience with the real hands showing through virtual content. Renderer binaries are rebuilt on virocore 3.1.0, with Spatial 1.4.0. The web build uses @reactvision/viro-web-renderer 1.1.0.
Advanced VPS
<ViroVPS>finds a scanned place and keeps tracking it.startTracking(id)takes a known location,"auto"searches by GPS and"visual"by camera image. Results come throughonLocalizedandonTrackingState.- Two ways to localise, behind one prop.
localization="device"(the default) downloads the place's map and matches on the phone.localization="server"sends camera frames to the GPU server instead, which holds up much better across days and lighting, and needs no map download.StudioSceneNavigatortakes the same choice asvpsLocalization. <ViroVPSAnchor>and the place's mesh. Content placed in map coordinates, and the scanned mesh (occlusion and physics), follow the map every frame.- Scanning from your app.
uploadScanRecording(target, outputDir, options?)zips a recording natively and sends it straight to Storage; on iOS the upload carries on in the background. Studio keeps the recording only while the scan is processed, unlesskeepRecordingis true, which merging a location's scans needs.getScan(scanId)follows processing.meshQualitypicks the mesh's detail:low,medium(the default) orhigh. - Record device depth while scanning (iOS with LiDAR, Android with ARCore Depth).
startRecording(outputDir, { depth: true })adds depth frames to the recording; set the navigator'sdepthCaptureEnabledwhen it mounts so the AR session is not reconfigured mid-scan. The scan upload carries the depth files. - Each scan says how far to trust its mesh:
scan.quality.mesh_confidenceisgood,fairorpoor, with reasons for whoever recorded (blank walls, a fast sweep, tracking that jumped). It never decides whether the map is accepted. - VPS calls go to Studio and need no address or credentials beyond the Studio session or the Expo plugin's
rvApiKeyandrvProjectId. Requests time out instead of hanging.
World mesh
- The mesh fuses depth frames into a room that persists on the depth-image and monocular paths, instead of rebuilding from the last frame.
worldMeshConfigtakesaccumulate,voxelSizeandmaxMemoryMB,sceneNavigator.resetWorldMesh()starts a new room, andgetWorldMeshStats()reportssource(lidar,depth,monocular,plane) andaccumulated. - Android: the world mesh is in the right place, read from each depth image's own stride, with confidence weighting samples instead of dropping them.
- iOS without LiDAR: estimated depth is placed where it was seen, so fusing it no longer leaves duplicated surfaces.
- The world mesh types are exported from the package root.
Meta Quest
- Studio scenes feel native in the headset. A menu on the left controller's menu button (or a palm pinch), panels styled after Meta Horizon OS at a quarter of the size, the HUD centred where the wearer looks, and placement along the controller's ray.
- The room stays put. Content on room surfaces, tap-placed models and the co-location frame keep their place when the wearer recentres;
onRoomMoved(listener)reports a recentre to your app. Plane scenes use the room's planes and pick the one nearest the wearer. - Input behaves like the platform's. Y goes back as B does, only a trigger or pinch selects, a hand and a controller on one side press once, and a released hand releases its pinch.
ViroController.getControllerRayAsync(source)says where a ray points. - Hand occlusion in passthrough:
handOcclusiononViroXRSceneNavigatorandViroVRSceneNavigatorlets the wearer's real hands show through virtual content in front of them (off by default;handOcclusionMode"mesh"or"capsules"). - Fewer crashes and leaks: videos no longer abort the app or leak, a scene's root can change as the headset view starts, and closing a scene logs no OpenXR errors.
- Expo plugin: Quest builds declare minSdkVersion 32, the Horizon OS SDK, a network security config and Meta's recommended activity settings, and no longer declare NFC.
Web
- Web AR content stays in the room on iPhone, and hides while tracking is lost (
hideContentWhenLostturns that off). From viro-web-renderer 1.1.0.
visionOS
- Studio scenes render in the ImmersiveSpace. They rooted in
ViroARScene, which renders nothing on visionOS, so a Studio scene was blank. They now root inViroScene, as on Meta Quest, in shared sessions too.
iOS Simulator
- Apps using Viro build and run in the iOS Simulator. ViroKit and the bridge ship as
ViroKit.xcframeworkandViroReact.xcframework, each with a simulator slice (arm64 and x86_64) beside the device one.
Everywhere
- Every scene navigator sends one usage ping when it mounts, replacing the device registration Spatial used to do. It carries no API key. Turn it off with
ViroTelemetry.setEnabled(false)or the Expo plugin'stelemetry: false. The iOS privacy manifest now ships with the pod. - Co-location: the replication socket sends a per-device id (
getColocationDeviceId()), and a join refused for the team's compute billing says so. - A click goes to what is drawn on top, not always the nearest object, and a click on nothing reaches
ViroController'sonClickagain. - Text sits where its vertical alignment puts it, and no longer disappears after a front-culled material.
- Video: a paused iOS video stays paused, and Android play and pause reach the player in the order they were made.
- Physics runs at real time on every display, ARCore reports the ambient light again, and a paused AR session stays paused when its options change.
- Animation chains type-check:
registerAnimationsaccepts names and nested sequences, as the native side always did, and colors inside a chain are processed. - Android: a
ViroARCamerano longer crashes the scene as it mounts, and GLB characters with one skin per mesh animate every part. - The world mesh's debug drawing no longer crashes iOS on a large accumulated mesh.
Viro3DObjectreads more of glTF:KHR_texture_transform,KHR_node_visibility,KHR_animation_pointer(node visibility, base color and emissive factors, texture offset, rotation and scale), textures onTEXCOORD_1and later sets, and emissive textures. Opaque and masked materials no longer show through where their texture's alpha is low, blended ones no longer hide what is behind them, characters whose rig animates a node above each joint move, skinned parts no longer vanish up close, a GLB with animation pointers no longer fails to load, one with 8-bit indices draws, and skinned GLBs draw on the web.- Sounds seek to fractional seconds,
Viro360ImagetakesstereoMode, shared frames answer{ success: false }outside Quest, and calls that do nothing on a platform say so once. - visionOS: spot light cones and morph targets match the other platforms.
- ViroKit targets iOS 15.1, the minimum the podspec already declared. The unsupported macOS target is gone from the native engine.
Check when upgrading
-
Emission now shows on physically based materials. A glTF
emissiveFactor, or an emissive color on a material withlightingModel: "PBR", was dropped before; a model that relied on that may now glow. -
A
styleon a scene navigator now applies. It was silently dropped before, so check the layout of any navigator you pass one. -
cloudAnchorProviderandgeospatialAnchorProviderare honoured whenprovideris not set. An app that still passescloudAnchorProvider="arcore"now uses ARCore Cloud Anchors and needs a Google Cloud API key; remove the prop or passproviderto keep ReactVision's. -
The iOS binaries moved to
ios/dist/ViroRenderer/ViroKit.xcframeworkandios/dist/lib/ViroReact.xcframework. The podspecs and the Expo plugin need nothing, but a script or Podfile that namesViroKit.frameworkorlibViroReact.aby path needs the new ones. The plugin no longer excludes arm64 from simulator builds and removes the exclusion it used to write, so runexpo prebuildagain.
See CHANGELOG.md for every change.