Kit App Template Integration#
Note
Applies to: Spatial Extensions, Kit 109.0.3+, CloudXR 6
This integration reference covers integrating XR functionality into applications built with the Kit App Template.
Kit App Template Overview#
The Kit App Template (kit-app-template) is the standard starting point for building Omniverse Kit SDK-based applications. It provides:
Application Templates: Starting points for different app types
Extension Templates: Scaffolding for new extensions
Build System:
repo.shfor building and packagingApplication Layers: Modular configuration system
Repository: kit-app-template
Three Integration Methods#
Method |
Flexibility |
Reusability |
Complexity |
Best For |
|---|---|---|---|---|
Direct .kit |
Low |
Low |
Low |
Quick prototypes |
Custom Bundle |
High |
High |
Medium |
Organizations |
Application Layer |
Medium |
Medium |
Medium |
Deployment configs |
Method A: Direct .kit File Integration#
Add XR directly to your application’s .kit file.
Step 1: Create Application with Kit App Template#
# Initialize kit app template (if not already)
git clone https://github.com/NVIDIA-Omniverse/kit-app-template.git
cd kit-app-template
# Create new application
./repo.sh template new
# Follow prompts:
# - Choose: Application
# - Template: Kit Base Editor (or USD Viewer, USD Composer, etc.)
# - Name: my_xr_app
This creates:
apps/
└── my_xr_app/
├── my_xr_app.kit
└── ...
Step 2: Add XR Bundle to .kit File#
# apps/my_xr_app/my_xr_app.kit
[package]
title = "My XR Application"
version = "1.0.0"
description = "XR-enabled application"
keywords = ["xr", "vr"]
[dependencies]
# Existing dependencies...
"omni.kit.uiapp" = {}
"omni.kit.viewport.window" = {}
# ... other deps ...
# Add XR bundle
"omni.kit.xr.bundle.generic" = {} # Cross-platform
# OR
# "omni.kit.xr.bundle.apple_vision_pro" = {} # For AVP
# "omni.kit.xr.bundle.quest" = {} # For Quest (if available)
[settings]
# Optional: XR-specific settings
defaults.xr.activeProfile = "vr"
defaults.xr.system.display = "OpenXR"
defaults.xr.profile.vr.renderQuality = "balanced"
Step 3: Create Startup Extension#
Create an extension to auto-start XR:
./repo.sh template new
# Choose: Extension
# Template: basic_python
# Name: my_xr_app.startup
# exts/my_xr_app.startup/my_xr_app/startup/extension.py
import omni.ext
import omni.kit.xr.core
import carb.events
class MyXRAppStartupExtension(omni.ext.IExt):
"""Auto-start XR on application launch."""
def on_startup(self, ext_id):
print("My XR App: Starting XR")
self.xr_core = omni.kit.xr.core.XRCore.get_singleton()
# Wait for XR system to be ready
self._wait_for_xr_ready()
def _wait_for_xr_ready(self):
"""Wait for XR system, then enable profile."""
import omni.kit.app
async def enable_xr_when_ready():
# Wait a frame for XR system to initialize
await omni.kit.app.get_app().next_update_async()
# Enable VR profile
self.xr_core.request_enable_profile("vr")
print("My XR App: VR profile enabled")
import asyncio
asyncio.ensure_future(enable_xr_when_ready())
def on_shutdown(self):
print("My XR App: Shutting down")
# Disable XR
if self.xr_core and self.xr_core.is_xr_enabled():
self.xr_core.request_disable_profile()
# exts/my_xr_app.startup/config/extension.toml
[package]
version = "1.0.0"
title = "My XR App Startup"
description = "Auto-start XR for My XR App"
[dependencies]
"omni.kit.xr.core" = {}
[[python.module]]
name = "my_xr_app.startup"
Step 4: Add Startup Extension to App#
# apps/my_xr_app/my_xr_app.kit
[dependencies]
"omni.kit.xr.bundle.generic" = {}
"my_xr_app.startup" = {} # Add startup extension
[settings.app.exts]
folders.'++' = [
"${app}/../../exts" # Include local extensions
]
Step 5: Build and Run#
# Build
./repo.sh build
# Run
./repo.sh launch --config=apps/my_xr_app/my_xr_app.kit
# Or directly
_build/linux-x86_64/release/kit/kit --enable apps/my_xr_app/my_xr_app.kit
Method B: Custom Bundle Extension#
Create a reusable XR bundle for your organization, then use across apps.
Step 1: Create Custom Bundle#
See Custom Bundles Guide for details.
# Create bundle extension
mkdir -p exts/my_company.xr.bundle.custom/config
# exts/my_company.xr.bundle.custom/config/extension.toml
[package]
version = "1.0.0"
title = "My Company XR Bundle"
description = "Custom XR configuration"
[dependencies]
"omni.kit.xr.core" = {}
"omni.kit.xr.system.openxr" = {}
"omni.kit.xr.system.simulatedxr" = {}
"omni.kit.xr.ui.stage" = {}
"omni.kit.xr.ui.window.profile" = {}
"omni.kit.xr.ui.window.viewport" = {}
[settings]
defaults.xr.activeProfile = "vr"
defaults.xr.profile.vr.renderQuality = "balanced"
# ... more settings ...
Step 2: Use Bundle in Multiple Apps#
# apps/app1/app1.kit
[dependencies]
"my_company.xr.bundle.custom" = {}
[settings.app.exts]
folders.'++' = ["${app}/../../exts"]
# apps/app2/app2.kit
[dependencies]
"my_company.xr.bundle.custom" = {} # Same bundle
[settings.app.exts]
folders.'++' = ["${app}/../../exts"]
Step 3: Version and Publish#
# Package bundle
./repo.sh package --ext my_company.xr.bundle.custom
# Publish to your extension registry
./repo.sh publish --ext my_company.xr.bundle.custom --registry my_company_registry
Method C: Application Layer#
Create modular deployment configurations using application layers.
Step 1: Create Base Application#
# apps/my_base_app/my_base_app.kit
[package]
title = "My Base Application"
version = "1.0.0"
description = "Base application without XR"
[dependencies]
# Core dependencies (no XR)
"omni.kit.uiapp" = {}
"omni.kit.viewport.window" = {}
"omni.kit.property.bundle" = {}
# ... application-specific extensions ...
[settings]
# Base application settings
app.name = "My Base Application"
app.window.title = "My Application"
Step 2: Create XR Application Layer#
# apps/my_app_xr_layer/my_app_xr_layer.kit
[package]
title = "My Application - XR Mode"
version = "1.0.0"
description = "XR layer for My Application"
keywords = ["app", "layer", "xr"]
[dependencies]
# Reference base application
"my.base.app" = {}
# Add XR support
"omni.kit.xr.bundle.generic" = {}
# Optional: XR startup extension
"my_xr_app.startup" = {}
[settings]
# Override app name for XR mode
app.name = "My Application (XR Mode)"
app.window.title = "My Application - XR"
# XR-specific settings
defaults.xr.activeProfile = "vr"
defaults.xr.system.display = "OpenXR"
# Performance tweaks for XR
rtx.ecoMode.enabled = false
rtx.post.aa.op = 3
[settings.app.exts]
folders.'++' = ["${app}/../../exts"]
Step 3: Create Additional Layers (Optional)#
# apps/my_app_streaming/my_app_streaming.kit
# Streaming layer
[package]
title = "My Application - Streaming"
version = "1.0.0"
[dependencies]
"my.base.app" = {}
"omni.kit.livestream.app" = {}
[settings]
livestream.enabled = true
# ... streaming settings ...
# apps/my_app_xr_streaming/my_app_xr_streaming.kit
# XR + Streaming combined
[package]
title = "My Application - XR Streaming"
version = "1.0.0"
[dependencies]
"my.base.app" = {}
"omni.kit.xr.bundle.generic" = {}
"omni.kit.livestream.app" = {}
"my_xr_app.startup" = {}
[settings]
# XR settings
defaults.xr.activeProfile = "vr"
# Streaming settings
livestream.enabled = true
Step 4: Launch Different Configurations#
# Desktop mode (no XR)
./repo.sh launch --config=apps/my_base_app/my_base_app.kit
# XR mode
./repo.sh launch --config=apps/my_app_xr_layer/my_app_xr_layer.kit
# Streaming mode
./repo.sh launch --config=apps/my_app_streaming/my_app_streaming.kit
# XR + Streaming
./repo.sh launch --config=apps/my_app_xr_streaming/my_app_xr_streaming.kit
Directory Structure#
kit-app-template/
├── apps/
│ ├── my_base_app/
│ │ └── my_base_app.kit
│ ├── my_app_xr_layer/
│ │ └── my_app_xr_layer.kit
│ ├── my_app_streaming/
│ │ └── my_app_streaming.kit
│ └── my_app_xr_streaming/
│ └── my_app_xr_streaming.kit
├── exts/
│ ├── my_xr_app.startup/
│ └── my_company.xr.bundle.custom/
└── repo.toml
Build and Deployment Workflows#
Development Workflow#
# 1. Build application
./repo.sh build --config=apps/my_xr_app/my_xr_app.kit
# 2. Run locally
./repo.sh launch --config=apps/my_xr_app/my_xr_app.kit
# 3. Package for distribution
./repo.sh package --config=apps/my_xr_app/my_xr_app.kit
CI/CD Integration#
# .github/workflows/build-xr-app.yml
name: Build XR Application
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Application
run: |
./repo.sh build --config=apps/my_xr_app/my_xr_app.kit
- name: Package Application
run: |
./repo.sh package --config=apps/my_xr_app/my_xr_app.kit
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: my-xr-app
path: _build/packages/
Multi-Platform Builds#
# Build for Windows
./repo.sh build --config=apps/my_xr_app/my_xr_app.kit --platform windows-x86_64
# Build for Linux
./repo.sh build --config=apps/my_xr_app/my_xr_app.kit --platform linux-x86_64
# Package all
./repo.sh package --config=apps/my_xr_app/my_xr_app.kit --all
Configuration Management#
Environment-Specific Settings#
# apps/my_xr_app/my_xr_app.kit
[settings]
# Development settings
[settings.dev]
xr.simulatedxr.enabled = true
defaults.xr.system.display = "SimulatedXR"
# Production settings
[settings.prod]
defaults.xr.system.display = "OpenXR"
persistent.xr.system.openxr.runtime = "system"
Runtime Configuration#
# Command-line override
# ./repo.sh launch --config=apps/my_xr_app/my_xr_app.kit \
# --/persistent/xr/profile/vr/renderQuality=performance
# In code
import carb.settings
settings = carb.settings.get_settings()
# Check environment
import os
if os.getenv("XR_DEV_MODE"):
settings.set("/xr/simulatedxr/enabled", True)
settings.set("/xr/system/display", "SimulatedXR")
Testing XR Applications#
Unit Tests#
# exts/my_xr_app.tests/my_xr_app/tests/test_xr_setup.py
import omni.kit.test
import omni.kit.xr.core
class TestXRSetup(omni.kit.test.AsyncTestCase):
async def setUp(self):
"""Set up test."""
pass
async def tearDown(self):
"""Clean up test."""
pass
async def test_xr_enabled(self):
"""Test XR can be enabled."""
xr_core = omni.kit.xr.core.XRCore.get_singleton()
# Enable VR profile
xr_core.request_enable_profile("vr")
# Wait for XR to enable
for _ in range(60): # Wait up to 60 frames
await omni.kit.app.get_app().next_update_async()
if xr_core.is_xr_enabled():
break
# Verify enabled
self.assertTrue(xr_core.is_xr_enabled())
# Disable
xr_core.request_disable_profile()
Run Tests#
# Run all tests
./repo.sh test
# Run specific test
./repo.sh test --filter=test_xr_setup
Troubleshooting#
Extension Not Found#
Issue: Custom bundle or extension not loading
Solution:
[settings.app.exts]
folders.'++' = [
"${app}/../../exts", # Local extensions
"/absolute/path/to/extensions" # Absolute path if needed
]
XR Not Auto-Starting#
Issue: XR doesn’t start automatically
Check:
Startup extension is in dependencies
Extension is enabled in logs
No errors in console
Debug:
# In startup extension
import carb
carb.log_info("XR Startup: Attempting to enable VR")
self.xr_core.request_enable_profile("vr")
carb.log_info("XR Startup: Request sent")
Settings Not Applied#
Issue: Application layer settings not overriding base
Solution: Ensure layer is loaded after base:
[dependencies]
"my.base.app" = {} # Load base first
"omni.kit.xr.bundle" = {} # Then XR
# Settings apply in order loaded
Best Practices#
Application Structure#
Modular Design: Separate base app from XR layer
Reusable Bundles: Share XR configs through bundles
Clear Naming: Use descriptive names for layers
Version Control: Track all .kit files in git
Settings Management#
Defaults in Bundles: Set defaults in custom bundles
Overrides in Apps: Override in app .kit files
Runtime Flexibility: Allow command-line overrides
Document Changes: Comment settings in .kit files
Testing#
Automated Tests: Test XR initialization
CI/CD: Build and test on every commit
Multi-Platform: Test on all target platforms
SimulatedXR: Use for automated testing
Next Steps#
Custom Bundles – Create custom XR bundles
Getting Started – Quick start guides
Settings Reference – Complete settings list
Key Takeaways
Kit App Template provides the build system (
repo.sh/repo.bat)Three integration methods for different needs
Application layers enable modular deployment
Custom bundles enable reusability
repo.sh handles building and packaging
Test with SimulatedXR for automation