Omniverse Realtime Viewer
NVIDIAOfficialCreated by NVIDIA Omniverse
- Skill
- Tool integration
- Software development
- Apache-2.0
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Omniverse Realtime Viewer skill acts as a central routing and architectural framework for developing USD-based 3D viewer applications. It provides a structured approach to composing rendering, scene state, and delivery mechanisms, ensuring that developers can integrate OVRTX rendering, OVStage scene management, and various UI or streaming adapters effectively. The skill emphasizes a modular architecture where the viewer runtime, UI/input adapters, and delivery systems are decoupled, allowing for consistent behavior across local and streamed environments.
What it does
- Provides a routing architecture for USD viewer apps, XR delivery, and GPU-accelerated rendering.
- Defines the separation of concerns between viewer runtime, UI adapters, and delivery systems.
- Offers guidance on integrating OVRTX for high-fidelity 3D rendering.
- Establishes conventions for camera interaction, scene state management, and input handling.
- Supports the implementation of specialized features like stylized rendering and CAE/CFD visualization.
- Provides protocols for agent-to-UI communication and scene control.
When to use it
- When starting the development of a new USD-based realtime viewer application.
- When integrating advanced rendering features like stylized visualization or AOV switching.
- When building XR or spatial editing capabilities into an existing Omniverse application.
- When you need to standardize the architecture for local and streamed viewer deployments.
- When implementing chat-driven scene control or agent-based inspection of a 3D scene.
Advantages
- Promotes a clean, modular architecture that separates rendering logic from UI and transport.
- Ensures consistent behavior across different delivery methods, such as local windows or WebRTC streaming.
- Provides clear paths for extending functionality without disrupting the core viewer runtime.
- Facilitates the integration of complex simulation and visualization data into the viewer.
- Standardizes conventions for scene state, selection, and camera control.
Usage examples
- “How do I set up a basic USD viewer application using the Omniverse Realtime Viewer architecture?”
- The agent will guide you to start with the viewer app reference, resolve dependencies, and implement the core runtime owner to manage the OVStage and OVRTX renderer.
- “I need to add stylized rendering to my existing viewer. Where should I start?”
- The agent will direct you to the stylized visualization references to implement the required USD/Lua/CUDA nodes within your existing runtime owner.
- “How can I enable an AI agent to control the viewer scene?”
- The agent will point to the A2UI Scene Copilot reference to implement an operation interface that allows the agent to send commands through the existing runtime owner.
- “How do I switch between different render outputs like beauty and depth in my viewer?”
- The agent will explain how to use the AOV switching reference to map RenderVars and update the RenderProduct's orderedVars through the runtime owner.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/nvidia/omniverse-realtime-viewer/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip omniverse-realtime-viewer.zip -d .agents/skills
Documentation by NVIDIA Omniverse
<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
<!-- SPDX-License-Identifier: Apache-2.0 -->
Omniverse Realtime Viewer
Build responsive USD viewers by composing OVRTX rendering, OVStage scene state, and the delivery/UI libraries appropriate to the app. Use this package for viewer architecture and interaction; use each selected SDK's upstream guidance for installation and exact release-specific APIs.
Start With The App
When delivery is explicit, select its recipe through
references/routing.mdand follow its current phase. Otherwise start withreferences/usd-viewer-app/README.md. For an existing app, keep its architecture and read only the references for the requested change. Broad app, conventions and UI catalogs are lookups as needed.Resolve the selected libraries through
references/dependencies/README.md. Preserve the project's manifest unless an upgrade is requested.Build a working frame and camera interaction in the chosen shell, then add the requested capabilities. Read
references/conventions.mdfor shared input, camera, selection, and protocol conventions.Use
references/viewer-ux-workflow/README.mdfor broader interface design. Loading, selection feedback, errors, and input responsiveness belong in the first working app, alongside rendering.Validate the actual delivery path with
references/validation.md. A browser screenshot does not validate a native window or a different transport.
Architecture
| Owner | Responsibility |
|---|---|
| Viewer runtime | Own the live OVStage, publication clock, OVRTX renderer, scene changes, and render stepping. |
| UI and input adapter | Display frames and copied app state; send user intent to the runtime owner. |
| Storage/query/simulation workers | Perform their assigned work and return results through the selected integration boundary. |
| Delivery adapter | Present locally or stream through ovstream; respect frame ownership and backpressure. |
Use OVRTX for USD/3D rendering. Browser apps display its WebRTC video; local apps present its output through their native shell. A missing GPU means rendering is unverified, not a reason to substitute a browser 3D renderer.
Keep viewer cameras, settings, effects, and transient edits in app-owned session
or runtime state so the source USD stays intact. Serialize scene mutation and
render stepping through the runtime owner. Read
references/ovstage-ovrtx-integration/README.md for that loop, then the population
or data-plane references when implementing scene loading or attribute writes.
Keep expensive loading and metadata work off the UI and render threads. Keep transport details behind a delivery adapter so camera, selection, properties, and loading state can be reused across local and streamed shells.
Add Capabilities As Needed
Use references/routing.md to select camera/picking, scene management, render
settings, cloud assets, simulation, editor tools, deployment, or CAE/CFD
visualization. Read the selected capability's implementation flow and its linked
contract; the full reference catalog is not a prerequisite for a first frame.
For simulation, use the routing reference's Simulation Ecosystem section plus
references/realtime-sim-integration/README.md. For UI-driven forces or control,
add references/interaction-round-trip/README.md.
For example scenes, use references/usd-sample-data/README.md. When a runtime
failure needs diagnosis, use references/troubleshooting/README.md and the
selected SDK's matching release guidance before changing the architecture.
Solid Modeling: Upstream First
For usd-brep, exact BRep, solid modeling, kernel failures, CAD topology, or
BrepArray questions, first read references/dependencies/README.md → USD BRep. Follow the
owning repository's current agent guidance, skills, operation docs, and package
API before selecting local integration references. Discover the upstream router
rather than assuming skill names or directory layouts remain fixed. Upstream
owns modeling semantics, schema rules, tuning, and diagnostics; this package
owns OVRTX display, worker handoff, selection mapping, and publication timing.
GPU Processing And Stylized Viewers
For custom GPU processing, chained outputs and lens sampling, read
references/spg-processing/README.md. For toon, ink, technical/X-Ray styles,
geometry strokes or full wireframe, continue to
references/stylized-visualization/implementation.md. Its USD/Lua/CUDA starting
node and geometry/depth/composite build sequence work with the selected viewer
recipe; use references/stylized-visualization/style-recipes.md for the preset
math and references/stylized-visualization/README.md for supporting contracts.
Implement the result inside the existing OVRTX/runtime owner and deliver the
published processed output. These instructions do not require a sample checkout
or a prior stylized-rendering implementation.
For an optional usd-brep geometry source, first read
references/dependencies/README.md → USD BRep and the owning repository's
current agent guidance, skills, and operation docs; then read
references/stylized-visualization/usd-brep-source.md for the display boundary.
XR Viewers
For headsets, immersive viewers, or spatial editors, start with
references/xr-viewer-recipe/README.md. Resolve SDK setup and contracts through
references/dependencies/ovxr.md; the library owns OpenXR lifecycle and frame
submission. For controllers, hands, navigation, or scene tools, add
references/xr-spatial-input/README.md and
references/ovxr-python-interactions/README.md. For projection-integrated UI,
read references/ovxr-composition-ui/README.md and
references/ovxr-composition-ui-validation/README.md.
Files
- ATTRIBUTION.mdAdded by AutoGineer943 B
- BENCHMARK.md13.4 KiB
- LICENSELicence file added by AutoGineer11.2 KiB
- SKILL.md6.4 KiB
- evals/evals.json7.0 KiB
- references/a2ui-scene-copilot/README.md10.9 KiB
- references/aov-switching/README.md10.5 KiB
- references/cae-cfd-visualization/README.md10.1 KiB
- references/cae-cfd-visualization/cae-data-ingestion.md5.6 KiB
- references/cae-cfd-visualization/coordinate-systems-and-up-axis.md11.0 KiB
- references/cae-cfd-visualization/data-and-operators.md11.7 KiB
- references/cae-cfd-visualization/driving-cae-viz-via-ovstage.md6.4 KiB
- references/cae-cfd-visualization/emitter-and-seed-sources.md16.3 KiB
- references/cae-cfd-visualization/glyphs.md7.1 KiB
- references/cae-cfd-visualization/ovstage-render-and-camera.md11.0 KiB
- references/cae-cfd-visualization/ovui-controls.md13.2 KiB
- references/cae-cfd-visualization/rtwt-blueprint-recreation.md11.9 KiB
- references/cae-cfd-visualization/streaming-cae-viewer.md25.9 KiB
- references/cae-cfd-visualization/temporal-playback.md9.2 KiB
- references/cae-cfd-visualization/usd-authoring-and-materials.md21.5 KiB
- references/cae-cfd-visualization/volume-rendering.md2.5 KiB
- references/camera-auto-select/README.md9.0 KiB
- references/camera-controls/README.md20.9 KiB
- references/camera-picker/README.md9.5 KiB
- references/cloud-assets/README.md4.5 KiB
- references/cloud-deployment/README.md19.6 KiB
- references/cloud-deployment/container-image-build.md2.2 KiB
- references/cloud-deployment/gpu-container-runtime.md2.8 KiB
- references/cloud-deployment/nvcf-self-hosted.md8.4 KiB
- references/cloud-deployment/nvcf-viewer-container-contract.md4.8 KiB
- references/cloud-deployment/webrtc-network-diagnostics.md3.9 KiB
- references/cloudxr-opaque-data-channel/README.md1.1 KiB
- references/conventions.md7.4 KiB
- references/cpp-native-viewer/README.md4.9 KiB
- references/cpp-native-viewer/build-details.md5.2 KiB
- references/cpp-native-viewer/interaction-features.md11.3 KiB
- references/cpp-native-viewer/presentation-loop.md8.0 KiB
- references/cpp-native-viewer/project-build.md3.4 KiB
- references/cpp-native-viewer/renderer-session.md7.1 KiB
- references/cpp-native-viewer/validation.md3.4 KiB
- references/dependencies/README.md6.8 KiB
- references/dependencies/electron-shm.md1.5 KiB
- references/dependencies/environment-validation.md6.6 KiB
- references/dependencies/frontend.md2.3 KiB
- references/dependencies/local-openusd-gpu.md8.7 KiB
- references/dependencies/nvidia-runtime.md14.8 KiB
- references/dependencies/ovrtx.md3.1 KiB
- references/dependencies/ovstream.md3.3 KiB
- references/dependencies/ovxr.md2.3 KiB
- references/dependencies/quick-setup.md2.6 KiB
- references/dependencies/skia-yoga.md936 B
- references/electron-shm-viewer/README.md2.5 KiB
- references/electron-shm-viewer/architecture-project.md6.3 KiB
- references/electron-shm-viewer/electron-client.md6.5 KiB
- references/electron-shm-viewer/protocol-interaction-lifecycle.md7.9 KiB
- references/electron-shm-viewer/python-shm-server.md5.5 KiB
- references/electron-shm-viewer/validation.md2.8 KiB
- references/exact-brep-in-usd/README.md2.5 KiB
- references/gl-viewport-overlay/README.md8.0 KiB
- references/gl-viewport-overlay/architecture.md4.1 KiB
- references/gl-viewport-overlay/example-gizmo.md5.5 KiB
- references/gl-viewport-overlay/interaction-pattern.md4.0 KiB
- references/gl-viewport-overlay/projection-alignment.md4.3 KiB
- references/headless-shm-cli/README.md12.3 KiB
- references/huggingface-usd/README.md7.7 KiB
- references/interaction-round-trip/README.md40.1 KiB
- references/local-viewer/README.md17.8 KiB
- references/native-picking-selection/README.md13.1 KiB
- references/navigation-presets/README.md4.6 KiB
- references/navigation-presets/preset-camera-ops.md5.1 KiB
- references/newton-physics/README.md8.8 KiB
- references/object-selection/README.md11.1 KiB
- references/ovrtx-rendering/README.md23.0 KiB
- references/ovstage-data-plane/README.md3.5 KiB
- references/ovstage-live-geometry/README.md3.3 KiB
- references/ovstage-ovrtx-integration/README.md5.0 KiB
- references/ovstage-population/README.md3.7 KiB
- references/ovstage-runtime/README.md3.1 KiB
- references/ovui-library/README.md3.3 KiB
- references/ovui-library/api-reference.md4.3 KiB
- references/ovui-library/extending.md4.8 KiB
- references/ovui-local-viewer-recipe/README.md4.7 KiB
- references/ovui-local-viewer-recipe/interaction-features.md16.9 KiB
- references/ovui-local-viewer-recipe/project-structure.md6.2 KiB
- references/ovui-local-viewer-recipe/setup-shell-renderer.md16.4 KiB
- references/ovui-local-viewer-recipe/validation-build-order.md6.1 KiB
- references/ovwidgets-editor-shell/README.md5.4 KiB
- references/ovxr-composition-ui-validation/README.md7.1 KiB
- references/ovxr-composition-ui-validation/evidence-gates.md3.5 KiB
- references/ovxr-composition-ui-validation/frustum-placement.md2.4 KiB
- references/ovxr-composition-ui-validation/library-only-validation.md8.1 KiB
- references/ovxr-composition-ui-validation/owned-orchestration.md5.3 KiB
- references/ovxr-composition-ui-validation/viewer-evidence.md4.0 KiB
- references/ovxr-composition-ui/README.md8.5 KiB
- references/ovxr-composition-ui/async-raster-pipeline.md5.0 KiB
- references/ovxr-composition-ui/compositor-passes-and-sync.md6.4 KiB
- references/ovxr-composition-ui/depth-tools.md5.0 KiB
- references/ovxr-composition-ui/editor-document-model.md4.8 KiB
- references/ovxr-composition-ui/experience-quality.md8.5 KiB
- references/ovxr-composition-ui/foveation-and-edge-math.md3.5 KiB
- references/ovxr-composition-ui/library-only-compositor.md10.4 KiB
- references/ovxr-composition-ui/native-build-and-discovery.md4.6 KiB
- references/ovxr-composition-ui/performance-and-telemetry.md7.9 KiB
- references/ovxr-composition-ui/primary-projection-compositor.md3.5 KiB
- references/ovxr-composition-ui/primary-projection.md4.1 KiB
- references/ovxr-composition-ui/projection-and-depth.md5.3 KiB
- references/ovxr-composition-ui/raster-abi.md3.0 KiB
- references/ovxr-composition-ui/sdk-frame-backend.md1.6 KiB
- references/ovxr-composition-ui/skia-yoga.md2.8 KiB
- references/ovxr-composition-ui/spatial-interaction.md5.6 KiB
- references/ovxr-composition-ui/spatial-surfaces-and-interaction.md10.4 KiB
- references/ovxr-composition-ui/telemetry-contract.md3.8 KiB
- references/ovxr-composition-ui/validation-and-live-gates.md3.9 KiB
- references/ovxr-foveation-and-display/README.md1.1 KiB
- references/ovxr-frame-loop-and-readback/README.md1.2 KiB
- references/ovxr-library-runtime/README.md1.1 KiB
- references/ovxr-library-runtime/ar-compositing.md4.4 KiB
- references/ovxr-library-runtime/frame-input-order.md2.2 KiB
- references/ovxr-library-runtime/library-only.md1.1 KiB
- references/ovxr-library-runtime/live-ar-controls.md4.3 KiB
- references/ovxr-library-runtime/mirror-lifetime.md4.1 KiB
- references/ovxr-library-runtime/settings-and-lifetime.md3.9 KiB
- references/ovxr-library-runtime/viewer-assembly.md225 B
- references/ovxr-openxr-runtime/README.md1012 B
- references/ovxr-python-interactions/README.md1.8 KiB
- references/ovxr-python-interactions/architecture.md5.5 KiB
- references/ovxr-python-interactions/feature-patterns.md7.4 KiB
- references/physics-simulation/README.md7.1 KiB
- references/prim-info-display/README.md10.9 KiB
- references/prim-pick-effects/README.md7.3 KiB
- references/prim-transform-safety/README.md8.6 KiB
- references/realtime-sim-integration/README.md7.0 KiB
- references/render-settings/README.md12.6 KiB
- references/routing.md37.7 KiB
- references/section-views/README.md5.8 KiB
- references/seg-outline-highlight/README.md1.5 KiB
- references/selection-animation/README.md5.0 KiB
- references/selection-feedback/README.md7.5 KiB
- references/smlib-brep-pitfalls/README.md2.5 KiB
- references/spg-processing/README.md8.0 KiB
- references/stage-attribute-reads/README.md6.2 KiB
- references/stage-hierarchy/README.md20.3 KiB
- references/stage-hierarchy/fallback-worker-protocol.md7.4 KiB
- references/stage-loading/README.md7.1 KiB
- references/stage-management/README.md6.6 KiB
- references/stage-queries/README.md6.1 KiB
- references/streaming-client/README.md25.6 KiB
- references/streaming-lifecycle/README.md4.6 KiB
- references/streaming-messages/README.md19.5 KiB
- references/streaming-messages/server-handler-map.md3.1 KiB
- references/streaming-server/README.md17.7 KiB
- references/streaming-server/frame-loop-and-continuity.md3.8 KiB
- references/streaming-viewer-recipe/README.md1.9 KiB
- references/streaming-viewer-recipe/client-protocol.md14.2 KiB
- references/streaming-viewer-recipe/interaction-features.md13.8 KiB
- references/streaming-viewer-recipe/project-structure.md7.3 KiB
- references/streaming-viewer-recipe/server-runtime.md20.2 KiB
- references/streaming-viewer-recipe/validation-build-order.md8.5 KiB
- references/streaming-vs-local/README.md9.4 KiB
- references/stylized-visualization/README.md8.7 KiB
- references/stylized-visualization/aov-guide-contracts.md8.1 KiB
- references/stylized-visualization/implementation.md11.4 KiB
- references/stylized-visualization/line-compositor-delivery.md7.7 KiB
- references/stylized-visualization/mesh-xray.md10.1 KiB
- references/stylized-visualization/reproduction-validation.md10.2 KiB
- references/stylized-visualization/style-composition-contract.md5.4 KiB
- references/stylized-visualization/style-recipes.md14.7 KiB
- references/stylized-visualization/usd-brep-source.md4.9 KiB
- references/subprocess-geometry-bridge/README.md3.5 KiB
- references/tauri-local-viewer/README.md6.7 KiB
- references/tauri-shm-transform-gizmo/README.md12.3 KiB
- references/transform-manipulator/README.md17.1 KiB
- references/troubleshooting/README.md11.2 KiB
- references/troubleshooting/scenario-playbooks.md24.7 KiB
- references/usd-sample-data/README.md12.0 KiB
- references/usd-viewer-app/README.md5.0 KiB
- references/validation.md6.3 KiB
- references/viewer-backend-interface/README.md20.1 KiB
- references/viewer-control-patterns/README.md4.8 KiB
- references/viewer-data-view-patterns/README.md5.6 KiB
- references/viewer-feedback-status/README.md5.0 KiB
- references/viewer-input-routing/README.md11.9 KiB
- references/viewer-layout-patterns/README.md4.7 KiB
- references/viewer-ux-workflow/README.md5.2 KiB
- references/viewport-overlays/README.md9.9 KiB
- references/viewport-overlays/cuda-compositing.md6.6 KiB
- references/viewport-resize/README.md4.0 KiB
- references/vulkan-compositing/README.md6.1 KiB
- references/vulkan-compositing/depth-overlays.md15.7 KiB
- references/vulkan-compositing/interop-and-lifecycle.md6.6 KiB
- references/webgl-shm-transport/README.md14.5 KiB
- references/windows-native-setup/README.md11.6 KiB
- references/xr-client-connection/README.md1.1 KiB
- references/xr-client-message-contract/README.md8.5 KiB
- references/xr-desktop-mirror/README.md13.8 KiB
- references/xr-session-modes-and-passthrough/README.md930 B
- references/xr-spatial-input/README.md2.3 KiB
- references/xr-spatial-input/advanced-tools.md5.2 KiB
- references/xr-spatial-input/controllers.md16.3 KiB
- references/xr-spatial-input/feature-validation.md4.9 KiB
- references/xr-spatial-input/gesture-arbitration.md4.9 KiB
- references/xr-spatial-input/gesture-filtering.md5.5 KiB
- references/xr-spatial-input/hand-recognizers.md4.0 KiB
- references/xr-spatial-input/hands.md10.3 KiB
- references/xr-spatial-input/navigation.md13.5 KiB
- references/xr-spatial-input/physics-interaction.md23.2 KiB
- references/xr-spatial-input/simulation-lifecycle.md5.9 KiB
- references/xr-spatial-input/stage-composition.md4.9 KiB
- references/xr-spatial-input/teleport-acceptance.md5.2 KiB
- references/xr-spatial-input/webxr-client.md3.9 KiB
- references/xr-tracking-anchor-and-scale/README.md950 B
- references/xr-viewer-recipe/README.md10.5 KiB
- skill-card.md7.7 KiB
- skill.oms.sig58.2 KiB
references/cae-cfd-visualization/streaming-cae-viewer.md
<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
<!-- SPDX-License-Identifier: Apache-2.0 -->
Streaming CAE Viewer (ovrtx → ovstream WebRTC → React)
How to deliver the CAE/CFD viewer to a browser: server-side ovrtx RTX rendering, streamed
as an ovstream WebRTC H.264 video to a React client, with DOM controls that drive
server-side OVStage/CAE scene ops over a JSON data channel. This matches the RTWT demo's
browser delivery.
The streaming shell is a known quantity — compose it, do not re-document it. The generic mechanics (server startup, client connect, message envelope, lifecycle, cloud deploy) live in the streaming skills; this doc only covers what is CAE-specific: the server scene runtime that reuses the CAE operator backend, the CAE message set, and how each React control maps to a CAE OVStage op.
Read first for the generic pieces, then return here:
references/streaming-viewer-recipe/README.md— the end-to-end browser-viewer recipe.references/streaming-server/README.md— server process, ovstreamServer(WEBRTC), BGRA.references/streaming-client/README.md— the React +@nvidia/ov-web-rtcclient.references/streaming-messages/README.md— the{event_type, payload}protocol + envelope.references/streaming-lifecycle/README.md— connect/readiness/reconnect/teardown.references/viewer-backend-interface/README.md,references/viewer-control-patterns/README.md— the control → backend command pattern this specializes.references/cloud-deployment/README.md— container, ports, TURN, scaling.
This doc's CAE write pattern (build stage, publish, omni:xform data-plane commit, write
floor) is documented once in ovstage-render-and-camera.md;
cross-link that rather than repeating the OVStage write details here.
1. Architecture recap
The server process owns everything: ovrtx (RTX render), ovstage (live stage substrate),
ovstream (WebRTC video + data channel), and an application-owned CAE operator backend. The
browser is video + DOM only — it never renders USD, runs no visualization operators, and holds
no scene truth; it shows a <video> element plus React control panels, forwards mouse input
natively, and sends/receives JSON on the data channel. This is exactly the topology in
references/streaming-viewer-recipe/README.md; the CAE-specific substitution is what the
single render-loop owner does per tick (§2) and which app messages it speaks (§3).
2. The CAE server runtime
Create one SceneRuntime as the serialized owner of OVStage + ovrtx: exactly one thread ever
calls renderer.step(), mutates the stage, or writes omni:xform. The ovstream callbacks
(on_message / on_input / on_connection) run on StreamSDK threads and only enqueue
onto that runtime's command queue — they never touch OV state directly.
Build the CAE operator backend in the app
Keep CAE code in application modules, for example:
cae_runtime/
ingestion.py # native file / array normalization -> Dataset
operators.py # representation(dataset, request) -> geometry + fields
usd_authoring.py # geometry + fields -> USDA layer
camera.py # numpy orbit state -> row-major camera xform
scene_runtime.py # queue, publish/write-floor, renderer.step, frame outputoperators.py loads the selected dataset, computes the requested representation, exposes its
field range and supported representations, and returns arrays to usd_authoring.py.
scene_runtime.py builds/publishes the USDA layer and commits the camera data-plane matrix.
Implement those contracts from data-and-operators.md,
usd-authoring-and-materials.md, and
ovstage-render-and-camera.md; do not import an external sample
application or modify sys.path.
Startup order
Same order the streaming server skill mandates; the CAE-specific step is #4 (warm up the CAE stage so first-use renderer work is paid before any client connects):
os.environ.setdefault("OVRTX_SKIP_USD_CHECK", "1")before importingovrtx/pxr.Construct
ovrtx.Rendererfirst (RendererConfig(sync_mode=True, active_cuda_gpus="0", keep_system_alive=True)).import ovstream(Warp is initialized lazily by the CAE backend on first use).Build the initial CAE stage and warm up: rebuild → attach →
step()in a loop until the first BGRA frame is produced (allocates the persistent BGRA + fallback buffers along the way).ovstream.initialize(...)— ref-counted; the matchingshutdown()runs only at process exit.stream = ovstream.Server(ovstream.ServerType.WEBRTC).Register
stream.on_connection/on_message/on_inputbeforestart().stream.start(ovstream.ServerConfig(width, height, target_fps, video_input=VideoInput.CUDA, webrtc_signal_port=49100, webrtc_public_ip=...)).Start the
/healthzgate (503 until the first converted frame, then 200).Start one render-loop thread.
Use the current upstream ovstream documentation and the selected deployment guidance to configure signaling, media, health, and display requirements. Do not infer ports, client limits, or headless-display requirements from this reference.
Per-tick contract (render_tick)
On the single render-loop thread, each tick:
Drain the command queue — apply camera events in order; coalesce rebuild-affecting commands last-wins (a dragged slider queues at most one rebuild). Returns whether a rebuild is needed.
If rebuild needed: reload data if the dataset changed, recompute the representation (
representation(...)/emitter_streamlines(...)), detach the prior stage, author and publish the new stage layer, thenrenderer.attach_ovstage(stage). At most once per tick.Commit the camera at a new ordinal via the data plane (a scene-runtime camera commit → PathDictionary →
query_from_path_list→write_attribute(MATRIX, UPSERT)), which advances the write floor. Committing every tick (even an unchanged pose) at a fresh ordinal keeps frames correctly ordered. See ovstage-render-and-camera.md.Step + convert:
renderer.step(render_products={rpp}, delta_time=dt, ordinal=N)→ mapLdrColoron CUDA through its full authored RenderVar path (for example,render_vars["/Render/Vars/LdrColor"].map(device=Device.CUDA)→wp.from_dlpack) → copy into the persistent BGRA buffer + swap R/B → return it.Nonemeans no fresh frame this tick; the loop streams the last-good / fallback frame.
The render-loop thread (the streaming server, not the runtime) then calls
stream.stream_video(ovstream.VideoFrame.from_cuda_array(bgra)).
LdrColor RGBA8 → BGRA8 (persistent CUDA buffer)
ovrtx emits LdrColor as uint8 [H, W, 4] RGBA; ovstream's CUDA video input needs
uint8 [H, W, 4] BGRA. Convert on-GPU with a Warp kernel — no CPU round-trip:
@wp.kernel
def swap_rb(img: wp.array3d(dtype=wp.uint8)):
i, j = wp.tid() # ONE thread per pixel (dim=(H, W))
r = img[i, j, 0]; b = img[i, j, 2]
img[i, j, 0] = b; img[i, j, 2] = rLaunch with dim=(H, W) (per-pixel). Launching with a channel axis (H, W, 4) runs the swap
for both k==0 and k==2 and cancels out — keep the 2-D form. Copy the mapped LdrColor
view into an app-owned persistent BGRA buffer and swap in place: the mapped view is only
valid inside its map() context and is reused by the next step(), and stream_video() does
not copy — it reads the buffer until the next call — so the buffer must stay alive and the
CUDA stream must be synchronized before handing it over.
Keep a persistent fallback frame (opaque black, A=255) and stream last-good / fallback every
tick while idle or loading — WebRTC drops the connection after ~7 s without frames. Run long
stage loads without blocking the heartbeat. Render is fixed 1920×1080 (ovrtx has no resize; the
client uses object-fit: contain).
Render-loop stability (guardrails any streaming viewer needs)
A single render-loop thread that also serves a live client has failure modes a local window never sees. Three guardrails, general to any renderer + client:
Pre-warm each supported GPU feature once at startup, before the loop serves and before any client connects. First use of a renderer feature may block frame production. Exercise only the supported geometry paths the app will use, then begin live streaming. This package does not support NVIDIA IndeX or direct-volume paths; do not add a volume pre-warm.
Verify render-loop stability with a real client — a headless sequential harness does not reproduce live-streaming failures. Some failures only appear under the paced render loop with the streaming path active and a client connected (live H.264 encode + GPU contention + per-frame CUDA interop). A feature-specific startup stall can be invisible to a "select example → render N frames sequentially" test and only surface with a browser client attached. A passing headless test is necessary but not sufficient — validate under production-like conditions (a continuous loop paced to the frame budget, streaming path live, a real or faithfully-stubbed client) before declaring a render-loop fix done. The
--selftestheadless path (§5) proves scene + frame + swap, but confirm the live leg with an actual client.Crash-isolate tests of GPU failure paths in a child subprocess. Current OVRTX suppresses the legacy Windows modal assertion/error dialogs. Use exit status and logs to detect crashes; use a per-frame heartbeat and bounded timeout to distinguish a live render loop from a freeze. Keep this test harness separate from the viewer's normal runtime ownership and cleanup.
3. The CAE message set
Extends the baseline {event_type, payload} protocol from references/streaming-messages.
Baseline events (openStageRequest/openStageResult, getChildrenRequest, selectPrimsRequest,
changeAOVRequest, cameraCommandRequest/cameraStateChanged, setViewportInputActive,
viewerError) are unchanged. The CAE extensions are app-specific — reserve them centrally in
one message module and gate them via capabilities so a generic client degrades cleanly:
| Client → server (command) | Payload | Server op (enqueued, coalesced) → sceneState |
|---|---|---|
setRepresentation | {mode} | set representation → rebuild |
setField | {name} | set active field → rebuild |
setColormap | {name} | set colormap LUT → rebuild |
setIso | {frac} (0–1 of field range) | isosurface level → rebuild |
setSlice | {frac, axis?} (0–1 along axis) | slice plane → rebuild |
setStreamlineSeed | {center:[x,y,z], radius} | move emitter seed → wo.emitter_streamlines → rebuild |
setEmitterVisible | {visible} | toggle the seed-sphere marker |
loadDataset | {id} (registry id; path/url are legacy aliases) | resolve id → reload dataset (refit) |
getSceneState | {} | push sceneState (no state change) |
Every command except getSceneState is validated, enqueued, and last-wins–coalesced on the render
loop; once accepted it triggers a (coalesced) sceneState push so all clients reconcile. How each
becomes an OVStage write (author → publish → advance write floor for geometry, or a data-plane
omni:xform / array write for the camera and emitter) is
driving-cae-viz-via-ovstage.md — do not restate it here. Keep
these CAE extensions in one message module so a generic client (which knows only the baseline events)
degrades cleanly.
Server → client is a server-authoritative state push — the client holds no scene truth, it renders
whatever the last sceneState gave it:
sceneState— a COMPLETE snapshot in the client-facing shape:{datasets:[{id,name}], fields:[{name,label?}], representation, field, colormap, iso, slice, emitter:{center,radius}, show_emitter, activeDataset, colormaps?, bounds?}. Compose it by remapping the render-loop-owned runtime'ssnapshot(); the internal snapshot keys (dataset,bbox,representations) are not the wire keys — normalize toactiveDataset,bounds,datasets:[{id,name}], and tolerate legacy path-string dataset entries so the picker always populates.cameraStateChanged,viewerError.
Message framing (the headline gotcha): wrap every server→client send
The single biggest trap, and the one that cost the most time: ovstream.Server.send_message(str)
puts a raw string on the data channel, but @nvidia/ov-web-rtc only surfaces a message to
onCustomEvent if it arrives as a wire frame {messageRecipient, messageType, data} — it routes by
messageRecipient and drops a bare string silently (no error, no console log). So
send_message(json.dumps({"event_type": ..., "payload": ...})) never reaches the client.
The two directions are symmetric: the client already frames its outgoing sends the same way, which is
exactly why the server unwraps {messageType, data} on receive. So client→server worked from day
one; server→client failed silently until the server framed too. The sceneState push, viewerError,
openStageResult, cameraStateChanged — all invisible until wrapped.
Server send — wrap the app envelope inside the wire frame:
def send_event(self, event_type, payload):
if self.server is None or not self.server.is_client_connected:
return
app = json.dumps({"event_type": event_type, "payload": payload}, default=str)
frame = json.dumps({"messageRecipient": "app", "messageType": "json", "data": app})
self.server.send_message(frame) # send_message(app) alone is silently droppedServer receive — unwrap the same frame the client wraps, then read the app envelope:
def decode_app_message(raw):
msg = json.loads(raw) if isinstance(raw, str) else raw
if isinstance(msg, dict) and "messageType" in msg and "data" in msg:
data = msg["data"]
msg = json.loads(data) if isinstance(data, str) else data
return msg if isinstance(msg, dict) and "event_type" in msg else NoneThe control → server-op path (the core)
Each React control follows one path:
React control →
{event_type, payload}wrapped in the{messageRecipient,messageType,data}frame over the data channel → server unwraps + validates →scene.enqueue_command(kind, payload)→ render loop drains (last-wins coalescing) → OVStage write / geometry rebuild at a new ordinal → advance write floor → nextrenderer.step(ordinal=N)→ stream the next BGRA frame → server pushes a coalescedsceneState(wrapped) → client reconciles.
Concrete emitter example: React drags a seed sphere → setStreamlineSeed{center, radius} → the
_h_streamline_seed handler validates center is [x,y,z] and enqueues → the loop coalesces to
the latest, rebuilds via wo.emitter_streamlines(wds, center, radius, color_field=field), authors
BasisCurves, publishes at ordinal N, steps, streams. setRepresentation/setField/setIso/
setSlice/setColormap map the same way — each an enqueued, coalesced command.
The CAE write details (author → open_usd_from_string → advance_write_floor → attach_ovstage,
and the data-plane omni:xform commit) belong to
ovstage-render-and-camera.md and
driving-cae-viz-via-ovstage.md — this doc reuses those patterns,
it does not restate them.
sceneState hydration (server-authoritative)
Push a COMPLETE sceneState at three moments so every attached client converges on the truth:
On connect — from the short-delayed initial-state thread, ~0.3 s after the data channel is ready (alongside
openStageResult+cameraStateChanged), so the dropdowns populate immediately.After
loadDataset— a dataset swap rebuilds the field list + bounds asynchronously on the loop, so push at two horizons (e.g. ~0.4 s and ~1.5 s) to catch the rebuilt fields.After any accepted state-changing command — coalesced (at most one trailing push in flight) so a slider drag doesn't flood the data channel or fight the client's optimistic echo.
The client applies each sceneState to populate the dataset + field dropdowns and to clear its
"waiting for scene state" gate (the first push flips ready). The dataset picker sends
loadDataset{id}; the server resolves that id through its dataset registry to a concrete path.
Example presets — the "uber-UI" walkthrough pattern
To turn a bare control panel into a guided walkthrough that reproduces named CAE examples,
drive the UI from declarative example presets the server advertises in sceneState.
Each preset binds a registered dataset to a representation, a default field/colormap/domain,
the set of control groups the UI should surface (controls), and a note on the exact
settings it replicates. Selecting a preset drives the scene and reconfigures the panel:
# server preset (application-owned declarative data)
{
"id": "time_varying_structural", "number": 1, "title": "Time-Varying Structural",
"dataset": "bumper_beam", "representation": "transient",
"field": "PlasticStrain", "colormap": "gist_rainbow",
"domain": [0.0, 0.065], "domain_locked": True,
"controls": ["timeline", "field", "colormap", "domain"], # gates which UI groups show
"example_notes": "Faces colored by PlasticStrain; locked domain 0-0.065; ...",
}Server side: ship the preset list (
list_examples()/get_example(id)), add asetExample {id}command that loads the dataset, sets the representation/field/colormap/ domain, and advertises the active example + itscontrols. Example 3 (Multi-Domain) is intentionally backlogged — omit it from the list rather than half-wiring it.Client side: render an example picker (chips) →
setExample; then gate control groups byexample.controlsso a transient example shows the Timeline group, a volume example shows Volume/ROI/Context, an aero example shows the Emitter group. Show theexample_notesas a concise explanation of the selected visualization.
Extend sceneState to carry the preset contract so the client can render the guided UI
without hardcoding it:
sceneState += {
examples: [{id, number, title, subtitle, controls, example_notes}],
activeExample: id | null,
timeline: {t, n_frames, playing, fps, speed, interpolate}, # transient examples
domain: {min, max, locked}, # colormap range + lock
transform:{scale, upAxis, offset}, lineWidth, # alignment controls
context: {available, visible}, # USD context asset toggle
}Each field is server-authoritative and echoed back after the corresponding setX command
(setExample, setTimeline, setPlaying, setInterpolate, setDomain, setDomainLock,
setVolumeParams, setRoi, setContextVisible, setTransform, setLineWidth). Keep them
in the one CAE message module (§3 head) so a generic client degrades cleanly.
Robustness: a control-panel render error must never black the video
The single highest-severity frontend trap: a React render error in the control panel can
unmount the whole app — including the <video> element — which drops the WebRTC session
(the symptom is "flash one frame, then black; connect/disconnect cycling ~400 ms"). It looks
like a codec/transport failure (you may even see an unrelated Unsupported Video Codec log)
but it is a crash in a sibling component tearing down the video.
Root cause seen in practice: the server sends emitter: {center: null, radius: 0} for a
non-emitter dataset, and the panel does center[axis].toFixed(...) on null → throws →
with no error boundary the whole tree unmounts. Two defenses, use both:
Null-guard every server-sent state field the panel reads. Make nullable fields nullable in the type (
emitter.center: Vec3 | null) and coalesce at the read site (const center = scene.emitter.center ?? [0,0,0]), in both the reducer and the panel.Wrap the control panel in a React error boundary so a panel exception is caught and rendered as a fallback without unmounting the
<video>. The video and the WebRTC connection must be structurally independent of the control panel's render success.
A single bad or missing field (a nullable emitter center, an empty timeline, a missing domain) must never be able to take down the stream. Treat the video subtree as sacrosanct.
Handler rules (from the baseline)
Every callback runs on a StreamSDK thread: validate, enqueue, return fast; never step or write.
Unwrap the browser frame
{"messageType":..,"data":"<json>"}beforejson.loads, and symmetrically wrap every outgoing send in that frame (see Message framing above) — a rawsend_messageis dropped silently. Dispatch by exactevent_typethrough a dict; unknown types warn and no-op.Send through one guarded helper that no-ops when
not server.is_client_connectedand swallows disconnect-race failures; cap data-channel messages at ~60000 bytes.On connect, push initial state on a short-delayed thread:
sceneState+openStageResult+cameraStateChanged(~0.3 s after connect so the data channel is ready).
4. React client specifics that matter
The generic client (provider, endpoint resolution, video element, subscriber fan-out) is in
references/streaming-client. What is worth calling out here:
Browser client dependency
Use the current ov-web-rtc acquisition and API guidance from the central nvidia-runtime dependency guide and the upstream package materials it links. Read the installed package types before choosing a connection API, event callback, config shape, or codec value. Keep this CAE guide focused on the app protocol rather than package-version behavior.
Direct connection shape (apply client readiness and ownership):
import { AppStreamer, StreamType, VideoCodec, type DirectConfig } from '@nvidia/ov-web-rtc';
const config: DirectConfig = {
videoElementId: 'remote-video', audioElementId: 'remote-audio',
signalingServer: host, signalingPort,
width: 1920, height: 1080,
codec: VideoCodec.H264, codecList: ['H264'],
nativeTouchEvents: true, fps: 60, maxReconnects: 5, reconnectDelay: 3000,
onStart: () => {}, onCustomEvent: dispatch, onStop: () => {},
};
const streamer = new AppStreamer(); // Retain for sendMessage and teardown.
await streamer.connect({ streamSource: StreamType.DIRECT, streamConfig: config });
// Resolution may be IN_PROGRESS; the provider gates sends on confirmed start success.Do not set a media/mediaPort field — media is SDP-negotiated UDP.
Receiving is shape-agnostic — unwrap recursively
Use the receive callback and payload contract documented by the currently installed browser client. Normalize the app envelope at one boundary; do not depend on undocumented transport-specific shapes. Depending on the build / transport path it hands the callback the app message as any of:
an already-parsed object
{event_type, payload}(the documentedmessageType:'json'path), ora raw JSON string (unparsed), or
{data:"<json>"}(legacy/GFN frame), or{message:"<json>"}(multi-part reassembly whose payload failed to parse) —
and combinations of these (e.g. a {data} whose value is itself a JSON string). So the client must
unwrap recursively — JSON.parse any string, then descend data / message — until it reaches an
object carrying event_type, then read {event_type, payload}; reject anything else. Do not assume the
documented messageType:'json' → JSON.parse(data) path is the only one that fires. Symmetrically, the
client wraps its own sends in the {messageRecipient,messageType,data} frame (§3 Message framing).
Rules that avoid "one frame then black"
Keep the
<video id="remote-video">React-rendered so it exists in the DOM beforeconnect()is called.The connect
useEffectdeps must be the immutable host/port (and the stabledispatch) only — never app state or the subscriber set. Tearing the connection down on ordinary re-renders is the classic one-frame-then-black bug.Follow client readiness: confirmed SDK start success permits app commands; a resolved
IN_PROGRESSresult does not. Send the firstgetSceneState/openStageRequestbefore waiting for a decoded scene frame.Mouse / keyboard / wheel / touch are forwarded natively by the library — never send them as JSON. Only app state + commands go over the data channel. Arm/disarm native input by region: viewport
onPointerEnter→setViewportInputActive{true}, control panels →{false}.Keep app state server-authoritative: the client optimistically echoes a
setXfor slider/select responsiveness, then reconciles on the nextsceneState.
5. Deploy + honest verification note
For containerization, ports (49100 signaling / UDP media / health), TURN, and scaling, use
references/cloud-deployment/README.md — do not hardcode deployment-specific ports here.
Honest status: the server side is verified end-to-end — ovstream.Server(WEBRTC).start()
binds :49100, produces ~60 fps BGRA frames, /healthz returns 200, and the CAE scene builds,
attaches, renders, and converts via swap_rb (there is a --selftest path that proves scene +
frame + swap + ovstream.start headlessly). The React client compiles and builds against the
real @nvidia/ov-web-rtc, and the message-framing fix (§3) is confirmed — once the server
wrapped its sends, sceneState reached onCustomEvent and the dropdowns hydrated. Full browser
WebRTC media negotiation still needs a real client against a GPU host to confirm the video leg —
treat that leg as unproven until run.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python, Needs Node.js
The author says: Orchestrator skill. Downstream focused references may require NVIDIA GPUs, ovrtx, ovstream, ovui, OpenUSD, Python, Node/React, Tauri, Electron, C++, or cloud GPU deployment access depending on the selected viewer path.
Security
What our scanner noticed· Medium risk
- Large base64-encoded blobs
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- NVIDIA Omniverse
- Publisher
- NVIDIA (Official)
- Source
- NVIDIA/skills · skills/omniverse-realtime-viewer · commit fce3cca
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE-APACHE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by NVIDIA Omniverse or NVIDIA.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download omniverse-realtime-viewer.zip