Modern web browsers are incredibly powerful, possessing direct access to the computer's Graphics Processing Unit (GPU) via the WebGL API. However, writing raw WebGL is notoriously difficult—requiring hundreds of lines of complex matrix mathematics just to draw a colored triangle. Three.js is a library that abstracts this complexity, allowing developers to build complex 3D scenes, lighting models, and animations using an intuitive object-oriented API.


Module 1: The Three Pillars of a 3D World

Every Three.js application requires three core components to render anything to the screen: The Scene, The Camera, and The Renderer.

scene.jsjavascript
import * as THREE from 'three';

// 1. The Scene Graph: The container that holds all objects, lights, and cameras.
const scene = new THREE.Scene();
// Optional: Add a background color or fog
scene.background = new THREE.Color(0x111111);
scene.fog = new THREE.FogExp2(0x111111, 0.02);

// 2. The Camera: Defines the perspective from which the user views the scene.
// Params: Field of View (FOV), Aspect Ratio, Near Clipping Plane, Far Clipping Plane
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 10); // Move camera back 10 units and up 2 units

// 3. The Renderer: The WebGL engine that computes the pixels and draws to the HTML <canvas>.
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
renderer.setSize(window.innerWidth, window.innerHeight);
// Enable physically accurate shadows
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);

Module 2: Meshes (Geometry + Materials)

A 3D object in Three.js is called a Mesh. A Mesh is composed of two things: Geometry (the mathematical skeleton defined by vertices and faces) and a Material (the skin that defines how it reacts to light).

mesh.jsjavascript
// Create a complex geometry (a knot)
const geometry = new THREE.TorusKnotGeometry(1, 0.3, 100, 16);

// Create a Physically Based Rendering (PBR) material
const material = new THREE.MeshStandardMaterial({
  color: 0xff0055,
  metalness: 0.8,    // Looks like metal
  roughness: 0.2,    // Slightly shiny
  envMapIntensity: 1 // Reflects the environment
});

const torusKnot = new THREE.Mesh(geometry, material);
// Enable shadows for this specific object
torusKnot.castShadow = true;
torusKnot.receiveShadow = true;

scene.add(torusKnot);

Module 3: Lighting Architecture

Without light, MeshStandardMaterial objects are entirely black. Lighting defines the mood and realism of your scene.

lighting.jsjavascript
// Ambient Light: Illuminates all objects equally from all sides. Casts no shadows.
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);

// Directional Light: Mimics the sun. Parallel rays originating from infinity.
const sunLight = new THREE.DirectionalLight(0xffffff, 1.5);
sunLight.position.set(10, 20, 10);
sunLight.castShadow = true;
// Optimize the shadow map resolution for performance
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
scene.add(sunLight);

// Point Light: Mimics a lightbulb. Emits light in all directions from a point.
const pointLight = new THREE.PointLight(0x00aaff, 2, 50);
pointLight.position.set(-5, 5, 0);
scene.add(pointLight);

Module 4: The Animation Loop & Controls

To make the scene interactive and animated, we create a render loop hooked into the browser's refresh rate.

loop.jsjavascript
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Add mouse controls to rotate, zoom, and pan the camera
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // Adds smooth friction

const clock = new THREE.Clock();

function animate() {
  requestAnimationFrame(animate);
  
  const elapsedTime = clock.getElapsedTime();

  // Rotate the object smoothly over time
  torusKnot.rotation.y = elapsedTime * 0.5;
  torusKnot.rotation.x = elapsedTime * 0.2;

  // Update controls for damping
  controls.update();

  // Render the final frame
  renderer.render(scene, camera);
}

animate();

Module 5: Advanced — Custom GLSL Shaders

Standard materials are pre-compiled by Three.js. If you want completely custom visual effects (like a glowing magical portal, flowing water, or dissolving particles), you must write your own shaders using GLSL (OpenGL Shading Language). Shaders run directly on the GPU in parallel across millions of pixels simultaneously.

shader.jsjavascript
const customShaderMaterial = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 }, // Passed from the JS animation loop
    uColor: { value: new THREE.Color(0x00ffff) }
  },
  
  // Vertex Shader: Runs once for every vertex. Used to deform shapes.
  vertexShader: `
    uniform float uTime;
    varying vec2 vUv;
    
    void main() {
      vUv = uv;
      vec3 newPosition = position;
      // Add a wave effect to the geometry based on time and the X coordinate
      newPosition.z += sin(newPosition.x * 10.0 + uTime) * 0.1;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
    }
  `,
  
  // Fragment Shader: Runs once for every pixel. Used to color the geometry.
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    
    void main() {
      // Create a scrolling neon stripe effect
      float strength = sin(vUv.y * 20.0 + uTime * 5.0);
      vec3 finalColor = mix(vec3(0.0), uColor, strength);
      gl_FragColor = vec4(finalColor, 1.0);
    }
  `
});