Building 2D Websites for the Metaverse (or at least for  the Oculus Quest Browser)
Tags: webdev, javascript, vr, xr
Published: 2021-11-26 05:13:38

As a long-time web developer and non-gaming VR fan I'm really excited about the potential for the web on virtual reality platforms like the Oculus Quest. Last week I spent a few hours toying with [my 2D tetris clone](https://github.com/xjamundx/tetris) on the Oculus Quest browser and actually got it installed it as a Progressive Web App on my headset. I'm excited to show off how I got this to work and what I learned in the process.

![Widescreen Tetris](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3pscalifn1dwcc16bb6d.png) 

---

## Oculus Quest is Essentially an Android Device

The Oculus Quest is basically an Android smartphone that you strap to your face. To get started developing for the Quest, even on the web, you're going to want to download [Android Studio](https://developer.android.com/studio) and the [Android SDK Platform Tools](https://developer.android.com/studio/releases/platform-tools). You'll be using the `adb` command from time to time to confirm your device is properly connected, install your PWAs and make other advanced configuration changes. You also will need to enable developer mode for your device, which you need to do from the Oculus app on your phone. There's also another step in the Oculus settings menu where you'll need to enable USB debugging.

Oculus provides some desktop software called [Oculus Developer Hub](https://developer.oculus.com/downloads/native-android/) that simplifies a number of key developer tasks like verifying your connection, disabling the guardian, casting and taking screenshots.

![Oculus Developer Hub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd9s8zt3qqvz6kgdkr55.png)
 
It’s definitely a lot of steps, but after you've got all of this setup you're well on your way to building Oculus VR apps in 2D using web technology. It's exciting!

![Oculus Developer Hub Allows Casting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ss3yrnn797d66t92soq.png)

## Browsing the 2D Web in VR

When you open up the Oculus Browser for the first time you might notice a few things that are unique about it compared to a normal web browser. The first is that it's capable of 3 browser windows side by side. So you're confronted with this 180&deg; wall of browser windows which measures over 3000pixels in width. The default width of each window according to the [oculus browser specs](https://developer.oculus.com/documentation/web/browser-specs/) is unique at 1000px wide by 505px high. And as of right now you can resize them, but only the width. You’re stuck with that strange height. (_Edit: [Width/Height Resizing is now available](https://twitter.com/vrhermit/status/1470149581279305734?s=20) as of Dec. 13, 2021._)

Try to pull up a few websites. If it's something interactive like my [tetris game](https://xjamundx.github.io/tetris) there's a good chance it won't quite work!!

![My bad Tetris Clone in the Oculus Browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqpadp1yq9nvxhovajsi.jpg)

If on the other hand you pull up a standard news site, blog or even the something optimized like the [React Three Fiber Demo App](https://rrppl0y8l4.csb.app/) they should all look and work great.
 
![React Three Fiber Demo App Rendered in the Oculus Browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4ox5p6k9wm8wtw4sjr1.png)

## Debugging Local Code

Assuming you're building your app on your local computer you probably want to see those updates immediately in the oculus browser. To do that you need to setup a reverse proxy which forwards all traffic from a port on your Oculus device to one on your computer:

```bash
adb reverse tcp:3000 tcp:3000
```

With that you should be able to enter in URLs like [http://localhost:3000](http://localhost:3000) in the oculus browser and have them work perfectly, reading files off of your computer.

If you're using something like codesandbox or glitch to host your files it can be really helpful to use this feature of Oculus Developer Hub which lets you enter in a URL and have it open automatically on your headset.
![ODH URL Pass thru](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8btom9nb81080riu795.jpg)

Now comes the mind blowing part. You can inspect your oculus browser window from inside of Google Chrome. You simply go to 
 [chrome://inspect/#devices](chrome://inspect/#devices) and click "inspect" on your device instance. It really feels like magic.

![chrome inspect devices](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4o9tta9vohy8uobqbind.png)

I mostly used `console.log` to log my event listeners, but as far as I can tell the full JavaScript debugger along with the network and element inspectors. Because going back and forth between your computer and your headset is obviously kind of a pain, I found testing by interacting with the little preview app inside of inspector window actually saved a lot of time.

## UX & Web API Considerations

✅ Now you have your app showing up in the Oculus browser and you're able to update and debug that app on your local computer. Here are some basic tips for optimizing that app for running in VR:

1. Use the [PointerEvents API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) for user input
2. Make buttons and text Larger
3. Optimize for a wide screen

My initial tetris implementation relied on keyboard input to move things around. When first porting it over I started using mouse events like `mousedown` and `mousemove` and was surprised when they didn't work. I shouldn't have been surprised though. The Oculus Browser is running on an Android device. Instead of mouse events it supports [Touch Events](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) and the slightly cleaner [PointerEvents API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events). Pointer Events give you have a single event for both touch and mouse events. They're fully supported in React and seem a little easier to work with than touch events, which support input from multiple touches simultaneously. 

Once you get your user input working properly make sure to make your interactive elements larger. As mobile web browsing began to take off a decade ago, both Apple and Google provided [UI guidelines](https://developer.apple.com/design/tips/#interactivity) for how users interact with their devices. One of the main ones was to give a lot of padding to buttons & other controls you expected the user would touch. This was to make sure when someone's finger didn't quite make the target your app would give them what they wanted anyway. This is even more important in VR where your controllers are in a constant state of motion. Make those inputs larger and given the blurry text we still have in VR, make your text larger as well.

My last realization is to consider the screen real estate you have in the Oculus Browser. You're dealing with 1000px wide, but only 505px high. It's a fairly wide screen, but it's really short. Scrolling in the Oculus Browser works fine, but I'd personally recommend designing for wide screen without having to scroll. Certainly for most games or more interactive apps you don't want to have to scroll to see some important part of the action. Think about how you can stretch your app out. Many tablet apps are designed to take advantage of space in landscape mode and I'm confident we'll figure out how to do this well for VR.


### More To Learn

My [tetris clone](https://xjamundx.github.io/tetris/) still isn't fully optimized for VR, but I made the buttons a lot bigger and migrated to use the Touch Events API so that pieces can be moved around as they are falling. I also got it [installed as a PWA](https://developer.oculus.com/documentation/web/pwa-gs/) so I can run it next to other apps in my library. My next steps are to migrate to the Pointer Events API and to figure out how to optimize for all of that horizontal screen real estate!

![Widescreen Tetris](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3pscalifn1dwcc16bb6d.png)
 

Once I get that sorted out there are definitely a few more questions I want to dive into. Do I need the [WebXR Gamepads API](https://www.w3.org/TR/webxr-gamepads-module-1/) to capture the various buttons and trigger inputs from the oculus touch controllers? (_**Follow up:** nope, they can't be accessed  outside of [immersive-vr](https://immersive-web.github.io/webxr/#dom-xrsessionmode-immersive-vr) mode._) Could I make a super wide game that spans 3 browser windows using [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) or the [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)? And then beyond that, is a 2D web for VR even a thing worth pursuing?  How hard would it be to use something like [a-frame](https://aframe.io/) or [React Three Fiber](https://github.com/pmndrs/react-three-fiber) with [use cannon](https://github.com/pmndrs/use-cannon) to make fully immersive 3D world? [People are doing it](https://blog.mozvr.com/hello-webxr/), so why not you and me? 

---


There are so many technologies generating enthusiasm right now in the world of web development, but I wouldn't sleep on building web apps for VR! Meta has sold over 10 million Quest 2 devices already and that growth seems to be sustainable. This is happening. What role is the 2D web going to have in virtual reality and the so-called metaverse? What about [WebXR ](https://experiments.withgoogle.com/collection/webxr?) and the 3D web? It's up to us to build the future we want to see. So start building!

----



1. https://techcrunch.com/2021/10/28/facebook-opens-oculus-store-to-2d-progressive-web-apps/
2. https://www.theverge.com/2021/11/16/22785469/meta-oculus-quest-2-10-million-units-sold-qualcomm-xr2
3. https://developer.oculus.com/documentation/web/browser-remote-debugging/
4. https://reactjs.org/blog/2018/05/23/react-v-16-4.html
5. https://developer.apple.com/design/human-interface-guidelines/ios/user-interaction/gestures/
6. https://www.w3.org/TR/webxr-gamepads-module-1/