Navigate

Search topics across all sections

GitHub
Lights

Light Types

Lights are what bring your 3D scene to life. Without them, most materials show up as solid black. Three.js gives you several light types, each mimicking a different real-world lighting situation.

You build a beautiful scene with detailed materials and textures, but everything renders pitch black. You check your meshes, your camera, your materials — everything looks right. The problem? You forgot to add lights. Most materials (Lambert, Phong, Standard, Physical) need at least one light source to be visible.

terminal
Scene renders but all meshes appear completely black.

Real-world

Think about the different lights in your home. Each one behaves differently, and Three.js has a match for each.

Ambient light is like daylight filling a room through windows — it is everywhere at once, comes from no particular direction, and casts no shadows. Everything gets the same amount.

Directional light is the sun — the rays are parallel because the source is so far away. Everything in your scene gets light from the same angle, no matter where it is.

Point light is a bare light bulb hanging from the ceiling — it radiates in all directions from a single point, and objects closer to it are brighter.

Spot light is a flashlight or a stage spotlight — it creates a cone of light pointing in one direction. Things outside the cone stay dark.

Picking the Right Light

Each light type has a trade-off between realism and performance. Here is a quick guide.

Base fill

Ambient or Hemisphere (cheapest)

Main light

Directional (sun, key light)

Local accents

Point or Spot (lamps, flashlights)

Soft panels

RectArea (PBR only, no shadows)

Guided Walkthrough

Let us light a scene step by step, from total darkness to a believable setup.

Step 1 — Prevent total darkness with ambient fill

step-1-ambient.tsxTSX
{/* Soft fill so nothing is pure black */}
<ambientLight intensity={0.3} color="#ffffff" />

Ambient light adds a flat amount of brightness to everything. Keep the intensity low (0.1 to 0.4) or your scene will look washed out — like a foggy day with no contrast.

Step 2 — Add a main directional light (the sun)

step-2-directional.tsxTSX
{/* The "sun" — parallel rays from one direction */}
<directionalLight
  position={[5, 10, 5]}
  intensity={1.5}
  castShadow
/>

This is your main light source. The position controls which direction the rays come from. Setting castShadow to true lets it create shadows (we will set those up in the shadows lesson).

Step 3 — Add a warm point light for local atmosphere

step-3-pointlight.tsxTSX
{/* A warm bulb near a table or lamp */}
<pointLight
  position={[2, 3, 1]}
  intensity={8}
  color="#ff8844"
  distance={20}
  decay={2}
/>

Point lights radiate in all directions from a single spot. The warm orange color and decay of 2 (physically correct falloff) make this feel like a real lamp. Objects farther away get less light.

No LightsCombined Lighting
LightingSetup.tsx
<Canvas>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
  {/* No lights — everything is black */}
</Canvas>

Without any lights, PBR materials render as pure black — the objects exist but you can't see them.

What you just learned

Ambient light fills the whole scene evenly — cheap but flat, no shadows

Directional light shoots parallel rays like the sun — great as a main light with shadows

Point light radiates in all directions from one spot — like a light bulb, with distance falloff

Spot light casts a cone of light — like a flashlight, with angle and penumbra controls

Question

A scene has only an AmbientLight. No matter how you position or rotate the objects, the shading never changes. Why? And what does that tell you about when ambient light alone is not enough?

Think about it...

You want to simulate a desk lamp shining down on a work surface. Which light type is the best fit?

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

Turn off all lights — complete darkness?

Try This!

Beginner

Enable only Point — watch it orbit

Try This!

Intermediate

Crank spotAngle to max

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

1
Removing lights instead of hiding them
Causes expensive shader recompilation every toggle
Don't do this
toggle-light.tsxTSX
// Toggle by adding/removing from scene
function toggleLight() {
  if (light.parent) {
    scene.remove(light);
  } else {
    scene.add(light);
  }
}
// Every add/remove recompiles all affected shaders!
Adding or removing a light changes the shader code for every affected material. Setting light.visible or intensity to 0 keeps the shader intact and just updates a number, which is orders of magnitude cheaper.
2
Too many lights tanking performance
Each light adds per-pixel shader calculations
Don't do this
too-many-lights.tsxTSX
// 20 point lights for atmosphere
for (let i = 0; i < 20; i++) {
  const light = new THREE.PointLight(0xff8844, 1, 10);
  light.position.set(Math.random() * 20, 2, Math.random() * 20);
  scene.add(light);
}
// 20 extra lighting passes per pixel — performance tanks
Each direct light adds per-pixel calculations in the shader. The cost scales linearly: 20 lights means 20 times the lighting work. For scenes that need many light sources, use baked lightmaps or a single environment map for ambient fill.
3
RectAreaLight has no effect on the mesh
Using it with a non-PBR material
Don't do this
rect-area-material.tsxTSX
// RectAreaLight with Lambert — light is ignored
<rectAreaLight args={[0xffffff, 5, 4, 4]} />
<mesh>
  <boxGeometry />
  <meshLambertMaterial color="#4488ff" />
</mesh>
RectAreaLight only works with MeshStandardMaterial and MeshPhysicalMaterial. It requires the PBR shader pipeline. If your rect light has no visible effect, check that all affected meshes use a PBR material.

Best Practices

Limit to 1-3 direct lights

Each direct light adds per-pixel shader work. Supplement with an environment map or hemisphere light for ambient fill instead of adding more direct lights.

Use helpers while developing

DirectionalLightHelper, SpotLightHelper, and PointLightHelper visualize light position and direction. They make aiming lights much easier. Remove them before shipping.

Toggle with visible, not add/remove

Setting light.visible to false avoids shader recompilation. Only add or remove lights when you are permanently changing the scene layout.

Hemisphere + Directional for outdoors

For quick outdoor scenes, combine a HemisphereLight (sky and ground fill) with one DirectionalLight (the sun). This classic combo looks convincing with minimal performance cost.