# three.js Administrator & Developer Guide

This guide covers the architecture, internals, build systems, performance tuning, and contribution workflow for **three.js v0.184.0** (revision r184). It is written for developers maintaining, extending, or deploying applications built on three.js. For usage tutorials, installation walkthroughs, and feature overviews, see the [User Guide](/guides/mrdoob/three.js/user-guide/).

---

## 1. Architecture Overview

three.js is a JavaScript 3D graphics library that creates and renders 3D scenes using WebGL and WebGPU. The library follows a scene-graph architecture where all renderable objects inherit from `Object3D` and are organized in a tree rooted at a `Scene` instance. A `Camera` defines the viewpoint, and a `Renderer` traverses the scene graph to produce frames.

### 1.1 High-Level Architecture

```
Application Code
       │
       ▼
┌──────────────────────────────────────────────┐
│  Scene Graph (Object3D tree)                 │
│  ├── Mesh (BufferGeometry + Material)        │
│  ├── Light (DirectionalLight, PointLight...) │
│  ├── Camera (PerspectiveCamera, Ortho...)    │
│  ├── Group, LOD, InstancedMesh, BatchedMesh  │
│  └── Audio, Sprite, Line, Points, Bone...    │
└──────────────────────────────┬───────────────┘
                               │
                    ┌──────────▼──────────┐
                    │     Renderer        │
                    │  ┌───────────────┐  │
                    │  │ WebGLRenderer │  │  (Legacy path)
                    │  └───────────────┘  │
                    │  ┌───────────────┐  │
                    │  │ WebGPURenderer│  │  (Modern path)
                    │  │  ├─ WebGPU   │  │
                    │  │  └─ WebGL    │  │  (fallback backend)
                    │  └───────────────┘  │
                    └─────────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │   GPU / Canvas      │
                    └─────────────────────┘
```

### 1.2 Dual Renderer Strategy

three.js maintains two rendering paths:

| Path | Entry | Renderer | Shader Language | Status |
|------|-------|----------|-----------------|--------|
| Legacy | `three` (default import) | `WebGLRenderer` | GLSL | Stable, widely deployed |
| Modern | `three/webgpu` | `WebGPURenderer` | WGSL (via TSL) | Active development |

The modern path uses a **backend abstraction layer** (`src/renderers/common/`) that allows `WebGPURenderer` to run on either the native WebGPU API or fall back to WebGL via `WebGLBackend`. This is distinct from the legacy `WebGLRenderer`, which directly manages WebGL state.

### 1.3 Core Design Patterns

- **Scene graph**: Tree of `Object3D` nodes with parent/child relationships, local and world transforms
- **Component composition**: Objects combine geometry (`BufferGeometry`) with appearance (`Material`)
- **Event system**: `EventDispatcher` mixin provides `addEventListener`/`removeEventListener`/`dispatchEvent` on all major classes
- **Clone/copy pattern**: Every class implements `clone()` (returns new instance) and `copy()` (copies into existing instance)
- **Serialization**: `toJSON()` on Object3D, Material, BufferGeometry, Texture produces a portable JSON format; `ObjectLoader` reconstructs
- **Dispose pattern**: GPU resources require explicit `dispose()` calls (geometry, material, texture, render target, renderer)
- **DataMap pattern**: The common renderer infrastructure uses `DataMap` instances to associate internal GPU state with user-facing objects without polluting their properties

> [!NOTE]
> three.js has **zero runtime dependencies**. All 5,875 source files are self-contained. Every package listed in `package.json` is a devDependency used only for building, testing, or documentation generation.

### 1.4 Module Organization

The library is organized into a strict module hierarchy:

```
src/
├── Three.Core.js        ← Barrel export for the WebGL path (default "three" import)
├── Three.TSL.js         ← Re-exports for the TSL node shading language
├── Three.WebGPU.js      ← Barrel export for WebGPU path ("three/webgpu")
├── constants.js         ← All enumerations and constant values
└── utils.js             ← Console output helpers (warn/error deduplication)
```

The `exports` field in `package.json` defines the public API surface:

| Import Path | Resolves To | Purpose |
|---|---|---|
| `three` | `build/three.module.js` | Core library (WebGL renderer) |
| `three/webgpu` | `build/three.webgpu.js` | WebGPU renderer + TSL |
| `three/tsl` | `build/three.tsl.js` | TSL shader language only |
| `three/addons` | `examples/jsm/Addons.js` | All addon modules |
| `three/addons/*` | `examples/jsm/*` | Individual addons |
| `three/src/*` | `src/*` | Raw source modules |

---

## 2. System Requirements

### 2.1 Runtime Requirements

| Requirement | Minimum | Recommended |
|---|---|---|
| Browser (WebGL) | Chrome 80+, Firefox 78+, Safari 14+, Edge 80+ | Latest stable |
| Browser (WebGPU) | Chrome 113+, Firefox 141+ (behind flag), Safari 18+ | Chrome latest |
| WebGL version | WebGL 2.0 | WebGL 2.0 |
| JavaScript | ES2015 (ES6) modules | ES2022 |
| Node.js (SSR/build) | 14+ | 18+ LTS |

> [!WARNING]
> WebGL 1 has not been supported since r163. Attempting to create a `WebGLRenderer` in a WebGL 1-only context will throw: `"THREE.WebGLRenderer: WebGL 1 is not supported since r163."` There is no fallback.

### 2.2 Development Requirements

| Tool | Version | Purpose |
|---|---|---|
| Node.js | 18+ | Build, test, dev server |
| npm | 8+ | Package management |
| Rollup | 4.6+ | Module bundling |
| ESLint | 9.0+ | Code linting |
| QUnit | 2.19+ | Unit testing |
| Puppeteer | 24+ | E2E screenshot testing |
| JSDoc | 4.0+ | Documentation generation |

### 2.3 Hardware Considerations

| Scenario | GPU | Notes |
|---|---|---|
| Basic scenes | Integrated GPU | Adequate for simple geometry, few lights |
| Complex scenes | Dedicated GPU | Required for heavy instancing, post-processing, shadows |
| WebGPU compute | Modern discrete GPU | Compute shaders require WebGPU-capable hardware |
| Mobile | Varies | Reduce draw calls, texture sizes, shadow map resolution |

---

## 3. Configuration Reference

three.js has no configuration files. All configuration is programmatic, passed through constructor options and property assignment.

> [!IMPORTANT]
> There are zero extractable config keys. Configuration is entirely programmatic through renderer constructor options, material properties, and scene settings. The subsections below document every configurable surface.

### 3.1 WebGLRenderer Constructor Options

```javascript
const renderer = new THREE.WebGLRenderer({
  canvas,                       // HTMLCanvasElement — existing canvas to render into
  context,                      // WebGL2RenderingContext — existing GL context
  precision,                    // "highp" | "mediump" | "lowp" — shader precision
  alpha,                        // boolean — transparent canvas (default false)
  premultipliedAlpha,           // boolean — premultiplied alpha (default true)
  antialias,                    // boolean — MSAA (default false)
  stencil,                      // boolean — stencil buffer (default true)
  preserveDrawingBuffer,        // boolean — keep frame buffer for screenshots (default false)
  powerPreference,              // "default" | "high-performance" | "low-power"
  failIfMajorPerformanceCaveat, // boolean — fail if software rendering (default false)
  logarithmicDepthBuffer        // boolean — logarithmic depth (default false)
});
```

### 3.2 WebGLRenderer Runtime Properties

| Property | Type | Default | Description |
|---|---|---|---|
| `shadowMap.enabled` | boolean | `false` | Enable shadow mapping |
| `shadowMap.type` | constant | `PCFShadowMap` | `BasicShadowMap`, `PCFShadowMap`, `PCFSoftShadowMap`, `VSMShadowMap` |
| `toneMapping` | constant | `NoToneMapping` | `LinearToneMapping`, `ReinhardToneMapping`, `CineonToneMapping`, `ACESFilmicToneMapping`, `AgXToneMapping`, `NeutralToneMapping` |
| `toneMappingExposure` | number | `1.0` | Exposure level for tone mapping |
| `outputColorSpace` | string | `SRGBColorSpace` | Output color space |
| `autoClear` | boolean | `true` | Clear before each render |
| `autoClearColor` | boolean | `true` | Clear color buffer |
| `autoClearDepth` | boolean | `true` | Clear depth buffer |
| `autoClearStencil` | boolean | `true` | Clear stencil buffer |
| `sortObjects` | boolean | `true` | Sort transparent objects |
| `localClippingEnabled` | boolean | `false` | Enable per-material clipping planes |

### 3.3 WebGPURenderer Initialization

```javascript
import { WebGPURenderer } from 'three/webgpu';

const renderer = new WebGPURenderer();
await renderer.init();  // REQUIRED — async initialization
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
```

> [!IMPORTANT]
> `WebGPURenderer` requires asynchronous initialization via `await renderer.init()`. Calling `render()` before `init()` completes will throw an error. The WebGPU path also falls back to `WebGLBackend` automatically when WebGPU is unavailable.

### 3.4 Scene Configuration

```javascript
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);    // Color, Texture, or null
scene.environment = envTexture;                   // Texture for IBL (image-based lighting)
scene.fog = new THREE.Fog(0xcccccc, 10, 100);    // Linear fog: color, near, far
scene.fog = new THREE.FogExp2(0xcccccc, 0.002);  // Exponential fog: color, density
scene.backgroundBlurriness = 0.0;                // 0-1, blur background texture
scene.backgroundIntensity = 1.0;                 // Background brightness multiplier
scene.backgroundRotation = new THREE.Euler();    // Rotate background
scene.overrideMaterial = material;               // Force all objects to use this material
```

### 3.5 Constants and Enumerations

All constants are defined in `src/constants.js`. Key groups:

| Group | Constants |
|---|---|
| Side | `FrontSide`, `BackSide`, `DoubleSide` |
| Blending | `NoBlending`, `NormalBlending`, `AdditiveBlending`, `SubtractiveBlending`, `MultiplyBlending`, `CustomBlending` |
| Depth | `NeverDepth`, `AlwaysDepth`, `LessDepth`, `LessEqualDepth`, `EqualDepth`, `GreaterEqualDepth`, `GreaterDepth`, `NotEqualDepth` |
| Texture Wrapping | `RepeatWrapping`, `ClampToEdgeWrapping`, `MirroredRepeatWrapping` |
| Texture Filtering | `NearestFilter`, `LinearFilter`, `NearestMipmapNearestFilter`, `NearestMipmapLinearFilter`, `LinearMipmapNearestFilter`, `LinearMipmapLinearFilter` |
| Texture Format | `AlphaFormat`, `RGBAFormat`, `RGBFormat`, `RedFormat`, `RGFormat`, `RedIntegerFormat`, `RGIntegerFormat`, `RGBAIntegerFormat`, `DepthFormat`, `DepthStencilFormat` |
| Texture Type | `UnsignedByteType`, `FloatType`, `HalfFloatType`, `UnsignedIntType`, `IntType`, `ByteType`, `ShortType`, `UnsignedShortType` |
| Encoding | `SRGBColorSpace`, `LinearSRGBColorSpace`, `DisplayP3ColorSpace`, `LinearDisplayP3ColorSpace` |
| Shadow Map | `BasicShadowMap`, `PCFShadowMap`, `PCFSoftShadowMap`, `VSMShadowMap` |
| Tone Mapping | `NoToneMapping`, `LinearToneMapping`, `ReinhardToneMapping`, `CineonToneMapping`, `ACESFilmicToneMapping`, `AgXToneMapping`, `NeutralToneMapping` |
| Coordinate System | `WebGLCoordinateSystem`, `WebGPUCoordinateSystem` |

### 3.6 Material Configuration Matrix

Common properties shared across all material types:

| Property | Type | Default | Description |
|---|---|---|---|
| `color` | Color | `0xffffff` | Base color |
| `map` | Texture | `null` | Color map texture |
| `opacity` | number | `1.0` | Overall opacity (requires `transparent: true` for <1) |
| `transparent` | boolean | `false` | Enable alpha blending |
| `side` | constant | `FrontSide` | Which face sides to render |
| `depthTest` | boolean | `true` | Enable depth testing |
| `depthWrite` | boolean | `true` | Write to depth buffer |
| `blending` | constant | `NormalBlending` | Blending mode |
| `wireframe` | boolean | `false` | Render as wireframe |
| `flatShading` | boolean | `false` | Flat (faceted) shading |
| `fog` | boolean | `true` | Affected by scene fog |
| `visible` | boolean | `true` | Whether to render |

**MeshPhysicalMaterial** advanced PBR properties (extends MeshStandardMaterial):

| Property | Type | Default | Description |
|---|---|---|---|
| `clearcoat` | number | `0.0` | Clearcoat layer intensity |
| `clearcoatRoughness` | number | `0.0` | Clearcoat roughness |
| `transmission` | number | `0.0` | Optical transmission (glass) |
| `ior` | number | `1.5` | Index of refraction |
| `thickness` | number | `0.0` | Volume thickness for transmission |
| `attenuationColor` | Color | `0xffffff` | Volume absorption color |
| `attenuationDistance` | number | `Infinity` | Volume absorption distance |
| `sheen` | number | `0.0` | Sheen layer intensity |
| `sheenColor` | Color | `0x000000` | Sheen tint |
| `sheenRoughness` | number | `1.0` | Sheen roughness |
| `iridescence` | number | `0.0` | Iridescence intensity |
| `anisotropy` | number | `0.0` | Anisotropic reflection strength |
| `dispersion` | number | `0.0` | Chromatic dispersion |
| `specularIntensity` | number | `1.0` | Specular reflection strength |
| `specularColor` | Color | `0xffffff` | Specular tint |

---

## 4. Deployment & Scaling

### 4.1 Bundling for Production

three.js is published as ES modules. The recommended build approach:

```javascript
// Import only what you need — tree-shaking removes the rest
import { Scene, PerspectiveCamera, WebGLRenderer, BoxGeometry,
         MeshStandardMaterial, Mesh, DirectionalLight } from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
```

**Rollup** (used by three.js itself):
```javascript
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';

export default {
  input: 'src/main.js',
  output: { file: 'dist/bundle.js', format: 'es' },
  plugins: [resolve(), terser()]
};
```

**Webpack**, **Vite**, **esbuild**, and **Parcel** all support three.js out of the box via the `module` and `exports` fields in `package.json`.

### 4.2 Tree-Shaking

three.js declares `"sideEffects": ["./src/nodes/**/*"]` in `package.json`. This tells bundlers that all modules except the node system are side-effect-free and can be safely eliminated when unused.

The tree-shaking test (`npm run test-treeshake`) verifies that importing individual classes does not pull in the entire library:

```bash
npm run test-treeshake   # rollup -c test/rollup.treeshake.config.js
```

**Best practices for minimal bundles:**

1. Import from `three` (not `three/src/*`) for optimized builds
2. Import addons individually: `three/addons/controls/OrbitControls.js` rather than `three/addons`
3. Avoid importing `three/webgpu` unless WebGPU features are needed (pulls in the entire node system)
4. Use `MeshBasicMaterial` or `MeshLambertMaterial` when PBR is unnecessary

### 4.3 CDN Deployment

For quick prototyping or non-bundled deployments:

```html
<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/"
  }
}
</script>
<script type="module">
  import * as THREE from 'three';
  import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>
```

> [!WARNING]
> Always pin a specific version when using CDNs (`@0.184.0`). three.js frequently has breaking changes between releases. The `latest` tag can silently break production applications.

### 4.4 Multiple Instances Detection

three.js detects when multiple copies are loaded and emits a console warning. This commonly occurs when:

- Dependencies bundle their own copy of three.js
- Import maps resolve to a different URL than `node_modules`
- Both CJS (`three.cjs`) and ESM (`three.module.js`) are loaded

The detection uses the global `__THREE_DEVTOOLS__` symbol.

### 4.5 Performance Scaling Strategies

| Technique | When to Use | Implementation |
|---|---|---|
| `InstancedMesh` | 100+ identical objects | Single draw call for all instances |
| `BatchedMesh` | Multiple geometries, fewer draw calls | Multi-draw batching API |
| `LOD` | Large scenes with distant objects | Automatic detail level switching |
| `WebGPURenderer` | Compute-heavy, modern browsers | Async init, compute shaders |
| Texture atlasing | Many small textures | Combine into single texture, adjust UVs |
| Geometry merging | Static scenes | `BufferGeometryUtils.mergeGeometries()` |
| Frustum culling | Default (automatic) | `object.frustumCulled = true` (default) |
| Layers | Selective rendering | 32-layer bitmask on objects and cameras |

---

## 5. Operations

### 5.1 Build System

three.js uses Rollup for building distributable bundles.

```bash
# Full build (all formats)
npm run build
# → rollup -c utils/build/rollup.config.js
# Produces: build/three.cjs, build/three.module.js,
#           build/three.webgpu.js, build/three.tsl.js

# ES module only (faster)
npm run build-module
# → rollup -c utils/build/rollup.config.js --configOnlyModule
```

The build configuration lives at `utils/build/rollup.config.js` and uses:
- `@rollup/plugin-node-resolve` for module resolution
- `@rollup/plugin-terser` for minification

> [!TIP]
> During development, use `npm start` (alias: `npm run dev`) which runs `node utils/build/dev.js && node utils/server.js -p 8080`. This builds incrementally and starts a local development server on port 8080.

### 5.2 Development Server

```bash
npm start
# Equivalent to: node utils/build/dev.js && node utils/server.js -p 8080
```

The dev server (`utils/server.js`) serves the project root, making examples accessible at `http://localhost:8080/examples/`.

### 5.3 Testing

three.js has three testing tiers:

#### Unit Tests (QUnit)

```bash
# Core library tests
npm run test-unit
# → qunit test/unit/three.source.unit.js

# Addon tests
npm run test-unit-addons
# → qunit test/unit/three.addons.unit.js

# Both (plus lint)
npm test
# → npm run lint && npm run test-unit && npm run test-unit-addons
```

Unit tests live in `test/unit/` and follow the same directory structure as `src/`. Each class has a corresponding test file.

#### E2E Screenshot Tests (Puppeteer)

```bash
# Run against WebGL
npm run test-e2e
# → node test/e2e/puppeteer.js

# Run against WebGPU
npm run test-e2e-webgpu
# → node test/e2e/puppeteer.js --webgpu

# Generate new reference screenshots
npm run make-screenshot
# → node test/e2e/puppeteer.js --make
```

E2E tests render examples with Puppeteer and compare screenshots pixel-by-pixel using `pngjs` and `jpeg-js`. Reference images are stored alongside tests.

#### Tree-Shaking Verification

```bash
npm run test-treeshake
# → rollup -c test/rollup.treeshake.config.js
```

Validates that tree-shaking works correctly and unused code is eliminated.

> [!NOTE]
> The full test suite (`npm test`) runs linting first, then unit tests. E2E tests are separate because they require a running browser and are slower. CI pipelines should run `npm test` for fast feedback and `npm run test-e2e` as a secondary step.

### 5.4 Linting

```bash
# Lint core source
npm run lint
# → npm run lint-core (eslint src)

# Auto-fix all directories
npm run lint-fix
```

ESLint configuration (`eslint.config.js`):
- ECMAScript 2022, source type: module
- Browser + Node + ES2017 globals
- Custom globals for three.js ecosystem: `__THREE_DEVTOOLS__`, `potpack`, `fflate`, `Stats`, GPU/XR prefixed globals
- Key enforced rules:
  - `no-throw-literal: error` — must throw Error objects
  - `quotes: single` — single quotes everywhere
  - `prefer-const` — use `const` when variable is never reassigned
  - `no-duplicate-imports` — combine imports from same module
  - `prefer-spread` — use spread over `.apply()`
- JSDoc rules: `check-types: error`, `require-param-type: error`, `require-returns-type: error`
- Ignored directories: `node_modules`, `build`, `libs` (vendored: acorn, codemirror, ternjs, esprima, jsonlint, signals), `3rdparty`, `vendor`

### 5.5 Documentation Generation

```bash
# Build API docs + LLM-friendly docs
npm run build-docs
# → jsdoc -c utils/docs/jsdoc.config.json && npm run build-llms

# LLM docs only
npm run build-llms
# → node utils/llms/build.js
```

The API documentation site source lives in `docs/` and is built with JSDoc using the config at `utils/docs/jsdoc.config.json`. The `build-llms` step generates LLM-optimized documentation via `utils/llms/build.js`.

### 5.6 Preview Builds

```bash
npm run preview
# → node utils/build/preview.js
```

Generates preview builds for testing changes before a full build.

---

## 6. Performance

### 6.1 Draw Call Optimization

Draw calls are the primary performance bottleneck in WebGL/WebGPU rendering. three.js provides several mechanisms to reduce them:

**InstancedMesh** — renders many copies of the same geometry+material in a single draw call:

```javascript
const mesh = new THREE.InstancedMesh(geometry, material, count);
// Set transforms for each instance
const matrix = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
  matrix.setPosition(x, y, z);
  mesh.setMatrixAt(i, matrix);
}
mesh.instanceMatrix.needsUpdate = true;

// Optional per-instance color
mesh.setColorAt(i, new THREE.Color(0xff0000));
mesh.instanceColor.needsUpdate = true;
```

**BatchedMesh** — multi-draw batching for mixed geometries:

```javascript
const batchedMesh = new BatchedMesh(maxInstanceCount, maxVertexCount, maxIndexCount);
const geoId = batchedMesh.addGeometry(geometry);
const instanceId = batchedMesh.addInstance(geoId);
batchedMesh.setMatrixAt(instanceId, matrix);
```

> [!CAUTION]
> `BatchedMesh` enforces strict limits. Exceeding `maxInstanceCount`, `maxVertexCount`, or `maxIndexCount` throws validation errors. Pre-calculate your maximums and add headroom. Error messages include: "THREE.BatchedMesh: Maximum item count reached" and "THREE.BatchedMesh: %.reservedSpace exceeded".

**Geometry Merging** — for completely static scenes:

```javascript
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
const merged = mergeGeometries([geo1, geo2, geo3]);
// Results in a single Mesh with one draw call
```

### 6.2 Memory Management

three.js does not automatically release GPU resources. Every GPU-backed object must be explicitly disposed:

```javascript
// Geometry
geometry.dispose();

// Material (and its textures)
material.dispose();
material.map?.dispose();
material.normalMap?.dispose();
material.envMap?.dispose();
// ... all texture properties

// Render targets
renderTarget.dispose();

// Renderer (releases all GPU resources)
renderer.dispose();
```

**Common memory leak pattern:**

```javascript
// BAD: Creates new geometry every frame
function animate() {
  const geo = new THREE.BoxGeometry(1, 1, 1);
  mesh.geometry = geo;  // Old geometry leaked!
}

// GOOD: Reuse or dispose
function animate() {
  mesh.geometry.dispose();
  mesh.geometry = new THREE.BoxGeometry(1, 1, 1);
}
```

### 6.3 Texture Optimization

| Technique | Impact | Implementation |
|---|---|---|
| Power-of-two textures | Avoids GPU padding | Use 256, 512, 1024, 2048 px dimensions |
| Compressed textures | 4-8x memory reduction | Use KTX2Loader with Basis Universal |
| Mipmaps | Better minification quality | Enabled by default for power-of-two |
| `texture.generateMipmaps` | Save VRAM for UI textures | Set `false` for non-3D textures |
| `texture.anisotropy` | Quality vs. performance | Set to `renderer.capabilities.getMaxAnisotropy()` for best quality |

### 6.4 Shadow Map Performance

Shadow mapping is one of the most expensive operations. Configuration choices significantly impact performance:

| Shadow Map Type | Quality | Cost | Notes |
|---|---|---|---|
| `BasicShadowMap` | Low | Lowest | Hard edges, fast |
| `PCFShadowMap` | Medium | Medium | Default, filtered edges |
| `PCFSoftShadowMap` | High | High | Softer edges, more samples |
| `VSMShadowMap` | High | Highest | Variance shadow maps, supports blurring |

Optimization strategies:
- Limit `shadow.mapSize` (512 for distant lights, 2048 maximum for hero lights)
- Set tight `shadow.camera.near`/`shadow.camera.far` bounds
- Disable shadows on objects that don't need them (`castShadow = false`, `receiveShadow = false`)
- Use `shadow.autoUpdate = false` for static scenes, call `shadow.needsUpdate = true` only when the scene changes

### 6.5 Frustum Culling and Layers

**Frustum culling** is enabled by default (`object.frustumCulled = true`). Objects outside the camera's view frustum are skipped during rendering. For objects with expensive bounding sphere calculations or known visibility, disable selectively.

**Layers** provide a 32-channel bitmask system for selective rendering and raycasting:

```javascript
// Assign object to layer 1
mesh.layers.set(1);

// Camera sees only layer 1
camera.layers.set(1);

// Enable multiple layers
camera.layers.enable(0);
camera.layers.enable(1);

// Raycaster respects layers
raycaster.layers.set(1);
```

### 6.6 Level of Detail (LOD)

```javascript
const lod = new THREE.LOD();
lod.addLevel(highDetailMesh, 0);     // Used when distance < 50
lod.addLevel(mediumDetailMesh, 50);  // Used when distance < 200
lod.addLevel(lowDetailMesh, 200);    // Used when distance >= 200
scene.add(lod);
```

LOD automatically switches between detail levels based on camera distance, computed each frame during `lod.update(camera)`.

### 6.7 Animation Performance

- Use `AnimationMixer.update(delta)` with the actual frame delta, not a fixed timestep
- Disable animations when objects are off-screen
- For large numbers of animated objects, consider skeletal animation with `SkinnedMesh`/`Bone`/`Skeleton` over per-vertex animation
- `AnimationAction.setEffectiveWeight(0)` stops a blended action from consuming CPU without removing it

### 6.8 WebGPU Performance Advantages

The WebGPU path offers performance improvements over WebGL for specific workloads:

- **Compute shaders**: Offload particle systems, physics, or mesh operations to the GPU via `renderer.compute()`
- **Reduced CPU overhead**: Better command batching and pipeline state caching
- **Render bundles**: `RenderBundle` reduces per-frame JavaScript overhead for static scene portions

---

## 7. Security

### 7.1 WebGL/WebGPU Context Security

> [!WARNING]
> WebGL and WebGPU execute code on the GPU. While browser sandboxing limits direct system access, several attack vectors exist that three.js applications should mitigate.

**Context loss**: WebGL contexts can be lost due to GPU driver crashes, system resource pressure, or malicious pages. Handle gracefully:

```javascript
renderer.domElement.addEventListener('webglcontextlost', (event) => {
  event.preventDefault();
  // Pause rendering, show user message
});

renderer.domElement.addEventListener('webglcontextrestored', () => {
  // Reinitialize resources
});
```

### 7.2 Cross-Origin Resource Loading

three.js loaders fetch external resources (textures, models, audio). Cross-origin requests are subject to CORS:

```javascript
const loader = new THREE.TextureLoader();
loader.crossOrigin = 'anonymous';  // Required for cross-origin textures

// For loaders using LoadingManager
const manager = new THREE.LoadingManager();
manager.crossOrigin = 'anonymous';
```

**Security considerations:**
- Textures loaded cross-origin without CORS headers will taint the canvas, preventing `toDataURL()` and `readPixels()`
- `preserveDrawingBuffer: true` is required for screenshots but exposes frame content to JavaScript
- Model files (GLTF, OBJ, FBX) can reference external textures — validate URLs in user-submitted content

### 7.3 User-Generated Content

When loading user-provided 3D models or scenes:

> [!WARNING]
> `ObjectLoader.parse()` can reconstruct arbitrary three.js scenes from JSON, including custom shader code in `ShaderMaterial`. Never load untrusted scene JSON without sandboxing.

- **Shader injection**: `ShaderMaterial` and `RawShaderMaterial` accept arbitrary GLSL/WGSL. Sanitize or reject user-provided shader code
- **Resource exhaustion**: Malicious models can contain extremely high polygon counts or massive textures. Validate geometry vertex counts and texture dimensions before loading
- **External references**: GLTF files can embed `data:` URIs or reference external URLs. Audit loaded resources
- **Script execution**: The three.js Editor supports embedded scripts via its script editor (using esprima for parsing). Never expose the editor to untrusted users without sandboxing

### 7.4 Timing Attacks

WebGL's `readPixels()` and timing of draw calls can theoretically leak cross-origin image data. Modern browsers mitigate this, but avoid rendering sensitive cross-origin content on the same canvas as user-controlled shaders.

---

## 8. Developer Internals

### 8.1 Repository Structure

```
three.js/
├── src/                         Core library source (ES modules)
│   ├── Three.Core.js            Main barrel export (WebGL path)
│   ├── Three.TSL.js             TSL node system re-exports
│   ├── Three.WebGPU.js          WebGPU path barrel export
│   ├── constants.js             All enumerations
│   ├── utils.js                 Console helpers
│   ├── core/                    Object3D, BufferGeometry, EventDispatcher, etc.
│   ├── renderers/               Rendering engines
│   │   ├── WebGLRenderer.js     Legacy WebGL renderer (~3000 lines)
│   │   ├── common/              Shared renderer infrastructure
│   │   │   ├── Renderer.js      Base class for modern path
│   │   │   ├── Backend.js       GPU backend abstraction
│   │   │   ├── RenderList.js    Render list management
│   │   │   ├── RenderObject.js  Per-object render state
│   │   │   ├── RenderBundle.js  Render bundle support
│   │   │   ├── RenderContext.js Render pass context
│   │   │   ├── DataMap.js       Internal state association
│   │   │   └── PostProcessing.js Post-processing support
│   │   ├── webgl-fallback/      WebGL backend for modern path
│   │   │   └── WebGLBackend.js  WebGL backend implementation
│   │   └── webgpu/              WebGPU backend
│   │       └── WebGPUBackend.js WebGPU backend implementation
│   ├── scenes/                  Scene, Fog, FogExp2
│   ├── cameras/                 Camera types
│   ├── lights/                  Light types + shadow classes
│   ├── materials/               All material types
│   ├── geometries/              All geometry types
│   ├── objects/                 Mesh, Line, Points, Sprite, etc.
│   ├── animation/               AnimationMixer, Clip, Action, Track
│   ├── loaders/                 Loader system + LoadingManager
│   ├── audio/                   Web Audio integration
│   ├── math/                    Vector, Matrix, Quaternion, etc.
│   ├── textures/                Texture types
│   ├── helpers/                 Visual debugging aids
│   ├── extras/                  Controls, Curves, Path, PMREMGenerator
│   └── nodes/                   Node-based shader system (TSL)
│       ├── core/                40+ node types
│       ├── utils/               Utility nodes
│       └── materialx/           MaterialX integration
├── examples/
│   ├── jsm/                     Addon modules (published as three/addons)
│   │   ├── controls/            OrbitControls, FlyControls, etc.
│   │   ├── loaders/             GLTFLoader, DRACOLoader, etc.
│   │   ├── exporters/           GLTFExporter, OBJExporter, etc.
│   │   ├── postprocessing/      EffectComposer, passes
│   │   ├── utils/               BufferGeometryUtils, SceneOptimizer, etc.
│   │   ├── Addons.js            Barrel export for all addons
│   │   └── ...                  Materials, geometries, curves, etc.
│   ├── fonts/                   Font data files (published as three/examples/fonts)
│   ├── models/                  Example 3D models
│   ├── shaders/                 Example shader code
│   └── textures/                Example textures
├── editor/                      Web-based 3D editor
│   ├── index.html               Editor entry point
│   ├── js/                      Editor JavaScript
│   │   ├── Editor.js            Core editor state
│   │   ├── commands/            24 undo/redo command classes
│   │   ├── libs/                UI framework, codemirror, esprima
│   │   └── ...                  Viewport, sidebar, menubar, etc.
│   ├── css/                     Editor styles
│   └── examples/                Editor example scenes
├── devtools/                    Browser devtools extension
├── manual/                      Tutorial content (multi-language)
├── docs/                        API documentation site source
├── test/
│   ├── unit/                    QUnit unit tests
│   ├── e2e/                     Puppeteer screenshot tests
│   └── treeshake/               Tree-shaking verification
├── utils/
│   ├── build/                   Rollup build scripts, dev server
│   │   ├── rollup.config.js     Main build configuration
│   │   ├── dev.js               Development build script
│   │   └── preview.js           Preview build script
│   ├── docs/                    JSDoc config + template
│   ├── llms/                    LLM-friendly docs builder
│   │   └── build.js             LLM docs generation script
│   └── server.js                Development server
├── build/                       Built output (gitignored)
├── package.json                 Zero runtime deps, all devDependencies
├── eslint.config.js             ESLint flat config (ES2022)
└── LICENSE                      MIT
```

### 8.2 Class Hierarchy

three.js contains 411 classes. Below is the complete inheritance hierarchy for all major subsystems.

#### EventDispatcher Tree

`EventDispatcher` is the root mixin for nearly all stateful classes:

```
EventDispatcher
├── Object3D
│   ├── Scene
│   ├── Camera
│   │   ├── PerspectiveCamera
│   │   ├── OrthographicCamera
│   │   ├── ArrayCamera
│   │   ├── StereoCamera
│   │   └── CubeCamera
│   ├── Mesh
│   │   ├── InstancedMesh
│   │   ├── BatchedMesh
│   │   └── SkinnedMesh
│   ├── Line
│   │   ├── LineSegments
│   │   │   └── LineLoop (conceptual, same level)
│   │   └── LineLoop
│   ├── Points
│   ├── Sprite
│   ├── Group
│   │   └── ClippingGroup
│   ├── LOD
│   ├── Bone
│   ├── Light
│   │   ├── AmbientLight
│   │   ├── DirectionalLight
│   │   ├── PointLight
│   │   ├── SpotLight
│   │   ├── HemisphereLight
│   │   ├── RectAreaLight
│   │   └── LightProbe
│   ├── Audio
│   │   └── PositionalAudio
│   └── AudioListener
├── BufferGeometry
│   ├── BoxGeometry
│   ├── SphereGeometry
│   ├── PlaneGeometry
│   ├── CircleGeometry
│   ├── CylinderGeometry
│   ├── ConeGeometry
│   ├── TorusGeometry
│   ├── TorusKnotGeometry
│   ├── RingGeometry
│   ├── CapsuleGeometry
│   ├── DodecahedronGeometry
│   ├── IcosahedronGeometry
│   ├── OctahedronGeometry
│   ├── TetrahedronGeometry
│   ├── PolyhedronGeometry
│   ├── LatheGeometry
│   ├── ExtrudeGeometry
│   ├── ShapeGeometry
│   ├── TubeGeometry
│   ├── EdgesGeometry
│   └── WireframeGeometry
├── Material
│   ├── MeshBasicMaterial
│   ├── MeshLambertMaterial
│   ├── MeshPhongMaterial
│   ├── MeshStandardMaterial
│   │   └── MeshPhysicalMaterial
│   ├── MeshToonMaterial
│   ├── MeshNormalMaterial
│   ├── MeshDepthMaterial
│   ├── MeshDistanceMaterial
│   ├── MeshMatcapMaterial
│   ├── ShaderMaterial
│   │   └── RawShaderMaterial
│   ├── LineBasicMaterial
│   │   └── LineDashedMaterial
│   ├── PointsMaterial
│   ├── SpriteMaterial
│   └── ShadowMaterial
├── Texture
│   ├── CubeTexture
│   ├── CanvasTexture
│   ├── CompressedTexture
│   ├── CompressedArrayTexture
│   ├── Data3DTexture
│   ├── DataArrayTexture
│   ├── DataTexture
│   ├── DepthTexture
│   ├── FramebufferTexture
│   └── VideoTexture
├── Controls (src/extras/Controls.js)
│   └── [addon controls extend this: OrbitControls, etc.]
├── Node (src/nodes/core/Node.js)
│   ├── ArrayNode
│   ├── AssignNode
│   ├── AttributeNode
│   ├── BypassNode
│   ├── ConstNode
│   ├── ContextNode
│   ├── IndexNode
│   ├── InputNode
│   ├── IsolateNode
│   ├── MRTNode
│   ├── OutputStructNode
│   ├── ParameterNode
│   ├── PropertyNode
│   ├── StackNode
│   ├── StructNode
│   ├── TempNode
│   ├── UniformNode
│   ├── VarNode
│   ├── VaryingNode
│   └── [40+ more node types in nodes/utils/, nodes/materialx/]
└── Renderer (src/renderers/common/Renderer.js)
    └── [WebGPURenderer extends this]
```

#### Shadow Hierarchy

```
LightShadow
├── DirectionalLightShadow
├── SpotLightShadow
└── PointLightShadow
```

#### Math Classes (standalone, no inheritance)

```
Vector2, Vector3, Vector4
Matrix2, Matrix3, Matrix4
Quaternion, Euler
Color
Box2, Box3
Sphere, Ray, Plane, Line3, Triangle
Frustum, FrustumArray
Spherical, Cylindrical
SphericalHarmonics3
MathUtils (static utility object)
```

#### Interpolant Hierarchy

```
Interpolant
├── CubicInterpolant
├── LinearInterpolant
├── DiscreteInterpolant
├── QuaternionLinearInterpolant
└── BezierInterpolant
```

#### KeyframeTrack Hierarchy

```
KeyframeTrack
├── BooleanKeyframeTrack
├── ColorKeyframeTrack
├── NumberKeyframeTrack
├── QuaternionKeyframeTrack
├── StringKeyframeTrack
└── VectorKeyframeTrack
```

#### BufferAttribute Typed Variants

```
BufferAttribute
├── Int8BufferAttribute
├── Uint8BufferAttribute
├── Uint8ClampedBufferAttribute
├── Int16BufferAttribute
├── Uint16BufferAttribute
├── Int32BufferAttribute
├── Uint32BufferAttribute
├── Float16BufferAttribute
└── Float32BufferAttribute
```

#### Render Target Hierarchy

```
RenderTarget
├── WebGLRenderTarget
│   ├── WebGL3DRenderTarget
│   ├── WebGLArrayRenderTarget
│   └── WebGLCubeRenderTarget
```

#### Curve Hierarchy

```
Curve
├── CurvePath
│   └── Path
│       └── Shape
├── LineCurve
├── LineCurve3
├── QuadraticBezierCurve
├── QuadraticBezierCurve3
├── CubicBezierCurve
├── CubicBezierCurve3
├── SplineCurve
├── CatmullRomCurve3
├── EllipseCurve
│   └── ArcCurve
```

#### Loader Hierarchy

```
Loader
├── FileLoader
├── TextureLoader
├── ImageLoader
├── ObjectLoader
├── MaterialLoader
├── BufferGeometryLoader
├── AnimationLoader
├── AudioLoader
├── CubeTextureLoader
├── CompressedTextureLoader
├── DataTextureLoader
└── [addon loaders: GLTFLoader, OBJLoader, FBXLoader, etc.]
```

### 8.3 Rendering Pipeline

#### WebGLRenderer Pipeline

The legacy `WebGLRenderer.render(scene, camera)` executes the following sequence:

```
render(scene, camera)
│
├── 1. Update scene graph matrices
│   └── scene.updateMatrixWorld()
│       └── Recursively computes world matrices for all children
│
├── 2. Update camera matrices
│   ├── camera.updateMatrixWorld()
│   └── camera.matrixWorldInverse = inverse(camera.matrixWorld)
│
├── 3. Project objects (frustum culling + sorting)
│   ├── Traverse scene graph
│   ├── Test each object against camera frustum (if frustumCulled=true)
│   ├── Check object.layers vs camera.layers
│   ├── Sort opaque objects front-to-back (minimize overdraw)
│   └── Sort transparent objects back-to-front (correct blending)
│
├── 4. Render shadow maps (if shadowMap.enabled)
│   ├── For each shadow-casting light:
│   │   ├── Set up shadow camera
│   │   ├── Render scene from light's perspective
│   │   └── Store depth in shadow map texture
│   └── Uses MeshDepthMaterial/MeshDistanceMaterial internally
│
├── 5. Set render state
│   ├── Clear buffers (if autoClear)
│   ├── Set viewport, scissor
│   └── Bind render target (or default framebuffer)
│
├── 6. Render opaque objects
│   ├── For each object in opaque list:
│   │   ├── Select/compile shader program
│   │   ├── Set uniforms (matrices, lights, material props)
│   │   ├── Bind textures, attributes, index buffer
│   │   └── Issue draw call (drawArrays or drawElements)
│   └── Instanced: drawArraysInstanced / drawElementsInstanced
│
├── 7. Render transparent objects
│   └── Same as step 6, back-to-front order
│
└── 8. Post-render
    ├── Reset state
    ├── Update info (render count, triangle count, etc.)
    └── Call animation loop callback
```

#### WebGPURenderer Pipeline (Modern Path)

The WebGPU path shares the same high-level structure but uses a backend abstraction:

```
Renderer.render(scene, camera)           ← src/renderers/common/Renderer.js
│
├── Backend.beginRender(renderContext)    ← WebGPUBackend or WebGLBackend
├── RenderList.sort()                    ← Opaque + transparent lists
├── For each RenderObject:
│   ├── NodeBuilder.build()              ← Compile node graph to shader
│   ├── Backend.draw(renderObject)       ← Issue GPU draw call
│   └── RenderBundle (if applicable)     ← Reuse encoded commands
└── Backend.finishRender(renderContext)
```

The `DataMap` pattern is used extensively in the common renderer to associate internal GPU state (pipelines, bind groups, buffers) with user-facing objects without modifying them:

```javascript
// Internal pattern used by renderer infrastructure
class SomeManager {
  constructor() {
    this._dataMap = new DataMap();
  }
  
  getInternalState(object) {
    return this._dataMap.get(object);
  }
}
```

#### Coordinate Systems

three.js uses a right-handed coordinate system (Y-up). The renderers handle coordinate system differences:

| System | Clip Space Z | Constant |
|---|---|---|
| WebGL | [-1, 1] | `WebGLCoordinateSystem` |
| WebGPU | [0, 1] | `WebGPUCoordinateSystem` |

Attempting to use `CubeCamera` or certain operations with the wrong coordinate system will throw: `"THREE.CubeCamera: Invalid coordinate system."` or `"THREE.Frustum: Invalid coordinate system."`.

### 8.4 Node System / TSL Architecture

The Three.js Shading Language (TSL) is a node-based shader authoring system that compiles to GLSL or WGSL depending on the renderer backend. It lives in `src/nodes/`.

#### Node Graph Architecture

```
User Code (TSL API)
       │
       ▼
  Node Graph (DAG of Node instances)
       │
       ▼
  NodeBuilder
       │
  ┌────┴────┐
  ▼         ▼
GLSL      WGSL
(WebGL)   (WebGPU)
```

**Node** (`src/nodes/core/Node.js`, extends `EventDispatcher`) is the base class. Every node represents a value or operation in the shader graph. Key properties:
- `nodeType` — data type (float, vec2, vec3, vec4, mat3, mat4, etc.)
- `updateType` — when to update (NONE, FRAME, RENDER, OBJECT)
- `build(builder)` — compile this node for the target backend

#### Core Node Types (src/nodes/core/)

| Node Class | Purpose |
|---|---|
| `ArrayNode` | Array data in shaders |
| `AssignNode` | Variable assignment |
| `AttributeNode` | Vertex attributes (position, normal, uv) |
| `BypassNode` | Pass-through with side effects |
| `ConstNode` | Constant values |
| `ContextNode` | Execution context scoping |
| `IndexNode` | Vertex/instance index |
| `InputNode` | External input values |
| `IsolateNode` | Prevent node sharing optimization |
| `MRTNode` | Multiple Render Targets |
| `OutputStructNode` | Structured shader output |
| `ParameterNode` | Shader parameters |
| `PropertyNode` | Material properties |
| `StackNode` | Sequential operation stacking |
| `StructNode` | Struct definitions |
| `TempNode` | Temporary variables |
| `UniformNode` | Uniform values |
| `VarNode` | Variable declarations |
| `VaryingNode` | Vertex-to-fragment interpolation |

#### Utility Nodes (src/nodes/utils/)

| Node Class | Purpose |
|---|---|
| `ConvertNode` | Type conversion |
| `CubeMapNode` | Cube map sampling |
| `FlipNode` | UV/coordinate flipping |
| `JoinNode` | Combine components (e.g., vec2 → vec4) |
| `LoopNode` | Shader loops |
| `ReflectorNode` | Planar reflections |
| `RotateNode` | Rotation transforms |
| `RTTNode` | Render-to-texture |
| `SplitNode` | Extract components (e.g., vec4.xyz) |

#### NodeBuilder Compilation

`NodeBuilder` compiles the node graph into shader code:

1. **Analyze**: Traverse the graph, determine types, resolve dependencies
2. **Build**: Generate shader code for each node in dependency order
3. **Link**: Produce final vertex/fragment shader with all declarations

Error conditions during build:
- `"THREE.NodeBuilder: Invalid chaining."` — node graph contains invalid connections
- Type mismatch errors when incompatible nodes are connected
- Missing attribute errors when required geometry data is absent

#### TSL Helper Functions

`src/Three.TSL.js` re-exports hundreds of helper functions that provide a fluent API for constructing node graphs:

```javascript
import { color, float, vec3, texture, normalMap, 
         mix, step, smoothstep, clamp } from 'three/tsl';

// Build a shader graph using TSL
const material = new NodeMaterial();
material.colorNode = mix(color(0xff0000), color(0x0000ff), uv().x);
```

#### MaterialX Integration

`src/nodes/materialx/lib/` provides MaterialX standard surface node implementations, enabling import of MaterialX-defined materials into the TSL system.

### 8.5 Module Reference

#### Core Modules (`src/core/`)

| Module | Lines | Key Exports | Patterns |
|---|---|---|---|
| `Object3D.js` | Large | `Object3D` | Scene graph node, parent/child, transform stack |
| `BufferGeometry.js` | Large | `BufferGeometry` | Attribute container, bounding volumes |
| `BufferAttribute.js` | Medium | `BufferAttribute` + 9 typed variants | Typed array wrapper, update ranges |
| `EventDispatcher.js` | Small | `EventDispatcher` | Observer pattern, addEventListener/dispatch |
| `Raycaster.js` | Medium | `Raycaster` | Mouse picking, recursive intersection |
| `Clock.js` | Small | `Clock` | Delta time, elapsed time |
| `Layers.js` | Small | `Layers` | 32-bit bitmask channel system |
| `Uniform.js` | Small | `Uniform`, `UniformsGroup` | Shader uniform containers |
| `RenderTarget.js` | Medium | `RenderTarget` + WebGL variants | Off-screen render destinations |

#### Renderer Modules (`src/renderers/`)

| Module | Key Exports | Notes |
|---|---|---|
| `WebGLRenderer.js` | `WebGLRenderer` | ~3000 lines, legacy path, direct WebGL state management |
| `common/Renderer.js` | `Renderer` | Base class for modern path (WebGPU/WebGL-fallback) |
| `common/Backend.js` | `Backend` | Abstract GPU backend interface |
| `common/RenderList.js` | `RenderList` | Opaque/transparent sorting |
| `common/RenderObject.js` | `RenderObject` | Per-object render state |
| `common/RenderBundle.js` | `RenderBundle` | Command recording for reuse |
| `common/RenderContext.js` | `RenderContext` | Render pass parameters |
| `common/DataMap.js` | `DataMap` | WeakMap-like internal state association |
| `common/PostProcessing.js` | `PostProcessing` | Built-in post-processing for modern path |
| `webgpu/WebGPUBackend.js` | `WebGPUBackend` | WebGPU native backend |
| `webgl-fallback/WebGLBackend.js` | `WebGLBackend` | WebGL backend for modern path |

#### Animation Modules (`src/animation/`)

| Module | Key Exports | Purpose |
|---|---|---|
| `AnimationMixer.js` | `AnimationMixer` | Drives all animations on a root object |
| `AnimationClip.js` | `AnimationClip` | Named collection of keyframe tracks |
| `AnimationAction.js` | `AnimationAction` | Playback control (play, stop, crossfade, loop) |
| `KeyframeTrack.js` | `KeyframeTrack` + 6 typed variants | Time→value interpolation |
| `PropertyBinding.js` | `PropertyBinding` | Resolves track name strings to object properties |
| `AnimationObjectGroup.js` | `AnimationObjectGroup` | Groups objects for shared animation |
| `AnimationUtils.js` | `AnimationUtils` | Static helpers (makeClipAdditive, subclip) |

`PropertyBinding` handles the name resolution syntax: `"objectName.propertyName[index]"`. Parse failures emit descriptive errors.

#### Loader Modules (`src/loaders/`)

| Module | Key Exports | Purpose |
|---|---|---|
| `Loader.js` | `Loader` | Base class: path, crossOrigin, headers |
| `LoadingManager.js` | `LoadingManager`, `DefaultLoadingManager` | Coordination: onStart/onLoad/onProgress/onError |
| `FileLoader.js` | `FileLoader` | XHR-based file loading, responseType support |
| `Cache.js` | `Cache` | Global file-level caching (enabled/disabled) |
| `TextureLoader.js` | `TextureLoader` | Image → Texture |
| `ImageLoader.js` | `ImageLoader` | Image element loading |
| `ObjectLoader.js` | `ObjectLoader` | Full scene deserialization from JSON |

#### Math Modules (`src/math/`)

| Module | Key Exports | Notable Methods |
|---|---|---|
| `Vector3.js` | `Vector3` | add, sub, multiply, dot, cross, normalize, length, lerp, applyMatrix4, applyQuaternion, project, unproject |
| `Matrix4.js` | `Matrix4` | multiply, invert, decompose, compose, lookAt, makeRotation*, makeTranslation, makePerspective, makeOrthographic |
| `Quaternion.js` | `Quaternion` | setFromAxisAngle, setFromRotationMatrix, setFromEuler, slerp, multiply, invert |
| `Euler.js` | `Euler` | setFromRotationMatrix, setFromQuaternion, reorder; order: 'XYZ'/'YXZ'/etc. |
| `Color.js` | `Color` | set, setHex, setRGB, setHSL, lerp, multiply, convertSRGBToLinear, convertLinearToSRGB |
| `Box3.js` | `Box3` | setFromObject, expandByPoint, containsPoint, intersectsBox, clampPoint |
| `Sphere.js` | `Sphere` | setFromPoints, containsPoint, intersectsBox, intersectsPlane |
| `Ray.js` | `Ray` | intersectBox, intersectSphere, intersectTriangle, intersectPlane |
| `Frustum.js` | `Frustum` | setFromProjectionMatrix, intersectsObject, containsPoint |
| `MathUtils.js` | `MathUtils` | clamp, degToRad, radToDeg, lerp, generateUUID, randFloat, randInt, isPowerOfTwo |

#### Extras Modules (`src/extras/`)

| Module | Key Exports | Purpose |
|---|---|---|
| `Controls.js` | `Controls` | Base class: object, domElement, enabled, connect/disconnect/dispose |
| `curves/*.js` | Various Curve classes | Parametric curves for paths and extrusions |
| `core/Path.js` | `Path`, `ShapePath` | 2D path operations: moveTo, lineTo, bezierCurveTo, arc |
| `core/Shape.js` | `Shape` | 2D shape with holes, for extrusion |
| `PMREMGenerator.js` | `PMREMGenerator` | Prefiltered environment maps for IBL |
| `DataUtils.js` | `DataUtils` | toHalfFloat/fromHalfFloat conversion |
| `ImageUtils.js` | `ImageUtils` | Image data manipulation |
| `ShapeUtils.js` | `ShapeUtils` | Triangulation: area, isClockWise, triangulateShape |
| `TextureUtils.js` | `TextureUtils` | Texture manipulation helpers |
| `Earcut.js` | `Earcut` | Polygon triangulation algorithm |

### 8.6 Code Patterns & Conventions

#### Naming Conventions

| Convention | Example | Usage |
|---|---|---|
| PascalCase | `MeshStandardMaterial` | Classes, constructors |
| camelCase | `updateMatrixWorld` | Methods, properties |
| UPPER_SNAKE | `FrontSide`, `PCFShadowMap` | Constants (in constants.js) |
| `_` prefix | `_vector`, `_matrix` | Module-level reusable temp objects |
| `is` prefix | `isMesh`, `isBufferGeometry` | Type-check booleans |

#### Type Checking Pattern

three.js uses boolean flags instead of `instanceof` for type checking throughout the codebase:

```javascript
// Every class sets a type flag
class Mesh extends Object3D {
  constructor() {
    super();
    this.isMesh = true;
    this.type = 'Mesh';
  }
}

// Checked via property access (faster than instanceof, survives bundling)
if (object.isMesh) { /* ... */ }
if (material.isMeshStandardMaterial) { /* ... */ }
```

#### Reusable Temporary Objects

To avoid garbage collection pressure, modules declare module-scope temporary math objects:

```javascript
const _vector = new Vector3();
const _matrix = new Matrix4();
const _quaternion = new Quaternion();

class SomeClass {
  someMethod() {
    // Reuse instead of allocating
    _vector.set(1, 2, 3).applyMatrix4(this.matrix);
  }
}
```

> [!CAUTION]
> These temporaries are shared within a module. They are not thread-safe and should not be stored or passed to callbacks that may execute asynchronously.

#### Clone/Copy Pattern

Every data class implements both `clone()` and `copy()`:

```javascript
class Material extends EventDispatcher {
  copy(source) {
    this.name = source.name;
    this.color.copy(source.color);
    // ... copy all properties
    return this;
  }
  
  clone() {
    return new this.constructor().copy(this);
  }
}
```

#### Serialization Pattern

`toJSON()` produces a portable representation; the corresponding Loader reconstructs:

```javascript
// Serialize
const json = object.toJSON();

// Deserialize
const loader = new THREE.ObjectLoader();
const reconstructed = loader.parse(json);
```

The JSON format uses `metadata.type` to identify the class and `metadata.version` for format evolution.

#### Dispose Pattern

GPU resources require explicit cleanup:

```javascript
// Material tracks allocated resources
material.dispose();  // Fires 'dispose' event
// Listeners (e.g., renderer) clean up GPU resources in response

geometry.dispose();  // Fires 'dispose' event
texture.dispose();   // Fires 'dispose' event
renderTarget.dispose();
renderer.dispose();  // Cleans up everything
```

#### Console Warning Deduplication

`src/utils.js` provides `warnOnce()` functionality to prevent flooding the console with repeated warnings (e.g., deprecated API usage).

### 8.7 Testing Strategy

#### Test Organization

```
test/
├── unit/
│   ├── three.source.unit.js      Entry point for core tests
│   ├── three.addons.unit.js      Entry point for addon tests
│   └── src/                      Mirrors src/ directory structure
│       ├── core/
│       │   ├── Object3D.tests.js
│       │   ├── BufferGeometry.tests.js
│       │   └── ...
│       ├── math/
│       │   ├── Vector3.tests.js
│       │   └── ...
│       └── ...
├── e2e/
│   ├── puppeteer.js              E2E test runner
│   └── ...                       Reference screenshots
└── treeshake/
    └── ...                       Tree-shaking verification
```

#### Unit Test Framework

Tests use **QUnit** and follow a consistent structure:

```javascript
QUnit.module('Core', () => {
  QUnit.module('Object3D', () => {
    QUnit.test('add/remove', (assert) => {
      const parent = new Object3D();
      const child = new Object3D();
      parent.add(child);
      assert.strictEqual(child.parent, parent);
    });
  });
});
```

#### E2E Screenshot Tests

The Puppeteer-based E2E system:
1. Launches a headless browser
2. Loads each example page
3. Captures a screenshot after rendering stabilizes
4. Compares pixel-by-pixel against reference images using `pngjs`/`jpeg-js`
5. Fails if difference exceeds threshold

```bash
# Generate new reference screenshots
npm run make-screenshot

# Run comparison tests (WebGL)
npm run test-e2e

# Run comparison tests (WebGPU)
npm run test-e2e-webgpu
```

#### What Gets Tested

| Level | Coverage | Runner |
|---|---|---|
| Unit | Core classes, math, loaders, materials, geometries | QUnit |
| E2E | Visual output of examples (pixel comparison) | Puppeteer |
| Tree-shaking | Bundle size when importing individual classes | Rollup |
| Lint | Code style, JSDoc types | ESLint |

### 8.8 Editor Architecture

The three.js editor (`editor/`) is a full web-based 3D scene editor with an undo/redo system.

#### Command Pattern

All editor operations are encapsulated as command objects in `editor/js/commands/`:

| Command Class | Operation |
|---|---|
| `AddObjectCommand` | Add object to scene |
| `RemoveObjectCommand` | Remove object from scene |
| `SetPositionCommand` | Change object position |
| `SetRotationCommand` | Change object rotation |
| `SetScaleCommand` | Change object scale |
| `SetMaterialCommand` | Assign material to object |
| `SetGeometryCommand` | Assign geometry to mesh |
| `SetValueCommand` | Generic property change |
| `SetColorCommand` | Change color property |
| `SetMaterialValueCommand` | Change material property |
| `SetMaterialColorCommand` | Change material color |
| `SetMaterialMapCommand` | Change material texture |
| `MoveObjectCommand` | Reparent in scene graph |
| `MultiCmdsCommand` | Batch multiple commands |
| ... | 24 command classes total |

Each command implements `execute()` and `undo()`, stored in a history stack.

#### UI System

The editor uses a custom UI framework (`editor/js/libs/ui.js`) with these widget classes:

`UIElement`, `UIDiv`, `UIRow`, `UIPanel`, `UIInput`, `UISelect`, `UICheckbox`, `UIColor`, `UINumber`, `UIText`, `UITextArea`, `UIButton`, `UIBreak`, `UISpan`

#### Script Editor

The editor includes a code editor (powered by CodeMirror) that allows users to write per-object scripts. Scripts are parsed with esprima for syntax validation.

#### XR Support

The editor viewport supports VR/XR preview modes for testing immersive experiences.

### 8.9 Potential Improvements

Based on source analysis and open issues:

#### Architecture

1. **WebGPU XR support**: XR is not supported with the WebGPU backend — the error message `"THREE.XRManager: XR is not supported with WebGPU backend."` is explicit. This limits adoption of the modern renderer for immersive applications.

2. **Node system complexity**: The TSL node system (`src/nodes/`) contains 40+ core node types. The `NodeBuilder` compilation path is complex and error-prone, with several known issues around type inference and chaining validation.

3. **WebGLRenderer size**: At ~3,000 lines, `WebGLRenderer.js` is the largest single file. The modern path's `Renderer.js` + backend separation is a better architecture, but the legacy renderer cannot be refactored without breaking changes.

#### Known Open Issues

| Issue | Area | Description |
|---|---|---|
| #33404 | WebXR | AR crashes Chrome 147+ |
| #33394 | TSL | `textureLoad` with `int(0)` produces GLSL2 compile error |
| #33403 | TSL | `Return()` value support incomplete |
| #33291 | Animation | Reverse playback edge cases |
| #29963 | GLTFLoader | UTF-8 filename encoding |
| #31994 | GLTFLoader | Negative scaling affects lighting |
| #26613 | SVGLoader | Incorrect rendering of certain SVGs |
| #33416 | TSL | String/arrayBuffer method support |
| #33412 | TSL | `setName` on attributes |

#### Code Quality Opportunities

- **Inconsistent error handling in BatchedMesh**: Error messages reference `%` placeholder syntax (e.g., `"%.reservedSpace exceeded"`) which suggests incomplete string formatting
- **Shadow map disposal**: Shadow maps are not always cleaned up when lights are removed from the scene
- **Loader error propagation**: Some addon loaders swallow errors silently rather than propagating to the `LoadingManager.onError` callback
- **DepthTexture format validation**: The renderer validates DepthTexture formats but error messages could be more specific about which formats are supported for which operations

### 8.10 Contributing

#### Development Workflow

```bash
# Clone
git clone https://github.com/mrdoob/three.js.git
cd three.js

# Install dependencies
npm install

# Start development server
npm start
# → http://localhost:8080

# Run tests before submitting
npm test

# Lint and auto-fix
npm run lint-fix

# Build production bundles
npm run build
```

#### Code Style Requirements

- **ES2022** module syntax (`import`/`export`)
- **Single quotes** for strings
- **`const`** by default, `let` only when reassignment is needed
- **No `var`** declarations
- **Tabs** for indentation
- **No trailing semicolons** in function declarations
- All JSDoc types must be specified (`@param {type}`, `@returns {type}`)
- Throw `Error` objects, never literals (`no-throw-literal: error`)
- Use spread syntax over `.apply()` (`prefer-spread`)
- No duplicate imports from the same module (`no-duplicate-imports`)

#### File Organization Rules

- One class per file (matching filename)
- Constructor parameters first, then properties, then methods
- `clone()` and `copy()` at the end of the class body
- `toJSON()` after clone/copy
- Static methods after instance methods

#### Addon Development

Addons live in `examples/jsm/` and are published under `three/addons`:

```javascript
// examples/jsm/controls/MyControl.js
import { Controls } from 'three';

class MyControl extends Controls {
  constructor(object, domElement) {
    super(object, domElement);
    // ...
  }
  
  connect() { /* bind events */ }
  disconnect() { /* unbind events */ }
  update() { /* per-frame logic */ }
  dispose() { /* cleanup */ }
}

export { MyControl };
```

Addons may import from `three` but never from `three/src/*` directly. This ensures they work with both source and built versions.

> [!TIP]
> The `Addons.js` barrel file at `examples/jsm/Addons.js` re-exports all addons. When adding a new addon, add its export to this file so it is accessible via `import { MyAddon } from 'three/addons'`.

---

## 9. Integration Points

### 9.1 Addon Ecosystem

The `examples/jsm/` directory contains the official addon ecosystem, published as `three/addons`. Major categories:

#### Controls

| Addon | Import | Purpose |
|---|---|---|
| `OrbitControls` | `three/addons/controls/OrbitControls.js` | Orbit around target (most common) |
| `MapControls` | `three/addons/controls/MapControls.js` | Map-style pan/zoom/rotate |
| `TrackballControls` | `three/addons/controls/TrackballControls.js` | Unconstrained rotation |
| `FlyControls` | `three/addons/controls/FlyControls.js` | Flight simulator-style |
| `FirstPersonControls` | `three/addons/controls/FirstPersonControls.js` | FPS camera |
| `PointerLockControls` | `three/addons/controls/PointerLockControls.js` | Pointer lock FPS |
| `ArcballControls` | `three/addons/controls/ArcballControls.js` | Arcball rotation |
| `DragControls` | `three/addons/controls/DragControls.js` | Drag objects in 3D |
| `TransformControls` | `three/addons/controls/TransformControls.js` | Translate/rotate/scale gizmo |

All controls extend `Controls` (`src/extras/Controls.js`) which provides: `object`, `domElement`, `enabled`, `state`, `keys`, `mouseButtons`, `touches`, and `connect()`/`disconnect()`/`update()`/`dispose()` lifecycle methods.

#### Loaders

| Addon | Format | Notes |
|---|---|---|
| `GLTFLoader` | glTF 2.0 (.gltf, .glb) | Primary 3D format, supports extensions |
| `DRACOLoader` | Draco compressed | Used with GLTFLoader for compressed meshes |
| `KTX2Loader` | KTX2/Basis Universal | GPU-compressed textures |
| `OBJLoader` | Wavefront OBJ | Legacy format, no animation |
| `FBXLoader` | Autodesk FBX | Animation support |
| `STLLoader` | Stereolithography | 3D printing format |
| `PLYLoader` | Stanford PLY | Point clouds, meshes |
| `PCDLoader` | Point Cloud Data | Point clouds |
| `ColladaLoader` | COLLADA (.dae) | XML-based, older format |
| `SVGLoader` | SVG | 2D vector to 3D geometry |
| `RGBELoader` | Radiance RGBE (.hdr) | HDR environment maps |
| `EXRLoader` | OpenEXR | HDR images |
| `HDRCubeTextureLoader` | HDR Cube | HDR cube map textures |
| `LDrawLoader` | LDraw | LEGO brick models |
| `3DMLoader` | Rhinoceros 3DM | Rhino models |
| `3MFLoader` | 3MF | 3D manufacturing format |
| `VRMLLoader` | VRML | Legacy 3D web format |
| `BVHLoader` | BVH | Motion capture data |

> [!NOTE]
> `GLTFLoader` is the recommended format for web 3D. It supports PBR materials, animations, morph targets, and numerous extensions. Use `DRACOLoader` for mesh compression and `KTX2Loader` for texture compression to minimize download sizes.

#### Exporters

| Addon | Format |
|---|---|
| `GLTFExporter` | glTF 2.0 (.gltf, .glb) |
| `OBJExporter` | Wavefront OBJ |
| `STLExporter` | STL (ASCII/binary) |
| `PLYExporter` | Stanford PLY |
| `USDZExporter` | Apple USDZ (AR Quick Look) |
| `ColladaExporter` | COLLADA (.dae) |

#### Post-Processing

```javascript
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new ShaderPass(someShader));

function animate() {
  composer.render();  // Instead of renderer.render()
}
```

> [!TIP]
> The WebGPU path has built-in post-processing via `PostProcessing` (`src/renderers/common/PostProcessing.js`) that uses TSL nodes instead of the addon `EffectComposer`. For the modern path, prefer the built-in system.

#### Utilities

| Addon | Purpose |
|---|---|
| `BufferGeometryUtils` | `mergeGeometries()`, `computeMikkTSpaceTangents()`, interleave attributes |
| `SceneOptimizer` | Automated scene optimization |
| `ShadowMapViewer` | Debug visualization for shadow maps |
| `WorkerPool` | Web Worker thread pool for parallel loading |
| `LDrawUtils` | LDraw model processing utilities |

### 9.2 Build Tool Integration

#### Vite

```javascript
// vite.config.js
export default {
  // No special configuration needed — three.js works out of the box
  // Optionally optimize dependency pre-bundling:
  optimizeDeps: {
    include: ['three']
  }
};
```

#### Webpack

```javascript
// webpack.config.js
module.exports = {
  resolve: {
    // three.js uses package.json exports field (webpack 5+)
    // No additional configuration needed
  }
};
```

#### TypeScript

three.js ships with TypeScript type definitions generated from JSDoc annotations. No `@types/three` package is needed for recent versions:

```typescript
import * as THREE from 'three';

const scene: THREE.Scene = new THREE.Scene();
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
```

### 9.3 Framework Integration

#### React (react-three-fiber)

The React ecosystem uses `@react-three/fiber` as the standard binding:

```jsx
import { Canvas } from '@react-three/fiber';

function App() {
  return (
    <Canvas>
      <mesh>
        <boxGeometry />
        <meshStandardMaterial color="orange" />
      </mesh>
      <ambientLight />
      <directionalLight position={[10, 10, 5]} />
    </Canvas>
  );
}
```

#### Web Components

three.js scenes can be encapsulated in web components:

```javascript
class ThreeScene extends HTMLElement {
  connectedCallback() {
    const renderer = new THREE.WebGLRenderer();
    this.appendChild(renderer.domElement);
    // ... setup scene
  }
  
  disconnectedCallback() {
    this.renderer.dispose();
    // ... cleanup
  }
}
customElements.define('three-scene', ThreeScene);
```

### 9.4 WebXR Integration

three.js includes built-in WebXR support through the renderer's XR manager:

```javascript
renderer.xr.enabled = true;

// VR
document.body.appendChild(VRButton.createButton(renderer));

// AR
document.body.appendChild(ARButton.createButton(renderer));

renderer.setAnimationLoop(function () {
  renderer.render(scene, camera);
});
```

> [!WARNING]
> XR is only supported with `WebGLRenderer` or the `WebGLBackend` of `WebGPURenderer`. Using the native `WebGPUBackend` with XR will throw: `"THREE.XRManager: XR is not supported with WebGPU backend."` Issue #33404 also documents WebXR AR crashes in Chrome 147+.

### 9.5 Audio Integration

three.js wraps the Web Audio API for spatialized 3D audio:

```javascript
const listener = new THREE.AudioListener();
camera.add(listener);

// Non-positional (background music)
const sound = new THREE.Audio(listener);
new THREE.AudioLoader().load('music.mp3', (buffer) => {
  sound.setBuffer(buffer);
  sound.play();
});

// Positional (3D spatialized)
const positionalSound = new THREE.PositionalAudio(listener);
mesh.add(positionalSound);  // Sound follows the mesh in 3D space

// Analysis
const analyser = new THREE.AudioAnalyser(sound, 256);
const frequencyData = analyser.getFrequencyData();
```

`AudioListener` attaches to the camera and creates/manages the `AudioContext` singleton. `PositionalAudio` extends `Audio` with a `PannerNode` for 3D spatialization.

### 9.6 Devtools Integration

The `devtools/` directory contains a browser extension panel for inspecting three.js scenes at runtime. It uses `DevToolsEventTarget` as a bridge between the page and the extension panel.

Applications opt into devtools support via the `__THREE_DEVTOOLS__` global:

```javascript
if (typeof __THREE_DEVTOOLS__ !== 'undefined') {
  __THREE_DEVTOOLS__.dispatchEvent(
    new CustomEvent('observe', { detail: scene })
  );
}
```

### 9.7 Helpers for Development

three.js includes visual debugging helpers that render directly in the scene:

| Helper | Visualizes |
|---|---|
| `AxesHelper` | RGB axes (X=red, Y=green, Z=blue) |
| `GridHelper` | Ground plane grid |
| `PolarGridHelper` | Polar coordinate grid |
| `ArrowHelper` | Direction vector arrow |
| `BoxHelper` | Object bounding box wireframe |
| `Box3Helper` | Box3 wireframe |
| `PlaneHelper` | Plane normal and extent |
| `CameraHelper` | Camera frustum wireframe |
| `DirectionalLightHelper` | Directional light direction |
| `HemisphereLightHelper` | Hemisphere light orientation |
| `PointLightHelper` | Point light position |
| `SpotLightHelper` | Spotlight cone |
| `SkeletonHelper` | Bone structure wireframe |

```javascript
// Add axes helper to any object
const axes = new THREE.AxesHelper(5);
scene.add(axes);

// Visualize a camera's frustum
const helper = new THREE.CameraHelper(camera);
scene.add(helper);
```

---

## 10. Troubleshooting

### 10.1 Common Errors and Solutions

> [!NOTE]
> Below are the most frequently encountered errors from the 82 error messages in the three.js source. Each includes the exact message text and resolution steps.

#### WebGL Context Errors

**Error:** `THREE.WebGLRenderer: WebGL 1 is not supported since r163.`
**Cause:** Browser or device only supports WebGL 1.
**Solution:** Use a modern browser (Chrome 80+, Firefox 78+, Safari 14+) that supports WebGL 2.

**Error:** WebGL context creation failures
**Cause:** GPU drivers, browser extensions blocking WebGL, or too many active contexts.
**Solution:** Check `navigator.gpu` or `canvas.getContext('webgl2')` before creating a renderer. Dispose unused renderers.

#### Renderer Initialization

**Error:** Methods called before `renderer.init()` completes
**Cause:** `WebGPURenderer` requires async initialization.
**Solution:** Always `await renderer.init()` before calling `render()`, `setSize()`, or other methods.

#### Buffer and Attribute Errors

> [!WARNING]
> `BufferAttribute` validates that its data is a typed array. Passing a regular `Array` or incorrect type will throw an error. Always use `Float32Array`, `Uint16Array`, etc.

**Error:** BufferAttribute typed array check
**Cause:** Non-typed array passed to BufferAttribute constructor.
**Solution:** Use the appropriate typed variant (`Float32BufferAttribute`, etc.) or pass a typed array.

#### Depth Texture Errors

**Error:** WebGLRenderTarget DepthTexture size mismatch
**Cause:** DepthTexture dimensions don't match the RenderTarget.
**Solution:** Ensure DepthTexture width/height matches the RenderTarget's width/height.

**Error:** DepthTexture format validation
**Cause:** Invalid format/type combination for DepthTexture.
**Solution:** Use `DepthFormat` with `UnsignedIntType` or `DepthStencilFormat` with `UnsignedInt248Type`.

#### BatchedMesh Errors

**Error:** `THREE.BatchedMesh: Maximum item count reached.`
**Cause:** Attempted to add more instances than `maxInstanceCount`.
**Solution:** Increase `maxInstanceCount` in the constructor, or reuse instances.

**Error:** `THREE.BatchedMesh: %.reservedSpace exceeded.`
**Cause:** Geometry vertex/index data exceeds reserved space.
**Solution:** Increase `maxVertexCount`/`maxIndexCount` in the constructor.

#### Animation Errors

**Error:** KeyframeTrack validation errors
**Cause:** Invalid keyframe data (NaN values, non-monotonic times, mismatched array lengths).
**Solution:** Validate animation data before creating tracks. Use `AnimationClip.validate()`.

**Error:** PropertyBinding parse failures
**Cause:** Invalid binding path string format.
**Solution:** Use the format `"objectName.propertyName[index]"`. Verify object names match scene hierarchy.

#### Node System Errors

**Error:** `THREE.NodeBuilder: Invalid chaining.`
**Cause:** Incompatible node connections in TSL graph.
**Solution:** Check that connected nodes have compatible types. Use explicit type conversion nodes.

#### Multiple Instances Warning

**Warning:** Multiple Three.js instances detected
**Cause:** Application loads more than one copy of three.js.
**Solution:** Check for duplicate dependencies. Use import maps or bundler aliases to ensure a single copy. Run `npm ls three` to find duplicates.

#### Coordinate System Errors

**Error:** `THREE.CubeCamera: Invalid coordinate system.`
**Cause:** CubeCamera used with wrong coordinate system setting.
**Solution:** Ensure the renderer's coordinate system matches expectations. WebGL uses `WebGLCoordinateSystem`, WebGPU uses `WebGPUCoordinateSystem`.

> [!TIP]
> Enable the three.js devtools browser extension for real-time scene inspection. Many rendering issues (missing objects, incorrect materials, wrong transforms) are immediately visible in the scene graph inspector.

### 10.2 Performance Debugging

| Symptom | Likely Cause | Diagnostic |
|---|---|---|
| Low FPS, high draw calls | Too many objects | `renderer.info.render.calls` |
| Low FPS, few draw calls | Complex shaders/geometry | GPU profiler (Chrome DevTools → Performance) |
| Memory growth over time | Missing dispose() calls | `renderer.info.memory` (geometries, textures) |
| Stuttering | Garbage collection | Avoid allocations in render loop |
| Black screen | Missing lights or wrong material | Add `AmbientLight`, check `material.side` |
| Objects invisible | Wrong layer, frustum culled, scale 0 | Check `object.layers`, `object.visible`, `object.scale` |

```javascript
// Monitor renderer statistics
console.log(renderer.info.render.calls);       // Draw calls per frame
console.log(renderer.info.render.triangles);   // Triangles per frame
console.log(renderer.info.memory.geometries);  // Allocated geometries
console.log(renderer.info.memory.textures);    // Allocated textures
```

---

_Generated May 2026 from mrdoob/three.js at 477da61. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
