chore: sync release state after merge batch
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
---
|
||||
name: phase-gated-debugging
|
||||
description: "Use when debugging any bug. Enforces a 5-phase protocol where code edits are blocked until root cause is confirmed. Prevents premature fix attempts."
|
||||
risk: safe
|
||||
source: community
|
||||
date_added: "2026-03-28"
|
||||
---
|
||||
|
||||
# Phase-Gated Debugging
|
||||
|
||||
## Overview
|
||||
|
||||
AI coding agents see an error and immediately edit code. They guess at fixes, get it wrong, and spiral. This skill enforces a strict 5-phase protocol where you CANNOT edit source code until the root cause is identified and confirmed.
|
||||
|
||||
Based on [claude-debug](https://github.com/krabat-l/claude-debug) (full plugin with PreToolUse hook enforcement).
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
|
||||
- a bug keeps getting "fixed" without resolving the underlying issue
|
||||
- you need to slow an agent down and force disciplined debugging before code edits
|
||||
- the failure is intermittent, a regression, performance-related, or otherwise hard to isolate
|
||||
- you want an explicit user confirmation checkpoint before any fix is applied
|
||||
|
||||
## The Protocol
|
||||
|
||||
### Phase 1: REPRODUCE
|
||||
Run the failing command/test. Capture the exact error. Run 2-3 times for consistency.
|
||||
- Do NOT read source code
|
||||
- Do NOT hypothesize
|
||||
- Do NOT edit any files
|
||||
|
||||
### Phase 2: ISOLATE
|
||||
Read code. Add diagnostic logging marked `// DEBUG`. Re-run with diagnostics. Binary search to narrow down.
|
||||
- Only `// DEBUG` marked logging is allowed
|
||||
- Do NOT fix the bug even if you see it
|
||||
|
||||
### Phase 3: ROOT CAUSE
|
||||
Analyze WHY at the isolated location. Use "5 Whys" technique. Remove debug logging.
|
||||
|
||||
State: "This is my root cause analysis: [explanation]. Do you agree, or should I investigate further?"
|
||||
|
||||
**WAIT for user confirmation. Do NOT proceed without it.**
|
||||
|
||||
### Phase 4: FIX
|
||||
Remove all `// DEBUG` lines. Apply minimal change addressing confirmed root cause.
|
||||
- Only edit files related to root cause
|
||||
- Do NOT refactor unrelated code
|
||||
|
||||
### Phase 5: VERIFY
|
||||
Run original failing test — must pass. Run related tests. For intermittent bugs, run 5+ times.
|
||||
If verification fails: root cause was wrong, go back to Phase 2.
|
||||
|
||||
## Bug-Type Strategies
|
||||
|
||||
| Type | Technique |
|
||||
|------|-----------|
|
||||
| Crash/Panic | Stack trace backward — trace the bad value to its source |
|
||||
| Wrong Output | Binary search — log midpoint, halve search space each iteration |
|
||||
| Intermittent | Compare passing vs failing run logs — find ordering divergence |
|
||||
| Regression | `git bisect` — find the offending commit |
|
||||
| Performance | Timing at stage boundaries — find the bottleneck |
|
||||
|
||||
## Key Rules
|
||||
|
||||
1. NEVER edit source code in phases 1-3 (except `// DEBUG` in phase 2)
|
||||
2. NEVER proceed past phase 3 without user confirmation
|
||||
3. ALWAYS reproduce before investigating
|
||||
4. ALWAYS verify after fixing
|
||||
@@ -12,22 +12,23 @@ source: community
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
|
||||
// Simple procedural animation
|
||||
const clock = new THREE.Clock();
|
||||
// Simple procedural animation with Timer (recommended in r183)
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
function animate() {
|
||||
const delta = clock.getDelta();
|
||||
const elapsed = clock.getElapsedTime();
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta;
|
||||
mesh.position.y = Math.sin(elapsed) * 0.5;
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
});
|
||||
```
|
||||
|
||||
**Note:** `THREE.Timer` is recommended over `THREE.Clock` as of r183. Timer pauses when the page is hidden and has a cleaner API. `THREE.Clock` still works but is considered legacy.
|
||||
|
||||
## Animation System Overview
|
||||
|
||||
Three.js animation system has three main components:
|
||||
@@ -118,6 +119,10 @@ track.setInterpolation(THREE.InterpolateSmooth); // Cubic spline
|
||||
track.setInterpolation(THREE.InterpolateDiscrete); // Step function
|
||||
```
|
||||
|
||||
### BezierInterpolant (r183)
|
||||
|
||||
Three.js r183 adds `THREE.BezierInterpolant` for bezier curve interpolation in keyframe tracks, enabling smoother animation curves with tangent control.
|
||||
|
||||
## AnimationMixer
|
||||
|
||||
Plays animations on an object and its descendants.
|
||||
|
||||
@@ -416,7 +416,24 @@ function dispose() {
|
||||
}
|
||||
```
|
||||
|
||||
### Clock for Animation
|
||||
### Timer and Clock for Animation
|
||||
|
||||
**Timer (recommended in r183)** - pauses when tab is hidden, cleaner API:
|
||||
|
||||
```javascript
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta * 0.5;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
**Clock (legacy, still works):**
|
||||
|
||||
```javascript
|
||||
const clock = new THREE.Clock();
|
||||
@@ -432,6 +449,17 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
### Animation Loop
|
||||
|
||||
Prefer `renderer.setAnimationLoop()` over manual `requestAnimationFrame`. It handles WebXR compatibility and is the standard Three.js pattern:
|
||||
|
||||
```javascript
|
||||
renderer.setAnimationLoop(() => {
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
### Responsive Canvas
|
||||
|
||||
```javascript
|
||||
@@ -483,6 +511,21 @@ lod.addLevel(lowDetailMesh, 100);
|
||||
scene.add(lod);
|
||||
```
|
||||
|
||||
## WebGPU Renderer (r183)
|
||||
|
||||
Three.js includes an experimental WebGPU renderer as an alternative to WebGL:
|
||||
|
||||
```javascript
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
```
|
||||
|
||||
WebGPU uses TSL (Three.js Shading Language) instead of GLSL. The WebGL renderer remains the default and is fully supported.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-geometry` - Geometry creation and manipulation
|
||||
|
||||
@@ -543,6 +543,36 @@ new THREE.SphereGeometry(1, 16, 16); // Performance mode
|
||||
geometry.dispose();
|
||||
```
|
||||
|
||||
## BatchedMesh (r183)
|
||||
|
||||
`BatchedMesh` is a higher-level alternative to `InstancedMesh` that supports multiple geometries in a single draw call. As of r183, it supports **per-instance opacity** and **per-instance wireframe**.
|
||||
|
||||
```javascript
|
||||
const batchedMesh = new THREE.BatchedMesh(maxGeometryCount, maxVertexCount, maxIndexCount);
|
||||
batchedMesh.sortObjects = true; // Enable depth sorting for transparency
|
||||
|
||||
// Add different geometries
|
||||
const boxId = batchedMesh.addGeometry(new THREE.BoxGeometry(1, 1, 1));
|
||||
const sphereId = batchedMesh.addGeometry(new THREE.SphereGeometry(0.5, 16, 16));
|
||||
|
||||
// Add instances of those geometries
|
||||
const instance1 = batchedMesh.addInstance(boxId);
|
||||
const instance2 = batchedMesh.addInstance(sphereId);
|
||||
|
||||
// Set transforms
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(2, 0, 0);
|
||||
batchedMesh.setMatrixAt(instance1, matrix);
|
||||
|
||||
// Per-instance opacity (r183)
|
||||
batchedMesh.setOpacityAt(instance1, 0.5);
|
||||
|
||||
// Per-instance visibility
|
||||
batchedMesh.setVisibleAt(instance2, false);
|
||||
|
||||
scene.add(batchedMesh);
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-fundamentals` - Scene setup and Object3D
|
||||
|
||||
@@ -189,6 +189,18 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
#### OrbitControls Programmatic Methods (r183)
|
||||
|
||||
```javascript
|
||||
// Programmatic camera movement
|
||||
controls.dolly(1.5); // Dolly in/out (zoom for perspective cameras)
|
||||
controls.pan(deltaX, deltaY); // Pan the camera
|
||||
controls.rotate(deltaAzimuth, deltaPolar); // Rotate around target
|
||||
|
||||
// Cursor style (r183)
|
||||
controls.cursorStyle = { orbit: "grab", pan: "move", dolly: "zoom-in" };
|
||||
```
|
||||
|
||||
### FlyControls
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -186,7 +186,7 @@ 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
|
||||
// Must initialize uniforms first (WebGL renderer only)
|
||||
RectAreaLightUniformsLib.init();
|
||||
|
||||
// RectAreaLight(color, intensity, width, height)
|
||||
@@ -199,7 +199,8 @@ scene.add(rectLight);
|
||||
const helper = new RectAreaLightHelper(rectLight);
|
||||
rectLight.add(helper);
|
||||
|
||||
// Note: Only works with MeshStandardMaterial and MeshPhysicalMaterial
|
||||
// Works with MeshStandardMaterial, MeshPhysicalMaterial
|
||||
// r183: Clearcoat on MeshPhysicalMaterial is now properly lit by RectAreaLight
|
||||
// Does not cast shadows natively
|
||||
```
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ import { KTX2Loader } from "three/addons/loaders/KTX2Loader.js";
|
||||
|
||||
const ktx2Loader = new KTX2Loader();
|
||||
ktx2Loader.setTranscoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/basis/",
|
||||
"https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/libs/basis/",
|
||||
);
|
||||
ktx2Loader.detectSupport(renderer);
|
||||
|
||||
@@ -267,6 +267,22 @@ gltfLoader.load("model-with-ktx2.glb", (gltf) => {
|
||||
});
|
||||
```
|
||||
|
||||
### GLTF with Meshopt Compression (r183)
|
||||
|
||||
```javascript
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
||||
import { MeshoptDecoder } from "three/addons/libs/meshopt_decoder.module.js";
|
||||
|
||||
const gltfLoader = new GLTFLoader();
|
||||
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
|
||||
|
||||
gltfLoader.load("compressed-model.glb", (gltf) => {
|
||||
scene.add(gltf.scene);
|
||||
});
|
||||
```
|
||||
|
||||
**KHR_meshopt_compression** is an alternative to Draco that often provides better compression for animated meshes and preserves mesh topology.
|
||||
|
||||
### Process GLTF Content
|
||||
|
||||
```javascript
|
||||
@@ -618,6 +634,10 @@ loadModel("model.glb").then((gltf) => {
|
||||
});
|
||||
```
|
||||
|
||||
## VRMLLoader Camera Support (r183)
|
||||
|
||||
As of r183, `VRMLLoader` supports loading cameras defined in VRML files.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-textures` - Texture configuration
|
||||
|
||||
@@ -515,6 +515,28 @@ function getMaterial(color) {
|
||||
material.dispose();
|
||||
```
|
||||
|
||||
## NodeMaterial / TSL (Future Direction)
|
||||
|
||||
Three.js is moving toward **NodeMaterial** and **TSL (Three.js Shading Language)** as the standard material system, especially for the WebGPU renderer:
|
||||
|
||||
```javascript
|
||||
import { MeshStandardNodeMaterial } from "three/addons/nodes/Nodes.js";
|
||||
import { color, uv, texture } from "three/addons/nodes/Nodes.js";
|
||||
|
||||
const material = new MeshStandardNodeMaterial();
|
||||
material.colorNode = texture(colorMap, uv());
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- NodeMaterial works with both WebGL and WebGPU renderers
|
||||
- `onBeforeCompile` does **not** work with the WebGPU renderer -- use NodeMaterial instead
|
||||
- TSL replaces GLSL for cross-renderer shader compatibility
|
||||
- Standard GLSL `ShaderMaterial` continues to work with the WebGL renderer
|
||||
|
||||
## Lambert/Phong IBL Support (r183)
|
||||
|
||||
As of r183, `MeshLambertMaterial` and `MeshPhongMaterial` support image-based lighting (IBL) via `scene.environment`. Previously, only PBR materials (Standard/Physical) responded to environment maps set on the scene.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-textures` - Texture loading and configuration
|
||||
|
||||
@@ -521,25 +521,46 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
## WebGPU Post-Processing (Three.js r150+)
|
||||
## WebGPU Post-Processing (Three.js r183)
|
||||
|
||||
The WebGPU renderer uses a node-based `PostProcessing` class instead of `EffectComposer`. Note that `EffectComposer` is **WebGL-only**.
|
||||
|
||||
```javascript
|
||||
import { postProcessing } from "three/addons/nodes/Nodes.js";
|
||||
import { pass, bloom, dof } from "three/addons/nodes/Nodes.js";
|
||||
import * as THREE from "three";
|
||||
import { pass, bloom, dof } from "three/tsl";
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
// Using node-based system
|
||||
const scenePass = pass(scene, camera);
|
||||
const bloomNode = bloom(scenePass, 0.5, 0.4, 0.85);
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
|
||||
// Create post-processing
|
||||
const postProcessing = new THREE.PostProcessing(renderer);
|
||||
postProcessing.outputNode = bloomNode;
|
||||
|
||||
// Scene pass
|
||||
const scenePass = pass(scene, camera);
|
||||
|
||||
// Add bloom
|
||||
const bloomPass = bloom(scenePass, 0.5, 0.4, 0.85);
|
||||
|
||||
// Set output
|
||||
postProcessing.outputNode = bloomPass;
|
||||
|
||||
// Render
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(() => {
|
||||
postProcessing.render();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Key Differences from EffectComposer
|
||||
|
||||
| EffectComposer (WebGL) | PostProcessing (WebGPU) |
|
||||
| ------------------------------- | -------------------------------- |
|
||||
| `addPass(new RenderPass(...))` | `pass(scene, camera)` |
|
||||
| `addPass(new UnrealBloomPass)` | `bloom(scenePass, ...)` |
|
||||
| `composer.render()` | `postProcessing.render()` |
|
||||
| Chain of passes | Node graph with `outputNode` |
|
||||
| GLSL shader passes | TSL node-based effects |
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Limit passes**: Each pass adds a full-screen render
|
||||
|
||||
@@ -637,6 +637,49 @@ if (value > 0.5) {
|
||||
color = mix(colorB, colorA, step(0.5, value));
|
||||
```
|
||||
|
||||
## TSL (Three.js Shading Language) - Future Direction
|
||||
|
||||
TSL is the new shader authoring system for Three.js, designed to work with both WebGL and WebGPU renderers. GLSL patterns above are **WebGL-only** and will not work with the WebGPU renderer.
|
||||
|
||||
### TSL Quick Start
|
||||
|
||||
```javascript
|
||||
import { MeshStandardNodeMaterial } from "three/addons/nodes/Nodes.js";
|
||||
import {
|
||||
uv, sin, timerLocal, vec4, color, positionLocal, normalLocal,
|
||||
float, mul, add
|
||||
} from "three/addons/nodes/Nodes.js";
|
||||
|
||||
const material = new MeshStandardNodeMaterial();
|
||||
|
||||
// Animated color based on UV and time
|
||||
const time = timerLocal();
|
||||
material.colorNode = color(sin(add(uv().x, time)), uv().y, 0.5);
|
||||
|
||||
// Vertex displacement
|
||||
material.positionNode = add(
|
||||
positionLocal,
|
||||
mul(normalLocal, sin(add(positionLocal.x, time)).mul(0.1))
|
||||
);
|
||||
```
|
||||
|
||||
### Key Differences from GLSL
|
||||
|
||||
| GLSL (WebGL only) | TSL (WebGL + WebGPU) |
|
||||
| ----------------------- | ---------------------------- |
|
||||
| `ShaderMaterial` | `MeshStandardNodeMaterial` |
|
||||
| String-based shaders | JavaScript node graph |
|
||||
| `onBeforeCompile` | Node composition |
|
||||
| Manual uniforms | `uniform()` node |
|
||||
| `texture2D()` | `texture()` node |
|
||||
| `gl_Position` | `positionNode` |
|
||||
| `gl_FragColor` | `colorNode` / `outputNode` |
|
||||
|
||||
### When to Use What
|
||||
|
||||
- **GLSL ShaderMaterial**: Existing WebGL projects, maximum shader control, porting existing shaders
|
||||
- **TSL NodeMaterial**: New projects, WebGPU support needed, cross-renderer compatibility
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-materials` - Built-in material types
|
||||
|
||||
@@ -22,13 +22,29 @@ Systematically create high-quality 3D scenes and interactive experiences using T
|
||||
|
||||
### 1. Essential Three.js Imports
|
||||
|
||||
Always use the correct CDN version (r128):
|
||||
Use ES module import maps for modern Three.js (r183+):
|
||||
|
||||
```javascript
|
||||
import * as THREE from "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js";
|
||||
```html
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
**CRITICAL**: Do NOT use example imports like `THREE.OrbitControls` - they won't work on the CDN.
|
||||
For production with npm/vite/webpack:
|
||||
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
```
|
||||
|
||||
### 2. Scene Initialization
|
||||
|
||||
@@ -55,16 +71,21 @@ document.body.appendChild(renderer.domElement);
|
||||
|
||||
### 3. Animation Loop
|
||||
|
||||
Use requestAnimationFrame for smooth rendering:
|
||||
Use `renderer.setAnimationLoop()` (preferred) or `requestAnimationFrame`:
|
||||
|
||||
```javascript
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
// Update object transformations here
|
||||
// Preferred: setAnimationLoop (handles WebXR compatibility)
|
||||
renderer.setAnimationLoop(() => {
|
||||
mesh.rotation.x += 0.01;
|
||||
mesh.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
|
||||
// Alternative: manual requestAnimationFrame
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
mesh.rotation.x += 0.01;
|
||||
mesh.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
@@ -93,13 +114,11 @@ Choose appropriate geometry types:
|
||||
- `PlaneGeometry` - flat surfaces, ground planes
|
||||
- `TorusGeometry` - donuts, rings
|
||||
|
||||
**IMPORTANT**: Do NOT use `CapsuleGeometry` (introduced in r142, not available in r128)
|
||||
**CapsuleGeometry** is available (stable since r142):
|
||||
|
||||
**Alternatives for capsules:**
|
||||
|
||||
- Combine `CylinderGeometry` + 2 `SphereGeometry`
|
||||
- Use `SphereGeometry` with adjusted parameters
|
||||
- Create custom geometry with vertices
|
||||
```javascript
|
||||
new THREE.CapsuleGeometry(0.5, 1, 4, 8); // radius, length, capSegments, radialSegments
|
||||
```
|
||||
|
||||
### 3. Apply Materials
|
||||
|
||||
@@ -162,9 +181,26 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Camera Controls (OrbitControls Alternative)
|
||||
### OrbitControls
|
||||
|
||||
Since `THREE.OrbitControls` isn't available on CDN, implement custom controls:
|
||||
With import maps or build tools, OrbitControls works directly:
|
||||
|
||||
```javascript
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
|
||||
// Update in animation loop
|
||||
renderer.setAnimationLoop(() => {
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Camera Controls (Alternative)
|
||||
|
||||
For lightweight custom controls without importing OrbitControls:
|
||||
|
||||
```javascript
|
||||
let isDragging = false;
|
||||
@@ -338,18 +374,18 @@ const material = new THREE.MeshStandardMaterial({
|
||||
|
||||
### Common Pitfalls to Avoid
|
||||
|
||||
- ❌ Using `THREE.OrbitControls` - not available on CDN
|
||||
- ❌ Using `THREE.CapsuleGeometry` - requires r142+
|
||||
- ❌ Using `outputEncoding` instead of `outputColorSpace` (renamed in r152)
|
||||
- ❌ Forgetting to add objects to scene with `scene.add()`
|
||||
- ❌ Using lit materials without adding lights
|
||||
- ❌ Not handling window resize
|
||||
- ❌ Forgetting to call `renderer.render()` in animation loop
|
||||
- ❌ Using `THREE.Clock` without considering `THREE.Timer` (recommended in r183)
|
||||
|
||||
## Example Workflow
|
||||
|
||||
User: "Create an interactive 3D sphere that responds to mouse movement"
|
||||
|
||||
1. **Setup**: Import Three.js (r128), create scene/camera/renderer
|
||||
1. **Setup**: Import Three.js, create scene/camera/renderer
|
||||
2. **Geometry**: Create `SphereGeometry(1, 32, 32)` for smooth sphere
|
||||
3. **Material**: Use `MeshStandardMaterial` for realistic look
|
||||
4. **Lighting**: Add ambient + directional lights
|
||||
@@ -449,7 +485,7 @@ const material = new THREE.MeshStandardMaterial({
|
||||
// Improve color accuracy and HDR rendering
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1.0;
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace; // Was outputEncoding in older versions
|
||||
|
||||
// Makes colors more vibrant and realistic
|
||||
```
|
||||
@@ -474,7 +510,7 @@ geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
|
||||
|
||||
### Post-Processing Effects
|
||||
|
||||
While advanced post-processing may not be available in r128 CDN, basic effects can be achieved with shaders and render targets.
|
||||
Post-processing effects are available via import maps or build tools. See `threejs-postprocessing` skill for EffectComposer, bloom, DOF, and more.
|
||||
|
||||
### Group Objects
|
||||
|
||||
@@ -490,36 +526,64 @@ scene.add(group);
|
||||
|
||||
Three.js artifacts require systematic setup:
|
||||
|
||||
1. Import correct CDN version (r128)
|
||||
1. Import Three.js via import maps or build tools
|
||||
2. Initialize scene, camera, renderer
|
||||
3. Create geometry + material = mesh
|
||||
4. Add lighting if using lit materials
|
||||
5. Implement animation loop
|
||||
5. Implement animation loop (prefer `setAnimationLoop`)
|
||||
6. Handle window resize
|
||||
7. Avoid r128 incompatible features
|
||||
7. Set `renderer.outputColorSpace = THREE.SRGBColorSpace`
|
||||
|
||||
Follow these patterns for reliable, performant 3D experiences.
|
||||
|
||||
## Modern Three.js & Production Practices
|
||||
## Modern Three.js Practices (r183)
|
||||
|
||||
While this skill focuses on CDN-based Three.js (r128) for artifact compatibility, here's what you'd do in production environments:
|
||||
|
||||
### Modular Imports with Build Tools
|
||||
### Modular Imports
|
||||
|
||||
```javascript
|
||||
// In production with npm/vite/webpack:
|
||||
// With npm/vite/webpack:
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
||||
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
### WebGPU Renderer (Alternative)
|
||||
|
||||
- Tree-shaking (smaller bundle sizes)
|
||||
- Access to full example library (OrbitControls, loaders, etc.)
|
||||
- Latest Three.js features (r150+)
|
||||
- TypeScript support
|
||||
Three.js r183 includes a WebGPU renderer as an alternative to WebGL:
|
||||
|
||||
```javascript
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
```
|
||||
|
||||
WebGPU uses TSL (Three.js Shading Language) instead of GLSL for custom shaders. See `threejs-shaders` for details.
|
||||
|
||||
### Timer (r183 Recommended)
|
||||
|
||||
`THREE.Timer` is recommended over `THREE.Clock` as of r183:
|
||||
|
||||
```javascript
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
**Benefits over Clock:**
|
||||
|
||||
- Not affected by page visibility (pauses when tab is hidden)
|
||||
- Cleaner API design
|
||||
- Better integration with `setAnimationLoop`
|
||||
|
||||
### Animation Libraries (GSAP Integration)
|
||||
|
||||
@@ -625,7 +689,7 @@ loader.load("model.gltf", (gltf) => {
|
||||
|
||||
### When to Use What
|
||||
|
||||
**CDN Approach (Current Skill):**
|
||||
**Import Map Approach:**
|
||||
|
||||
- Quick prototypes and demos
|
||||
- Educational content
|
||||
@@ -636,19 +700,16 @@ loader.load("model.gltf", (gltf) => {
|
||||
|
||||
- Client projects and portfolios
|
||||
- Complex applications
|
||||
- Need latest features (r150+)
|
||||
- Performance-critical applications
|
||||
- Team collaboration with version control
|
||||
|
||||
### Recommended Production Stack
|
||||
|
||||
```
|
||||
Three.js (latest) + Vite/Webpack
|
||||
Three.js r183 + Vite
|
||||
├── GSAP (animations)
|
||||
├── React Three Fiber (optional - React integration)
|
||||
├── Drei (helper components)
|
||||
├── Leva (debug GUI)
|
||||
└── Post-processing effects
|
||||
```
|
||||
|
||||
This skill provides CDN-compatible foundations. In production, you'd layer on these modern tools for professional results.
|
||||
|
||||
@@ -623,6 +623,14 @@ const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
|
||||
const textureSize = isMobile ? 1024 : 2048;
|
||||
```
|
||||
|
||||
## KTX2Loader BC3 Alpha Fix (r183)
|
||||
|
||||
As of r183, `KTX2Loader` correctly handles BC3 compressed textures with alpha channels, fixing previously incorrect alpha rendering.
|
||||
|
||||
## ISO 21496-1 Gainmap Metadata (r183)
|
||||
|
||||
Three.js r183 supports ISO 21496-1 gainmap metadata in HDR textures, enabling proper tone mapping of gainmap-based HDR images (such as those produced by recent smartphone cameras).
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-materials` - Applying textures to materials
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"skills": "./skills/",
|
||||
"interface": {
|
||||
"displayName": "Antigravity Awesome Skills",
|
||||
"shortDescription": "1,300 plugin-safe skills for coding, security, product, and ops workflows.",
|
||||
"shortDescription": "1,302 plugin-safe skills for coding, security, product, and ops workflows.",
|
||||
"longDescription": "Install a plugin-safe Codex distribution of Antigravity Awesome Skills. Skills that still need hardening or target-specific setup remain available in the repo but are excluded from this plugin.",
|
||||
"developerName": "sickn33 and contributors",
|
||||
"category": "Productivity",
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
name: phase-gated-debugging
|
||||
description: "Use when debugging any bug. Enforces a 5-phase protocol where code edits are blocked until root cause is confirmed. Prevents premature fix attempts."
|
||||
risk: safe
|
||||
source: community
|
||||
date_added: "2026-03-28"
|
||||
---
|
||||
|
||||
# Phase-Gated Debugging
|
||||
|
||||
## Overview
|
||||
|
||||
AI coding agents see an error and immediately edit code. They guess at fixes, get it wrong, and spiral. This skill enforces a strict 5-phase protocol where you CANNOT edit source code until the root cause is identified and confirmed.
|
||||
|
||||
Based on [claude-debug](https://github.com/krabat-l/claude-debug) (full plugin with PreToolUse hook enforcement).
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
|
||||
- a bug keeps getting "fixed" without resolving the underlying issue
|
||||
- you need to slow an agent down and force disciplined debugging before code edits
|
||||
- the failure is intermittent, a regression, performance-related, or otherwise hard to isolate
|
||||
- you want an explicit user confirmation checkpoint before any fix is applied
|
||||
|
||||
## The Protocol
|
||||
|
||||
### Phase 1: REPRODUCE
|
||||
Run the failing command/test. Capture the exact error. Run 2-3 times for consistency.
|
||||
- Do NOT read source code
|
||||
- Do NOT hypothesize
|
||||
- Do NOT edit any files
|
||||
|
||||
### Phase 2: ISOLATE
|
||||
Read code. Add diagnostic logging marked `// DEBUG`. Re-run with diagnostics. Binary search to narrow down.
|
||||
- Only `// DEBUG` marked logging is allowed
|
||||
- Do NOT fix the bug even if you see it
|
||||
|
||||
### Phase 3: ROOT CAUSE
|
||||
Analyze WHY at the isolated location. Use "5 Whys" technique. Remove debug logging.
|
||||
|
||||
State: "This is my root cause analysis: [explanation]. Do you agree, or should I investigate further?"
|
||||
|
||||
**WAIT for user confirmation. Do NOT proceed without it.**
|
||||
|
||||
### Phase 4: FIX
|
||||
Remove all `// DEBUG` lines. Apply minimal change addressing confirmed root cause.
|
||||
- Only edit files related to root cause
|
||||
- Do NOT refactor unrelated code
|
||||
|
||||
### Phase 5: VERIFY
|
||||
Run original failing test — must pass. Run related tests. For intermittent bugs, run 5+ times.
|
||||
If verification fails: root cause was wrong, go back to Phase 2.
|
||||
|
||||
## Bug-Type Strategies
|
||||
|
||||
| Type | Technique |
|
||||
|------|-----------|
|
||||
| Crash/Panic | Stack trace backward — trace the bad value to its source |
|
||||
| Wrong Output | Binary search — log midpoint, halve search space each iteration |
|
||||
| Intermittent | Compare passing vs failing run logs — find ordering divergence |
|
||||
| Regression | `git bisect` — find the offending commit |
|
||||
| Performance | Timing at stage boundaries — find the bottleneck |
|
||||
|
||||
## Key Rules
|
||||
|
||||
1. NEVER edit source code in phases 1-3 (except `// DEBUG` in phase 2)
|
||||
2. NEVER proceed past phase 3 without user confirmation
|
||||
3. ALWAYS reproduce before investigating
|
||||
4. ALWAYS verify after fixing
|
||||
@@ -12,22 +12,23 @@ source: community
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
|
||||
// Simple procedural animation
|
||||
const clock = new THREE.Clock();
|
||||
// Simple procedural animation with Timer (recommended in r183)
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
function animate() {
|
||||
const delta = clock.getDelta();
|
||||
const elapsed = clock.getElapsedTime();
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta;
|
||||
mesh.position.y = Math.sin(elapsed) * 0.5;
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
});
|
||||
```
|
||||
|
||||
**Note:** `THREE.Timer` is recommended over `THREE.Clock` as of r183. Timer pauses when the page is hidden and has a cleaner API. `THREE.Clock` still works but is considered legacy.
|
||||
|
||||
## Animation System Overview
|
||||
|
||||
Three.js animation system has three main components:
|
||||
@@ -118,6 +119,10 @@ track.setInterpolation(THREE.InterpolateSmooth); // Cubic spline
|
||||
track.setInterpolation(THREE.InterpolateDiscrete); // Step function
|
||||
```
|
||||
|
||||
### BezierInterpolant (r183)
|
||||
|
||||
Three.js r183 adds `THREE.BezierInterpolant` for bezier curve interpolation in keyframe tracks, enabling smoother animation curves with tangent control.
|
||||
|
||||
## AnimationMixer
|
||||
|
||||
Plays animations on an object and its descendants.
|
||||
|
||||
@@ -416,7 +416,24 @@ function dispose() {
|
||||
}
|
||||
```
|
||||
|
||||
### Clock for Animation
|
||||
### Timer and Clock for Animation
|
||||
|
||||
**Timer (recommended in r183)** - pauses when tab is hidden, cleaner API:
|
||||
|
||||
```javascript
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta * 0.5;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
**Clock (legacy, still works):**
|
||||
|
||||
```javascript
|
||||
const clock = new THREE.Clock();
|
||||
@@ -432,6 +449,17 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
### Animation Loop
|
||||
|
||||
Prefer `renderer.setAnimationLoop()` over manual `requestAnimationFrame`. It handles WebXR compatibility and is the standard Three.js pattern:
|
||||
|
||||
```javascript
|
||||
renderer.setAnimationLoop(() => {
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
### Responsive Canvas
|
||||
|
||||
```javascript
|
||||
@@ -483,6 +511,21 @@ lod.addLevel(lowDetailMesh, 100);
|
||||
scene.add(lod);
|
||||
```
|
||||
|
||||
## WebGPU Renderer (r183)
|
||||
|
||||
Three.js includes an experimental WebGPU renderer as an alternative to WebGL:
|
||||
|
||||
```javascript
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
```
|
||||
|
||||
WebGPU uses TSL (Three.js Shading Language) instead of GLSL. The WebGL renderer remains the default and is fully supported.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-geometry` - Geometry creation and manipulation
|
||||
|
||||
@@ -543,6 +543,36 @@ new THREE.SphereGeometry(1, 16, 16); // Performance mode
|
||||
geometry.dispose();
|
||||
```
|
||||
|
||||
## BatchedMesh (r183)
|
||||
|
||||
`BatchedMesh` is a higher-level alternative to `InstancedMesh` that supports multiple geometries in a single draw call. As of r183, it supports **per-instance opacity** and **per-instance wireframe**.
|
||||
|
||||
```javascript
|
||||
const batchedMesh = new THREE.BatchedMesh(maxGeometryCount, maxVertexCount, maxIndexCount);
|
||||
batchedMesh.sortObjects = true; // Enable depth sorting for transparency
|
||||
|
||||
// Add different geometries
|
||||
const boxId = batchedMesh.addGeometry(new THREE.BoxGeometry(1, 1, 1));
|
||||
const sphereId = batchedMesh.addGeometry(new THREE.SphereGeometry(0.5, 16, 16));
|
||||
|
||||
// Add instances of those geometries
|
||||
const instance1 = batchedMesh.addInstance(boxId);
|
||||
const instance2 = batchedMesh.addInstance(sphereId);
|
||||
|
||||
// Set transforms
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(2, 0, 0);
|
||||
batchedMesh.setMatrixAt(instance1, matrix);
|
||||
|
||||
// Per-instance opacity (r183)
|
||||
batchedMesh.setOpacityAt(instance1, 0.5);
|
||||
|
||||
// Per-instance visibility
|
||||
batchedMesh.setVisibleAt(instance2, false);
|
||||
|
||||
scene.add(batchedMesh);
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-fundamentals` - Scene setup and Object3D
|
||||
|
||||
@@ -189,6 +189,18 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
#### OrbitControls Programmatic Methods (r183)
|
||||
|
||||
```javascript
|
||||
// Programmatic camera movement
|
||||
controls.dolly(1.5); // Dolly in/out (zoom for perspective cameras)
|
||||
controls.pan(deltaX, deltaY); // Pan the camera
|
||||
controls.rotate(deltaAzimuth, deltaPolar); // Rotate around target
|
||||
|
||||
// Cursor style (r183)
|
||||
controls.cursorStyle = { orbit: "grab", pan: "move", dolly: "zoom-in" };
|
||||
```
|
||||
|
||||
### FlyControls
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -186,7 +186,7 @@ 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
|
||||
// Must initialize uniforms first (WebGL renderer only)
|
||||
RectAreaLightUniformsLib.init();
|
||||
|
||||
// RectAreaLight(color, intensity, width, height)
|
||||
@@ -199,7 +199,8 @@ scene.add(rectLight);
|
||||
const helper = new RectAreaLightHelper(rectLight);
|
||||
rectLight.add(helper);
|
||||
|
||||
// Note: Only works with MeshStandardMaterial and MeshPhysicalMaterial
|
||||
// Works with MeshStandardMaterial, MeshPhysicalMaterial
|
||||
// r183: Clearcoat on MeshPhysicalMaterial is now properly lit by RectAreaLight
|
||||
// Does not cast shadows natively
|
||||
```
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ import { KTX2Loader } from "three/addons/loaders/KTX2Loader.js";
|
||||
|
||||
const ktx2Loader = new KTX2Loader();
|
||||
ktx2Loader.setTranscoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/basis/",
|
||||
"https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/libs/basis/",
|
||||
);
|
||||
ktx2Loader.detectSupport(renderer);
|
||||
|
||||
@@ -267,6 +267,22 @@ gltfLoader.load("model-with-ktx2.glb", (gltf) => {
|
||||
});
|
||||
```
|
||||
|
||||
### GLTF with Meshopt Compression (r183)
|
||||
|
||||
```javascript
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
||||
import { MeshoptDecoder } from "three/addons/libs/meshopt_decoder.module.js";
|
||||
|
||||
const gltfLoader = new GLTFLoader();
|
||||
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
|
||||
|
||||
gltfLoader.load("compressed-model.glb", (gltf) => {
|
||||
scene.add(gltf.scene);
|
||||
});
|
||||
```
|
||||
|
||||
**KHR_meshopt_compression** is an alternative to Draco that often provides better compression for animated meshes and preserves mesh topology.
|
||||
|
||||
### Process GLTF Content
|
||||
|
||||
```javascript
|
||||
@@ -618,6 +634,10 @@ loadModel("model.glb").then((gltf) => {
|
||||
});
|
||||
```
|
||||
|
||||
## VRMLLoader Camera Support (r183)
|
||||
|
||||
As of r183, `VRMLLoader` supports loading cameras defined in VRML files.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-textures` - Texture configuration
|
||||
|
||||
@@ -515,6 +515,28 @@ function getMaterial(color) {
|
||||
material.dispose();
|
||||
```
|
||||
|
||||
## NodeMaterial / TSL (Future Direction)
|
||||
|
||||
Three.js is moving toward **NodeMaterial** and **TSL (Three.js Shading Language)** as the standard material system, especially for the WebGPU renderer:
|
||||
|
||||
```javascript
|
||||
import { MeshStandardNodeMaterial } from "three/addons/nodes/Nodes.js";
|
||||
import { color, uv, texture } from "three/addons/nodes/Nodes.js";
|
||||
|
||||
const material = new MeshStandardNodeMaterial();
|
||||
material.colorNode = texture(colorMap, uv());
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- NodeMaterial works with both WebGL and WebGPU renderers
|
||||
- `onBeforeCompile` does **not** work with the WebGPU renderer -- use NodeMaterial instead
|
||||
- TSL replaces GLSL for cross-renderer shader compatibility
|
||||
- Standard GLSL `ShaderMaterial` continues to work with the WebGL renderer
|
||||
|
||||
## Lambert/Phong IBL Support (r183)
|
||||
|
||||
As of r183, `MeshLambertMaterial` and `MeshPhongMaterial` support image-based lighting (IBL) via `scene.environment`. Previously, only PBR materials (Standard/Physical) responded to environment maps set on the scene.
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-textures` - Texture loading and configuration
|
||||
|
||||
@@ -521,25 +521,46 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
## WebGPU Post-Processing (Three.js r150+)
|
||||
## WebGPU Post-Processing (Three.js r183)
|
||||
|
||||
The WebGPU renderer uses a node-based `PostProcessing` class instead of `EffectComposer`. Note that `EffectComposer` is **WebGL-only**.
|
||||
|
||||
```javascript
|
||||
import { postProcessing } from "three/addons/nodes/Nodes.js";
|
||||
import { pass, bloom, dof } from "three/addons/nodes/Nodes.js";
|
||||
import * as THREE from "three";
|
||||
import { pass, bloom, dof } from "three/tsl";
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
// Using node-based system
|
||||
const scenePass = pass(scene, camera);
|
||||
const bloomNode = bloom(scenePass, 0.5, 0.4, 0.85);
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
|
||||
// Create post-processing
|
||||
const postProcessing = new THREE.PostProcessing(renderer);
|
||||
postProcessing.outputNode = bloomNode;
|
||||
|
||||
// Scene pass
|
||||
const scenePass = pass(scene, camera);
|
||||
|
||||
// Add bloom
|
||||
const bloomPass = bloom(scenePass, 0.5, 0.4, 0.85);
|
||||
|
||||
// Set output
|
||||
postProcessing.outputNode = bloomPass;
|
||||
|
||||
// Render
|
||||
function animate() {
|
||||
renderer.setAnimationLoop(() => {
|
||||
postProcessing.render();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Key Differences from EffectComposer
|
||||
|
||||
| EffectComposer (WebGL) | PostProcessing (WebGPU) |
|
||||
| ------------------------------- | -------------------------------- |
|
||||
| `addPass(new RenderPass(...))` | `pass(scene, camera)` |
|
||||
| `addPass(new UnrealBloomPass)` | `bloom(scenePass, ...)` |
|
||||
| `composer.render()` | `postProcessing.render()` |
|
||||
| Chain of passes | Node graph with `outputNode` |
|
||||
| GLSL shader passes | TSL node-based effects |
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Limit passes**: Each pass adds a full-screen render
|
||||
|
||||
@@ -637,6 +637,49 @@ if (value > 0.5) {
|
||||
color = mix(colorB, colorA, step(0.5, value));
|
||||
```
|
||||
|
||||
## TSL (Three.js Shading Language) - Future Direction
|
||||
|
||||
TSL is the new shader authoring system for Three.js, designed to work with both WebGL and WebGPU renderers. GLSL patterns above are **WebGL-only** and will not work with the WebGPU renderer.
|
||||
|
||||
### TSL Quick Start
|
||||
|
||||
```javascript
|
||||
import { MeshStandardNodeMaterial } from "three/addons/nodes/Nodes.js";
|
||||
import {
|
||||
uv, sin, timerLocal, vec4, color, positionLocal, normalLocal,
|
||||
float, mul, add
|
||||
} from "three/addons/nodes/Nodes.js";
|
||||
|
||||
const material = new MeshStandardNodeMaterial();
|
||||
|
||||
// Animated color based on UV and time
|
||||
const time = timerLocal();
|
||||
material.colorNode = color(sin(add(uv().x, time)), uv().y, 0.5);
|
||||
|
||||
// Vertex displacement
|
||||
material.positionNode = add(
|
||||
positionLocal,
|
||||
mul(normalLocal, sin(add(positionLocal.x, time)).mul(0.1))
|
||||
);
|
||||
```
|
||||
|
||||
### Key Differences from GLSL
|
||||
|
||||
| GLSL (WebGL only) | TSL (WebGL + WebGPU) |
|
||||
| ----------------------- | ---------------------------- |
|
||||
| `ShaderMaterial` | `MeshStandardNodeMaterial` |
|
||||
| String-based shaders | JavaScript node graph |
|
||||
| `onBeforeCompile` | Node composition |
|
||||
| Manual uniforms | `uniform()` node |
|
||||
| `texture2D()` | `texture()` node |
|
||||
| `gl_Position` | `positionNode` |
|
||||
| `gl_FragColor` | `colorNode` / `outputNode` |
|
||||
|
||||
### When to Use What
|
||||
|
||||
- **GLSL ShaderMaterial**: Existing WebGL projects, maximum shader control, porting existing shaders
|
||||
- **TSL NodeMaterial**: New projects, WebGPU support needed, cross-renderer compatibility
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-materials` - Built-in material types
|
||||
|
||||
@@ -22,13 +22,29 @@ Systematically create high-quality 3D scenes and interactive experiences using T
|
||||
|
||||
### 1. Essential Three.js Imports
|
||||
|
||||
Always use the correct CDN version (r128):
|
||||
Use ES module import maps for modern Three.js (r183+):
|
||||
|
||||
```javascript
|
||||
import * as THREE from "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js";
|
||||
```html
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
**CRITICAL**: Do NOT use example imports like `THREE.OrbitControls` - they won't work on the CDN.
|
||||
For production with npm/vite/webpack:
|
||||
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
```
|
||||
|
||||
### 2. Scene Initialization
|
||||
|
||||
@@ -55,16 +71,21 @@ document.body.appendChild(renderer.domElement);
|
||||
|
||||
### 3. Animation Loop
|
||||
|
||||
Use requestAnimationFrame for smooth rendering:
|
||||
Use `renderer.setAnimationLoop()` (preferred) or `requestAnimationFrame`:
|
||||
|
||||
```javascript
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
// Update object transformations here
|
||||
// Preferred: setAnimationLoop (handles WebXR compatibility)
|
||||
renderer.setAnimationLoop(() => {
|
||||
mesh.rotation.x += 0.01;
|
||||
mesh.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
|
||||
// Alternative: manual requestAnimationFrame
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
mesh.rotation.x += 0.01;
|
||||
mesh.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
@@ -93,13 +114,11 @@ Choose appropriate geometry types:
|
||||
- `PlaneGeometry` - flat surfaces, ground planes
|
||||
- `TorusGeometry` - donuts, rings
|
||||
|
||||
**IMPORTANT**: Do NOT use `CapsuleGeometry` (introduced in r142, not available in r128)
|
||||
**CapsuleGeometry** is available (stable since r142):
|
||||
|
||||
**Alternatives for capsules:**
|
||||
|
||||
- Combine `CylinderGeometry` + 2 `SphereGeometry`
|
||||
- Use `SphereGeometry` with adjusted parameters
|
||||
- Create custom geometry with vertices
|
||||
```javascript
|
||||
new THREE.CapsuleGeometry(0.5, 1, 4, 8); // radius, length, capSegments, radialSegments
|
||||
```
|
||||
|
||||
### 3. Apply Materials
|
||||
|
||||
@@ -162,9 +181,26 @@ function animate() {
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Camera Controls (OrbitControls Alternative)
|
||||
### OrbitControls
|
||||
|
||||
Since `THREE.OrbitControls` isn't available on CDN, implement custom controls:
|
||||
With import maps or build tools, OrbitControls works directly:
|
||||
|
||||
```javascript
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
|
||||
// Update in animation loop
|
||||
renderer.setAnimationLoop(() => {
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Camera Controls (Alternative)
|
||||
|
||||
For lightweight custom controls without importing OrbitControls:
|
||||
|
||||
```javascript
|
||||
let isDragging = false;
|
||||
@@ -338,18 +374,18 @@ const material = new THREE.MeshStandardMaterial({
|
||||
|
||||
### Common Pitfalls to Avoid
|
||||
|
||||
- ❌ Using `THREE.OrbitControls` - not available on CDN
|
||||
- ❌ Using `THREE.CapsuleGeometry` - requires r142+
|
||||
- ❌ Using `outputEncoding` instead of `outputColorSpace` (renamed in r152)
|
||||
- ❌ Forgetting to add objects to scene with `scene.add()`
|
||||
- ❌ Using lit materials without adding lights
|
||||
- ❌ Not handling window resize
|
||||
- ❌ Forgetting to call `renderer.render()` in animation loop
|
||||
- ❌ Using `THREE.Clock` without considering `THREE.Timer` (recommended in r183)
|
||||
|
||||
## Example Workflow
|
||||
|
||||
User: "Create an interactive 3D sphere that responds to mouse movement"
|
||||
|
||||
1. **Setup**: Import Three.js (r128), create scene/camera/renderer
|
||||
1. **Setup**: Import Three.js, create scene/camera/renderer
|
||||
2. **Geometry**: Create `SphereGeometry(1, 32, 32)` for smooth sphere
|
||||
3. **Material**: Use `MeshStandardMaterial` for realistic look
|
||||
4. **Lighting**: Add ambient + directional lights
|
||||
@@ -449,7 +485,7 @@ const material = new THREE.MeshStandardMaterial({
|
||||
// Improve color accuracy and HDR rendering
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1.0;
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace; // Was outputEncoding in older versions
|
||||
|
||||
// Makes colors more vibrant and realistic
|
||||
```
|
||||
@@ -474,7 +510,7 @@ geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
|
||||
|
||||
### Post-Processing Effects
|
||||
|
||||
While advanced post-processing may not be available in r128 CDN, basic effects can be achieved with shaders and render targets.
|
||||
Post-processing effects are available via import maps or build tools. See `threejs-postprocessing` skill for EffectComposer, bloom, DOF, and more.
|
||||
|
||||
### Group Objects
|
||||
|
||||
@@ -490,36 +526,64 @@ scene.add(group);
|
||||
|
||||
Three.js artifacts require systematic setup:
|
||||
|
||||
1. Import correct CDN version (r128)
|
||||
1. Import Three.js via import maps or build tools
|
||||
2. Initialize scene, camera, renderer
|
||||
3. Create geometry + material = mesh
|
||||
4. Add lighting if using lit materials
|
||||
5. Implement animation loop
|
||||
5. Implement animation loop (prefer `setAnimationLoop`)
|
||||
6. Handle window resize
|
||||
7. Avoid r128 incompatible features
|
||||
7. Set `renderer.outputColorSpace = THREE.SRGBColorSpace`
|
||||
|
||||
Follow these patterns for reliable, performant 3D experiences.
|
||||
|
||||
## Modern Three.js & Production Practices
|
||||
## Modern Three.js Practices (r183)
|
||||
|
||||
While this skill focuses on CDN-based Three.js (r128) for artifact compatibility, here's what you'd do in production environments:
|
||||
|
||||
### Modular Imports with Build Tools
|
||||
### Modular Imports
|
||||
|
||||
```javascript
|
||||
// In production with npm/vite/webpack:
|
||||
// With npm/vite/webpack:
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
||||
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
### WebGPU Renderer (Alternative)
|
||||
|
||||
- Tree-shaking (smaller bundle sizes)
|
||||
- Access to full example library (OrbitControls, loaders, etc.)
|
||||
- Latest Three.js features (r150+)
|
||||
- TypeScript support
|
||||
Three.js r183 includes a WebGPU renderer as an alternative to WebGL:
|
||||
|
||||
```javascript
|
||||
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
|
||||
|
||||
const renderer = new WebGPURenderer({ antialias: true });
|
||||
await renderer.init();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
```
|
||||
|
||||
WebGPU uses TSL (Three.js Shading Language) instead of GLSL for custom shaders. See `threejs-shaders` for details.
|
||||
|
||||
### Timer (r183 Recommended)
|
||||
|
||||
`THREE.Timer` is recommended over `THREE.Clock` as of r183:
|
||||
|
||||
```javascript
|
||||
const timer = new THREE.Timer();
|
||||
|
||||
renderer.setAnimationLoop(() => {
|
||||
timer.update();
|
||||
const delta = timer.getDelta();
|
||||
const elapsed = timer.getElapsed();
|
||||
|
||||
mesh.rotation.y += delta;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
**Benefits over Clock:**
|
||||
|
||||
- Not affected by page visibility (pauses when tab is hidden)
|
||||
- Cleaner API design
|
||||
- Better integration with `setAnimationLoop`
|
||||
|
||||
### Animation Libraries (GSAP Integration)
|
||||
|
||||
@@ -625,7 +689,7 @@ loader.load("model.gltf", (gltf) => {
|
||||
|
||||
### When to Use What
|
||||
|
||||
**CDN Approach (Current Skill):**
|
||||
**Import Map Approach:**
|
||||
|
||||
- Quick prototypes and demos
|
||||
- Educational content
|
||||
@@ -636,19 +700,16 @@ loader.load("model.gltf", (gltf) => {
|
||||
|
||||
- Client projects and portfolios
|
||||
- Complex applications
|
||||
- Need latest features (r150+)
|
||||
- Performance-critical applications
|
||||
- Team collaboration with version control
|
||||
|
||||
### Recommended Production Stack
|
||||
|
||||
```
|
||||
Three.js (latest) + Vite/Webpack
|
||||
Three.js r183 + Vite
|
||||
├── GSAP (animations)
|
||||
├── React Three Fiber (optional - React integration)
|
||||
├── Drei (helper components)
|
||||
├── Leva (debug GUI)
|
||||
└── Post-processing effects
|
||||
```
|
||||
|
||||
This skill provides CDN-compatible foundations. In production, you'd layer on these modern tools for professional results.
|
||||
|
||||
@@ -623,6 +623,14 @@ const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
|
||||
const textureSize = isMobile ? 1024 : 2048;
|
||||
```
|
||||
|
||||
## KTX2Loader BC3 Alpha Fix (r183)
|
||||
|
||||
As of r183, `KTX2Loader` correctly handles BC3 compressed textures with alpha channels, fixing previously incorrect alpha rendering.
|
||||
|
||||
## ISO 21496-1 Gainmap Metadata (r183)
|
||||
|
||||
Three.js r183 supports ISO 21496-1 gainmap metadata in HDR textures, enabling proper tone mapping of gainmap-based HDR images (such as those produced by recent smartphone cameras).
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-materials` - Applying textures to materials
|
||||
|
||||
Reference in New Issue
Block a user