Integrate Five SDK development on the React framework using the Function Components and Hooks pattern. Full source examples: JavaScript | TypeScript
What you will learn in this chapter
- Setting up the development environment.
- How to import the Five SDK.
- Displaying a 3D space on the screen.
Preparation
Development Environment
- You need a modern browser.
Info
Five SDK has the following browser support. Pick whichever one you are comfortable with:
| Safari | Safari on iOS | Chrome | Chrome for Android | Edge | Firefox |
|---|---|---|---|---|---|
| >= 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 initialize 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# npm 6.x
npm create vite@9.1.1 my-react-app --template react-ts
# npm 7+, extra double-dash is needed:
npm create vite@9.1.1 my-react-app -- --template react-tsCreate the directory for this tutorial under src: src/0.getting-started.
Each tutorial creates a new directory as a record, making it easier to summarize and find. When the course is finished you will end up with a directory structure like this.
src
├── 0.getting-started
├── 1.displaying-work
├── 2.knowing-state
...
The complete code sample follows the same directory structure, so you can refer to it at any time.
Tip
If you are familiar with other build tools such as Webpack, Snowpack, or parcel, you can use them as well.
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>Importing directly via <script type="module" src="./index"></script> is a feature of Vite. If you use another build tool, handle the code import and entry file yourself — for example, with HtmlWebpackPlugin under Webpack.
Writing the Test Logic
Let's first create a simple Hello World to make sure the whole setup runs end to end.
const app = document.querySelector("#app");
// highlight-start
app.innerHTML = "Hello World.";
// highlight-end
export {};const app = document.querySelector("#app")!;
// highlight-start
app.innerHTML = "Hello World.";
// highlight-end
export {};The trailing export {}; is needed because Vite imports with type="module", so every file must be a module and therefore requires an export. If you use another build tool, write it according to that tool's requirements.
Start the server with npm run dev, then navigate to the current page at "http://localhost:3000/src/0.getting-started/index.html".
Info
Check your console: the port number may vary depending on your configuration and on which ports are currently in use, so rely on the console output. If you use another build tool, start the server according to that tool's requirements.
You will then see the following output on the page
Hello World.This output means the build tool is set up correctly.
The following chapters will no longer describe the steps above in detail, so please complete them along the 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-domThe required dependencies are
- @realsee/five Five SDK
- three three.js, the graphics/math library that Five SDK depends on. Use the exact
0.117.1version. - react the React framework
- react-dom React's browser-side renderer
npm install @realsee/five@6.8.9 three@0.117.1 react react-dom @types/react @types/react-domThe required dependencies are
- @realsee/five Five SDK
- three three.js, the graphics/math library that Five SDK depends on. Use the exact
0.117.1version. - react the React framework
- react-dom React's browser-side renderer
- @types/react the TypeScript type declarations for the React framework
- @types/react-dom the TypeScript type declarations for React's browser-side renderer
Info
If npm install errors out while installing dependencies, try adding the --force flag.
Rendering a 3D Space
It's time to render a VR scene and take a look.
Loading the 3D Space
Delete your earlier Hello World code. We'll rewrite it. You don't need to understand what the following code means yet — you will learn that in the next chapter.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
// The data URL of work.json
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url) {
const [work, setWork] = useState(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
const FiveProvider = createFiveProvider();
const App = () => {
const work = useFetchWork(workURL);
return work && <FiveProvider initialWork={work}>
<FiveCanvas width={512} height={512}/>
</FiveProvider>;
};
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};import React, { FC, useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { Work, parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
/** The data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url: string) {
const [work, setWork] = useState<Work | null>(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
const FiveProvider = createFiveProvider();
const App: FC = () => {
const work = useFetchWork(workURL);
return work && <FiveProvider initialWork={work}>
<FiveCanvas width={512} height={512}/>
</FiveProvider>;
};
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};Go back to your browser and see whether a 3D space is already displayed in the top-left position. You can operate the view with your mouse or touch gestures — the basic browsing features are already included.
Making the View Fill the Whole Screen
Even if you don't fully understand how the code above works, we can see that FiveCanvas has width and height props, which look a lot like the dimensions of the view. And viewing it in the browser, the view is in the top-left corner, which confirms this guess. That's right — they are used to set the dimensions of the view.
So let's try, in the React Hooks style we are familiar with, to make it fill the screen.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
/** The data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url) {
const [work, setWork] = useState(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
// highlight-start
/**
* Get the current window dimensions
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: get the current window dimensions
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
// highlight-end
const FiveProvider = createFiveProvider();
const App = () => {
const work = useFetchWork(workURL);
// highlight-start
const size = useWindowDimensions();
// highlight-end
return work && <FiveProvider initialWork={work}>
// highlight-start
<FiveCanvas {...size}/>
// highlight-end
</FiveProvider>;
};
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};import React, { FC, useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { Work, parseWork } from "@realsee/five";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
/** The data URL of work.json */
const workURL = "https://vr-public.realsee-cdn.cn/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url: string) {
const [work, setWork] = useState<Work | null>(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
// highlight-start
/**
* Get the current window dimensions
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: get the current window dimensions
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
// highlight-end
const FiveProvider = createFiveProvider();
const App: FC = () => {
const work = useFetchWork(workURL);
// highlight-start
const size = useWindowDimensions();
// highlight-end
return work && <FiveProvider initialWork={work}>
// highlight-start
<FiveCanvas {...size}/>
// highlight-end
</FiveProvider>;
};
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};Go back to your browser and check whether it matches your expectations.
You did great 🥳!
Organizing and Splitting the Code
Right now all of our code is written in a single js / ts file. Although you can see all the logic at a glance, it is rather messy. Splitting the content into multiple files will improve this.
- Split
Appinto its own file. - Split the
useFetchWorkfunction into its own file. - Split the
useWindowDimensionsfunction into its own file.
import { useState, useEffect } from "react";
import { parseWork } from "@realsee/five";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url) {
const [work, setWork] = useState(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
export { useFetchWork };import { useState, useEffect } from "react";
/**
* Get the current window dimensions
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: get the current window dimensions
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
export { useWindowDimensions };import React from "react";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { useFetchWork } from "./useFetchWork";
import { useWindowDimensions } from "./useWindowDimensions";
/** The 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 = () => {
const work = useFetchWork(workURL);
const size = useWindowDimensions();
return work && <FiveProvider initialWork={work}>
<FiveCanvas {...size}/>
</FiveProvider>;
};
export { App };import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};import { useState, useEffect } from "react";
import { Work, parseWork } from "@realsee/five";
/**
* React Hook: fetch the work object from the work.json address
* @param url the data address of work.json
* @returns the work object, or null while still fetching
*/
function useFetchWork(url: string) {
const [work, setWork] = useState<Work | null>(null);
useEffect(() => {
setWork(null);
fetch(url)
.then(response => response.text())
.then(text => setWork(parseWork(text)));
},[url]);
return work;
}
export { useFetchWork };import { useState, useEffect } from "react";
/**
* Get the current window dimensions
*/
function getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
/**
* React Hook: get the current window dimensions
*/
function useWindowDimensions() {
const [size, setSize] = useState(getWindowDimensions);
useEffect(() => {
const listener = () => setSize(getWindowDimensions());
window.addEventListener("resize", listener, false);
return () => window.removeEventListener("resize", listener, false);
});
return size;
}
export { useWindowDimensions };import React, { FC } from "react";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { useFetchWork } from "./useFetchWork";
import { useWindowDimensions } from "./useWindowDimensions";
/** The 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: FC = () => {
const work = useFetchWork(workURL);
const size = useWindowDimensions();
return work && <FiveProvider initialWork={work}>
<FiveCanvas {...size}/>
</FiveProvider>;
};
export { App };import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";
ReactDOM.render(<App/>, document.querySelector("#app"));
export {};Isn't that much more comfortable? Each file is very concise, and it's easy to understand what each one does.
What You Will Learn in the Next Chapter
What you will learn in the next chapter
- What a Work is.
- How the code you just wrote works — for example, how the
FiveProvider/FiveCanvascomponents work.
