Building a Simple Web VR UI with A-frame

paul christophe
Neon Daylight
Published in
3 min readApr 24, 2016

--

A-frame is a wrapper for three.js that makes it easy to to create cross-platform Web VR experiences. If you haven’t already, take a look at the A-frame’s examples to get a feel for how it works and what it can do.

In this post, I’m going to show you how to create a VR experience that uses your gaze to toggle between two 360° image scenes. To create this effect we’ll use some A-frame specific markup and a tiny bit of javascript.

Let’s start with a basic HTML5 skeleton with a link to the current version of A-frame.

<script src=”https://rawgit.com/aframevr/aframe/b813db0614ac2b518e547105e810b5b6eccfe1c8/dist/aframe.min.js"></script>

I’ve also set up a codepen example aframe.

With the boilerplate in place, let’s start creating our VR scene by adding an <a-scene> element. This is the root element of an A-frame project and can contain shapes, cameras, images, videos, and any other manner of component for the VR scene. We’ll start with a simple red sphere:

<a-scene>
<a-sphere color="#F44336" radius="1" position="0 2 0"></a-sphere>
</a-scene>

Take a look in a browser or on your phone, you’ve got a VR scene!

Next, let’s add a camera and cursor so that we can “click” on the spheres when we gaze at them. Setting ‘fuse’ to true lets A-frame know to bind the camera hover to the click event which we’ll be using later. The timeout is how long in milliseconds to wait until the hover triggers the event.

<a-scene>
<a-camera position="0 2 4">
<a-cursor color="#4CC3D9" fuse="true" timeout="10"></a-cursor>
</a-camera>


...
</a-scene>

A-frame has a concept of “components”, which are a way to extend custom functionality to VR elements via Javascript. With the bones of the scene in place, the next step is to write a component which will handle the switching of the 360° image when a gaze event takes place. Here is a version that logs to the console on a gaze:

<script>
AFRAME.registerComponent('set-sky', {
schema: {default: ''},
init() {
this.el.addEventListener('click', () => {
console.log(this.data);
});
}
});
</script>

The first parameter to “registerComponent” is a name for the component and the second is an object that contains the functionality. For our purposes we’ll only need to hook into the schema object and the “init” method, but there are several more you can explore in the A-frame documentation. The code above binds to the “click” event and logs the components “data” to the console. Setting the default key in schema indicates that if no value is passed to the component it will set ‘this.data’ to an empty string.

To attach a component’s functionality to an A-frame item, add it as an attribute. We’ll add the “set-sky” component to the sphere we created earlier and assign it the data “hello”:

<a-sphere set-sky="hello" color="#F44336" radius="1" position="0 2 0"></a-sphere>

Gaze at the sphere and checkout the console!

To set a 360° image as the overall VR environment, we use an A-frame element called <a-sky>. This elements acts as a giant sphere encompassing the scene with an image applied as its material. For now just place one in the scene, we’ll add an image to it later:

<a-sky></a-sky>

Next let’s place another navigation sphere into the scene and add distinct images as the “data” on our set-sky components. <a-sky> elements require equirectangular projection images to look correct, so I’ve found two on Flickr that we’ll use in this demo:

<a-sphere color=”#F44336" radius=”1" position=”-4 2 0" set-sky="https://c3.staticflickr.com/2/1475/26239222850_cabde81c39_k.jpg"></a-sphere><a-sphere color=”#FFEB3B” radius=”1" position=”4 2 0" set-sky="https://c2.staticflickr.com/2/1688/25044226823_53c979f8a1_k.jpg"></a-sphere>

The final step is to modify our “set-sky” component so that it sets the <a-sky>’s source on gaze using the image urls we’ve passed in as data:

AFRAME.registerComponent('set-sky', {
schema: {default: ''},
init() {
const sky = document.querySelector('a-sky');

this.el.addEventListener('click', () => {
sky.setAttribute('src', this.data);
});
}
});

That’s it! We have a fully operational VR scene with two different surroundings and gaze navigation to get between them. If yours isn’t working, check it against this codepen or gist.

--

--