Generated banner for Omniverse Realtime Viewer
Generated logo for Omniverse Realtime Viewer

Omniverse Realtime Viewer

OpenAIOfficialCreated by NVIDIA OmniverseDistributed by OpenAI

  • Skill
  • Meta (authoring, orchestration, planning, memory)
  • Software development
  • Apache-2.0
  • Medium risk

From the author

Use as the top-level router for Omniverse Realtime Viewer USD app requests and focused viewer reference documents.
— the description by NVIDIA Omniverse

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The Omniverse Realtime Viewer skill acts as a central orchestrator for developing USD-based viewer applications. It provides a structured approach to selecting implementation recipes, enforcing architectural conventions, and managing dependencies. By utilizing a set of focused reference documents, it guides developers through the lifecycle of building, configuring, and validating viewer applications, ensuring consistent behavior across different delivery paths such as local workstations or streaming environments.

What it does

  • Routes development requests to specific implementation recipes based on the target delivery path.
  • Enforces architectural rules for USD rendering, stage management, and UI integration.
  • Provides guidance on camera selection, input handling, and viewport interaction.
  • Standardizes the integration of AOV switching and render product configuration.
  • Facilitates the capture of validation evidence for viewer readiness.
  • Maintains separation between user-provided USD files and application-specific session state.

When to use it

  • When initiating the development of a new USD viewer application within the Omniverse ecosystem.
  • When determining the appropriate delivery path for a viewer, such as local native or streaming.
  • When needing to implement consistent camera, selection, or UI behavior across viewer projects.
  • When integrating advanced rendering features like AOV switching into an existing viewer.

Advantages

  • Ensures architectural consistency across diverse viewer implementations.
  • Provides a clear, modular path for adding specific capabilities like input routing or data display.
  • Promotes clean separation of concerns between stage data and viewer-owned state.
  • Standardizes the validation process for consistent delivery.

Usage examples

“I need to build a browser-based viewer for USD files.”
The agent will route you to the streaming viewer recipe, providing guidance on WebRTC stream setup, UI integration, and viewport interaction.
“How do I implement AOV switching in my local USD viewer?”
The agent will provide the AOV switching reference, detailing how to map render vars and update the display state on the server.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/openai/omniverse-realtime-viewer/download
  2. Unzip 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

This is the top-level entry point for the Omniverse Realtime Viewer skill package. It is self-contained: all required routing, conventions, and validation guidance live in the selected references.

Use the focused reference documents as implementation recipes. This file chooses the right recipes and preserves the architectural rules that must hold across all generated viewer apps.

Instructions

Start by classifying the requested viewer, then read only the references needed for that delivery path and feature set. Implement the render path first, layer interaction and UI behavior on top of it, and finish by capturing validation evidence from references/validation.md.

Read Order

  1. Read references/routing.md to choose the delivery path and focused references.

  2. Read references/conventions.md before implementing camera, input, selection, viewport, streaming protocol, scene loading, or environment behavior.

  3. For broad viewer requests, read references/usd-viewer-app/README.md.

  4. If the delivery path is unclear, read references/streaming-vs-local/README.md.

  5. If the prompt includes layout, panels, controls, inspectors, status, or UX, read references/viewer-ux-workflow/README.md and then the focused viewer UI references. This applies to React/WebRTC, Tauri, Electron, ovui, ovwidgets, and Dear ImGui apps; "frontend" means user-facing UI, not only browser UI.

  6. For viewport interaction, read references/viewer-input-routing/README.md before references/camera-controls/README.md, references/native-picking-selection/README.md, or references/object-selection/README.md.

  7. Read only the focused capability references needed for the requested app.

  8. Use references/validation.md to capture review evidence before handoff.

Non-Negotiables

  • Use ovrtx for all USD and 3D rendering.

  • Browser apps display an ovstream WebRTC video stream plus UI. The browser does not render USD geometry.

  • Do not substitute WebGL, Three.js, Babylon.js, PlayCanvas, A-Frame, model-viewer, react-three-fiber, glTF browser viewers, or other client-side 3D renderers.

  • If local validation cannot run because the GPU/runtime environment is absent, scaffold the ovrtx path and document the runtime requirement. Do not add a browser-renderer fallback.

  • Keep user USD files unmodified. Viewer cameras, render products, render vars, settings, selection metadata, and runtime state belong in session/composite layers or app state.

  • Keep one owner for renderer.step(), stage mutation, native picking, selection writes, and live attribute writes.

  • Keep dependency acquisition in references/dependencies/README.md and deployment choices in references/cloud-deployment/README.md; do not duplicate package locations or deployment setup.

Focused Reference Families

  • Entry points and recipes: references/usd-viewer-app/README.md, references/streaming-viewer-recipe/README.md, references/ovui-local-viewer-recipe/README.md, references/streaming-vs-local/README.md, references/electron-shm-viewer/README.md, references/ovwidgets-editor-shell/README.md.

  • Rendering and stage: references/ovrtx-rendering/README.md, references/stage-loading/README.md, references/stage-management/README.md, references/render-settings/README.md, references/aov-switching/README.md, references/stage-hierarchy/README.md, references/stage-queries/README.md, references/stage-attribute-reads/README.md, references/prim-transform-safety/README.md, references/usd-sample-data/README.md.

  • Delivery and runtime: references/streaming-server/README.md, references/streaming-client/README.md, references/streaming-messages/README.md, references/streaming-lifecycle/README.md, references/local-viewer/README.md, references/tauri-local-viewer/README.md, references/cpp-native-viewer/README.md, references/headless-shm-cli/README.md, references/viewer-backend-interface/README.md, references/webgl-shm-transport/README.md.

  • Viewer UI/UX: references/viewer-ux-workflow/README.md, references/viewer-layout-patterns/README.md, references/viewer-control-patterns/README.md, references/viewer-data-view-patterns/README.md, references/viewer-feedback-status/README.md.

  • Interaction: references/viewer-input-routing/README.md, references/camera-controls/README.md, references/object-selection/README.md, references/native-picking-selection/README.md, references/selection-feedback/README.md, references/selection-animation/README.md, references/transform-manipulator/README.md, references/gl-viewport-overlay/README.md, references/ovui-library/README.md, references/prim-pick-effects/README.md, references/prim-info-display/README.md, references/viewport-overlays/README.md.

  • Infrastructure: references/dependencies/README.md, references/windows-native-setup/README.md, references/cloud-assets/README.md, references/cloud-deployment/README.md, references/troubleshooting/README.md.

Build Workflow

  1. Classify the prompt by delivery path, target user, required capabilities, runtime environment, validation needs, and explicit constraints.

  2. Select a small reference set. Start with the recipe or routing reference, then add focused capabilities such as camera, picking, hierarchy, properties, render settings, transform tools, cloud assets, or deployment.

  3. Read selected references before writing app code. Follow their build order, import order, data-channel contracts, and renderer ownership rules.

  4. Implement the core render path first, then input routing and camera, then selection and data panels, then scene/settings features, then packaging or deployment.

  5. Treat the selected references as the behavior contract for API shape, compatibility, and generated project structure.

  6. Capture validation evidence before calling the viewer ready.

Examples

  • For a browser viewer request, use the streaming recipe references plus camera, picking, hierarchy, properties, render settings, and stream-status references.

  • For a local workstation viewer request, use the local or native delivery references plus renderer setup, stage loading, viewport input, and validation.

Completion Checklist

  • Selected references match the user's intent and delivery path.

  • No code path uses a browser-side 3D renderer for USD.

  • The generated app has one clear owner for render stepping and stage mutation.

  • User USD files remain untouched by viewer-owned session data.

  • Camera, input, selection, scene loading, and stream behavior follow references/conventions.md.

  • Setup/build/run results and visual interaction evidence are captured with references/validation.md.

Files

references/streaming-viewer-recipe/server-runtime.md

Streaming Server Runtime

2. Install Dependencies And Configure The Environment

Read references/dependencies FIRST. Its references/nvidia-runtime.md file is the source of truth for NVIDIA runtime locations. Do not guess install paths and do not repeat ovstream, ovui, ovrtx, or ov-web-rtc client acquisition details in this recipe.

Do this on the server side:

  • Install ovrtx using the package guidance in references/dependencies.

  • Install ovstream using the current package guidance in references/dependencies. If ovstream.initialize() reports missing native StreamSDK libraries, follow the current dependency guidance.

  • Install warp-lang for CUDA-side channel conversion (pip install warp-lang).

  • Install numpy for matrices and camera math (pip install numpy).

  • Install usd-core==24.11 only when the server process needs direct pxr queries. Pin to 24.11 — newer versions cause TfType schema conflicts with ovrtx. Prefer subprocess query mode on Windows or when USD registry conflicts appear.

For generated browser viewers, create app-local setup and run wrappers rather than pointing users at repo-level scripts. The setup wrapper should install the server dependencies above, run the verification checks from references/dependencies/environment-validation.md, and fail with the exact command that did not pass. The run wrapper should set OVRTX_SKIP_USD_CHECK, derive OVRTX_BIN_PATH from the installed ovrtx package when needed, preserve the selected ovstream package layout, start the server, and write logs to a known project-local path.

Do this on the frontend side:

  • Create a Vite React app (npm create vite@latest frontend -- --template react-ts).

  • Configure and install @nvidia/ov-web-rtc using references/dependencies. Use only the standalone ovstream Direct connection pattern from streaming-client; do not use Kit, OVC, NVCF, or GFN client connection profiles in the browser WebRTC config. If OKAS or another orchestrator launches the container, convert its exposed endpoint into Direct server and signalingPort values.

  • Add normal UI dependencies only when they are part of the requested UI. Keep the core connection path dependency-light.

Set these environment contracts before starting the server:

  • OVRTX_SKIP_USD_CHECK=1 must be set before ovrtx is imported or the renderer is constructed.

  • OVRTX_BIN_PATH must point at the ovrtx bin directory when materials or renderer plugins fail to resolve.

  • The ovrtx plugin library path must be first in the dynamic library path if another USD build is present.

  • OVSTREAM_LIB_PATH must point at the ovstream native library directory when the Python binding cannot find native libraries.

  • If ovstream native libraries are not found, use the current runtime guidance from references/dependencies instead of copying stale fallback library paths from older recipes.

Decision points:

  • If the target is local development, use WebRTC signaling port 49100, stream port defaulting through ovstream, and public IP 127.0.0.1.

  • If the target is LAN access, expose signaling host and port through frontend URL parameters and environment variables.

  • If the target is cloud deployment, do not invent a new deployment model in this recipe; read references/cloud-deployment and keep to supported paths.

  • If running on Windows with pxr imports for advanced USD inspection, prefer a separate USD query subprocess rather than importing pxr in the ovrtx render process.

Common failure modes:

  • usd-core detected, duplicate USD debug symbols, _tf import failures, or MDL resolver crashes usually mean import order or library path is wrong.

  • Magenta materials usually mean OVRTX_BIN_PATH or plugin library path is missing.

  • ovstream import or initialize failure usually means native StreamSDK libraries are missing, OVSTREAM_LIB_PATH points at the wrong layout, the platform build does not match, or GPU/driver support is missing.

  • No matching distribution found for ovrtx: wrong package guidance, unsupported platform, or unsupported Python version; re-check references/dependencies.

  • ovstream package not found: wrong package source, stale package metadata, wrong platform tag, or network/proxy issue; re-check references/dependencies.

Read for depth: see references/dependencies for install commands, references/ovrtx-rendering and references/streaming-server for the full environment and native library contracts.

3. Build The Server Runtime Shell

Do this:

  • In server/ov_web_viewer_server.py, parse width, height, target FPS, signaling port, public IP, initial scene URL/path, asset root, and settings path.

  • Construct a single application runtime object that owns the renderer runtime, scene manager, stream server, message router, input router, settings store, and command queue.

  • Follow the canonical startup order: set env, construct an ovrtx renderer with native selection outline support when needed, load the initial stage through open_usd() or open_usd_from_string(), warm up the renderer, initialize ovstream, register callbacks, start readiness health, then start the render loop.

  • Initialize ovstream once, create a WebRTC server, register on_connection, on_message, and on_input, then start the server.

  • Enter one render loop that drains queued commands, updates camera/selection/settings state, steps ovrtx when a scene is loaded, converts the frame to BGRA, and submits video to ovstream.

  • On shutdown, stop streaming, close the ovstream server, close renderer resources if exposed by the API, and call ovstream shutdown exactly once for each initialize call.

Canonical startup sequence:

set OVRTX_SKIP_USD_CHECK=1
import ovrtx and construct Renderer(RendererConfig(sync_mode=True, selection_outline_enabled=True))
load initial stage:
  build an inline root USDA that sublayers the user stage and authors viewer render config
  renderer.open_usd_from_string(inline_root_usda)
  bind /OVCamera omni:xform
  initialize native selection outline styles and clear outline groups
warm up renderer:
  write camera transform
  step /Render/OVServer/ViewportTexture0 several frames
  probe render vars and allocate persistent BGRA stream buffer
initialize ovstream and register callbacks:
  on_connection -> push_initial_state
  on_message -> JSON app protocol
  on_input -> raw mouse/keyboard input routed through viewer-input-routing
start /healthz:
  503 until first valid frame
  200 after first successful converted frame
start render loop thread

Critical contracts:

  • Register callbacks before server.start().

  • Keep callbacks fast. They may be called from StreamSDK internal threads.

  • Do not call renderer load/reset/step/write APIs directly from ovstream callbacks. Enqueue work for the render loop.

  • Guard send_message with the connected-client state.

  • Maintain explicit runtime states: starting, idle/no scene, loading, streaming, error, shutting down.

  • Keep the most recent loaded stage URL, root hierarchy summary, selection, render settings, and loading state in server memory so a newly connected browser can receive initial state.

  • Readiness is not liveness: /healthz must return 503 not ready until the render loop has produced and copied the first valid frame, then 200 ok.

  • Readiness must not depend on an active browser client or on stream_video() succeeding. Before any client connects, frame submission can no-op or raise transient no-client/disconnect errors depending on the selected ovstream build.

Decision points:

  • If no initial scene is configured, start the server in idle state and let the frontend send openStageRequest.

  • If an initial scene is configured, load it before or during the first render loop iteration, then push state when the client connects.

  • If one client is already connected and a second browser connects, follow ovstream's one-client WebRTC constraint. Either reject the new client clearly or replace the old session intentionally.

  • If the render loop falls behind target FPS, prefer dropping frames or reducing render quality over running concurrent renderer steps.

Common failure modes:

  • Registering callbacks after start() causes missed connection and data-channel events.

  • Calling renderer.step() during reset_stage(), open_usd*(), or reference mutation causes races, stale buffers, or crashes.

  • Sending messages while no client is connected silently loses important state unless the runtime pushes initial state after connection.

Read for depth: see references/streaming-server and references/streaming-lifecycle for the full lifecycle contract.

4. Construct The ovrtx Renderer

Do this:

  • Create the renderer in server/renderer_runtime.py after environment variables are set.

  • Use synchronous rendering first. Add asynchronous rendering only after buffer lifetime, readiness, and stream pacing are explicitly handled.

  • Store the active render product path, stream width, stream height, current frame index, and whether a valid stage is loaded.

  • Expose render-loop-only operations for loading a scene, resetting the stage, stepping a frame, mapping render vars, enqueueing and decoding pick queries, setting selection outline groups, and writing live attributes.

Critical contracts:

  • The application calls renderer.step() explicitly. ovrtx does not run a hidden app loop for the viewer.

  • Pass the exact viewer RenderProduct path to every step call.

  • Extract LdrColor from the returned frame. This is RGBA8 from ovrtx.

  • For AOVs, handle both single-tensor and multi-tensor render var outputs. Single-tensor outputs are consumed directly through DLPack; multi-tensor outputs must select a named image tensor and read params separately. Image tensors are channel-last (H x W x C), not channel-first.

  • Map CUDA buffers for streaming. Avoid CPU round trips in the normal streaming path.

  • Keep mapped or converted frame buffers alive until stream_video() returns.

  • Use write_attribute for live camera transforms and other live state. Write omni:xform, not authored xformOp:*, for interactive updates.

  • Use the correct transform semantic and create-new prim mode for attributes that may not already exist in Fabric.

Decision points:

  • If the app only needs basic video streaming, start with LdrColor only.

  • Object selection uses native pick queries. Do not add segmentation render vars just to make picking work.

  • If render settings include debug segmentation view, keep both render vars available and switch the streamed image source intentionally.

  • If the renderer reports stale GPU hangs after a crash, inspect running Python GPU processes before changing code.

Common failure modes:

  • Unable to find RenderProduct prim means scene setup did not create the path used by renderer.step().

  • Black frame usually means camera relation, render product resolution, render var source, or camera transform is invalid.

  • Red/blue color swap means ovrtx RGBA was submitted to ovstream without BGRA conversion.

  • Live camera changes doing nothing usually means the app wrote xformOp:transform instead of omni:xform, or used existing-only prim mode.

Read for depth: see references/ovrtx-rendering for the full renderer construction, frame extraction, and live attribute contract.

5. Implement Scene Loading

Do this in server/scene_loader.py and call it only from the render loop:

  • Resolve the requested URL/path against the configured asset root, allowed schemes, and security policy.

  • Create viewer-owned camera, RenderProduct, RenderVar, and RenderSettings data in one inline root USDA string when the user stage lacks viewer render config.

  • Load the user stage without modifying it.

  • Store the viewer camera path and render product path in runtime state.

  • Reset selection, native selection outline groups, hierarchy cache, pending pick queries, and loading progress for the new stage.

  • Fit the camera to the stage bounds unless the user requested preserving the current camera or using an authored stage camera.

Critical contracts:

  • Every loaded stage needs Camera -> RenderProduct -> RenderVar -> RenderSettings wiring that ovrtx can find.

  • The viewer camera path must be the same path used by camera controls when writing omni:xform.

  • Do not inject lights unless the user explicitly asks for viewer-controlled lighting. User stages usually own their lighting.

  • Include segmentation render vars only for explicit debug/AOV display modes, not for picking.

  • Prefer renderer.open_usd_from_string() for inline roots that sublayer the user USD and author viewer render config. This avoids temporary file lifetime issues while preserving relative asset resolution through the sublayer path.

  • Do not call reference or layer-add APIs after a stage is already loaded unless the renderer has been reset to an empty stage and the operation is part of the serialized load path.

Decision points:

  • Use a single inline root USDA string with subLayers = [@user_scene@] when the user file needs viewer camera/render-product/render-var data.

  • If the user stage has an authored camera and the requested policy is stage-camera, copy its focal length, apertures, clipping range, and transform into the viewer camera.

  • If the user requests persistent camera across scene switches, keep camera state but sanitize and refit only when the old state is invalid for the new bounds.

  • If the user requests viewer lighting controls, add explicit viewer-owned light prims only with a verified live apply path or an explicit reload/profile workflow; otherwise leave lighting untouched and omit live lighting controls.

Common failure modes:

  • Inline roots that omit or misquote the user sublayer path fail composition or break relative asset resolution.

  • Camera path mismatch makes input appear connected but the view never moves.

  • A stage-load operation that reports an error must not be treated as a successful load just because the enqueue call returned.

Read for depth: see references/stage-loading, references/render-settings, references/selection-feedback, and references/stage-hierarchy for the full contracts.

6. Build Frame Streaming

Do this in server/stream_server.py and server/frame_converter.py:

  • Start ovstream in WebRTC mode.

  • Configure width, height, target FPS, signaling port, optional public IP, and video codec policy.

  • For each rendered frame, map LdrColor on CUDA, convert RGBA8 to BGRA8 on CUDA, wrap the CUDA buffer as an ovstream video frame, and submit it.

  • Pace the render loop to target FPS while allowing command queue work to run between frames.

  • Send loading and error state messages even when video frames are temporarily unavailable.

  • Log the first valid converted BGRA frame and set readiness before depending on browser connection state. This lets validation distinguish renderer/frame-conversion failures from WebRTC negotiation failures.

Critical contracts:

  • ovstream expects BGRA8 for raw CUDA frames; ovrtx LdrColor is RGBA8.

  • Avoid CPU readback in the normal path. CPU readback is acceptable only for debugging screenshots or tests.

  • stream_video() does not own a deep copy of the source buffer. Keep the buffer alive until the call returns.

  • stream_video() can fail during disconnect races. Catch and debug-log transient failures; do not crash the render loop.

  • First-frame readiness should be set after render-var mapping and RGBA-to-BGRA conversion into the persistent app-owned stream buffer. Do not wait for an attached browser client.

  • Stream width, height, frame pitch, RenderProduct resolution, and camera aspect must agree for the fixed stream size.

  • The WebRTC signaling port is not the media port. The browser discovers media endpoints through SDP.

  • For local WebRTC development, set the server public IP to 127.0.0.1 when ICE discovery otherwise hangs.

Decision points:

  • Use raw frames first. Add H264, H265, AV1, or custom encoded frames only when latency, bandwidth, or deployment constraints require it.

  • If using encoded frames, make the encoder own color format conversion and frame lifetime explicitly.

  • If no client is connected, still run scene loading and state updates, but consider pausing expensive frame submission work.

  • If the user asks for RTSP, treat it as a separate delivery mode; the browser-streamed Omniverse Realtime Viewer path should remain WebRTC.

Common failure modes:

  • Connected browser with no video often means frontend configured a media port manually, server ICE/public IP is wrong, or frame submission never happens.

  • One frame then black usually means the frontend connected, received state, rerendered, and accidentally terminated/restarted the AppStreamer connection. Inspect server logs for connected=True followed by connected=False within about a second.

  • Wrong colors mean missing RGBA-to-BGRA conversion.

  • GPU memory growth can mean mapped frame resources or conversion buffers are retained beyond the intended frame lifetime.

Read for depth: see references/streaming-server and references/streaming-lifecycle for the full frame streaming contract.

Requirements and compatibility

Written for: OpenAI Codex

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.

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
OpenAI (Official)
Distributed by
OpenAI
Source
openai/plugins · plugins/nvidia/skills/omniverse-realtime-viewer · commit d420d13
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (written by AutoGineer)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by NVIDIA Omniverse or OpenAI.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download omniverse-realtime-viewer.zip