Where to begin with VR in a browser?

Let’s start with the basics. A-Frame because it makes it easy for me with what I already know of HTML5 and JavaScript. Is it WebXR compatible? Yes, it is in its current release 1.0.4.

Image for post
Image for post
Basic Hello World In A-Frame
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World A-Frame</title>
<meta name="description" content="Hello World, WebXR! in A-Frame">
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
</head>
<body>
<a-scene background="color: #FAFAFA">
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
</a-scene>
</body>
</html>

So what does A-Frame give us to begin with? The Hello World example. Well that’s cool, but I want more. Like an environment around the geometric shapes and the ability to move around in VR. So let’s do that!

The best way to add an environment is with the a-frame-environment-component. I found it on GitHub here:

https://github.com/supermedium/aframe-environment-component

So add that and we get:

Image for post
Image for post

In the code we have:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World A-Frame</title>
<meta name="description" content="Hello World, WebXR! in A-Frame">
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-environment-component@1.1.0/dist/aframe-environment-component.min.js"></script>
</head>
<body>
<a-scene background="color: #FAFAFA">
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
<a-entity environment="preset: forest"></a-entity></a-scene>
</body>
</html>

But we lost the plane and shadowing at the bottom of the geometric shapes? Well it’s still there, just below the environment, buried. Let’s fix that. There is a way to edit the appearance of the scene inside an “Inspector” with the keys ctrl-alt-i giving you this:

Image for post
Image for post

Notice that you can now select the plane on the upper left and move it by dragging with the green arrow upward into the scene in the middle of the screen. The x, y and z “position” of the plane will be visible in the upper right of the screen and will change accordingly. You can now adjust the positions of the sphere, cube and cylinder upwards as well, correcting them now that the plane has been moved up. Just select the appropriate entities on the upper left.

Ok, let’s do more, let’s change the environment parameters. Select <a-entity> just below <a-plane> on the upper left.

Image for post
Image for post

On the right you will see ENVIRONMENT and under it dressing and dressingColor. I selected mushroom and a purple dressing color, just to be different. Now you might think that these changes will stay if you leave the page, but you would be disappointed; they don’t!

Image for post
Image for post

So we have to save them in a way. Select <a-scene> on the upper right. Then click on the “copy entity HTML to clip board” button which is a small icon to the right of gltf icon in the top upper right corner of the screen (I’ve circled it in red in the image above). Paste the clip board below your HTML into your editor of choice and you should get something like this:

Image for post
Image for post
We pasted our clip board into an editor (Free: Sublime)

Now notice that the <a-scene>, its entities, <a-box>, <a-sphere>, <a-cylinder>, <a-plane> are all there with their x, y, z positions as changed inside the Inspector. Copy these new positions over your corresponding entity positions above. Also notice the <a-entity environment=”preset: forest; active: true; seed: 8; skyType: gradient; skyColor: #24b59f; . . . is literally full of parameters. Too many in fact for our purposes. So let me clean that up for you, we only need the dressing and dressingColor we modified earlier. So modifying and deleting out the not needed code parameters, we get something like this:

Image for post
Image for post

We did lose our shadowing, but we will correct that in a bit. Notice we have everything from the original Hello World including a new environment with a ground landscape, sky and purple mushrooms surrounding us! Here is the code for that:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World A-Frame</title>
<meta name="description" content="Hello World, WebXR! in A-Frame">
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-environment-component@1.1.0/dist/aframe-environment-component.min.js"></script></head>
<body>
<a-scene background="color: #FAFAFA">
<a-box position="-1 0.66921 -3" rotation="0 45 0" color="#4CC3D9" shadow="" material="" geometry=""></a-box>
<a-sphere position="0 1.44508 -5" radius="1.25" color="#EF2D5E" shadow="" material="" geometry=""></a-sphere>
<a-cylinder position="1 0.8993 -3" radius="0.5" height="1.5" color="#FFC65D" shadow="" material="" geometry=""></a-cylinder>
<a-plane position="0 0.08958 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow="" material="" geometry=""></a-plane>
<a-entity environment="preset: forest; dressing: mushrooms; dressingColor: #6e1d8b;"></a-entity></a-scene>
</body>
</html>

Not bad really, pretty tight code for everything we get! That’s A-Frame for you. Now let’s take a look at the documentation on shadowing. It can be found in the A-Frame master documentation here:

See if you can figure out how to do it? Here is what I got:

Image for post
Image for post

Wow, look at that! I got shadows on the plane and on the sphere by adding <a-entity light=…> to the scene and casting and receiving shadows on the <a-plane> entity. Here is the code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World A-Frame</title>
<meta name="description" content="Hello World, WebXR! in A-Frame">
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-environment-component@1.1.0/dist/aframe-environment-component.min.js"></script></head>
<body>
<a-scene background="color: #FAFAFA">
<a-box position="-1 0.66921 -3" rotation="0 45 0" color="#4CC3D9" shadow="" material="" geometry=""></a-box>
<a-sphere position="0 1.44508 -5" radius="1.25" color="#EF2D5E" shadow="" material="" geometry=""></a-sphere>
<a-cylinder position="1 0.8993 -3" radius="0.5" height="1.5" color="#FFC65D" shadow="" material="" geometry=""></a-cylinder>
<a-plane position="0 0.08958 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow="recieve: true" material="" geometry=""></a-plane>
<a-entity environment="preset: forest; dressing: mushrooms; dressingColor: #6e1d8b;"></a-entity><a-entity light="type:directional; castShadow:true;" position="1 1 1"></a-entity></a-scene>
</body>
</html>

If you wanted to change the directional casting of the shadows, you would just change the position of the light inside of the Inspector. Easy really given what you already know. I’ll leave mine unchanged for now. We have to get on to what I promised. Being able to move around in VR. This next stuff should require a VR Headset. This is where you lose most people, because they just don’t have the hardware or want to purchase it.

Time for a plug: you can find out more on my VR Blog at: https://rocketvirtual.com

Now moving around. That can be done multiple ways. The trick here is to do it in such a way that multiple vendor VR headsets and controllers all work in multiple browser versions. That can be a really big challenge! With all the new VR headset gear coming out, changes to the browser specs and changes to your code base, it’s sort of like trying to hit multiple moving targets with one single arrow! Therefore, it’s not so amazing that code breaks over time, until things settle down, if they ever do. Ok, I’ll stop complaining now.

Before we begin, everything should look “something” like this link:

Also, you should be aware of inspect in the browser console:

Image for post
Image for post
Inspect in the browser Console (Shown here in Chrome)

On a PC you right mouse button click and select down to inspect. Now select the tab labeled Console. As you can see above you get the A-Frame version, the Three.js version and other information which can be useful in debugging. I won’t go into detail about that here, but I wanted you to be aware of this in case in the future you run into bugs. Everyone eventually will. Now close the inspect with the X and let’s move on.

Image for post
Image for post
Move with thumbstick or touchpad and teleport with left controller trigger button

Moving around within VR can be done multiple ways. The way I choose is via the thumb stick and teleportation with the following code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Advanced Hello World A-Frame</title>
<meta name="description" content="Advanced Hello World, WebXR! in A-Frame">
<!-- *** CHANGE THESE TO COMPONENTS ON YOUR SERVER *** -->
<script src="aframe-master/dist/aframe-v1.0.4.min.js"></script>
<script src="aframe-environment-component-master/dist/aframe-environment-component.min.js"></script>
<script src="aframe-extras-master/dist/aframe-extras.min.js"></script>
<script src="aframe-teleport-controls-master/dist/aframe-teleport-controls.js"></script>
<script src="superframe-master/components/thumb-controls/dist/aframe-thumb-controls-component.min.js"></script>
</head>
<body>
<a-scene background="color: #FAFAFA">
<!-- Basic movement and teleportation -->
<a-entity id="cameraRig" movement-controls="constrainToNavMesh: true;" navigator="cameraRig: #cameraRig; cameraHead: #head; collisionEntities: .collision; ignoreEntities: .clickable" position="0 0 0" rotation="0 0 0">
<!-- camera -->
<a-entity id="head" camera="active: true" position="0 1.6 0" look-controls="pointerLockEnabled: true; reverseMouseDrag: true" ></a-entity>
<!-- Left Controller -->
<a-entity class="leftController" hand-controls="hand: left; handModelStyle: lowPoly; color: #15ACCF" tracked-controls vive-controls="hand: left" oculus-touch-controls="hand: left" windows-motion-controls="hand: left" teleport-controls="cameraRig: #cameraRig; teleportOrigin: #head; button: trigger; curveShootingSpeed: 18; landingMaxAngle: 60" visible="true"></a-entity>
<!-- Right Controller -->
<a-entity class="rightController" hand-controls="hand: right; handModelStyle: lowPoly; color: #15ACCF" tracked-controls vive-controls="hand: right" oculus-touch-controls="hand: right" windows-motion-controls="hand: right" laser-controls raycaster="showLine: true; far: 10; interval: 0; objects: .clickable, a-link;" line="color: lawngreen; opacity: 0.5" visible="true"></a-entity>
</a-entity>
<a-box position="-1 0.66921 -3" rotation="0 45 0" color="#4CC3D9" shadow="" material="" geometry=""></a-box>
<a-sphere position="0 1.44508 -5" radius="1.25" color="#EF2D5E" shadow="" material="" geometry=""></a-sphere>
<a-cylinder position="1 0.8993 -3" radius="0.5" height="1.5" color="#FFC65D" shadow="" material="" geometry=""></a-cylinder>
<a-plane position="0 0.08958 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow="recieve: true" material="" geometry=""></a-plane>
<a-entity environment="preset: forest; dressing: mushrooms; dressingColor: #6e1d8b;"></a-entity><a-entity light="type:directional; castShadow:true;" position="1 1 1"></a-entity></a-scene>
</body>
</html>

Here is a working example using just such code:

You may have notice I changed the A-Frame components to those stored on my server in the <script scr= . . . > lines. This is because A-Frame is developing further as I write this article and I wanted to make sure I showed you a working copy. I’m sorry but you must change those for yourself now to the latest code based. Here is a list of used framework components and where they can be found (copy these to your server and reference them directly):

Image for post
Image for post
My VR Blog at https://rocketvirtual.com

So how do I get this code to a web server? The basic principles are, simply FTP, and there is nothing secret here.

The alternative to this approach is to use Node.js which is outside the scope of this article, but you can find out how here. Ultimately you’ll probably want your own server to host your VR code. Then you’ll be able to do cool things like have a magic window.

Now again, If you’d like to see some more of my latest examples, check me out at my VR Blog and please subscribe to my newsletter for updates.

UPDATE: If you are just starting out, here are follow up articles I posted on Medium about browser VR with A-Frame. They should give you the basics.

Advanced Hello World for A-Frame

A Parade Of Planets In VR

Written by

Founder, VR coder, Sci-Fi Blogger with ideas for human technological-evolution.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store