threejs-lighting

Complete Three.js lighting system covering all light types, shadows, and environment-based illumination. Supports six light types (ambient, hemisphere, directional, point, spot, rect area) with detailed shadow configuration for each, including map size, camera frustum, bias tuning, and softness controls Includes environment lighting via HDR and cube textures with PMREM generation, light probes for ambient capture, and contact shadows as a fast alternative Provides three production-ready setups: three-point studio lighting, outdoor daylight with hemisphere gradients, and indoor area lighting with multiple rect lights Features performance optimization guidance including light layer masking, shadow frustum tightening, and baked lighting strategies for complex scenes

INSTALLATION
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-lighting
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$2a

Light

Description

Shadow Support

Cost

AmbientLight

Uniform everywhere

No

Very Low

HemisphereLight

Sky/ground gradient

No

Very Low

DirectionalLight

Parallel rays (sun)

Yes

Low

PointLight

Omnidirectional (bulb)

Yes

Medium

SpotLight

Cone-shaped

Yes

Medium

RectAreaLight

Area light (window)

No*

High

*RectAreaLight shadows require custom solutions

AmbientLight

Illuminates all objects equally. No direction, no shadows.

// AmbientLight(color, intensity)

const ambient = new THREE.AmbientLight(0xffffff, 0.5);

scene.add(ambient);

// Modify at runtime

ambient.color.set(0xffffcc);

ambient.intensity = 0.3;

HemisphereLight

Gradient from sky to ground color. Good for outdoor scenes.

// HemisphereLight(skyColor, groundColor, intensity)

const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b4513, 0.6);

hemi.position.set(0, 50, 0);

scene.add(hemi);

// Properties

hemi.color; // Sky color

hemi.groundColor; // Ground color

hemi.intensity;

DirectionalLight

Parallel light rays. Simulates distant light source (sun).

// DirectionalLight(color, intensity)

const dirLight = new THREE.DirectionalLight(0xffffff, 1);

dirLight.position.set(5, 10, 5);

// Light points at target (default: 0, 0, 0)

dirLight.target.position.set(0, 0, 0);

scene.add(dirLight.target);

scene.add(dirLight);

DirectionalLight Shadows

dirLight.castShadow = true;

// Shadow map size (higher = sharper, more expensive)

dirLight.shadow.mapSize.width = 2048;

dirLight.shadow.mapSize.height = 2048;

// Shadow camera (orthographic)

dirLight.shadow.camera.near = 0.5;

dirLight.shadow.camera.far = 50;

dirLight.shadow.camera.left = -10;

dirLight.shadow.camera.right = 10;

dirLight.shadow.camera.top = 10;

dirLight.shadow.camera.bottom = -10;

// Shadow softness

dirLight.shadow.radius = 4; // Blur radius (PCFSoftShadowMap only)

// Shadow bias (fixes shadow acne)

dirLight.shadow.bias = -0.0001;

dirLight.shadow.normalBias = 0.02;

// Helper to visualize shadow camera

const helper = new THREE.CameraHelper(dirLight.shadow.camera);

scene.add(helper);

PointLight

Emits light in all directions from a point. Like a light bulb.

// PointLight(color, intensity, distance, decay)

const pointLight = new THREE.PointLight(0xffffff, 1, 100, 2);

pointLight.position.set(0, 5, 0);

scene.add(pointLight);

// Properties

pointLight.distance; // Maximum range (0 = infinite)

pointLight.decay; // Light falloff (physically correct = 2)

PointLight Shadows

pointLight.castShadow = true;

pointLight.shadow.mapSize.width = 1024;

pointLight.shadow.mapSize.height = 1024;

// Shadow camera (perspective - 6 directions for cube map)

pointLight.shadow.camera.near = 0.5;

pointLight.shadow.camera.far = 50;

pointLight.shadow.bias = -0.005;

SpotLight

Cone-shaped light. Like a flashlight or stage light.

// SpotLight(color, intensity, distance, angle, penumbra, decay)

const spotLight = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 6, 0.5, 2);

spotLight.position.set(0, 10, 0);

// Target (light points at this)

spotLight.target.position.set(0, 0, 0);

scene.add(spotLight.target);

scene.add(spotLight);

// Properties

spotLight.angle; // Cone angle (radians, max Math.PI/2)

spotLight.penumbra; // Soft edge (0-1)

spotLight.distance; // Range

spotLight.decay; // Falloff

SpotLight Shadows

spotLight.castShadow = true;

spotLight.shadow.mapSize.width = 1024;

spotLight.shadow.mapSize.height = 1024;

// Shadow camera (perspective)

spotLight.shadow.camera.near = 0.5;

spotLight.shadow.camera.far = 50;

spotLight.shadow.camera.fov = 30;

spotLight.shadow.bias = -0.0001;

// Focus (affects shadow projection)

spotLight.shadow.focus = 1;

RectAreaLight

Rectangular area light. Great for soft, realistic lighting.

import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";

import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib.js";

// Must initialize uniforms first

RectAreaLightUniformsLib.init();

// RectAreaLight(color, intensity, width, height)

const rectLight = new THREE.RectAreaLight(0xffffff, 5, 4, 2);

rectLight.position.set(0, 5, 0);

rectLight.lookAt(0, 0, 0);

scene.add(rectLight);

// Helper

const helper = new RectAreaLightHelper(rectLight);

rectLight.add(helper);

// Note: Only works with MeshStandardMaterial and MeshPhysicalMaterial

// Does not cast shadows natively

Shadow Setup

Enable Shadows

// 1. Enable on renderer

renderer.shadowMap.enabled = true;

renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// Shadow map types:

// THREE.BasicShadowMap - fastest, low quality

// THREE.PCFShadowMap - default, filtered

// THREE.PCFSoftShadowMap - softer edges

// THREE.VSMShadowMap - variance shadow map

// 2. Enable on light

light.castShadow = true;

// 3. Enable on objects

mesh.castShadow = true;

mesh.receiveShadow = true;

// Ground plane

floor.receiveShadow = true;

floor.castShadow = false; // Usually false for floors

Optimizing Shadows

// Tight shadow camera frustum

const d = 10;

dirLight.shadow.camera.left = -d;

dirLight.shadow.camera.right = d;

dirLight.shadow.camera.top = d;

dirLight.shadow.camera.bottom = -d;

dirLight.shadow.camera.near = 0.5;

dirLight.shadow.camera.far = 30;

// Fix shadow acne

dirLight.shadow.bias = -0.0001; // Depth bias

dirLight.shadow.normalBias = 0.02; // Bias along normal

// Shadow map size (balance quality vs performance)

// 512 - low quality

// 1024 - medium quality

// 2048 - high quality

// 4096 - very high quality (expensive)

Contact Shadows (Fake, Fast)

import { ContactShadows } from "three/examples/jsm/objects/ContactShadows.js";

const contactShadows = new ContactShadows({

  resolution: 512,

  blur: 2,

  opacity: 0.5,

  scale: 10,

  position: [0, 0, 0],

});

scene.add(contactShadows);

Light Helpers

import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";

// DirectionalLight helper

const dirHelper = new THREE.DirectionalLightHelper(dirLight, 5);

scene.add(dirHelper);

// PointLight helper

const pointHelper = new THREE.PointLightHelper(pointLight, 1);

scene.add(pointHelper);

// SpotLight helper

const spotHelper = new THREE.SpotLightHelper(spotLight);

scene.add(spotHelper);

// Hemisphere helper

const hemiHelper = new THREE.HemisphereLightHelper(hemiLight, 5);

scene.add(hemiHelper);

// RectAreaLight helper

const rectHelper = new RectAreaLightHelper(rectLight);

rectLight.add(rectHelper);

// Update helpers when light changes

dirHelper.update();

spotHelper.update();

Environment Lighting (IBL)

Image-Based Lighting using HDR environment maps.

import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

const rgbeLoader = new RGBELoader();

rgbeLoader.load("environment.hdr", (texture) => {

  texture.mapping = THREE.EquirectangularReflectionMapping;

  // Set as scene environment (affects all PBR materials)

  scene.environment = texture;

  // Optional: also use as background

  scene.background = texture;

  scene.backgroundBlurriness = 0; // 0-1, blur the background

  scene.backgroundIntensity = 1;

});

// PMREMGenerator for better reflections

const pmremGenerator = new THREE.PMREMGenerator(renderer);

pmremGenerator.compileEquirectangularShader();

rgbeLoader.load("environment.hdr", (texture) => {

  const envMap = pmremGenerator.fromEquirectangular(texture).texture;

  scene.environment = envMap;

  texture.dispose();

  pmremGenerator.dispose();

});

Cube Texture Environment

const cubeLoader = new THREE.CubeTextureLoader();

const envMap = cubeLoader.load([

  "px.jpg",

  "nx.jpg",

  "py.jpg",

  "ny.jpg",

  "pz.jpg",

  "nz.jpg",

]);

scene.environment = envMap;

scene.background = envMap;

Light Probes (Advanced)

Capture lighting from a point in space for ambient lighting.

import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js";

// Generate from cube texture

const lightProbe = new THREE.LightProbe();

scene.add(lightProbe);

lightProbe.copy(LightProbeGenerator.fromCubeTexture(cubeTexture));

// Or from render target

const cubeCamera = new THREE.CubeCamera(

  0.1,

  100,

  new THREE.WebGLCubeRenderTarget(256),

);

cubeCamera.update(renderer, scene);

lightProbe.copy(

  LightProbeGenerator.fromCubeRenderTarget(renderer, cubeCamera.renderTarget),

);

Common Lighting Setups

Three-Point Lighting

// Key light (main light)

const keyLight = new THREE.DirectionalLight(0xffffff, 1);

keyLight.position.set(5, 5, 5);

scene.add(keyLight);

// Fill light (softer, opposite side)

const fillLight = new THREE.DirectionalLight(0xffffff, 0.5);

fillLight.position.set(-5, 3, 5);

scene.add(fillLight);

// Back light (rim lighting)

const backLight = new THREE.DirectionalLight(0xffffff, 0.3);

backLight.position.set(0, 5, -5);

scene.add(backLight);

// Ambient fill

const ambient = new THREE.AmbientLight(0x404040, 0.3);

scene.add(ambient);

Outdoor Daylight

// Sun

const sun = new THREE.DirectionalLight(0xffffcc, 1.5);

sun.position.set(50, 100, 50);

sun.castShadow = true;

scene.add(sun);

// Sky ambient

const hemi = new THREE.HemisphereLight(0x87ceeb, 0x8b4513, 0.6);

scene.add(hemi);

Indoor Studio

// Multiple area lights

RectAreaLightUniformsLib.init();

const light1 = new THREE.RectAreaLight(0xffffff, 5, 2, 2);

light1.position.set(3, 3, 3);

light1.lookAt(0, 0, 0);

scene.add(light1);

const light2 = new THREE.RectAreaLight(0xffffff, 3, 2, 2);

light2.position.set(-3, 3, 3);

light2.lookAt(0, 0, 0);

scene.add(light2);

// Ambient fill

const ambient = new THREE.AmbientLight(0x404040, 0.2);

scene.add(ambient);

Light Animation

const clock = new THREE.Clock();

function animate() {

  const time = clock.getElapsedTime();

  // Orbit light around scene

  light.position.x = Math.cos(time) * 5;

  light.position.z = Math.sin(time) * 5;

  // Pulsing intensity

  light.intensity = 1 + Math.sin(time * 2) * 0.5;

  // Color cycling

  light.color.setHSL((time * 0.1) % 1, 1, 0.5);

  // Update helpers if using

  lightHelper.update();

}

Performance Tips

  • Limit light count: Each light adds shader complexity
  • Use baked lighting: For static scenes, bake to textures
  • Smaller shadow maps: 512-1024 often sufficient
  • Tight shadow frustums: Only cover needed area
  • Disable unused shadows: Not all lights need shadows
  • Use light layers: Exclude objects from certain lights
// Light layers

light.layers.set(1); // Light only affects layer 1

mesh.layers.enable(1); // Mesh is on layer 1

otherMesh.layers.disable(1); // Other mesh not affected

// Selective shadows

mesh.castShadow = true;

mesh.receiveShadow = true;

decorMesh.castShadow = false; // Small objects often don't need to cast

See Also

  • threejs-materials - Material light response
  • threejs-textures - Lightmaps and environment maps
  • threejs-postprocessing - Bloom and other light effects
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card