If your first React Three Fiber scene renders as a flat black circle, nothing is wrong with you. You probably created geometry without a useful camera, material, light, or controls.
Here is the smallest setup I would start with today.
npm create vite@latest r3f-scene -- --template react
cd r3f-scene
npm install three @react-three/fiber @react-three/drei
npm run dev
Replace src/App.jsx with this:
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import "./App.css";
function Sphere() {
return (
<mesh>
<sphereGeometry args={[1.5, 48, 48]} />
<meshStandardMaterial color="#e11d48" roughness={0.45} metalness={0.1} />
</mesh>
);
}
export default function App() {
return (
<main className="stage">
<Canvas camera={{ position: [0, 1.5, 5], fov: 45 }}>
<color attach="background" args={["#101114"]} />
<ambientLight intensity={0.45} />
<directionalLight position={[4, 6, 3]} intensity={1.8} />
<Sphere />
<OrbitControls enableDamping />
</Canvas>
</main>
);
}
And give the canvas real space:
html,
body,
#root {
width: 100%;
height: 100%;
margin: 0;
}
.stage {
width: 100vw;
height: 100vh;
background: #101114;
}
That is already a complete 3D scene: canvas, camera, mesh, geometry, material, light, and controls.
The Pieces That Matter
React Three Fiber is not "Three.js but React-looking." It is a React renderer for Three.js. The JSX tags are still Three concepts.
<mesh>
<sphereGeometry args={[1.5, 48, 48]} />
<meshStandardMaterial color="#e11d48" />
</mesh>
The mesh is the object. The geometry is the shape. The material is how the surface responds to light.
If you skip material, you do not have a visible surface worth looking at. If you skip light while using meshStandardMaterial, the object can look black. If you skip camera positioning, your object may be technically there but framed badly.
Do Not Start With a Model Loader
A common beginner mistake is loading a GLB model before you understand the scene. That makes debugging miserable because every issue looks like an asset problem.
Start with a primitive:
function Box() {
return (
<mesh rotation={[0.4, 0.4, 0]}>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="#22c55e" />
</mesh>
);
}
If the box renders, your React, canvas, camera, lighting, and CSS are fine. Then add models.
Add Motion Carefully
Animation in React Three Fiber usually belongs in useFrame. Do not animate by putting React state updates in a render loop unless you want unnecessary rerenders.
import { useFrame } from "@react-three/fiber";
import { useRef } from "react";
function SpinningSphere() {
const ref = useRef();
useFrame((_, delta) => {
ref.current.rotation.y += delta * 0.6;
});
return (
<mesh ref={ref}>
<sphereGeometry args={[1.5, 48, 48]} />
<meshStandardMaterial color="#38bdf8" roughness={0.35} />
</mesh>
);
}
This changes the Three object directly. React does not need to rerender 60 times per second just because a sphere rotates.
Add a Floor
A floating object can look fake even when the code is correct. Add a simple floor so light and position become easier to read.
function Floor() {
return (
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -1.6, 0]}>
<planeGeometry args={[20, 20]} />
<meshStandardMaterial color="#27272a" />
</mesh>
);
}
Then use it:
<Canvas camera={{ position: [0, 1.5, 5], fov: 45 }}>
<color attach="background" args={["#101114"]} />
<ambientLight intensity={0.45} />
<directionalLight position={[4, 6, 3]} intensity={1.8} />
<SpinningSphere />
<Floor />
<OrbitControls enableDamping />
</Canvas>
My Defaults
For a first production-ish scene, I would use:
- Vite instead of Create React App.
-
sphereGeometry, not oldsphereBufferGeometryexamples. -
meshStandardMaterialfor realistic light response. -
OrbitControlswhile developing, even if you remove it later. - One ambient light and one directional light before getting fancy.
- Fixed canvas height. Most "my scene is blank" bugs are CSS bugs.
What I Would Avoid
I would not start with physics, post-processing, GLTF models, shadows, or scroll-driven camera animation.
Those are fun, but they multiply the number of things that can be wrong. Get one primitive on screen first. Make it lit. Make it move. Then build.
Debug Checklist
- Canvas has width and height.
-
Canvasis imported from@react-three/fiber. - Camera is far enough back to see the object.
- Material matches your lighting setup.
- Object is near
[0, 0, 0]. - DevTools console has no asset import errors.
- Controls are enabled while debugging.
That is the base. Once this renders, everything else is iteration.
Top comments (1)
One of the most things that makes me up for front-end every time i get tired of it, is 3D websites! and I love how detailed is your explanation, thanks