-
Semantic Masking —
semanticMaskprop onViroMaterial(Android + iOS)Selectively show or hide a material based on what the AR session classifies each pixel as in the real world. A per-frame 256×144 semantic segmentation image from ARCore is used to discard fragments at the GPU level — no CPU readback, no extra render pass.
ViroMaterials.createMaterials({ // Only render on pixels classified as sky skyOnly: { diffuseColor: "#ffffff", semanticMask: { mode: "showOnly", labels: ["sky"], }, }, // Invisible on people (useful for occlusion) hidePeople: { diffuseColor: "#00ff00", semanticMask: { mode: "hide", labels: ["person"], }, }, });
modecontrols the discard direction:Mode Behaviour "showOnly"Fragment rendered only where the pixel matches a label "hide"Fragment discarded where the pixel matches a label "debug"Overrides color: blue = unlabeled, teal→orange gradient = classified pixels labels— one or more of:"sky","building","tree","road","sidewalk","terrain","structure","object","vehicle","person","water"iOS setup: requires the ARCore Semantics pod. Add
includeSemantics: trueto the Expo plugin config inapp.json. Ifprovider: "arcore"orincludeARCore: trueis already set, the pod is included automatically. The prop is silently ignored when the session has not yet produced a semantic image. -
requestRequiredPermissions(permissions?)utilityPrompts the user for the specified permissions and resolves with their granted status. Pass a
ViroPermission[]to request only what your feature needs; omit it to request all four.import { requestRequiredPermissions } from "@reactvision/react-viro"; // Camera only const { camera } = await requestRequiredPermissions(["camera"]); // All four const result = await requestRequiredPermissions();
-
checkPermissions(permissions?)utilityNon-prompting read of current permission status. Never shows a system dialog.
import { checkPermissions } from "@reactvision/react-viro"; const { camera, microphone } = await checkPermissions(["camera", "microphone"]); if (!camera) { // guide user to Settings }
ViroPermission("camera" | "microphone" | "storage" | "location") is exported as a standalone type.ViroPermissionsResultkeys are typedboolean?— only keys for the requested permissions are present in the resolved object. -
Animated GLB support — skeletal animation, morph targets, and skinning
GLB/glTF 2.0 models with embedded animations are now fully supported on both platforms. Three animation systems are covered:
System Description Skeletal animation Bone-driven character and creature rigs Morph targets Blend-shape facial animation and shape keys Skinning Vertex-weight deformation tied to a skeleton Animations are played via the existing
ViroAnimatedComponentAPI — no new props required. Multiple animations embedded in a single GLB file are each exposed as a named clip. -
Expo 54 and Expo 55 support
The package peer dependency range and Expo config plugin are updated to support both Expo SDK 54 and Expo SDK 55.
-
[Android]
ViroARImageMarker—onAnchorFoundnever firesThe native
ARScene.javacallback path for image anchors was not bridging theonAnchorFoundevent to the React Native layer. The marker component appeared to work (the tracked image drove the AR overlay position) but the JSonAnchorFoundhandler was never called, making it impossible to react to detection in user code. -
[Android] App crash on launch on 16 KB page-size devices (Android 15 / 16) — #429
All bundled
.astatic libraries have been recompiled and aligned to 16 KB boundaries. Devices that enforce the new ABI requirement (Android 15 and later) were crashing immediately onSystem.loadLibrarybecause the dynamic linker rejected unaligned segments in the.soproduced from the old.afiles. -
[Android] Fatal
SIGSEGVafter returning from background — #445Three independent bugs combined to produce a guaranteed crash whenever the OS reclaimed the OpenGL/EGL context while the app was in the background:
-
Background model downloads — assets that finished downloading while paused queued GPU-upload tasks that fired against the destroyed context on resume. GPU tasks are now gated on EGL context validity before execution.
-
Stale texture IDs — the AR session retained OpenGL texture handles from the destroyed context and attempted to render with them on the next frame. Texture handles are now invalidated on context loss and re-created on resume.
-
Render-queue shutdown race (VIRO-4537) — a pre-existing null-ordering bug prevented the render queue from being cleanly shut down during
dispose(), leaving a partially torn-down renderer reachable. The shutdown sequence is now ordered correctly.
-
-
[iOS] Invalid Podfile syntax error on EAS iOS builds — #441
The Expo config plugin (
withViro) was writing apoddirective with a string literal in a position that CocoaPods does not accept, producing:Invalid Podfile file: syntax error, unexpected string literal, expecting end-of-inputThe generated Podfile snippet is now syntactically valid in all EAS build environments.
-
[Android] Model texture overlays entire screen during video recording
VRODriverOpenGLmaintains a CPU-side cache of the currently-bound OpenGL texture per unit and bound shader program. This cache was shared between the display EGL context and the recording EGL context.When
VRORecorderEglSurfaceDisplay::bind()switched to the recording context the cache still reflected display-context state. The recording blit updated the cache (RTT texture → unit 0); wheninvalidate()restored the display context the cache falsely reported that the RTT texture was still bound, skippedglBindTexture, and sampled the wrong texture — causing the model's diffuse texture to overlay the full display frame.The texture binding cache is now invalidated whenever the active EGL surface changes.
-
[iOS]
ViroPortalSceneinterior content not rendering — #452Portal interior content (3D objects,
Viro360Image, etc.) was invisible on iOS in v2.53.0 while the portal frame and stencil hole rendered correctly.VRODisplayOpenGLiOS::bind()was missing two OpenGL state resets thatVRORenderTargetOpenGL::bind()already included:glStencilMask(0xFF)beforeglClear— portal rendering leaves the stencil write-mask at0x0F(lower 4 bits only); without this resetGL_STENCIL_BUFFER_BITinglCleardid not clear the upper bits, leaving stale values that failed the stencil test on the following frame and prevented portal contents from drawing.glStencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 0xFF, 0xFF)afterglClear— resets the stencil function to always-pass so non-portal geometry rendered after the portal pass is not inadvertently clipped.
Android was unaffected because it uses
VRORenderTargetOpenGL::bind()directly which already contained both resets.
-
ViroARSceneNavigator—providerreplacescloudAnchorProviderandgeospatialAnchorProviderThe two separate props are merged into a single
providerprop that controls both the cloud anchor and geospatial anchor backends simultaneously.Before:
<ViroARSceneNavigator cloudAnchorProvider="reactvision" geospatialAnchorProvider="reactvision" initialScene={{ scene: MyARScene }} />
After:
// provider defaults to "reactvision" — prop can be omitted entirely <ViroARSceneNavigator initialScene={{ scene: MyARScene }} /> // Or to override: <ViroARSceneNavigator provider="arcore" initialScene={{ scene: MyARScene }} />
ViroCloudAnchorProviderandViroGeospatialAnchorProvidertypes are now deprecated aliases for the newViroProvidertype. Remove them from props; useproviderinstead. The old types still compile with a deprecation warning to ease migration. -
Expo plugin (
withViro) —providerreplacescloudAnchorProviderandgeospatialAnchorProviderThe two separate Expo plugin options are merged into a single
provideroption inapp.json. The old options are deprecated but still accepted as overrides.Before:
["@reactvision/react-viro", { "cloudAnchorProvider": "reactvision", "geospatialAnchorProvider": "reactvision", "rvApiKey": "...", "rvProjectId": "..." }]
After:
["@reactvision/react-viro", { "provider": "reactvision", "rvApiKey": "...", "rvProjectId": "..." }]
Setting
provider: "arcore"continues to inject ARCore pods on iOS and force dynamic linkage, exactly ascloudAnchorProvider: "arcore"did before. Settingprovider: "reactvision"injects location permissions on both platforms (previously only triggered whengeospatialAnchorProvider: "reactvision"was explicit). -
ViroARPlaneSelector — new architecture (scene-event-driven)
The component no longer self-discovers planes through pre-allocated
ViroARPlanedetector slots. You must forward the parentViroARSceneanchor 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>
The old self-contained usage (no ref, no anchor wiring) no longer works.
-
gpsToArWorld(devicePose, lat, lng, alt)utility — converts a GPS coordinate to an AR world-space[x, y, z]offset from the device's current geospatial pose. Uses Mercator projection + compass heading. Available in@reactvision/react-viro. -
latLngToMercator(lat, lng)utility — WGS84 Mercator projection returning metres. Building block forgpsToArWorldand custom geo math. -
ReactVision — Cloud Anchor Provider
The
"reactvision"provider routeshostCloudAnchor/resolveCloudAnchorthrough the ReactVision platform — no Google Cloud configuration or API key required. The existinghostCloudAnchor,resolveCloudAnchor, andonCloudAnchorStateChangeAPI is unchanged. -
ReactVision — Cloud Anchor Management API
8 new methods on
arSceneNavigatorfor full CRUD and analytics on cloud anchors (available whenprovider="reactvision", the default):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 All calls are handled entirely inside the compiled native binary — no API keys or endpoint URLs are present in the JS bundle.
-
ReactVision — Geospatial Anchor Provider + Management API
GPS-tagged anchors are available through the ReactVision platform. 5 new management methods on
arSceneNavigator: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 -
New
ViroProvidertypeCanonical union type
"none" | "arcore" | "reactvision"exported from the package. Replaces the oldViroCloudAnchorProviderandViroGeospatialAnchorProvider(now deprecated aliases). -
ViroARPlaneSelector — tap-position object placement
Objects placed as
childrenofViroARPlaneSelectornow appear at the exact point the user tapped, not at the plane's geometric centre.The world-space tap position from
onClickStateis converted to the plane's local coordinate space using the full inverse rotation matrix (R = Rx·Ry·Rz, X-Y-Z Euler order as used byVROMatrix4f) and clamped to the plane surface (Y = 0 in local space). Children retain their own Y offset (position={[0, 0.5, 0]}etc.) relative to the tap point. -
ViroARPlaneSelector —
onPlaneSelectedreceives tap positiononPlaneSelected?: (plane: ViroPlaneUpdatedMap, tapPosition?: [number, number, number]) => void;
tapPositionis the world-space ray–surface intersection point. -
ViroARPlaneSelector —
onPlaneRemovedpropCalled when ARKit/ARCore removes a tracked plane. Receives the
anchorIdstring. Selection is automatically cleared if the removed plane was selected. -
ViroARSceneNavigator —
depthEnabledpropActivates the depth sensor (LiDAR on supported iOS devices, monocular depth estimator as fallback; ARCore Depth API on Android 1.18+) without enabling occlusion rendering. Virtual objects are not occluded, but depth data becomes available for:
performARHitTest— returnsDepthPointresults- distance measurement use-cases
When
occlusionMode="depthBased"is set at the same time,occlusionModetakes precedence and full depth-based occlusion is used instead.<ViroARSceneNavigator depthEnabled={true} ... />
Platform Requirement iOS LiDAR device or monocular fallback (all devices) Android ARCore Depth API — ARCore 1.18+ -
ViroARSceneNavigator —
depthDebugEnabledpropDebug visualisation of the depth texture over the camera feed. Colours represent depth values: magenta = no data, blue = near, red = far. Useful for verifying depth coverage before relying on hit-test results.
<ViroARSceneNavigator depthEnabled={true} depthDebugEnabled={true} ... />
Default:
false. Both iOS and Android. -
ViroARSceneNavigator —
preferMonocularDepthprop (iOS only)When
true, forces iOS to use the monocular depth estimator even on LiDAR-equipped devices. Useful for testing depth behaviour on older hardware or when LiDAR accuracy is not required and power consumption is a concern.Default:
false(LiDAR used when available). -
ViroARPlaneSelector —
hideOverlayOnSelectionpropControls whether the plane overlay hides once a plane is selected. Default
true— the overlay disappears after selection so only yourchildrencontent remains visible. Passfalseto keep the overlay visible (e.g. to show the plane boundary while the user repositions content). Unselected planes are always hidden after a selection regardless of this prop. -
ViroARPlaneSelector —
materialpropPass a
ViroMaterials-registered material name to customise the plane overlay surface. Defaults to the built-in translucent blue. -
ViroARPlaneSelector —
handleAnchorRemovedpublic methodNew public instance method matching
handleAnchorFound/handleAnchorUpdated. Removes a plane from the visible set and clears selection if needed. -
ARKit/ARCore plane detection — both orientations enabled by default
Previously only horizontal planes were detected unless
anchorDetectionTypeswas set explicitly. The default is now horizontal + vertical at all layers:Layer File C++ default VROARScene.hiOS native default VRTARScene.mmJS fallback default ViroARScene.tsx -
Shader modifiers — custom
sampler2DuniformsShader modifier code can now declare and receive
uniform sampler2Dinputs. Previously, sampler declarations in modifiers were silently ignored and the GPU always read texture unit 0. Now each named sampler is assigned its own texture unit and bound correctly at draw time.ViroMaterials.createMaterials({ noisyMetal: { lightingModel: "PBR", shaderModifiers: { surface: { uniforms: "uniform sampler2D noise_tex;", body: ` float noise = texture(noise_tex, _surface.diffuse_texcoord * 3.0).r; _surface.roughness = mix(0.2, 0.9, noise); _surface.metalness = mix(0.4, 1.0, noise); ` } }, materialUniforms: [ { name: "noise_tex", type: "sampler2D", value: require("./textures/noise.png") } ] } });
ViroShaderUniform.typenow accepts"sampler2D"andvalueaccepts arequire()image reference. -
Shader modifiers — runtime texture uniform update
ViroMaterials.updateShaderUniformnow accepts"sampler2D"as a type, allowing any texture bound to a modifier sampler to be swapped at runtime:ViroMaterials.updateShaderUniform("colorGraded", "lut_tex", "sampler2D", isDaytime ? require("./lut_day.png") : require("./lut_night.png"));
-
Shader modifiers — custom varyings between vertex and fragment stages
A new
varyingsfield on shader modifier entry points lets vertex-stage (Geometry) modifiers pass typed data to fragment-stage (Surface / Fragment) modifiers. Declare the same name in both stages; the engine injectsout/indeclarations automatically:shaderModifiers: { geometry: { varyings: ["highp float displacement_amount"], uniforms: "uniform float time;", body: ` float wave = sin(_geometry.position.x * 4.0 + time) * 0.1; _geometry.position.y += wave; displacement_amount = abs(wave) / 0.1; ` }, surface: { varyings: ["highp float displacement_amount"], body: `_surface.roughness = mix(0.1, 0.9, displacement_amount);` } }
-
Shader modifiers — scene depth buffer access
Fragment modifier entry points can set
requiresSceneDepth: trueto receivescene_depth_texture(sampler2D) andscene_viewport_size(vec2) automatically. Enables soft particles, contact edge glow, depth-based fog, and intersection effects. On older Adreno/Mali GPUs that cannot sample the depth buffer in-pass, the engine automatically inserts a blit to aGL_R32Fcolor attachment.fragment: { requiresSceneDepth: true, body: ` vec2 screenUV = gl_FragCoord.xy / scene_viewport_size; float sceneDepth = texture(scene_depth_texture, screenUV).r; float softFactor = clamp(abs(sceneDepth - gl_FragCoord.z) / 0.1, 0.0, 1.0); _output_color.a *= softFactor; ` }
-
Shader modifiers — live AR camera texture access
Fragment modifier entry points can set
requiresCameraTexture: trueto sample the live AR camera feed on any geometry. Two uniforms are bound automatically:ar_camera_texture(the camera feed) andar_camera_transform(amat3correcting for device orientation and aspect ratio). The sampler type difference between platforms (samplerExternalOESon Android,sampler2Don iOS) is handled invisibly — developer GLSL is identical on both platforms.surface: { requiresCameraTexture: true, body: ` vec2 cameraUV = (ar_camera_transform * vec3(_surface.diffuse_texcoord, 1.0)).xy; _surface.diffuse_color = texture(ar_camera_texture, cameraUV); ` }
Enables magnifying glass, portal, refraction, warp, and camera-feed-on-geometry effects.
-
Shader modifiers — deterministic priority ordering
VROShaderModifiernow has apriorityfield (default 0). Multiple modifiers on the same material are injected in ascending priority order. Engine-internal modifiers (AR shadow, occlusion) use priority -100; user modifiers default to 0; debug overlays use 100. Prevents engine modifiers from interfering with user-defined effects regardless of attachment order. -
Updated
ViroShaderModifiertypeexport type ViroShaderModifier = { uniforms?: string; body?: string; varyings?: string[]; // pass typed data from vertex to fragment stage requiresSceneDepth?: boolean; // auto-bind scene_depth_texture + scene_viewport_size requiresCameraTexture?: boolean; // auto-bind ar_camera_texture + ar_camera_transform }; export type ViroShaderUniform = { name: string; type: "float" | "vec2" | "vec3" | "vec4" | "mat4" | "sampler2D"; value: number | number[] | ReturnType<typeof require>; };
-
GLB/3D models — washed-out / overexposed colours (
virocore/ViroRenderer/VROMaterialShaderBinding.cpp,standard_fsh.glsl)Models loaded from GLB files (and some OBJ/FBX assets) appeared overexposed or had their colours washed out. Root cause:
material_emissive_colorwas being added to the fragment shader output for every material, including those with no intentional emission. GLB materials often carry a non-zero emission value in their PBR data; added on top of the diffuse+specular result it pushed the final colour toward white. Removed thematerial_emissive_colorandmaterial_alpha_cutoffuniforms from the standard shader binding — these were incorrectly applied to all materials instead of only emissive/masked ones. -
Android — physics body crash on scene close (
virocore/ViroRenderer/capi/Node_JNI.cpp)Closing a scene that contained physics-enabled nodes crashed with a null pointer dereference at
VRONode::setTransformDelegate+56. The GL-thread lambdas queued bynativeSetTransformDelegateandnativeRemoveTransformDelegatecallednode->setTransformDelegate()without first checking whether thestd::weak_ptr<VRONode>had already expired. Added anif (!node) { return; }guard in both lambdas so that a node destroyed before the lambda runs is silently skipped instead of crashing. -
Android — New Architecture Metro error (
viro/android/viro_bridge/…/PerfMonitor.java)"You should not use ReactNativeHost directly in the New Architecture" was thrown during dev-menu initialisation.
PerfMonitor.setView()calledgetReactNativeHost().getReactInstanceManager().getDevSupportManager(), which throws under the New Architecture. Replaced with the New-Arch API:getReactHost().getDevSupportManager(). -
iOS —
startVideoRecordingsilent failure /stopVideoRecordingreturns{success: false, errorCode: 0}(virocore/ios/ViroKit/VROViewRecorder.mm,VROViewAR.mm)Video recording was completely non-functional after the move to the React Native New Architecture. Several independent bugs combined to produce a silent failure with no error callback and an empty URL on stop:
[AVAssetWriter startWriting]return value was never checked. A failed writer still set_isRecording = YES, causing the stop path to hit thekVROViewErrorAlreadyStoppedbranch and returnerrorCode: 0.- The pixel buffer pool was never validated after
startWriting. A nil pool produced a null_videoPixelBufferused later without a check. AVAssetWriterwas created before the video dimensions were validated; a zero-size view (not yet laid out) produced an invalid writer.AVAudioSessionwas configured withoutmode:AVAudioSessionModeVideoRecordingand without[session setActive:YES]. On iOS 17+ ARKit takes control of the audio session, silently preventingAVAudioRecorderfrom writing data; the resulting empty/unplayable audio file then causedgenerateFinalVideoFileto callhandler(NO)→completionHandler(NO, nil, nil, kVROViewErrorUnknown).generateFinalVideoFilehard-failed when the audio file was missing or unplayable, with no fallback.
Fixes applied:
- Added dimension guard (
kVROViewErrorInitialization) before writer creation. - Added
startWritingreturn check with cleanup andkVROViewErrorInitialization. - Added pixel buffer pool nil check with writer cancellation and error callback.
- Added nil check for
AVAudioRecorderafterinitWithURL:settings:error:. - Added
-recordreturn value check with a diagnostic log. - Set
mode:AVAudioSessionModeVideoRecordingand[session setActive:YES]inVROViewARso the audio session is properly activated before recording starts. generateFinalVideoFilenow falls back to video-only output when the audio file is missing or unplayable, instead of failing the entire recording.
-
ViroARPlaneSelector — index-mapping mismatch (root cause of ghost planes)
The old implementation pre-allocated 25
ViroARPlaneslots per alignment and mapped them by JS array index. The C++ constraint matcher assigns anchors non-deterministically, so the slot at indexidid not reliably hold the planedetectedPlanes[i]referred to. The rewrite uses one<ViroARPlane anchorId={id}>per confirmed anchor — no mismatch possible. -
ViroARPlaneSelector — selected plane disappeared on selection
Opacity was computed as
isSelected ? 0 : isVisible ? 1 : 0— the selected plane hid itself immediately after tap. Fixed toselectedPlaneId === null || isSelected ? 1 : 0. -
ViroARPlaneSelector — children duplicated across all plane slots
Children were rendered inside every one of the 50 pre-allocated slots. Now rendered once, only on the selected plane, wrapped in a
ViroNodeat the tap position. -
ViroARPlaneSelector —
onPlaneDetectedreturn value ignoredReturning
falsefromonPlaneDetectedpreviously had no effect. Now correctly prevents the plane from being added to the visible set. -
ViroARPlaneSelector — removed planes not cleaned up
Disappeared planes were never removed from internal state. The new
handleAnchorRemoveddeletes the entry from the Map and resets selection if needed. -
VROARPlaneAnchor —
hasSignificantChangesAND→OR threshold logicThe previous implementation required both the absolute (>1 cm) and the relative (>5 %) extent thresholds to pass simultaneously. For large planes (floors, walls) the relative check almost never passed once the plane was mature, silently dropping most ARKit update notifications. Fixed to OR: either threshold alone triggers an update.
-
VROARPlaneAnchor — hard 100 ms update throttle suppressed early detection
ARKit sends rapid update bursts in the first seconds of plane detection. A fixed 100 ms minimum interval discarded most of them. Replaced with an adaptive throttle: 33 ms (≈30 fps) for the first 20 updates, 66 ms (≈15 fps) thereafter.
-
createGeospatialAnchor,createTerrainAnchor,createRooftopAnchor— supported withprovider="reactvision".GPS→AR placement uses Mercator projection + compass heading to compute the relative AR-frame offset, then creates a native ARKit / ARCore local anchor. No VPS, no ARCore Geospatial API, and no ARCore pods are required.
Method ReactVision placement createGeospatialAnchor(lat, lng, alt, quat)GPS absolute altitude createTerrainAnchor(lat, lng, altAboveTerrain, quat)deviceAlt + altAboveTerraincreateRooftopAnchor(lat, lng, altAboveRooftop, quat)deviceAlt + altAboveRooftopThe returned
anchorIdis a native AR anchor tracked by VIO for the session. Placement accuracy matches device GPS accuracy (~3–10 m horizontally). -
ViroARPlaneSelector —
useActualShapenow defaults totruePreviously the bounding-rect
ViroQuadfallback was used whenever vertices were absent; now the polygon path is always preferred and the quad is only used as a fallback before ARKit provides boundary vertices.
This release integrates the ReactVision native backend into ViroCore:
- Cloud anchor hosting and resolving via the ReactVision platform (Android + iOS)
- Geospatial anchor CRUD, proximity search, and GPS→AR placement
ReactVisionprovider wired into the AR session layer on both platforms
- Full Shader Support: Complete implementation of shader modifiers for iOS and Android platforms
- Shader Overrides: New
shaderOverridesprop for real-time shader customization across both platforms - Shader Propagation: Intelligent shader propagation system down the node tree with proper timing
- Fragment Output Standardization: Unified fragment shader outputs across platforms
- Texture Handling in Shaders: Full texture support in shader overrides
- Animated Shader Support: Uniform binding for animated shaders
- Material Animation Preservation: Materials with animations are preserved during shader application
- Lighting Properties in Shaders: Lighting properties are properly copied and maintained in custom shaders
- Material Sharing: Materials now shared efficiently across instances for improved performance
- Depth-based AR Hit Testing: Enhanced AR hit test functionality using depth information
- Monocular Depth Fallback: Non-LiDAR devices now automatically fallback to monocular depth estimation
- Throttle Mechanism: Added performance throttle to prevent system overload
- iOS Memory Leaks (Critical): Completely eliminated memory leaks on iOS platform (both viro and virocore)
- Portal Crashes (Critical): Fixed crashes when unmounting portals on iOS
- Material Overflow: Fixed cloned materials array overflow that caused crashes
- VRX Asset Loading: Resolved VRX asset loading issues
- Monocular Depth Alignment: Fixed monocular depth frame alignment issues
- Double Anchor Reference: Fixed issue with creating duplicate anchor references
- Gravity Type Crash: Fixed Android crash caused by incorrect gravity type definition (now correctly typed as 3D vector
[number, number, number]) - hitResultId: Fixed hitResultId availability issue in AR hit tests
- Thread Locks: Refactored implementation to avoid thread locks
- Depth Integration: Improved depth integration with simplified logic
- Debug logs and visualizations from production code
- Spam/noisy logging
This release includes 21 commits from virocore focused on:
- Native shader support and modifiers
- Memory management improvements
- Depth processing enhancements
Previous release baseline for v2.52.0 changes.
- Fixed pod install issues: Adjusted ViroKit requirements
- Resolved persisting pod installation failures
- Fixed pod install issues: Rebuilt ViroCore framework for iOS
- Resolved pod installation failures
- Improved compatibility with modern CocoaPods versions
- Fixed framework architecture issues
-
Enhanced Fabric compatibility: Migrated 30 methods across 8 Java modules to use Fabric's
UIBlockpattern- Fixed
ReactNoCrashBridgeNotAllowedSoftExceptionerrors in production - Replaced deprecated
getNativeModule(UIManagerModule.class)withUIManagerHelper.getUIManager() - Updated to use
com.facebook.react.fabric.interop.UIBlockandUIBlockViewResolver - Modules updated: ARSceneModule, ARSceneNavigatorModule, CameraModule, ControllerModule, NodeModule, SceneModule, SceneNavigatorModule, VRT3DSceneNavigatorModule
- Fixed
-
Improved prop handling: Added Fabric-aware error recovery system in VRTNodeManager
- Removed
isAttachedToWindow()checks that blocked prop updates in Fabric's pre-attachment phase - Implemented
safelyApplyProp()pattern with automatic retry on transient failures - Enhanced error logging for better debugging
- Refactored 28 @ReactProp methods for consistent error handling
- Reduced boilerplate code by ~250 lines
- Removed
-
Better resilience: Automatic prop retry handles GL context initialization timing issues
- Prevents props from being silently lost during scene transitions
- Recovers from view state timing issues on low-end devices
- Improved stability during AR session interruptions
- Added support for React Native New Architecture (Fabric)
- Added examples demonstrating how to use ViroReact with automatic architecture detection
- Updated documentation with information about the New Architecture support
- Deprecated legacy architecture support (removed completely)
- Compatibility with Expo 52
- Removed Telemetry
- Cleaned codebase
- fix(ViroBase): fix onClick not working for <ViroText /> components
#277 - fix(react): remove unnecessary debug logging
#276 - fix(ViroBase): fix onClick not working for <ViroText /> components (#277)
#272
- Fix screenshot taking and screen recording in AR
#256 - docs: update readme installation instructions
#259 - feat: added code of conduct
#255 - Update ISSUE_TEMPLATE.md
219fff7
- Fix screenshot taking
844be5a
- Support kotlin and Expo SDK 50 for Android
#249
- Fix Expo plugin issues, dependency issues, and stabilize
#247 - v2.23.1-alpha
#243 - Update README.md
#206 - Bump react-devtools-core from 4.27.7 to 4.28.5
#235 - Bump xml2js and @expo/config-plugins
#236 - Bump semver from 5.7.1 to 5.7.2
#234 - Bump @babel/traverse from 7.17.0 to 7.23.2
#231 - Bump hermes-engine and react-native
#209 - Fix for 'Tried to register two views with the same name VRTQuad' in ViroSurface
#180 - Bump shell-quote and @react-native-community/cli-tools
#208 - Bump @sideway/formula from 3.0.0 to 3.0.1
#195 - Bump decode-uri-component from 0.2.0 to 0.2.2
#182 - Bump @xmldom/xmldom from 0.7.5 to 0.7.8
#176 - Bump minimatch from 3.0.4 to 3.1.2
#178 - Bump json5 from 1.0.1 to 1.0.2
#191 - ViroSurface Fix
#199 - Bump simple-plist from 1.3.0 to 1.3.1
#139 - Bump async from 2.6.3 to 2.6.4
#131 - Bump plist from 3.0.4 to 3.0.5
#115 - Bump minimist from 1.2.5 to 1.2.6
#114 - Bump ansi-regex from 4.1.0 to 4.1.1
#113 - Update INSTALL_ANDROID.md
#98 - Update README.md
#126 - Remove unnecessary logging from Viro3DObject
#132 - Add VR AndroidManifest injection
#104 - Add supporter image for Morrow
#111 - Add out-of-the-box expo plugin support
#88 - Update INSTALL_IOS.md
#96 - Rewrite repo in typescript
#72 - Update INSTALL.md
#80 - Update README.md
#85 - Enable bitcode + chroma threshold
#78 - v2.22.0
#69 - Update INSTALL_IOS.md
#68 - Update LICENSE
#67 - Add out-of-the-box expo plugin support (#88)
#87 - Revert "Fix iOS compatibility and ViroVideo (#47)"
3a4b8e0
- Fix iOS compatibility and ViroVideo
#47
- Update package.json
#46 - Update
#42 - Update INSTALL_ANDROID.md
#38 - docs: updates links and also file type change
#27 - docs: fixed typo
#26 - Updating the discord invite link
#10 - Bumping version for release.
#9 - Removing references to fbjs.
#8 - fix typo in package.json
#6 - Adding NPM publish action
#4 -
- Removed the star from every pod as when doing pod install it drops …
#1
- Removed the star from every pod as when doing pod install it drops …
- First
4fb045b - Remove broken scripts
2d94c22 - Updating Readme to give better install instructions and moving examples to their own page(#7)
bee93cc