Navigate

Search topics across all sections

GitHub
Scene Basics

Scene, Camera & Renderer

Every 3D scene needs three things to work: a place to put your objects, a viewpoint to look from, and something to draw the picture on your screen. Miss any one of these, and you get a blank canvas.

You just wrote your first React Three Fiber code. You create a Canvas, add a box, and... nothing. The screen is completely black. You check the code three times — everything looks right. What happened?

terminal
Canvas renders but shows only a black screen. No errors in console.

Real-world

Think of it like making a movie. You need three things:

A movie set (the Scene) — where you place your actors, props, and lights.

A cameraman (the Camera) — who decides what angle to film from.

A projector (the Renderer) — that takes the film and shows it on a screen.

Miss any one of these, and you get... a black screen. Just like our beginner above. They forgot the lights on set!

Scene

The movie set

Camera

The cameraman

Renderer

The projector

Screen

What you see!

Hands-On: Your First Scene

The good news? In React Three Fiber, one component sets up the Scene, Camera, and Renderer all at once. Let's build something you can see in three quick steps.

Step 1: Set up the film studio

App.tsxTSX
<Canvas>
  {/* Your 3D world starts here */}
</Canvas>

The Canvas component creates your Scene, Camera, and Renderer automatically. Think of it as building the entire film studio with one line. The camera defaults to position [0, 0, 5] — five steps back from center stage.

Step 2: Place an actor on set

App.tsxTSX
<Canvas>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
</Canvas>

A mesh is like an actor: it has a body (boxGeometry = cube shape) and a costume (meshStandardMaterial = orange surface). But wait — the screen is still black! Can you guess why?

Step 3: Turn on the lights!

App.tsxTSX
<Canvas>
  <ambientLight intensity={0.5} />
  <directionalLight position={[5, 5, 5]} />
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
</Canvas>

Now your orange cube is visible! The ambientLight is like turning on the room lights — everything gets evenly lit. The directionalLight adds sunlight from a direction, giving your cube depth and shadows. Try changing "orange" to "hotpink" and see what happens.

Without LightingWith Lighting
Scene.tsx
<Canvas>
  <mesh>
    <boxGeometry />
    <meshBasicMaterial color="orange" />
  </mesh>
</Canvas>

MeshBasicMaterial doesn't need light — but looks flat with no depth or shading.

What you just learned

A 3D scene needs three things: a Scene (the set), a Camera (the viewpoint), and a Renderer (the screen output).

In R3F, the <Canvas> component creates all three automatically — no manual setup needed.

Most materials need at least one light source to be visible. No light = black screen.

The camera defaults to position [0, 0, 5], meaning it looks at the origin from 5 units back.

Question

If the Camera is like a cameraman, what happens if you move the cameraman inside the box? Can they see anything? What if you point the camera the wrong way?

Think about it...

You create a Canvas with a mesh inside, but the screen is black. What's most likely missing?

Hint: Think about what happens in a real room when the lights are off...

Try These Challenges

Put what you learned into practice. Try each challenge in the demo above using the Leva controls, then check the solution.

Try This!

Beginner

Change the camera position to [0, 10, 0] — what do you see?

Try This!

Beginner

Add a second mesh next to the first one

Try This!

Beginner

Remove the ambientLight — what happens?

These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.

1
Forgetting to position the camera
The scene renders but the screen is completely black
Don't do this
App.tsxTSX
// Camera is at (0,0,0) — inside the cube!
<Canvas camera={{ position: [0, 0, 0] }}>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
</Canvas>
By default the camera starts at the origin (0, 0, 0). If your objects are also at the origin, the camera is literally inside them and you see nothing. Always move the camera back (positive Z) and make sure you have a light source.
2
Not adding a light source
Objects exist but appear completely black
Don't do this
App.tsxTSX
<Canvas>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
  {/* No lights! Like a room with no windows. */}
</Canvas>
MeshStandardMaterial is a physically-based material that requires light to be visible. Without any light, everything appears black. Add an ambientLight for general illumination and a directionalLight for shadows and depth.
3
Enabling preserveDrawingBuffer unnecessarily
Performance degrades for no visible benefit
Don't do this
App.tsxTSX
<Canvas gl={{
  antialias: true,
  preserveDrawingBuffer: true,
  alpha: true,
}}>
preserveDrawingBuffer prevents the GPU from discarding the frame buffer after compositing, which costs performance. Only enable it if you need to capture screenshots with canvas.toDataURL(). Start minimal and add features as needed.

Best Practices

Cap the Pixel Ratio

R3F caps at 2 by default, which is great. High-DPI screens (3x) render 9x the pixels — a huge performance hit with barely any visual difference.

Keep Objects Near the Origin

Center your content around (0, 0, 0). Objects at extreme positions like (100000, 0, 0) will visibly jitter due to floating-point precision limits.

Tight Near/Far Planes

The camera has a near and far clipping plane — like minimum and maximum focus distance. Keep them as tight as possible. A near of 0.001 and far of 100000 wastes precision and causes visual glitches.

Start Minimal

Don't enable alpha, preserveDrawingBuffer, or stencil unless you need them. Each adds overhead. Start with just antialias: true and add features as required.