Scene, Camera, Renderer
Start with the minimum Three.js setup, then compare it to the JSX you actually write in React Three Fiber.
React Three Fiber Three.js
Pinned example stack
react@19.1.1react-dom@19.1.1@react-three/fiber@9.3.0three@0.180.0
Exact Conversion
Switch between the React Three Fiber and Three.js examples, then test the R3F result in the live preview below.
import { Canvas } from '@react-three/fiber';
function Cube() { return ( <mesh> <boxGeometry args={[1.6, 1.6, 1.6]} /> <meshNormalMaterial /> </mesh> );}
export default function App() { return ( <div style={{ height: '100vh', background: '#10131a' }}> <Canvas camera={{ fov: 60, position: [0, 1.4, 4] }} dpr={[1, 2]}> <color attach="background" args={['#10131a']} /> <Cube /> </Canvas> </div> );}import * as THREE from 'three';
const scene = new THREE.Scene();scene.background = new THREE.Color('#10131a');
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);camera.position.set(0, 1.4, 4);
const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));renderer.setSize(window.innerWidth, window.innerHeight);document.body.style.margin = '0';document.body.appendChild(renderer.domElement);
const cube = new THREE.Mesh(new THREE.BoxGeometry(1.6, 1.6, 1.6), new THREE.MeshNormalMaterial());scene.add(cube);
function onResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);}
window.addEventListener('resize', onResize);renderer.render(scene, camera);Live preview
What Changed
<Canvas />replaces manual renderer creation, sizing, and the initial render call.- The scene background becomes
<color attach="background" ... />. - The camera moves into the
cameraprop on<Canvas />. - The mesh still exists. You are just declaring it instead of constructing it by hand.
Read This Translation
Section titled “Read This Translation”new THREE.Scene()is mostly implicit once you enter<Canvas />.scene.add(cube)becomes JSX nesting.renderer.setPixelRatio(...)maps nicely todpr={[1, 2]}for a practical default.
This is the first page to internalize before reading anything more advanced. If this translation feels natural, most basic R3F examples will stop looking like special syntax and start looking like normal scene setup.