React VR app example of web-based applications How much does it cost to create sample React VR app

How much does it cost to create sample React VR app


React VR framework to create web based virtual reality apps – what a staggering initiative! In December last year Oculus announced the pre-release profiting from React Native technology. It means new and simpler opportunities both in making and viewing VR experiences. Hence the next question emerges: how much does it cost to create VR web apps and how to do a sample React VR app.

In this article our dev team is going to showcase the possibilities of React VR Oculus. We’ll make a simple React VR example, a 360-degree virtual reality tour to view in a web browser. With this technology you can even try out virtual reality without a VR headset, which is awesome.

To begin with, let us show you the project we did with React VR, and then elaborate on the process. This is how the final React VR sample of virtual reality experience will look like in your browser.

React VR sample gif

But first things first. What is React VR?

What is React VR?

React VR is a JavaScript library (framework) that has been developed by Oculus with the aim of creating web-based virtual reality applications. It is a part of bigger React entity. React is a JavaScript library (framework) by Facebook for building interactive UIs for web and mobile environments. React Native is used to build mobile apps on JS, specifically.

According to Oculus, React JS VR projects are going to run on the VR web browser under the name Carmel. The pre-packed release of React VR app is available for download with the source code on Github for preview so that anyone could give feedback.

Thus, it is a great tool for any web developer and/or VR developer. Why? Because of ability to start making VR web apps even without a VR headset in possession.

What is WebVR?

WebVR, the experimental API that makes it easier to create VR experiences for web. Some call it a VR web browser – in a way that anyone could try virtual reality directly in a browser. And yet, no need for VR devices like Google Cardboard, Oculus Rift or HTC Vive.

It is similar to 360-videos like you’ve seen on YouTube. But most noteworthy you can navigate through it in as well. WebVR also works in pairing with React VR library and Carmel VR browser.

Our demo project

Here we will be creating a small VR web application – a React VR example of virtual reality tours in 360-degree view and navigation. We’ll use React VR sample of panoramic images by Oculus, which would look something like this in your browser:

React VR sample image

There will be few locations, like restaurants and coffee shops for users to see in all-round view. We will also add rotation and buttons (arrows) to point out possible directions to enter other locations. As a result, it is going to serve as short and plain demonstration of how React VR works and its possibilities.

We’ll go in step by step mode, showing code samples of our React VR project. In the end you’ll also find our team’s estimate for how much does it cost to create VR web apps with React VR. The final version of our VR tour for web browsers will consist of 5 locations, much as these:

how to make VR web apps with React VR

Technical requirements

To create a React VR app one has to have Node.js installed first of all. This JavaScript environment powers code compiling and running a local server. One most probably also needs NPM, a package manager by Node.js with lots of libraries and reusable code. Same, Three.js as possible additional 3D library.

With WebVR and WebGL APIs we can already render 3D imagery within a web browser. Since you do not need any special VR devices or headsets to build a React VR app, just basic stuff is enough. What you actually do need along React VR for making web apps is:

  • A PC/laptop on Windows
  • A compatible browser
  • A latest Node.js version
  • A VR headset (optional)

What are the compatible VR web browsers?

React VR framework is usually layered this way: React VR > React runtime > OVRUI > Three.js > WebVR and browser. OVRUI by the way, is a library helping with geometrical types and objects to build user interfaces for VR web apps.

React VR project setup

To make VR web apps as our React VR example first we have to do a short setup with tools provided by Oculus. To start, we install the React VR CLI tool using NPM:

npm install -g react-vr-cli

With it we create a new directory for web application and name it TMExample for our React VR app project:

react-vr init TMExample

This may take some time, so do not worry. Then we place cd into our directory:

cd TMExample 

To check if it’s working, we test a local server with:

npm start

After all of this is done, open the following URL in your web browser: http://localhost:8081/vr. Clearly, give it few moments to initialize the application, and you should see the animated VR environment like this:

React VR initial setup

Now you good to go with building your own web based virtual reality apps with React VR. Let’s explain how we built our simple VR tour app.

Creating a VR tour for web

The structure of our app’s directory is as follows:


The code of a web app would be in the index.vr.js file, while the static_assets directory hosts external resources (images, 3D models). In addition, you can learn more on how to get started with React VR project. Now, the index.vr.js file contains the following:

import React from 'react';
import {
from 'react-vr';
class TMExample  extends React.Component {
     render() {
          return (
          <Pano source={asset('chess-world.jpg')}/>
                    padding: 0.02,
                    fontSize: 0.8,
                    layoutOrigin: [0.5, 0.5],
                    transform: [{translate: [0, 0, -3]}],
AppRegistry.registerComponent('TMExample', () => TMExample);

VR components in use

We use React Native packager for code pre-processing, compilation, bundling and asset loading. In render function there are view, pano and text components. Each of these React VR components comes with a style attribute to help control the layout.

To wrap it up finally, check that the root component gets registered with AppRegistry.registerComponent. It bundles the application and also readies it to run. Next step to highlight in our React VR app project is compiling 2 main files.

Index.vr.js file

In constructor we’ve indicated the data for VR tour app. These are scene images, buttons to switch between scenes with X-Y-Z coordinates, values for animations. All the images we contain in static_assets folder.

constructor (props) {
    this.state =  {
      scenes: [{scene_image: 'initial.jpg', step: 1, navigations: [{step:2, translate: [0.73,-0.15,0.66], rotation: [0,36,0] }] },
               {scene_image: 'step1.jpg', step: 2, navigations: [{step:3, translate: [-0.43,-0.01,0.9], rotation: [0,140,0] }]},
               {scene_image: 'step2.jpg', step: 3, navigations: [{step:4, translate: [-0.4,0.05,-0.9], rotation: [0,0,0] }]},
               {scene_image: 'step3.jpg', step: 4, navigations: [{step:5, translate: [-0.55,-0.03,-0.8], rotation: [0,32,0] }]},
               {scene_image: 'step4.jpg', step: 5, navigations: [{step:1, translate: [0.2,-0.03,-1], rotation: [0,20,0] }]}],
      animationWidth: 0.05,
      animationRadius: 50

Then we’ve changed the output of images linking them to state, previously indicated in constructor.

    <Pano source={asset(this.state.current_scene['scene_image'])}
         transform: [{translate: [0, 0, 0]}] 

Navigational buttons

In each scene we’ve placed transition buttons for navigation within a tour, taking data from state. Subscribing to onInput event to convey switching between scenes, binding this to it as well.

        <Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
          onLoad={this.sceneOnLoad} onLoadEnd={this.sceneOnLoadEnd}
          style={{ transform: [{translate: [0, 0, 0]}] }}/>
              return  <Mesh  key={i}
                                layoutOrigin: [0.5, 0.5],
                                transform: [{translate: item['translate']},
                                            {rotateX: item['rotation'][0]},
                                            {rotateY: item['rotation'][1]},
                                            {rotateZ: item['rotation'][2]}]
                      onInput={ e => that.onNavigationClick(item,e)}>
                                     style={{ width: 0.15,
                                            borderRadius: 50,
                                            justifyContent: 'center',
                                            alignItems: 'center',
                                            borderStyle: 'solid',
                                            borderColor: '#FFFFFF80',
                                            borderWidth: 0.01
                                            style={{ width: that.state.animationWidth,
                                                   borderRadius: that.state.animationRadius,
                                                   backgroundColor: '#FFFFFFD9'
     if(e.nativeEvent.inputEvent.eventType === "mousedown" && e.nativeEvent.inputEvent.button === 0){
          var new_scene = this.state.scenes.find(i => i['step'] === item.step);
          this.setState({current_scene: new_scene});
          postMessage({ type: "sceneChanged"})
    postMessage({ type: "sceneLoadStart"})

    postMessage({ type: "sceneLoadEnd"})
this.sceneOnLoad = this.sceneOnLoad.bind(this);
this.sceneOnLoadEnd = this.sceneOnLoadEnd.bind(this);
this.onNavigationClick = this.onNavigationClick.bind(this);

Button animation

Below, we’ll display the code for navigation button animations. We’ve built animations on button increase principle, applying conventional requestAnimationFrame.

this.animatePointer = this.animatePointer.bind(this);
    var delta = this.state.animationWidth + 0.002;
    var radius = this.state.animationRadius + 10;
    if(delta >= 0.13){
        delta = 0.05;
        radius = 50;
    this.setState({animationWidth: delta, animationRadius: radius})
    this.frameHandle = requestAnimationFrame(this.animatePointer);


    if (this.frameHandle) {
        this.frameHandle = null;

In componentWillMount function we’ve indicated the current scene. Then we’ve also subscribed to message event for data exchange with the main thread. We do it this way due to a need to work out a React VR component in a separate thread.

In onMainWindowMessage function we only process one message with newCoordinates key. We’ll elaborate later why we do so. Similarly, we’ve subscribed to onInput event to convey arrow turns.

     window.addEventListener('message', this.onMainWindowMessage);
     this.setState({current_scene: this.state.scenes[0]})
     switch ( {
          case 'newCoordinates':
               var scene_navigation = this.state.current_scene.navigations[0];
               this.state.current_scene.navigations[0]['translate'] = [,,]
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
         style={{ transform: [{translate: [0, 0, 0]}] }}/>
     switch (nativeEvent.keyCode) {
           case 38:
                 this.state.current_scene.navigations[0]['rotation'][1] += 4;
           case 39:
                 this.state.current_scene.navigations[0]['rotation'][0] += 4;
           case 40:
                 this.state.current_scene.navigations[0]['rotation'][2] += 4;

Arrow turns are done with ↑→↓ alt keys, for Y-X-Z axes respectively.

Furthermore, see and download the whole index.vr.js file as part of our React VR example.

Client.js file

Moving further into our React VR example of virtual reality web applications, we’ve added the code below into init function. The goal is processing of ondblclick, onmousewheel and message events, where the latter is in rendering thread for message exchanges. Also, we’ve kept a link to vr and vr.player._camera objects.

window.playerCamera = vr.player._camera;
window.vr = vr;
window.ondblclick= onRendererDoubleClick;
window.onmousewheel = onRendererMouseWheel;
vr.rootView.context.worker.addEventListener('message', onVRMessage);

We’ve introduced the onVRMessage function for zoom returning to default when scenes change. Also, we have added the loader when scene change occurs.

function onVRMessage(e) {
     switch ( {
          case 'sceneChanged':
               if (window.playerCamera.zoom != 1) {
                    window.playerCamera.zoom = 1;
          case 'sceneLoadStart':
             document.getElementById('loader').style.display = 'block';
          case 'sceneLoadEnd':
             document.getElementById('loader').style.display = 'none';

onRendererDoubleClick function for 3D-coordinates calculation and sending messages to vr component to change arrow coordinates. The get3DPoint function is custom to our web VR application and looks like this:

function onRendererDoubleClick(){
    var x  = 2 * (event.x / window.innerWidth) - 1;
    var y = 1 - 2 * ( event.y / window.innerHeight );
    var coordinates = get3DPoint(window.playerCamera, x, y);
    vr.rootView.context.worker.postMessage({ type: "newCoordinates", coordinates: coordinates });

Switch to mouse wheel

We’ve used the onRendererMouseWheel function for switching zoom to a mouse wheel.

function onRendererMouseWheel(){
     if (event.deltaY > 0 ){
          if(window.playerCamera.zoom  > 1) {
               window.playerCamera.zoom -= 0.1;
     else {
          if(window.playerCamera.zoom < 3) {
               window.playerCamera.zoom += 0.1;

Exporting coordinates

Then we’ve utilized Three.js to work with 3D-graphics. In this file we’ve rather conveyed one function to export screen coordinated to world coordinates.

import * as THREE from 'three';
export function get3DPoint(camera,x,y){
    var mousePosition = new THREE.Vector3(x, y, 0.5);
    var dir = mousePosition.sub(camera.position).normalize();
    return dir;

Check and download the whole client.js file on Github demo. There’s probably no need to explain how the cameraHelper.js file works, as it is plain simple, and you can download it as our ReactVR demo as well.

And this is it, this is how we’ve created our short VR tour using React VR framework. The source code of this whole project is available for download at our demo React VR GitHub.

The result: VR Tour demo

So here is our React VR app result we’ve been showing you how to build.

Also, bear in mind, that this was the demonstration of general possibilities of React VR. It has already made VR web apps possible thanks to Facebook efforts, and with official full release of React VR there will be more.

The cost of making a React VR app

Obviously, calculating the cost to make web-based virtual reality applications using React VR can not be precise. It is a grey(ish) area at this point in time. This React VR framework by Oculus is still pending for official release and is expected to be enhanced considerably yet. And yet, as we’ve shown in our VR tour demo, making VR web apps is already possible.

And we’ve only used official free samples from React VR library. To build your own project you would have to install a local server and CMS, as well as create 360-degree images and three-dimensional objects. The cost estimate for such VR web app here at ThinkMobiles we imply a $40 hourly rate.

Task # of hours Cost, USD
React VR setup 10 400
Images, 3D objects creation 10 400
VR Development 30 1.200
CMS setup 20 800
Backend 30 1.200
Total 100 4.000

VR web app development: $4.000 – $10.000, 1-3 weeks.

In conclusion

Note, that cost of any custom React VR app for web would depend on the amount of 3D-imagery and backend buildup. On our side, 1 developer was engaged in this task. And yet, it took about one week to create this VR tour from zero.

The principal challenge of our React VR app was data exchange between the main and virtual reality component thread. We’ve actually put together 5 locations to view and switch between for this short web VR tour.

Finally, you can view our VR tour in full, and read more of our related articles about:

Discover new horizons with our AR & VR articles

  • E-books about AR & VR apps developing
  • Our newest articles