Potato Logo Half Baked City Potato Logo

Getting Started With WebXR Part 3 – Desktop / Laptop Sessions

Before I begin, I'd like to mention how important it is in my opinion to make your WebXR apps cross platform. Why?

  • Making your apps cross platform gives you a larger audience
  • More importantly, the experience your app provides via a desktop/mobile browser is obviously just a "taste" of what they could really be experiencing if they were in a VR headset

That "taste" will entice more people to try VR out and grow our user base, increasing the demand for new hardware, developers, etc which in turn fuels progress in this still budding industry

Step 1

In this tutorial, we'll be extending our code from Part 2 to let Desktop / Laptop users look around using their mouse. Like before, three.js has a community supported component to handle this called PointerLockControls.js which makes use of the Pointer Lock API

Start by placing PointerLockControls.js into /scripts/three/examples/jsm/controls/ because it has a relative import to three.module.js

Now let's create a brand new module called /scripts/core/SessionHandler.js that we'll move our VRButton creation into and that uses PointerLockControls like so

Make sure to delete the VRButton code from Main.js

Essentially what happens is our PointerLockControls takes care of tracking the mouse and rotating the camera around accordingly after it acquires a lock. It can only acquire a lock after user interaction, so we create an event handler to determine when the user clicks the screen and then request the lock

We'll import SessionHandler into Main.js with import SessionHandler from './SessionHandler.js'; and then create an instance of it in the constructor right before setting the animation loop using this._sessionHandler = new SessionHandler(this._renderer, this._camera);

And thus we're done adding functionality to let the user use the mouse to look around. Thank you three.js community for making life easy. We're not quite done just yet though

Step 2

There are plenty of cosmetic things we should do

  1. Display a Click to Start button similar to the VR Button instead of letting the user click anywhere on the screen
  2. Don't display the VR Button when the user isn't coming from an XR Device, and likewise don't display the Click to Start button if the user is on an XR Device
  3. Make the Click to Start Button disappear after the user clicks on it, and reappear when they unlock the pointer

We'll handle the first thing by looking inside VRButton.js and seeing how they create their button. Using that as inspiration we can come up with something like this for SessionHandler.js

I opted for placing the button in a div to make it easier to center rather than using a set width to calculate displacement like in VRButton.js

Unfortunately, now the VR Button covers our Click to Start button. It's time to figure out if our user is using an XR Device or not and use that information to decide which button to display. Once again if we look inside VRButton.js we'll find some useful code that we can add to setup.js so it looks like this

Great, now we know right from the beginning whether our user is coming from an XR Device or not. All that's left to decide is how we get this information to our SessionHandler

We could pass the deviceType as an argument for Main, and then pass it from Main to the SessionHandler, but I personally would want to keep that information in a more global scope. So for this tutorial we'll make a module called global.js that just exports an empty dictionary that can be edited by any module that imports it. It looks like this

Next we'll:

  • Import global into setup.js, Main.js, and SessionHandler.js using import global from './global.js';
  • Replace deviceType with global.deviceType in setup.js
  • Check for global.deviceType == "XR" where we enable xr in the renderer in Main.js
  • Check for global.deviceType == "XR" where we add the VRButton in SessionHandler.js
  • Check for global.deviceType == "POINTER" where we setup the Pointer Start Button in SessionHandler.js

What follows is our Click to Start button is no longer hidden by the VR Button and is fully functional too. The only thing left to do is toggle whether it is displayed or not which we'll take care of after the 'click' listener we made for the button using

Great job, we now have a website that supports both VR browsers and Desktop / Laptop browsers providing custom start buttons depending on what device is being used

We're all set to add Mobile support in the last tutorial of the series!

Finished code in action

Git Repository


  • Pointer Lock API – API that hides the mouse and provides data on mouse movement based on deltas rather than the limited positions on the screen

Feeling generous/want to support me in writing tutorials? Then buy me a coffee, which I'll probably use for boba or almonds (raw and unsalted you heathens) because I don't like coffee

Continue on to Part 4 – Mobile Sessions


Please Wait...

Log in/Sign up to comment

Server error, please try again later