Android Support/ Vizard to WebXR Export Guide

Export Vizard and SightLab VR applications to WebXR for running on Quest 3, phones, and other stand alone android based devices and VR headsets. Additionally, convert osgb models to glb format with PBR shaders.
Quick Start
Step 1: Export Your Script
Open a windows Powershell window (also click the + icon if wanting to run the server)
cd "pathTo\Android_Support"
python webxr_builder.py example_test_sightlab.py -m webxr -o ./output_folder
or with a texture directory
python webxr_builder.py example_test_sightlab.py -m webxr -o ./output_folder -t textures/
Step 2: Start Local Server
cd "pathTo\output_folder\webxr"
python -m http.server 9000
Step 3: View in Browser
Open http://localhost:9000 in Chrome or Edge
Model Conversion
The exporter automatically converts models:
| Input Format | Method |
|---|---|
| .glb, .gltf | Direct copy |
| .osgb, .osg, .ive | osgconv → .obj → Blender → .glb (note: Textures need to manually be saved first) |
| .fbx, .obj, .dae | Blender → .glb |
Requirements:
- Blender 3.6+ (for conversions)
osgconvtool (for OSG formats) (download from here, extract and place "bin" in the root folder)
For osgb models need to first manually save the textures
right click on the texture - go to Properties - left click on the gear icon - save as .dds in the textures folder
Once they are in the textures folder run the converter script and the .glb model will be saved into output_folder\output_folder\webxr\models folder
Alternatively, you can just run the convert_models.py python script if you're only wanting to convert .osgb models

Quest 3 Testing (Cloudflare Tunnel)
One-Time Setup
winget install cloudflare.cloudflared --accept-package-agreements --accept-source-agreements
Start Tunnel (with server still running from previous step)
& "C:\Program Files (x86)\cloudflared\cloudflared.exe" tunnel --url http://localhost:9000
You'll get a URL like: https://xxxxx.trycloudflare.com
On Quest 3/ Android XR Devices
- Open Meta Browser
- Navigate to the tunnel URL
- Click Enter VR
- Use controller buttons and triggers
On Phone/ Desktop
- Open Browser
- Navigate to the tunnel URL
- Click Enter VR for Google Cardboard/VR Devices
Notes
- No account required for quick tunnels
- URL changes each time you restart
- Keep both terminals running while testing
Supported Features
Model Loading
| Vizard Code | WebXR Translation |
|---|---|
vizfx.addChild('model.glb') |
Three.js GLTFLoader |
viz.addChild('model.glb') |
Three.js GLTFLoader |
Model Transforms
| Vizard Code | WebXR Translation |
|---|---|
model.setScale([x, y, z]) |
object.scale.set(x, y, z) |
model.setPosition([x, y, z]) |
object.position.set(x, y, z) |
model.setEuler([yaw, pitch, roll]) |
object.rotation.set() (radians) |
pos= parameter |
Initial position |
scale= parameter |
Initial scale |
Visibility
| Vizard Code | WebXR Translation |
|---|---|
model.visible(viz.TOGGLE) |
object.visible = !object.visible |
model.visible(viz.ON) |
object.visible = true |
model.visible(viz.OFF) |
object.visible = false |
Key Bindings
| Vizard Code | WebXR Translation |
|---|---|
vizact.onkeydown('key', func) |
document.addEventListener('keydown') |
VR Controller Buttons (Quest 3)
| Button | Controller | WebXR Index |
|---|---|---|
| A | Right | 4 |
| B | Right | 5 |
| X | Left | 4 |
| Y | Left | 5 |
| Trigger | Both | 0 |
| Grip | Both | 1 |
Object Grabbing
SightLab Method (Recommended)
sightlab.addSceneObject('duck', duck, grab=True)
sightlab.addSceneObject('ball', ball, grab=True)
In WebXR:
- Press trigger to grab objects within 1 meter
- Release trigger to drop
- Works with both controllers
Manual Method
Use special comments in your OpenXR code:
# WEBXR_BUTTON: BUTTON_RIGHT_TRIGGER -> grabDuck
# WEBXR_BUTTON_UP: BUTTON_RIGHT_TRIGGER -> releaseDuck
# WEBXR_BUTTON: BUTTON_RIGHT_TRIGGER -> grabDuck
# WEBXR_BUTTON_UP: BUTTON_RIGHT_TRIGGER -> releaseDuck
WebXR Controls
- WASD - Move forward/back/left/right
- Mouse - Look around (click to enable)
- Enter VR button - For VR headsets
AR/Passthrough Mode (In Progress)
The exporter detects passthrough patterns and enables WebXR AR mode:
Detected Patterns:
- xr.getPassthroughFB() - Meta Quest
- xr.getPassthroughVarjo() - Varjo
- xr.getPassthroughHTC() - HTC Vive
- viz.clearcolor(viz.BLACK, 0.0) - Transparent background
WebXR AR Features:
- Uses immersive-ar session type
- Transparent background (camera passthrough)
- Button shows "Enter AR"
Limited Support
| Feature | Status |
|---|---|
viz.addAudio() |
File copied, not yet playing |
| Mouse bindings | Structure exists, needs work |
Not Yet Supported
| Category | Features |
|---|---|
| Physics | viz.phys.enable(), collisions, velocity |
| Animation | vizact.ontimer(), moveTo(), spinTo() |
| Objects | clone(), addTexQuad(), setParent() |
| UI | InfoPanel(), dialogs, inputs |
| Advanced | Avatars, shaders, multiplayer, proximity |
Output Structure
output_folder/
├── webxr/
│ ├── index.html # Main WebXR app
│ └── models/ # Converted GLB models
├── android_twa/ # Android wrapper (optional)
└── BUILD_INSTRUCTIONS.md
Building APKs (Optional)
Using Capacitor
cd webxr_output
npm init -y
npm install @capacitor/core @capacitor/cli @capacitor/android
npx cap init "MyApp" com.company.app
npx cap add android
npx cap open android
Using TWA
Open the generated android_twa project in Android Studio and build.
Using PWABuilder
- Host WebXR app on HTTPS
- Go to https://pwabuilder.com
- Generate Android package
Alternative: Godot Export (Not Yet Implemented)
For native Android VR apps with better performance, a Godot export path is planned:
python webxr_builder.py your_script.py -m godot -o ./output_folder
Pros:
- Native Android performance
- Full OpenXR feature access
- Supports Quest, Pico, and other standalone headsets
Cons:
- Requires Godot 4.x installed
- Manual build process in Godot Editor
- Larger app size
Status: Scaffolding exists but not fully implemented. Use WebXR for now.
Troubleshooting
Model not converting
- Ensure Blender is installed
- Check input file exists
- Try manual conversion in Blender
WebXR not working
- Use HTTPS (required for WebXR)
- Check browser console (F12)
- Test WebXR support: https://immersive-web.github.io/webxr-samples/
Refresh not showing changes
- Hard refresh:
Ctrl+Shift+R - Add
?v=2to URL - Use Incognito window
Debugging
Press F12 to open browser console:
Loading model: models/duck.glb scale: [0.5, 0.5, 0.5]
BUTTON_A pressed
Grabbed duck with right controller
Released duck
Last updated: January 25, 2026