Add 260+ Claude Code skills from skills.sh
Complete collection of AI agent skills including: - Frontend Development (Vue, React, Next.js, Three.js) - Backend Development (NestJS, FastAPI, Node.js) - Mobile Development (React Native, Expo) - Testing (E2E, frontend, webapp) - DevOps (GitHub Actions, CI/CD) - Marketing (SEO, copywriting, analytics) - Security (binary analysis, vulnerability scanning) - And many more... Synchronized from: https://skills.sh/ Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
488
threejs-fundamentals/skill.md
Normal file
488
threejs-fundamentals/skill.md
Normal file
@@ -0,0 +1,488 @@
|
||||
---
|
||||
name: threejs-fundamentals
|
||||
description: Three.js scene setup, cameras, renderer, Object3D hierarchy, coordinate systems. Use when setting up 3D scenes, creating cameras, configuring renderers, managing object hierarchies, or working with transforms.
|
||||
---
|
||||
|
||||
# Three.js Fundamentals
|
||||
|
||||
## Quick Start
|
||||
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
|
||||
// Create scene, camera, renderer
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
window.innerWidth / window.innerHeight,
|
||||
0.1,
|
||||
1000,
|
||||
);
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
// Add a mesh
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
scene.add(cube);
|
||||
|
||||
// Add light
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
||||
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||
dirLight.position.set(5, 5, 5);
|
||||
scene.add(dirLight);
|
||||
|
||||
camera.position.z = 5;
|
||||
|
||||
// Animation loop
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
cube.rotation.x += 0.01;
|
||||
cube.rotation.y += 0.01;
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
|
||||
// Handle resize
|
||||
window.addEventListener("resize", () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
});
|
||||
```
|
||||
|
||||
## Core Classes
|
||||
|
||||
### Scene
|
||||
|
||||
Container for all 3D objects, lights, and cameras.
|
||||
|
||||
```javascript
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x000000); // Solid color
|
||||
scene.background = texture; // Skybox texture
|
||||
scene.background = cubeTexture; // Cubemap
|
||||
scene.environment = envMap; // Environment map for PBR
|
||||
scene.fog = new THREE.Fog(0xffffff, 1, 100); // Linear fog
|
||||
scene.fog = new THREE.FogExp2(0xffffff, 0.02); // Exponential fog
|
||||
```
|
||||
|
||||
### Cameras
|
||||
|
||||
**PerspectiveCamera** - Most common, simulates human eye.
|
||||
|
||||
```javascript
|
||||
// PerspectiveCamera(fov, aspect, near, far)
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
75, // Field of view (degrees)
|
||||
window.innerWidth / window.innerHeight, // Aspect ratio
|
||||
0.1, // Near clipping plane
|
||||
1000, // Far clipping plane
|
||||
);
|
||||
|
||||
camera.position.set(0, 5, 10);
|
||||
camera.lookAt(0, 0, 0);
|
||||
camera.updateProjectionMatrix(); // Call after changing fov, aspect, near, far
|
||||
```
|
||||
|
||||
**OrthographicCamera** - No perspective distortion, good for 2D/isometric.
|
||||
|
||||
```javascript
|
||||
// OrthographicCamera(left, right, top, bottom, near, far)
|
||||
const aspect = window.innerWidth / window.innerHeight;
|
||||
const frustumSize = 10;
|
||||
const camera = new THREE.OrthographicCamera(
|
||||
(frustumSize * aspect) / -2,
|
||||
(frustumSize * aspect) / 2,
|
||||
frustumSize / 2,
|
||||
frustumSize / -2,
|
||||
0.1,
|
||||
1000,
|
||||
);
|
||||
```
|
||||
|
||||
**ArrayCamera** - Multiple viewports with sub-cameras.
|
||||
|
||||
```javascript
|
||||
const cameras = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const subcamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
|
||||
subcamera.viewport = new THREE.Vector4(
|
||||
Math.floor(i % 2) * 0.5,
|
||||
Math.floor(i / 2) * 0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
);
|
||||
cameras.push(subcamera);
|
||||
}
|
||||
const arrayCamera = new THREE.ArrayCamera(cameras);
|
||||
```
|
||||
|
||||
**CubeCamera** - Renders environment maps for reflections.
|
||||
|
||||
```javascript
|
||||
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);
|
||||
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
|
||||
scene.add(cubeCamera);
|
||||
|
||||
// Use for reflections
|
||||
material.envMap = cubeRenderTarget.texture;
|
||||
|
||||
// Update each frame (expensive!)
|
||||
cubeCamera.position.copy(reflectiveMesh.position);
|
||||
cubeCamera.update(renderer, scene);
|
||||
```
|
||||
|
||||
### WebGLRenderer
|
||||
|
||||
```javascript
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
canvas: document.querySelector("#canvas"), // Optional existing canvas
|
||||
antialias: true, // Smooth edges
|
||||
alpha: true, // Transparent background
|
||||
powerPreference: "high-performance", // GPU hint
|
||||
preserveDrawingBuffer: true, // For screenshots
|
||||
});
|
||||
|
||||
renderer.setSize(width, height);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
|
||||
// Tone mapping
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1.0;
|
||||
|
||||
// Color space (Three.js r152+)
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
// Shadows
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
|
||||
// Clear color
|
||||
renderer.setClearColor(0x000000, 1);
|
||||
|
||||
// Render
|
||||
renderer.render(scene, camera);
|
||||
```
|
||||
|
||||
### Object3D
|
||||
|
||||
Base class for all 3D objects. Mesh, Group, Light, Camera all extend Object3D.
|
||||
|
||||
```javascript
|
||||
const obj = new THREE.Object3D();
|
||||
|
||||
// Transform
|
||||
obj.position.set(x, y, z);
|
||||
obj.rotation.set(x, y, z); // Euler angles (radians)
|
||||
obj.quaternion.set(x, y, z, w); // Quaternion rotation
|
||||
obj.scale.set(x, y, z);
|
||||
|
||||
// Local vs World transforms
|
||||
obj.getWorldPosition(targetVector);
|
||||
obj.getWorldQuaternion(targetQuaternion);
|
||||
obj.getWorldDirection(targetVector);
|
||||
|
||||
// Hierarchy
|
||||
obj.add(child);
|
||||
obj.remove(child);
|
||||
obj.parent;
|
||||
obj.children;
|
||||
|
||||
// Visibility
|
||||
obj.visible = false;
|
||||
|
||||
// Layers (for selective rendering/raycasting)
|
||||
obj.layers.set(1);
|
||||
obj.layers.enable(2);
|
||||
obj.layers.disable(0);
|
||||
|
||||
// Traverse hierarchy
|
||||
obj.traverse((child) => {
|
||||
if (child.isMesh) child.material.color.set(0xff0000);
|
||||
});
|
||||
|
||||
// Matrix updates
|
||||
obj.matrixAutoUpdate = true; // Default: auto-update matrices
|
||||
obj.updateMatrix(); // Manual matrix update
|
||||
obj.updateMatrixWorld(true); // Update world matrix recursively
|
||||
```
|
||||
|
||||
### Group
|
||||
|
||||
Empty container for organizing objects.
|
||||
|
||||
```javascript
|
||||
const group = new THREE.Group();
|
||||
group.add(mesh1);
|
||||
group.add(mesh2);
|
||||
scene.add(group);
|
||||
|
||||
// Transform entire group
|
||||
group.position.x = 5;
|
||||
group.rotation.y = Math.PI / 4;
|
||||
```
|
||||
|
||||
### Mesh
|
||||
|
||||
Combines geometry and material.
|
||||
|
||||
```javascript
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
// Multiple materials (one per geometry group)
|
||||
const mesh = new THREE.Mesh(geometry, [material1, material2]);
|
||||
|
||||
// Useful properties
|
||||
mesh.geometry;
|
||||
mesh.material;
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
// Frustum culling
|
||||
mesh.frustumCulled = true; // Default: skip if outside camera view
|
||||
|
||||
// Render order
|
||||
mesh.renderOrder = 10; // Higher = rendered later
|
||||
```
|
||||
|
||||
## Coordinate System
|
||||
|
||||
Three.js uses a **right-handed coordinate system**:
|
||||
|
||||
- **+X** points right
|
||||
- **+Y** points up
|
||||
- **+Z** points toward viewer (out of screen)
|
||||
|
||||
```javascript
|
||||
// Axes helper
|
||||
const axesHelper = new THREE.AxesHelper(5);
|
||||
scene.add(axesHelper); // Red=X, Green=Y, Blue=Z
|
||||
```
|
||||
|
||||
## Math Utilities
|
||||
|
||||
### Vector3
|
||||
|
||||
```javascript
|
||||
const v = new THREE.Vector3(x, y, z);
|
||||
v.set(x, y, z);
|
||||
v.copy(otherVector);
|
||||
v.clone();
|
||||
|
||||
// Operations (modify in place)
|
||||
v.add(v2);
|
||||
v.sub(v2);
|
||||
v.multiply(v2);
|
||||
v.multiplyScalar(2);
|
||||
v.divideScalar(2);
|
||||
v.normalize();
|
||||
v.negate();
|
||||
v.clamp(min, max);
|
||||
v.lerp(target, alpha);
|
||||
|
||||
// Calculations (return new value)
|
||||
v.length();
|
||||
v.lengthSq(); // Faster than length()
|
||||
v.distanceTo(v2);
|
||||
v.dot(v2);
|
||||
v.cross(v2); // Modifies v
|
||||
v.angleTo(v2);
|
||||
|
||||
// Transform
|
||||
v.applyMatrix4(matrix);
|
||||
v.applyQuaternion(q);
|
||||
v.project(camera); // World to NDC
|
||||
v.unproject(camera); // NDC to world
|
||||
```
|
||||
|
||||
### Matrix4
|
||||
|
||||
```javascript
|
||||
const m = new THREE.Matrix4();
|
||||
m.identity();
|
||||
m.copy(other);
|
||||
m.clone();
|
||||
|
||||
// Build transforms
|
||||
m.makeTranslation(x, y, z);
|
||||
m.makeRotationX(theta);
|
||||
m.makeRotationY(theta);
|
||||
m.makeRotationZ(theta);
|
||||
m.makeRotationFromQuaternion(q);
|
||||
m.makeScale(x, y, z);
|
||||
|
||||
// Compose/decompose
|
||||
m.compose(position, quaternion, scale);
|
||||
m.decompose(position, quaternion, scale);
|
||||
|
||||
// Operations
|
||||
m.multiply(m2); // m = m * m2
|
||||
m.premultiply(m2); // m = m2 * m
|
||||
m.invert();
|
||||
m.transpose();
|
||||
|
||||
// Camera matrices
|
||||
m.makePerspective(left, right, top, bottom, near, far);
|
||||
m.makeOrthographic(left, right, top, bottom, near, far);
|
||||
m.lookAt(eye, target, up);
|
||||
```
|
||||
|
||||
### Quaternion
|
||||
|
||||
```javascript
|
||||
const q = new THREE.Quaternion();
|
||||
q.setFromEuler(euler);
|
||||
q.setFromAxisAngle(axis, angle);
|
||||
q.setFromRotationMatrix(matrix);
|
||||
|
||||
q.multiply(q2);
|
||||
q.slerp(target, t); // Spherical interpolation
|
||||
q.normalize();
|
||||
q.invert();
|
||||
```
|
||||
|
||||
### Euler
|
||||
|
||||
```javascript
|
||||
const euler = new THREE.Euler(x, y, z, "XYZ"); // Order matters!
|
||||
euler.setFromQuaternion(q);
|
||||
euler.setFromRotationMatrix(m);
|
||||
|
||||
// Rotation orders: 'XYZ', 'YXZ', 'ZXY', 'XZY', 'YZX', 'ZYX'
|
||||
```
|
||||
|
||||
### Color
|
||||
|
||||
```javascript
|
||||
const color = new THREE.Color(0xff0000);
|
||||
const color = new THREE.Color("red");
|
||||
const color = new THREE.Color("rgb(255, 0, 0)");
|
||||
const color = new THREE.Color("#ff0000");
|
||||
|
||||
color.setHex(0x00ff00);
|
||||
color.setRGB(r, g, b); // 0-1 range
|
||||
color.setHSL(h, s, l); // 0-1 range
|
||||
|
||||
color.lerp(otherColor, alpha);
|
||||
color.multiply(otherColor);
|
||||
color.multiplyScalar(2);
|
||||
```
|
||||
|
||||
### MathUtils
|
||||
|
||||
```javascript
|
||||
THREE.MathUtils.clamp(value, min, max);
|
||||
THREE.MathUtils.lerp(start, end, alpha);
|
||||
THREE.MathUtils.mapLinear(value, inMin, inMax, outMin, outMax);
|
||||
THREE.MathUtils.degToRad(degrees);
|
||||
THREE.MathUtils.radToDeg(radians);
|
||||
THREE.MathUtils.randFloat(min, max);
|
||||
THREE.MathUtils.randInt(min, max);
|
||||
THREE.MathUtils.smoothstep(x, min, max);
|
||||
THREE.MathUtils.smootherstep(x, min, max);
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Proper Cleanup
|
||||
|
||||
```javascript
|
||||
function dispose() {
|
||||
// Dispose geometries
|
||||
mesh.geometry.dispose();
|
||||
|
||||
// Dispose materials
|
||||
if (Array.isArray(mesh.material)) {
|
||||
mesh.material.forEach((m) => m.dispose());
|
||||
} else {
|
||||
mesh.material.dispose();
|
||||
}
|
||||
|
||||
// Dispose textures
|
||||
texture.dispose();
|
||||
|
||||
// Remove from scene
|
||||
scene.remove(mesh);
|
||||
|
||||
// Dispose renderer
|
||||
renderer.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
### Clock for Animation
|
||||
|
||||
```javascript
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
function animate() {
|
||||
const delta = clock.getDelta(); // Time since last frame (seconds)
|
||||
const elapsed = clock.getElapsedTime(); // Total time (seconds)
|
||||
|
||||
mesh.rotation.y += delta * 0.5; // Consistent speed regardless of framerate
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
```
|
||||
|
||||
### Responsive Canvas
|
||||
|
||||
```javascript
|
||||
function onWindowResize() {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(width, height);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
}
|
||||
window.addEventListener("resize", onWindowResize);
|
||||
```
|
||||
|
||||
### Loading Manager
|
||||
|
||||
```javascript
|
||||
const manager = new THREE.LoadingManager();
|
||||
|
||||
manager.onStart = (url, loaded, total) => console.log("Started loading");
|
||||
manager.onLoad = () => console.log("All loaded");
|
||||
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);
|
||||
manager.onError = (url) => console.error(`Error loading ${url}`);
|
||||
|
||||
const textureLoader = new THREE.TextureLoader(manager);
|
||||
const gltfLoader = new GLTFLoader(manager);
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Limit draw calls**: Merge geometries, use instancing, atlas textures
|
||||
2. **Frustum culling**: Enabled by default, ensure bounding boxes are correct
|
||||
3. **LOD (Level of Detail)**: Use `THREE.LOD` for distance-based mesh switching
|
||||
4. **Object pooling**: Reuse objects instead of creating/destroying
|
||||
5. **Avoid `getWorldPosition` in loops**: Cache results
|
||||
|
||||
```javascript
|
||||
// Merge static geometries
|
||||
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
||||
const merged = mergeGeometries([geo1, geo2, geo3]);
|
||||
|
||||
// LOD
|
||||
const lod = new THREE.LOD();
|
||||
lod.addLevel(highDetailMesh, 0);
|
||||
lod.addLevel(medDetailMesh, 50);
|
||||
lod.addLevel(lowDetailMesh, 100);
|
||||
scene.add(lod);
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-geometry` - Geometry creation and manipulation
|
||||
- `threejs-materials` - Material types and properties
|
||||
- `threejs-lighting` - Light types and shadows
|
||||
Reference in New Issue
Block a user