Can’t access my WebXR from Meta Quest

When I first tried building a basic WebXR app for my Quest 3 headset, I got caught by a few gotchas. I’ll describe them below.

I used BabylonJS & Vite for my setup, but while the code examples will be tailored toward that in some instances, the concepts will hopefully be universally relevant.

Bluesky
Threads
Twitter / X
Mastodon
Instagram

Access the page from your headset

You’re probably developing on your laptop or desktop, in which case, at many points along the way you will want to open the page in your headset.

Vite’s defaults will give you an address that will only work on the device you’re running the process on though. ie…

http://localhost:3000

You turn that into a link accessible from any device online by adding the following host value to your vite.config.js file. It’s not enough though, so keep reading.

import { defineConfig } from 'vite';

///////////////////

export default defineConfig({
  root: 'src',
  build: {
    outDir: '../dist',
    emptyOutDir: true,
  },
  server: {
    host: '0.0.0.0', // This makes the server accessible publicly
    port: 3000
  }
}); 

Now, when you restart the server you’ll get both a local URL and a network URL. Use the network URL to access the page from another device while the server is running.

Recognise the Quest as an XR supported device

The next stumbling block is that you cannot enter VR or AR mode unless the device is being served through an SSL connection. If it’s not, opening the page on the Quest headset will look just like on your laptop — It won’t report as XR capable and therefore won’t give you a button to enter immersive mode (Or if you manually created the button, it won’t work).

You can fix this during development with a temporary certificate.

First install the @vitejs/plugin-basic-ssl package.

npm i @vitejs/plugin-basic-ssl

Then update your vite.config.js file like this:

import { defineConfig } from 'vite';
import basicSsl from '@vitejs/plugin-basic-ssl'; // Don't forget the import

///////////////////

export default defineConfig({
  root: 'src',
  build: {
    outDir: '../dist',
    emptyOutDir: true,
  },
  server: {
    host: '0.0.0.0',
    port: 3000
  },

  // This gives you a basic SSL certificate
  plugins: [
    basicSsl({
      name: 'test', // name of certification
      domains: ['*.custom.com'], // custom trust domains
      certDir: '/Users/.../.devServer/cert' // custom certification directory
    })
  ]

}); 

Now when you restart he server you’ll get a public address that you can use in your Headset. The address might look the same, but it’s not, it’s https instead of http.

When you access it, it will give you a warning about an unknown certificate, but you can click advanced and proceed anyway. This is safe, since you made the page.

Side-note: AI told me to do the below, but I found it doesn’t do the job. On it’s own it will create an https link, but it won’t create a certificate. If you do the above instead, you don’t need the below because you’ll get both automatically.

Not needed:

server: {
    https: true,
    port: 3000
},

Thanks…

I also dissect and speculate on design and development.
Digging into subtle details and implications, and exploring broad perspectives and potential paradigm shifts.
Check out my conceptual articles on Substack or find my latest below.


You can also find me on Threads, Bluesky, Mastodon, or xTwitter for more diverse posts about ongoing projects.

My latest articles

Storyboarding Immersive Experiences

Storyboarding 360 degree immersive experiences requires a different approach to traditional media…

Staging XR scenes (Keep doing your crappy little drawings)

Some people create beautiful perspective illustrations to visualise and storyboard their virtual reality designs And it’s tempting to think you’re not a strong designer if you’re not doing that too…

Focal point blocking for XR media

Planning out a linear VR experience requires thinking about where the viewers attention might be. Thinking about the focal points…

Designing immersive experiences

In traditional cinema, TV, or even the more modern phone screen, there’s limited screen real-estate. But removing that limitation creates a design problem…

The future is not prompt engineered

Let’s not pretend the importance of prompt engineering is ubiquitous. The most prevalent power of generative AI is in the way it adapts to us, not the other way around…

The typography of dates, times, & filenames

A deep dive into carefully considered date formatting, line length and general typography attributes of filenames…
Bluesky
Threads
Twitter / X
Mastodon
Instagram


Author:

Date:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.