Design for virtual reality

November 19, 2015

2016 will be the year of virtual reality. Oculus is coming, Lands End launched on Samsung Gear VR and Google is ramping up Cardboard. But how do we design these new experiences? We simply prototype them in Framer.


My background in architecture at the Delft University of Technology spiked my interest into VR. The architectural design process involves a lot of drawing, maquette making and model rendering. And it takes heavy spatial imagination to translate something from the screen to the real world. VR can narrow this spatial gap dramatically, so I started experimenting.

Those experiments resulted in VRComponent – and it makes designing for VR easy and accessible. Get started with the template below.

Download Template


VRComponent gives you a lot of behaviour for free and it works with modern mobile devices. It uses the device orientation (or mouse input) to manipulate the orientation of the environment, which you can set up with a simple cubemap. By default, it animates beautifully with momentum and spring physics. You don't have to be a 3D expert to get started, but some familiarity with Framer is helpful.

Framer is not a full 3D engine so there are limitations to what you can do with VRComponent. This post takes you through the setup and the following concepts to design your VR experience:

  1. Create a panoramic environment
  2. Project layers over the environment
  3. Animate projected layers
  4. Line of sight
  5. Shifting the environment
  6. Interacting with layers

Create a panoramic environment

There are multiple ways of rendering a panoramic view. VRComponent uses a cubemap to project the environment on the sides of a cube. The user is positioned in the center, while the orientation of the cube is fixed. Simply instantiate VRComponent and a textureless cube pops up.

{VRComponentVRLayer} = require "VRComponent"
vr = new VRComponent


By specifying images for all six sides, the cube seems to be replaced by the new environment.

vr = new VRComponent
    front:  "images/front.png"
    left:   "images/left.png"
    right:  "images/right.png"
    back:   "images/back.png"
    top:    "images/top.png"
    bottom: "images/bottom.png"


To map your environment, you can look for cubemap images online. The images from the examples have been made by Emil Persson.

In a virtual environment, each side is often named by the positive or negative X, Y, or Z axis:

  • right — positive-x
  • top — positive-y
  • front — positive-z
  • left — negative-x
  • bottom — negative-y
  • back — negative-z

If you want to learn how to make your own cubemaps, I recommend reading this article by Paul Lewis. Feel free to send a pull request to include yours.

Project layers over the environment

Layers in Framer are positioned with x and y values, following the Cartesian coordinate system. Everything is measured relatively to the "start" of the canvas, which simply means top-left in Framer. Obviously, virtual reality has no top-left, so we'll need a different coordinate system.

An alternative to the Cartesian system is the Spherical coordinate system. Here, each position is described in space around a central origin.

heading has a polar angle from 0° to 360° where north is 0°
elevation has a zenith angle from -90° to 90° where horizon is 0°
distance defined in pixels

The distance defaults to 1200, equal to perspective. When distance and perspective are equal, layers retain the same size they had before projecting.

layer = new VRLayer
    heading: 230
    elevation: 10

To simplify setting the coordinates of layers, aim VRComponent at the latest projected layer with this property:

vr.lookAtLatestProjectedLayer = true

Animate projected layers

Changes to the heading and elevation of projected layers, can be animated like any other numerical property.

layer = new VRLayer
        heading: -30
        elevation: 5

When a layer is projected with a heading of 0°, animating to -30° will animate the layer to the left. Animating to 330° animates it to the right.

layer = new VRLayer
    heading: -30
print layer.heading
# returns 330 

Line of sight

To understand the direction the user is facing, imagine a vector (a line pointing in a direction) sticking out of the back of your mobile device.

VRComponent contains all information about the heading and elevation of this vector, as well as the tilt around its axis (from -180° to 180°). You can listen for orientation changes using OrientationDidChange event.

# direct access through property 
heading = vr.heading
# continues updates 
vr.on Events.OrientationDidChange(data) ->
    heading =   data.heading
    elevation = data.elevation
    tilt =      data.tilt

The heading and elevation values are important to define what the user is looking at, and what part of the UI needs focus. Meanwhile, the tilt value can be used to keep layers aligned with the viewer.


Shifting the environment

You can overwrite the direction the user is facing, by changing the heading and elevation values of VRComponent. Changing these values rotates the horizon around the user. On desktop this can be used to create beautiful cinematic transitions.

# instant change 
vr.heading = 180
# animated change 
        heading: 90

On mobile, you can temporarily override the elevation using an animation. When the animation is done, the horizon snaps back to the value from the gyroscope. Keep in mind that animating the elevation, shifts the horizon to an unnatural position, and this can be disorienting for the user.

Interacting with layers

Detecting clicks and taps is similar to what you already know. Keep in mind that layers are projected at a certain distance, so the actual size might be smaller than you'd expect. Make sure the hit areas are large enough.

The orientation layer on desktop blocks all interaction with the layers underneath. If this is a problem, you can disable the orientation layer. With the orientation layer disabled, you can still look around using your arrow keys.

vr.orientationLayer = false

Instead of using taps or clicks, you can experiment with alternative interaction patterns for VR. Here's a fun puzzle I made to explore a new VR interaction: look and stare to select. It works beautifully on iPhone.



I hope this post got you excited about designing for VR! If you missed it at the beginning, here's VRComponent on GitHub. Over time you can expect more features, like stereoscopic VR to present different images to the left and right eye. Pull requests, issues or nice cubemaps are greatly appreciated.

If you have questions about VR, explorations or prototypes - please post them to our Facebook community. I'm excited to see what you dream up!