VR web apps can be built with React VR apps. WebVR is an experimental API enabling the creation and viewing of VR experiences in your browser. This new technology enables you to grant access to virtual reality regardless of the devices at hand.

The only thing you need to make a React VR app is a headset and a compatible browser. If you are just viewing a web VR application then you don’t need even for a headset.

React VR is a great framework to build VR websites or apps on JavaScript. It utilizes the same design as React Native and lets you make virtual reality tours and under interfaces with the provided components.

vr-app

How to make a VR app

Technical Requirements

Before getting started with React VR, You required a proper setup for the dependencies that will be used to build and manage a React VR app. These are Node.js and the React VR CLI.

You need to install Node.js, ensure that the latest version is used. If not, do the following:

  • MacOS: Install Node.js using Homebrew
  • Windows: Install it from the nodejs.org
  • Linux: Use sudo apt-get install nodejs command

Then you have to install the React VR CLI using npm:

npm install -g react-vr-cli.

Getting Started

Navigate to the directory where you wish to create a new project and run the react-vr init MyFirstReactVR command.

Change the directory name to something like MyFirstReactVR and run npm start .

Click and try to drag your cursor around. Also, in browsers that support WebVR, you’ll be able to explore this VR environment with a headset in full virtual reality mode.

How to develop VR apps

Now let’s make a VR tour with a few scenes and navigations in them. First of all, you need to prepare the architecture. In this example, we will make buttons within each scene for navigations and declare this in the constructor of a React component named index.js.vr:

constructor(props) {
    super(props);
    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]
        }]
    }]
}

Also, declare current_scene in the state in the constructor:

constructor(props) {
        this.state = {
            ...
            current_scene: {}
                ...
        }

For rendering, change the render() method, as seen below:

render() {
    return ( < View >
        < Pano source = {
            asset(this.state.current_scene['scene_image'])
        }
        style = {
            {
                transform: [{
                    translate: [0, 0, 0]
                }]
            }
        }
        /> {
            this.state.current_scene['navigations'].map(function(item, i) {
                return <Mesh key = {
                    i
                }
                style = {
                        {
                            layoutOrigin: [0.5, 0.5],
                            transform: [{
                                translate: item['translate']
                            }, {
                                rotateX: item['rotation'][0]
                            }, {
                                rotateY: item['rotation'][1]
                            }, {
                                rotateZ: item['rotation'][2]
                            }]
                        }
                    } >
                    < VrButton
                style = {
                        {
                            width: 0.15,
                            height: 0.15,
                            borderRadius: 50,
                            backgroundColor: 'blue'
                        }
                    } >
                    < /VrButton> < /Mesh>
            })
        } < /View>
    )
}

The last step to make this work is to set the current_scene state to the first element of the scenes array componentWillMount function:

componentWillMount() {
    this.setState({
        current_scene: this.state.scenes[0]
    });
}

The result should be like this on screen:

Read More:   Can IoT-enabled smart factories and smart manufacturing make a difference? 2022

Now add a simple animation for the button and implement the logic to navigate between scenes. First of all, for navigation, you need to subscribe to the onInput event for our Mesh element, bind this function to this in constructor, and implement it:

...
constructor(props) {
    ...
    this.onNavigationClick = this.onNavigationClick.bind(this);
    ...
}
...
onNavigationClick(item, e) {
        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
            });
        }
    }
    ...
render() {
    var that = this;
    ... < Mesh key = {
            i
        }
        ...
    onInput = {
            e => that.onNavigationClick(item, e)
        }
        .... >
        ...
}

Then added a simple animation try it out. For this, you have added one more button inside the existing one in the render method and changed the size of it. Use native JS requestAnimationFrame function:

const DEFAULT_ANIMATION_BUTTON_RADIUS = 50;
const DEFAULT_ANIMATION_BUTTON_SIZE = 0.05;
constructor(props) {
        ...
        this.state = {
                ...
                animationWidth: DEFAULT_ANIMATION_BUTTON_SIZE,
                    animationRadius: DEFAULT_ANIMATION_BUTTON_RADIUS
                    ...
            }
            ...
        this.animatePointer = this.animatePointer.bind(this);
    }
    ...
componentWillUnmount() {
    if (this.frameHandle) {
        cancelAnimationFrame(this.frameHandle);
        this.frameHandle = null;
    }
}
componentDidMount() {
    this.animatePointer();
}
animatePointer() {
        var delta = this.state.animationWidth + 0.002;
        var radius = this.state.animationRadius + 10;
        if (delta >= 0.13) {
            delta = DEFAULT_ANIMATION_BUTTON_SIZE;
            radius = DEFAULT_ANIMATION_BUTTON_RADIUS;
        }
        this.setState({
            animationWidth: delta,
            animationRadius: radius
        })
        this.frameHandle = requestAnimationFrame(this.animatePointer);
    }
    ...
render() {
    ... < VrButton
    style = {
            {
                width: 0.15,
                height: 0.15,
                borderRadius: 50,
                justifyContent: 'center',
                alignItems: 'center',
                borderStyle: 'solid',
                borderColor: '#FFFFFF80',
                borderWidth: 0.01
            }
        } >
        < VrButton
    style = {
            {
                width: that.state.animationWidth,
                height: that.state.animationWidth,
                borderRadius: that.state.animationRadius,
                backgroundColor: '#FFFFFFD9'
            }
        } >
        < /VrButton> < /VrButton>
        ...
}

Now let’s implement manipulations with the animated button and its rotation. It will rotate the button on an X-Y-Z axis. To do so, you need to subscribe to the onInput event for the Pano component and change the rotation via arrow-up, arrow-right, and arrow-down buttons.

The last thing is to implement messaging of the VR thread and Main thread to exchange data. Below is the subscription code on receiving messages and posting a message when a scene changes or an image starts/ends loading.

componentWillMount() {
      window.addEventListener('message', this.onMainWindowMessage);
      ...
  }
  onMainWindowMessage(e) {
      switch (e.data.type) {
          case 'newCoordinates':
              var scene_navigation = this.state.current_scene.navigations[0];
              this.state.current_scene.navigations[0]['translate'] = [e.data.coordinates.x, e.data.coordinates.y, e.data.coordinates.z]
              this.forceUpdate();
              break;
          default:
              return;
      }
  }
  onNavigationClick(item, e) {
      ...
      postMessage({
          type: "sceneChanged"
      })
      this.state.animationWidth = DEFAULT_ANIMATION_BUTTON_SIZE;
      this.state.animationRadius = DEFAULT_ANIMATION_BUTTON_RADIUS;
      this.animatePointer();
      ...
  }
  sceneOnLoad() {
      postMessage({
          type: "sceneLoadStart"
      })
  }
  sceneOnLoadEnd() {
      postMessage({
          type: "sceneLoadEnd"
      })
  }
  render() {
      ... < Pano...
      onLoad = {
          this.sceneOnLoad
      }
      onLoadEnd = {
              this.sceneOnLoadEnd
          }
          ... / >
  }

In client.js, implement a zoom with the mouse wheel and a position change with a double-click. you need to store the VR instance and VRcamera instance to implement the logic above.

function init(bundle, parent, options) {
    const vr = new VRInstance(bundle, 'TMExample', parent, {
        // Add custom options here
        ...options,
    });
    vr.render = function() {
        // Any custom behavior you want to perform on each frame goes here
    };
    // Begin the animation loop
    vr.start();
    window.playerCamera = vr.player._camera;
    window.vr = vr;
    return vr;

Then subscribe to ondblclick and onmousewheel and implement the zoom and change position logic.

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
      });
  }
  function onRendererMouseWheel() {
      if (event.deltaY > 0) {
          if (window.playerCamera.zoom > 1) {
              window.playerCamera.zoom -= 0.1;
              window.playerCamera.updateProjectionMatrix();
          }
      } else {
          if (window.playerCamera.zoom < 3) {
              window.playerCamera.zoom += 0.1;
              window.playerCamera.updateProjectionMatrix();
          }
      }
  }

get3DPoint is your custom function to transform screen coordinates to world coordinates using Three.js, implemented in cameraHelper.js.

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

Sometimes, loading scene images takes time. thus, you have implemented the loader to show this process. In index.html, add a loader and CSS based on this w3cschool example.

<style>
    body { margin: 0; }
    #loader {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 1;
    width: 150px;
    height: 150px;
    margin: -75px 0 0 -75px;
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid #3498db;
    width: 120px;
    height: 120px;
    -webkit-animation: spin 2s linear infinite;
    animation: spin 2s linear infinite;
    }
    @-webkit-keyframes spin {
    0% { -webkit-transform: rotate(0deg); }
    100% { -webkit-transform: rotate(360deg); }
    }
    @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
    }
    .animate-bottom {
    position: relative;
    -webkit-animation-name: animatebottom;
    -webkit-animation-duration: 1s;
    animation-name: animatebottom;
    animation-duration: 1s
    }
    @-webkit-keyframes animatebottom {
    from { bottom:-100px; opacity:0 }
    to { bottom:0px; opacity:1 }
    }
    @keyframes animatebottom {
    from{ bottom:-100px; opacity:0 }
    to{ bottom:0; opacity:1 }
    }
    #myDiv {
    display: none;
    text-align: center;
    }
</style>
<body>
    <div id='content' style="width:100%; height:100%">
        <div id="loader"></div>
    </div>
    <script src="https://codersera.com/blog/how-to-make-react-vr-apps-2/./client.bundle?platform=vr"></script>
    <script>
        ReactVR.init('../index.vr.bundle?platform=vr&dev=true', document.getElementById('content'));
    </script>
</body>

And don’t forget message in client.js from the VR thread to enable/disable animation:

function init(bundle, parent, options) {
    ...
    vr.rootView.context.worker.addEventListener('message', onVRMessage);
    ...
  }
  function onVRMessage(e) {
    switch (e.data.type) {
      case 'sceneChanged':
      if (window.playerCamera.zoom != 1) {
        window.playerCamera.zoom = 1;
        window.playerCamera.updateProjectionMatrix();
      }
      break;
      case 'sceneLoadStart':
        document.getElementById('loader').style.display = 'block';
      break;
      case 'sceneLoadEnd':
        document.getElementById('loader').style.display = 'none';
      break;
      default:
      return;
    }
  }

Check your index.html or client.js.

Read More:   Why React so popular for Front-end Development? Top 9 reasons

InApps – Top App development company in Vietnam

When it comes to coding an app, you have three options: you can either hire an app development agency to build and design your product. You can create your own internal design and development team, or you can build the app yourself.

InApps is a leading application development company in Vietnam. We have extensive experience in developing different applications in all industries. Please view Our portfolio. As long as you have an idea, we will help you turn it into reality. Share your ideas with us now.

List of Keywords users find our article on Google

[sociallocker id=”2721″]

react vr
create vr app
react native vr
how to develop vr apps
react setstate
dna vr
nodejs org
reactvr
w3cschool
react vr game
react native share whatsapp
this setstate
react constructor
react vr tutorial
build a virtual reality application with react learning
vr bundle
border radius react native
componentwillmount
react native transform
setstate react
0.15 * 50
make vr app
react js vr
react native zoom
npm threejs
react-native-vision-camera
headset cartoon
react native vision camera
react virtual reality
react native virtual reality
constructor custom cursor
react-vr
.map is not a function react
react native position absolute
vr react native
this.setstate
infinite outsourcing solutions
react native camera
webkit postmessage
react native templates
var headset
react native border
react recruitment
javascript display none
three js react native
react native template design
drag react native
front end loader hire
index vr
loader react
saas loader
360 spin images for ecommerce
react native app development
react native mobile app development
react native app development company
how to make a vr app
webvr portfolio
react vr documentation
build a vr app
create vr apps
event check-in software for radius
cli elearning
how to create vr apps
offshore it translator
react style display none
how to develop vr application
onn headphones
react native vr app
zoom react native
react native 0.66
three.js mesh
react-native-branch
react-icons npm
virtual reality react native
oculus app labs
adobe xd component states
react native branch
offshore translate
react icons npm
react native animated event
react native stories
building vr apps
emotion react npm
react native center text
camerax sample
react-native border radius
npm normalize
style-loader npm
adobe xd map
react a-frame
react native content loader
position absolute in react native
vr apps
adobe xd map template
border react native
react native loader
schedule component react
three js mesh
zindex react native
virtual office ho chi minh
vr travel case
js vector3
nodejs get parent directory
react image rotate
react native align to bottom
react native border radius
adobe xd to react native
react native animated button
react native bind
react native drag
react native rotate view
react-native-touch-id
.map react
case logic camera
opacity react native
react-native-camera
three js group rotation
borderradius react native
constructor react
mousepose for windows
used index vr
ecommerce xd template
react rotate image
react setstate array
webkit zoom
3498db
react web worker
react-content-loader
let’s play vr
react array state
react native translate
react onmousewheel
requestanimationframe react native
bind this react
display:none javascript
hire webkit developers
js addeventlistener
react addlistener
react native design templates
react native range
react native sketch
react window infinite loader
threejs loaders
vector3 three js
#3498db
node js constructor
react double click
react get mouse position
react native animation loop
react native rotate animation
react native zindex
react-translate
transform.rotation
vietnam coordinates
wheel game crypto software development
react justify content
rotate arrow css
three js react
translate react native
z index in react native
display none javascript
react loader
case logic high zoom camera case
ondblclick
portfolio website using react
react native free template
react set state
react sketch app
react-phone-number-input
vr top of vietnam
adobe xd css export
how to add border in react native
in app messaging react native
loader in react js example
react rotation
this.state is null
z-index react native
margin top in react js
react disable zoom
react state array
react native game development
vr app development
react native mobile development
vr development
hire dedicated react native developers
react js mobile app development
hire react native development services
react native mobile app development company
react native application development services
react native mobile app development services
react native development services
Read More:   Learn Android App Development - How to start?

[/sociallocker]

Rate this post
As a Senior Tech Enthusiast, I bring a decade of experience to the realm of tech writing, blending deep industry knowledge with a passion for storytelling. With expertise in software development to emerging tech trends like AI and IoT—my articles not only inform but also inspire. My journey in tech writing has been marked by a commitment to accuracy, clarity, and engaging storytelling, making me a trusted voice in the tech community.

Let’s create the next big thing together!

Coming together is a beginning. Keeping together is progress. Working together is success.

Let’s talk

Get a custom Proposal

Please fill in your information and your need to get a suitable solution.

    You need to enter your email to download

      Success. Downloading...