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

Omniverse Realtime Viewer

NVIDIAOfficialCreated by NVIDIA Omniverse

  • Skill
  • Tool integration
  • Software development
  • Apache-2.0
  • Medium risk

From the author

Use as the top-level router for Omniverse Realtime Viewer USD apps, XR delivery, SPG GPU processing, stylized rendering, 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 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

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/nvidia/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

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

  1. When delivery is explicit, select its recipe through references/routing.md and follow its current phase. Otherwise start with references/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.

  2. Resolve the selected libraries through references/dependencies/README.md. Preserve the project's manifest unless an upgrade is requested.

  3. Build a working frame and camera interaction in the chosen shell, then add the requested capabilities. Read references/conventions.md for shared input, camera, selection, and protocol conventions.

  4. Use references/viewer-ux-workflow/README.md for broader interface design. Loading, selection feedback, errors, and input responsiveness belong in the first working app, alongside rendering.

  5. Validate the actual delivery path with references/validation.md. A browser screenshot does not validate a native window or a different transport.

Architecture

OwnerResponsibility
Viewer runtimeOwn the live OVStage, publication clock, OVRTX renderer, scene changes, and render stepping.
UI and input adapterDisplay frames and copied app state; send user intent to the runtime owner.
Storage/query/simulation workersPerform their assigned work and return results through the selected integration boundary.
Delivery adapterPresent 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

references/viewer-backend-interface/README.md

Viewer Backend Interface

Triggers

Use this skill for ViewerBackend, local shared UI, backend-agnostic React viewer UI, reusable viewer components, viewer interface adapters, or cross-transport UI.

Use this when a frontend should share the same panels, inspectors, selection controls, asset list, and viewer widgets across WebRTC streaming, Electron SHM, Tauri SHM/native IPC, or a future transport.

Purpose

The local viewer UI module is generated React component code plus a TypeScript interface contract. The contract lets UI components depend on one ViewerBackend object instead of transport-specific APIs such as AppStreamer messages, Electron preload calls, Tauri commands, or future IPC layers.

The shared UI does not render USD or 3D content. All USD rendering still uses ovrtx in the appropriate server or native process. In OVStage-backed apps, the backend runtime also owns stage lifetime, ordinals, write floors, and renderer publication. The UI displays a video, canvas, or pixel surface owned by the transport and overlays reusable React controls that call ViewerBackend.

Read These Skills

NeedRead
Browser/WebRTC transportstreaming-client, streaming-messages, streaming-lifecycle
Electron + SHM local transportelectron-shm-viewer, webgl-shm-transport
Tauri/native desktop transporttauri-local-viewer
Camera input behaviorviewer-input-routing, camera-controls
Picking and selectionviewer-input-routing, object-selection, selection-feedback
Hierarchy and property datastage-hierarchy, stage-attribute-reads
AOV and render settings messagesaov-switching, render-settings

Local Module Setup

Generate these files inside the frontend app unless the user requests a different local structure:

frontend/src/viewer-ui/
  ViewerBackend.ts
  types.ts
  StageTree.tsx
  PropertyPanel.tsx
  Inspector.tsx
  PrimIconSprite.tsx
  USDAsset.tsx
  index.ts

Use index.ts as the local barrel export. Do not add an external package dependency for shared viewer UI.

Import components and types from the local module:

import {
  Inspector,
  PrimIconSprite,
  PropertyPanel,
  StageTree,
  USDAsset,
  type FrameData,
  type PrimNode,
  type PrimProperty,
  type USDAssetItem,
  type ViewerBackend,
} from './viewer-ui';

The local index.ts exports Inspector, InspectorProps, PrimIconSprite, PropertyPanel, StageTree, StageTreeProps, USDAsset, and all shared viewer types.

ViewerBackend Interface

Implement this interface at the transport boundary. Components should call this interface, not raw WebRTC, Electron, Tauri, or server-message APIs.

export interface ViewerBackend {
  connect(): Promise<void>;
  disconnect(): void;
  loadStage(path: string): Promise<void>;
  resize?(width: number, height: number): Promise<void>;
  sendRenderScale?(scale: number): Promise<void>;
  setCamera(params: CameraParams): Promise<void>;
  cameraMouseButton(input: PointerInput): Promise<boolean>;
  cameraMouseMove(x: number, y: number): Promise<void>;
  cameraWheel(delta: number): Promise<void>;
  onFrame(callback: (frame: FrameData) => void): () => void;
  onStats?(callback: (stats: FrameBudgetStats) => void): () => void;
  onLoadProgress?(callback: (progress: LoadProgressEvent) => void): () => void;
  onAOVStateChanged?(callback: (active: string, available: string[]) => void): () => void;
  changeAOV?(aov: string): Promise<void>;
  getCapabilities?(): Promise<ViewerCapabilities>;
  invokeFeature?<T = unknown>(feature: string, payload: Record<string, unknown>): Promise<T>;
  onSelectionChanged(callback: (paths: string[]) => void): () => void;
  pick(x: number, y: number): Promise<string | null>;
  getStageTree(rootPath?: string): Promise<PrimNode[]>;
  selectPrims(paths: string[]): Promise<void>;
  getProperties(path: string): Promise<PrimProperty[]>;
}

Method contract:

MethodContract
connect()Establish the transport, register event/frame listeners, and resolve when commands can be sent. Guard duplicate calls from React remounts.
disconnect()Remove listeners, stop frame pumps, close transport handles, and reject or clear pending resolvers. Make cleanup safe to call more than once.
loadStage(path)Resolve when the runtime has produced the new scene's first valid frame and published its matching scene state. Reject failure, cancellation, or supersession; transport acceptance alone is not completion. Preserve the active scene during download and invalidate scene-local UI at renderer handoff. Track decoded-video readiness separately.
resize?(width, height)Resize a backend-owned dynamic render target when supported. Fixed-resolution video and fixed render-product transports should implement a no-op or omit this method.
sendRenderScale?(scale)Request a render-scale change when the backend supports adaptive scaling. Clamp to supported values and publish the effective scale through frame or stats updates when possible.
setCamera(params)Set camera state directly for backends that own explicit camera parameters. Native-input transports may resolve without action if camera motion is driven by pointer messages.
cameraMouseButton(input)Send a button press/release to the camera controller. Return true when the backend classifies the gesture as a click so callers can perform selection picking.
cameraMouseMove(x, y)Send pointer motion in viewport-local CSS pixels. Continuous input should be fire-and-forget internally but the Promise should settle quickly.
cameraWheel(delta)Send wheel zoom input. Preserve the backend's existing wheel sign convention from viewer-input-routing and camera-controls.
onFrame(callback)Subscribe to frame arrivals or frame timing. Return an unsubscribe function. FrameData.pixels is optional because WebRTC video transports may expose only timing.
onStats?(callback)Subscribe to transport/render performance stats such as FPS, queue depth, dropped frames, latency, and WebRTC inbound RTP stats when available.
onLoadProgress?(callback)Subscribe to stage-load progress phases. Use this for progress bars and disabled UI states during load.
onAOVStateChanged?(callback)Subscribe to active AOV and available AOV list changes. Call immediately with cached state when available so controls populate after reconnect.
changeAOV?(aov)Request an AOV/render-var switch. Reject unsupported AOV names or no-op only when the backend intentionally has no AOV support.
getCapabilities?()Return transport-neutral feature flags and effective runtime capabilities, such as supported AOVs, transform modes, pick effects, physics impulse support, and settings keys.
invokeFeature?(feature,payload)Optional extension command for app-specific capabilities. Reject unsupported features instead of falling through to transport internals.
onSelectionChanged(callback)Subscribe to canonical selected prim paths. Return an unsubscribe function and fan out both local UI selections and server/native selection events.
pick(x, y)Return the prim path under a viewport-element-local CSS pixel coordinate, or null. Never require callers to pass window coordinates.
getStageTree(rootPath?)Return normalized PrimNode[] for the root or requested prim path. It may use cached tree data, lazy queries, or a full hierarchy snapshot.
selectPrims(paths)Select the canonical prim paths in the backend and publish the same path list through onSelectionChanged. Also update native selection/highlight state when supported.
getProperties(path)Return displayable properties for a prim as PrimProperty[]. Normalize backend dictionaries, USD values, or typed command responses at this boundary.

Critical Coordinate Contract

pick(x, y), cameraMouseButton(input), and cameraMouseMove(x, y) use viewport-element-local CSS pixel coordinates, not window coordinates.

For a local adapter that owns DOM gestures, subtract the viewport element rect. WebRTC/AppStreamer owns native viewport input: subscribe to its resulting selection events instead of forwarding a second DOM camera/pick path. The local release handler below assumes its adapter also received the matching press and motion events:

function toViewportPoint(event: React.PointerEvent, viewport: HTMLElement) {
  const rect = viewport.getBoundingClientRect();
  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  };
}

const { x, y } = toViewportPoint(event, viewportElement);
const clicked = await backend.cameraMouseButton({ x, y, button: event.button, pressed: false });
if (clicked) {
  const pickedPath = await backend.pick(x, y);
  await backend.selectPrims(pickedPath ? [pickedPath] : []);
}

If a backend needs render-product pixels, map from viewport-local CSS pixels to the contained image/canvas area inside the backend or viewport adapter. Do not pass raw PointerEvent.clientX/clientY into ViewerBackend.

Frame Delivery Contract

FrameData.pixels is optional. WebRTC/AppStreamer transports usually render into a <video> element and can only report frame timing, decoded dimensions, or stats through onFrame. SHM, Tauri, or future pixel transports may provide RGBA pixels.

Shared UI components must not require pixel data. Viewport display components may choose the transport-specific surface:

TransportDisplay surfaceonFrame payload
WebRTC streaming<video> from AppStreamerTiming/dimensions; pixels usually absent
Electron SHMCanvas/WebGL texture upload from SHMRGBA pixels or transport-local buffer metadata adapted to FrameData
Tauri SHM/native IPCCanvas/ImageData or texture uploadRGBA pixels when copied/decoded for the React layer
Future transportTransport-owned surfaceAt least width, height, encoding, and timing when available

Type Catalog

export interface CameraParams {
  azimuth?: number;
  elevation?: number;
  distance?: number;
  target?: [number, number, number];
}

export interface FrameData {
  width: number;
  height: number;
  encoding: 'rgba';
  pixels?: Uint8ClampedArray;
  frameIndex?: number;
  renderScale?: number;
}

export interface FrameBudgetStats {
  timestampMs: number;
  fps: number;
  sourceFps: number;
  frameIntervalMs: number;
  deliveryMs: number;
  queueDepth: number;
  skippedFrames: number;
  droppedFrames: number;
  renderScale: number;
  backpressure: boolean;
  frame_time_ms?: number;
  stream_time_ms?: number;
  frames_rendered?: number;
  gpu_encoder_active?: boolean;
  roundTripTimeMs?: number;
  packetsLost?: number;
  jitter?: number;
  framesDecoded?: number;
  freezeCount?: number;
  framesPerSecond?: number;
}

export type LoadProgressPhase =
  | 'resolving_asset'
  | 'loading_stage'
  | 'compiling_shaders'
  | 'ready';

export interface LoadProgressEvent {
  phase: LoadProgressPhase;
  stage_url?: string;
}

export type PrimType = 'xform' | 'scope' | 'geom' | 'light' | 'camera';

export interface PrimNode {
  name?: string;
  path: string;
  children?: PrimNode[] | null;
  hasChildren?: boolean;
  type?: PrimType;
}

export type USDPrim = PrimNode;

export interface PrimProperty {
  name: string;
  type: string;
  value: string;
}

export interface USDAssetItem {
  name: string;
  url: string;
}

export interface PointerInput {
  x: number;
  y: number;
  button: number;
  pressed: boolean;
}

export interface ViewerCapabilities {
  aovs?: string[];
  renderSettings?: string[];
  runtimeTransforms?: boolean;
  pickEffects?: string[];
  physicsImpulse?: boolean;
  transport?: 'webrtc' | 'electron-shm' | 'tauri' | 'ovui' | 'native' | string;
}

Normalize transport payloads to these types before data reaches shared components. In particular, convert server fields such as has_children or boolean children into hasChildren, and convert property dictionaries into PrimProperty[].

Capability Extensions

Keep optional features out of the required interface so the same UI can run on WebRTC, Electron SHM, Tauri, ovui, or future transports. Use getCapabilities() to decide whether to show controls, and use invokeFeature() or a typed adapter method in the transport adapter for the actual command.

Useful feature names:

  • runtimeTransform: move, rotate, or scale selected prims through the runtime owner.

  • pickEffect: apply a verified selection-driven material, visibility, or effect change.

  • physicsImpulse: run a bounded physics worker and apply returned pose samples through parent runtime state.

Rules:

  • Shared components should never receive live OVStage handles, OVRTX handles, DLPack buffers, SHM pointers, or process-local tokens.

  • The backend adapter translates feature commands into data-channel messages, Tauri invokes, Electron IPC, or local API calls.

  • Physics controls should be disabled unless the backend reports either a verified PhysX.attach_ovstage(stage, read_ordinal=...) path or a bounded OVPhysX worker path.

  • A missing capability is a normal unsupported state, not a reason to add a browser-side renderer or mutate user USD files.

Shared Components

ComponentUse
StageTreeDisplays the USD hierarchy, selected-row state, expandable prims, and prim type icons. Wire row selection to backend.selectPrims() and expansion/lazy loading to backend.getStageTree(path) when the component props require callbacks.
PropertyPanelDisplays PrimProperty[] for one prim. Feed it data from backend.getProperties(selectedPath).
InspectorHigher-level selected-prim inspector. Use it when the app wants shared selection/property behavior instead of composing PropertyPanel directly.
PrimIconSpriteDefines the icon sprite used by hierarchy rows and inspector UI. Render once near the application root.
USDAssetDisplays a loadable USD asset item. Feed it USDAssetItem values and call backend.loadStage(asset.url) on activation.

When generating components, keep prop names small and stable. Do not bake transport APIs into components; adapt the transport to ViewerBackend instead.

Minimum prop contracts:

export interface StageTreeProps {
  backend: ViewerBackend;
  selectedPaths: string[];
  rootPath?: string;
}

export interface PropertyPanelProps {
  properties: PrimProperty[];
}

export interface InspectorProps {
  backend: ViewerBackend;
  selectedPaths: string[];
}

export interface USDAssetProps {
  asset: USDAssetItem;
  backend?: ViewerBackend;
  onLoad?: (asset: USDAssetItem) => void;
}

Minimum behavior:

  • StageTree loads root nodes with backend.getStageTree(rootPath) on mount, loads children when an expandable row opens, highlights selectedPaths, and calls backend.selectPrims([path]) on row activation.

  • PropertyPanel renders a compact name/type/value table and treats values as display strings unless another skill adds editing behavior.

  • Inspector subscribes to selected paths through props, fetches properties for the primary selected path with backend.getProperties(path), cancels stale responses on selection change, and renders an empty state for no selection.

  • PrimIconSprite may be a no-op component when the app uses text labels or CSS icons instead of an SVG sprite.

  • USDAsset renders one loadable asset row or button and calls onLoad(asset) when supplied; otherwise it calls backend.loadStage(asset.url) when a backend prop is supplied.

Implementing a New Backend

Use the hook-per-transport pattern:

useWebRTCBackend.ts -> AppStreamer + data-channel messages + video timing
useShmBackend.ts    -> Electron preload API + SHM frame pump + JSON control messages
useTauriBackend.ts  -> Tauri commands/events/channels + native frame delivery

Implementation rules:

  • Return one stable ViewerBackend object from the hook with useMemo.

  • Keep transport objects, request resolvers, caches, and subscriber sets in refs.

  • Convert transport events into shared callbacks: frame, stats, load progress, AOV state, and selection.

  • Add timeouts to request/response promises for loadStage, pick, getStageTree, and getProperties.

  • Resolve responses by request id when the protocol supports it; otherwise bucket by URL/path/message type.

  • Normalize all hierarchy nodes, property values, AOV names, and selected paths at the backend boundary.

  • Make disconnect() clear subscribers only when the app is truly tearing down; ordinary event-handler cleanup should only unsubscribe that handler.

  • Preserve the single render-thread/server ownership rules from the transport skill. The React backend is an adapter, not a renderer.

Resolver pattern:

type Resolver<T> = {
  resolve: (value: T) => void;
  reject: (error: Error) => void;
  timer: number;
};

const selectionHandlers = useRef(new Set<(paths: string[]) => void>());
const frameHandlers = useRef(new Set<(frame: FrameData) => void>());
const treeResolvers = useRef(new Map<string, Resolver<PrimNode[]>[]>());
const propertyResolvers = useRef(new Map<string, Resolver<PrimProperty[]>[]>());
const treeCache = useRef(new Map<string, PrimNode[]>());

function emitSelection(paths: string[]) {
  for (const handler of selectionHandlers.current) handler(paths);
}

function resolveBucket<T>(buckets: Map<string, Resolver<T>[]>, key: string, value: T) {
  const bucket = buckets.get(key) || [];
  buckets.delete(key);
  for (const resolver of bucket) {
    window.clearTimeout(resolver.timer);
    resolver.resolve(value);
  }
}

Transport notes:

  • WebRTC/AppStreamer: connect() owns one AppStreamer connection. Route onCustomEvent messages into resolver buckets and subscriber sets. onFrame usually publishes timing from video playback quality or stats; leave pixels undefined.

  • Electron SHM: connect() attaches preload/native SHM APIs and starts one frame pump. Convert SHM frames to the viewport's upload path and publish shared FrameData only for data the shared UI needs.

  • Tauri SHM/native IPC: connect() registers Tauri event listeners and frame channels once. Decode binary RGBA frames when the React layer owns a canvas; otherwise publish timing/dimensions and let the viewport adapter own pixels.

Integration Recipe

  1. Generate frontend/src/viewer-ui/ with the ViewerBackend types and local React components required by the app.

  2. Implement a backend hook for the chosen transport: useWebRTCBackend, useShmBackend, useTauriBackend, or a new hook.

  3. Mount the transport viewport surface: <video>, <canvas>, or a native pixel-presenting component.

  4. Give the viewport one input owner. WebRTC uses AppStreamer native input; local DOM adapters convert coordinates before calling camera/pick methods.

  5. Subscribe to backend selection and frame/stat events in React effects.

  6. Render shared UI components against the backend rather than raw transport APIs.

  7. Keep transport-specific message names and native handles inside the backend hook.

WebRTC skeleton (the backend hook owns AppStreamer input and connection state):

function ViewerApp() {
  const backend = useWebRTCBackend(config); // stable identity for this endpoint
  const [connectionError, setConnectionError] = useState<string | null>(null);
  const [selectedPaths, setSelectedPaths] = useState<string[]>([]);

  useEffect(() => {
    let active = true;
    void backend.connect().catch(error => {
      if (active) setConnectionError(String(error));
    });
    return () => { active = false; backend.disconnect(); };
  }, [backend]);

  useEffect(() => backend.onSelectionChanged(setSelectedPaths), [backend]);


  return (
    <>
      <PrimIconSprite />
      {connectionError && <div role="alert">{connectionError}</div>}
      <main className="viewer-shell">
        <section className="viewport">
          <video id="remote-video" />
        </section>
        <aside className="sidebar">
          <StageTree backend={backend} selectedPaths={selectedPaths} />
          <Inspector backend={backend} selectedPaths={selectedPaths} />
        </aside>
      </main>
    </>
  );
}

Keep the dependency direction the same: app UI calls local viewer UI components, those components call ViewerBackend, and only backend hooks know the transport.

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