Skip to content

Android Support/ Vizard to WebXR Export Guide

AI Agent

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)
  • osgconv tool (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

AI Agent


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

  1. Open Meta Browser
  2. Navigate to the tunnel URL
  3. Click Enter VR
  4. Use controller buttons and triggers

On Phone/ Desktop

  1. Open Browser
  2. Navigate to the tunnel URL
  3. 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.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 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

  1. Host WebXR app on HTTPS
  2. Go to https://pwabuilder.com
  3. 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=2 to 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

Was this page helpful?