Appearance
Your First Scene
FreshThis tutorial will assume some React knowledge.
Setting Up the Canvas
We'll start by importing the <Canvas /> component from @react-three/fiber and putting it in our React tree.
jsx
import { createRoot } from 'react-dom/client'
import { Canvas } from '@react-three/fiber'
function App() {
return (
<div id="canvas-container">
<Canvas />
</div>
)
}
createRoot(document.getElementById('root')).render(<App />)The Canvas component does some important setup work behind the scenes:
- It sets up a Scene and a Camera, the basic building blocks necessary for rendering
- It renders our scene every frame — you do not need a traditional render-loop
TIP
Canvas is responsive to fit the parent node, so you can control how big it is by changing the parent's width and height, in this case #canvas-container.
Adding a Mesh Component
To actually see something in our scene, we'll add a lowercase <mesh /> native element, which is the direct equivalent to new THREE.Mesh().
jsx
<Canvas>
<mesh />INFO
Note that we don't need to import anything — all three.js objects will be treated as native JSX elements, just like you can write <div /> or <span /> in regular ReactDOM. The general rule is that Fiber components are available under the camel-case version of their name in three.js.
A Mesh is a basic scene object in three.js, and it's used to hold the geometry and the material needed to represent a shape in 3D space. We'll create a new mesh using a BoxGeometry and a MeshStandardMaterial which automatically attach to their parent.
jsx
<Canvas>
<mesh>
<boxGeometry />
<meshStandardMaterial />
</mesh>
</Canvas>This is equivalent to the following three.js code:
js
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
const renderer = new THREE.WebGLRenderer()
renderer.setSize(width, height)
document.querySelector('#canvas-container').appendChild(renderer.domElement)
const mesh = new THREE.Mesh()
mesh.geometry = new THREE.BoxGeometry()
mesh.material = new THREE.MeshStandardMaterial()
scene.add(mesh)
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()Constructor Arguments
According to the docs for BoxGeometry we can optionally pass three arguments for: width, length and depth:
js
new THREE.BoxGeometry(2, 2, 2)In Fiber we use the args prop, which always takes an array whose items represent the constructor arguments.
jsx
<boxGeometry args={[2, 2, 2]} />WARNING
Every time you change args, the object must be re-constructed!
Adding Lights
Next, we will add some lights to our scene:
jsx
<Canvas>
<ambientLight intensity={0.1} />
<directionalLight color="red" position={[0, 0, 5]} />Props
This introduces us to the last fundamental concept of Fiber — how React props work on three.js objects. When you set any prop on a Fiber component, it will set the property of the same name on the three.js instance.
jsx
<ambientLight intensity={0.1} />Which is the equivalent to:
jsx
const light = new THREE.AmbientLight()
light.intensity = 0.1Shortcuts
There are a few shortcuts for props that have a .set() method (colors, vectors, etc).
jsx
const light = new THREE.DirectionalLight()
light.position.set(0, 0, 5)
light.color.set('red')Which is the same as:
jsx
<directionalLight position={[0, 0, 5]} color="red" />The Result
Putting it all together:
jsx
import { Canvas } from "@react-three/fiber";
export default function App() {
return (
<Canvas>
<mesh>
<boxGeometry args={[2, 2, 2]} />
<meshPhongMaterial />
</mesh>
<ambientLight intensity={0.1} />
<directionalLight position={[0, 0, 5]} color="red" />
</Canvas>
);
}Things to try
- Try different materials like
MeshNormalMaterialorMeshBasicMaterial, give them a color - Try different geometries like
SphereGeometryorOctahedronGeometry - Try changing the
positionon ourmeshcomponent - Try extracting our mesh to a new component