Skip to main content
Documentation

Getting Started

Set up Five SDK with React class components and HOCs and render your first Realsee 3D space.

Info

This chapter integrates Five SDK in a React project using the ClassComponent + HOC pattern. Full source examples: JavaScript | TypeScript.

In this chapter you will learn

  • How to set up your development environment.
  • How to import the Five SDK.
  • How to render a 3D space on screen.

Preparation

Development environment

  • You need a modern browser.

Info

Five SDK supports the following browsers. Pick whichever one you are comfortable with:

SafariSafari on iOSChromeChrome for AndroidEdgeFirefox
>= 9>= 9>= 49>= 93>= 13>= 45
  • Install Node.js ^20.19.0 or >=22.12.0, matching the Vite 8 engine requirement used by this guide.

Using a build tool

This example initializes the development environment with Vite. You can bootstrap it yourself with the code below.

	# npm 6.x
	npm create vite@9.1.1 my-react-app --template react
	
	# npm 7+, extra double-dash is needed:
	npm create vite@9.1.1 my-react-app -- --template react

Under src, create the directory src/0.getting-started for this tutorial.

Every tutorial creates a new directory to keep its work, which makes it easier to summarize and look things up. When the course is finished you will end up with:

src
├── 0.getting-started
├── 1.displaying-work
├── 2.knowing-state
...

a directory structure like this. The complete code samples follow the same structure, so you can refer to them at any time.

Tip

If you are familiar with other build tools such as Webpack, Snowpack, or parcel, you can use them instead.

Creating the HTML file

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="data:;base64,iVBORw0KGgo=">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Getting Started</title>
  <!-- highlight-start -->
  <style>
    * { margin: 0; padding: 0; }
    html, body, #app { width: 100%; height: 100%; overflow: hidden; }
  </style>
  <!-- highlight-end -->
</head>
<body>
  <!-- highlight-start -->
  <div id="app"></div>
  <script type="module" src="./index"></script>
  <!-- highlight-end -->
</body>
</html>

Referencing the entry directly with <script type="module" src="./index"></script> is a Vite feature. If you use another build tool, handle the code import and entry file yourself — for example, use HtmlWebpackPlugin with webpack.

Writing the test logic

Let's start with a simple Hello World to make sure the whole pipeline runs.

const app = document.querySelector("#app");
// highlight-start
app.innerHTML = "Hello World.";
// highlight-end
export {};

The trailing export {}; is required because Vite imports the file with type="module", so every file needs to be a module and therefore needs an export. If you use another build tool, write it according to that tool's requirements.

Start the dev server with npm run dev, then open the current page at "http://localhost:3000/src/0.getting-started/index.html".

Info

Check your console: the port number may change depending on your configuration and which ports are currently in use, so rely on the console output as the source of truth. If you use another build tool, start the server according to that tool's requirements.

You will then see the output

Hello World.

on the page, which means the build tool is set up correctly.

The following chapters will not describe the steps above in detail; just complete them the same way.

Installing dependencies from npm

Install the dependencies in your project directory.

npm install @realsee/five@6.8.9 three@0.117.1 react react-dom @wordpress/compose

Required dependencies:

Rendering a 3D space

It's time to render a VR scene and take a look.

Loading the 3D space

Delete your previous Hello World code; we'll start over. You don't need to understand the meaning of the code below just yet — you will learn it in the next chapter.

import React, { Component, ComponentClass } from "react";
import ReactDOM from "react-dom";
import { Work, parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { compose } from "@wordpress/compose";

/** Data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

/**
 * React HOC that fetches the work
 * @param url the URL of work.json
 */
function withFetchWork(url) {
  return function(Compnent) {
    return class extends Component {
      state = { work: null };
      componentDidMount() {
        fetch(url).then(res => res.json()).then(json => {
          this.setState({ work: parseWork(json) });
        });
      }
      render() {
        if (this.state.work === null) return null;
        return <Compnent work={this.state.work} {...this.props}/>;
      }
    }
  }
}

const FiveProvider = createFiveProvider();
const App = compose(
  withFetchWork(workURL)
)(class extends Component {
  render() {
    const { work } = this.props;
    return <FiveProvider initialWork={work}>
      <FiveCanvas width={512} height={512}/>
    </FiveProvider>;
  }
});

ReactDOM.render(<App/>, document.querySelector("#app"));

export {};

Go back to your browser and check whether a 3D space is now displayed in the top-left corner. You can drive the view with your mouse or touch gestures — the basic browsing features are already included.

Making the view fill the whole screen

You may not fully understand how the code above works yet, but you can see that FiveCanvas has width and height props, which look a lot like the canvas dimensions. Viewing it in the browser, the view sits in the top-left corner, which confirms the guess. That's right — they are used to set the canvas dimensions.

So let's use the React Hooks approach we're familiar with to make it fill the screen.

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { compose } from "@wordpress/compose";

/** Data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

/**
 * React HOC that fetches the work
 * @param url the URL of work.json
 */
function withFetchWork(url) {
  return function(Compnent) {
    return class extends Component {
      state = { work: null };
      componentDidMount() {
        fetch(url).then(res => res.json()).then(json => {
          this.setState({ work: parseWork(json) });
        });
      }
      render() {
        if (this.state.work === null) return null;
        return <Compnent work={this.state.work} {...this.props}/>;
      }
    }
  }
}

/**
 * React HOC: gets the current window dimensions
 */
function withWindowDimensions() {
  return function(Compnent) {
    return class extends Component {
      state = this.getWindowDimensions();
      resizeListener = () => {
        this.setState(this.getWindowDimensions());
      };
      getWindowDimensions() {
        return { width: window.innerWidth, height: window.innerHeight };
      }
      componentDidMount() {
        window.addEventListener("resize", this.resizeListener, false);
      }
      componentWillUnmount() {
        window.removeEventListener("resize", this.resizeListener, false);
      }
      render() {
        const dimensions = { width: this.state.width, height: this.state.height };
        return <Compnent windowDimensions={dimensions} {...this.props}/>;
      }
    }
  }
}

const FiveProvider = createFiveProvider();
const App = compose(
  withFetchWork(workURL),
  withWindowDimensions()
)(
  class extends Component {
  render() {
    const { work, windowDimensions } = this.props;
    return <FiveProvider initialWork={work}>
      <FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
    </FiveProvider>;
  }
})

ReactDOM.render(<App/>, document.querySelector("#app"));

export {};

Go back to your browser and check whether it looks as expected.

Nice work 🥳 !

Reorganizing and splitting the code

Right now all of our code lives in a single js / ts file. While you can see all the logic at a glance, it's a bit messy. Splitting the content across multiple files will improve this.

  • Split App into its own file.
  • Split the withFetchWork function into its own file.
  • Split the withWindowDimensions function into its own file.

src/0.getting-started/withFetchWork.jsx

import React, { Component } from "react";
import { parseWork } from "@realsee/five";

/**
 * React HOC that fetches the work
 * @param url the URL of work.json
 */
function withFetchWork(url) {
  return function(Compnent) {
    return class extends Component {
      state = { work: null };
      componentDidMount() {
        fetch(url).then(res => res.json()).then(json => {
          this.setState({ work: parseWork(json) });
        });
      }
      render() {
        if (this.state.work === null) return null;
        return <Compnent work={this.state.work} {...this.props}/>;
      }
    }
  }
}

export { withFetchWork };

src/0.getting-started/withWindowDimensions.jsx

import React, { Component } from "react";

/**
 * React HOC: gets the current window dimensions
 */
function withWindowDimensions() {
  return function(Compnent) {
    return class extends Component {
      state = this.getWindowDimensions();
      resizeListener = () => {
        this.setState(this.getWindowDimensions());
      };
      getWindowDimensions() {
        return { width: window.innerWidth, height: window.innerHeight };
      }
      componentDidMount() {
        window.addEventListener("resize", this.resizeListener, false);
      }
      componentWillUnmount() {
        window.removeEventListener("resize", this.resizeListener, false);
      }
      render() {
        const dimensions = { width: this.state.width, height: this.state.height };
        return <Compnent windowDimensions={dimensions} {...this.props}/>;
      }
    }
  }
}

export { withWindowDimensions };

src/0.getting-started/App.jsx

import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { withFetchWork } from "./withFetchWork";
import { withWindowDimensions } from "./withWindowDimensions";

/** Data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

const FiveProvider = createFiveProvider();

const App = compose(
  withFetchWork(workURL),
  withWindowDimensions()
)(class extends Component {
  render() {
    const { work, windowDimensions } = this.props;
    return <FiveProvider initialWork={work}>
      <FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
    </FiveProvider>;
  }
});

export { App };

src/0.getting-started/index.jsx

import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";

ReactDOM.render(<App/>, document.querySelector("#app"));

export {};

Much more comfortable, isn't it? Every file is now concise, and it's easy to understand what each one does.

What you will learn in the next chapter

In the next chapter you will learn

  • What a Work is.
  • How the code we just wrote works — for example, how the FiveProvider / FiveCanvas components work.