Create 3D scenes, interactive experiences, and visual effects using Three.js. Use when user requests 3D graphics, WebGL experiences, 3D visualizations, animations, or interactive 3D elements.
Add this skill
npx mdskills install sickn33/threejs-skillsComprehensive Three.js guide with excellent patterns, workarounds, and troubleshooting for CDN constraints
1---2name: threejs-skills3description: Create 3D scenes, interactive experiences, and visual effects using Three.js. Use when user requests 3D graphics, WebGL experiences, 3D visualizations, animations, or interactive 3D elements.4source: https://github.com/CloudAI-X/threejs-skills5risk: safe6---78# Three.js Skills910Systematically create high-quality 3D scenes and interactive experiences using Three.js best practices.1112## When to Use1314- Requests 3D visualizations or graphics ("create a 3D model", "show in 3D")15- Wants interactive 3D experiences ("rotating cube", "explorable scene")16- Needs WebGL or canvas-based rendering17- Asks for animations, particles, or visual effects18- Mentions Three.js, WebGL, or 3D rendering19- Wants to visualize data in 3D space2021## Core Setup Pattern2223### 1. Essential Three.js Imports2425Always use the correct CDN version (r128):2627```javascript28import * as THREE from "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js";29```3031**CRITICAL**: Do NOT use example imports like `THREE.OrbitControls` - they won't work on the CDN.3233### 2. Scene Initialization3435Every Three.js artifact needs these core components:3637```javascript38// Scene - contains all 3D objects39const scene = new THREE.Scene();4041// Camera - defines viewing perspective42const camera = new THREE.PerspectiveCamera(43 75, // Field of view44 window.innerWidth / window.innerHeight, // Aspect ratio45 0.1, // Near clipping plane46 1000, // Far clipping plane47);48camera.position.z = 5;4950// Renderer - draws the scene51const renderer = new THREE.WebGLRenderer({ antialias: true });52renderer.setSize(window.innerWidth, window.innerHeight);53document.body.appendChild(renderer.domElement);54```5556### 3. Animation Loop5758Use requestAnimationFrame for smooth rendering:5960```javascript61function animate() {62 requestAnimationFrame(animate);6364 // Update object transformations here65 mesh.rotation.x += 0.01;66 mesh.rotation.y += 0.01;6768 renderer.render(scene, camera);69}70animate();71```7273## Systematic Development Process7475### 1. Define the Scene7677Start by identifying:7879- **What objects** need to be rendered80- **Camera position** and field of view81- **Lighting setup** required82- **Interaction model** (static, rotating, user-controlled)8384### 2. Build Geometry8586Choose appropriate geometry types:8788**Basic Shapes:**8990- `BoxGeometry` - cubes, rectangular prisms91- `SphereGeometry` - spheres, planets92- `CylinderGeometry` - cylinders, tubes93- `PlaneGeometry` - flat surfaces, ground planes94- `TorusGeometry` - donuts, rings9596**IMPORTANT**: Do NOT use `CapsuleGeometry` (introduced in r142, not available in r128)9798**Alternatives for capsules:**99100- Combine `CylinderGeometry` + 2 `SphereGeometry`101- Use `SphereGeometry` with adjusted parameters102- Create custom geometry with vertices103104### 3. Apply Materials105106Choose materials based on visual needs:107108**Common Materials:**109110- `MeshBasicMaterial` - unlit, flat colors (no lighting needed)111- `MeshStandardMaterial` - physically-based, realistic (needs lighting)112- `MeshPhongMaterial` - shiny surfaces with specular highlights113- `MeshLambertMaterial` - matte surfaces, diffuse reflection114115```javascript116const material = new THREE.MeshStandardMaterial({117 color: 0x00ff00,118 metalness: 0.5,119 roughness: 0.5,120});121```122123### 4. Add Lighting124125**If using lit materials** (Standard, Phong, Lambert), add lights:126127```javascript128// Ambient light - general illumination129const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);130scene.add(ambientLight);131132// Directional light - like sunlight133const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);134directionalLight.position.set(5, 5, 5);135scene.add(directionalLight);136```137138**Skip lighting** if using `MeshBasicMaterial` - it's unlit by design.139140### 5. Handle Responsiveness141142Always add window resize handling:143144```javascript145window.addEventListener("resize", () => {146 camera.aspect = window.innerWidth / window.innerHeight;147 camera.updateProjectionMatrix();148 renderer.setSize(window.innerWidth, window.innerHeight);149});150```151152## Common Patterns153154### Rotating Object155156```javascript157function animate() {158 requestAnimationFrame(animate);159 mesh.rotation.x += 0.01;160 mesh.rotation.y += 0.01;161 renderer.render(scene, camera);162}163```164165### Custom Camera Controls (OrbitControls Alternative)166167Since `THREE.OrbitControls` isn't available on CDN, implement custom controls:168169```javascript170let isDragging = false;171let previousMousePosition = { x: 0, y: 0 };172173renderer.domElement.addEventListener("mousedown", () => {174 isDragging = true;175});176177renderer.domElement.addEventListener("mouseup", () => {178 isDragging = false;179});180181renderer.domElement.addEventListener("mousemove", (event) => {182 if (isDragging) {183 const deltaX = event.clientX - previousMousePosition.x;184 const deltaY = event.clientY - previousMousePosition.y;185186 // Rotate camera around scene187 const rotationSpeed = 0.005;188 camera.position.x += deltaX * rotationSpeed;189 camera.position.y -= deltaY * rotationSpeed;190 camera.lookAt(scene.position);191 }192193 previousMousePosition = { x: event.clientX, y: event.clientY };194});195196// Zoom with mouse wheel197renderer.domElement.addEventListener("wheel", (event) => {198 event.preventDefault();199 camera.position.z += event.deltaY * 0.01;200 camera.position.z = Math.max(2, Math.min(20, camera.position.z)); // Clamp201});202```203204### Raycasting for Object Selection205206Detect mouse clicks and hovers on 3D objects:207208```javascript209const raycaster = new THREE.Raycaster();210const mouse = new THREE.Vector2();211const clickableObjects = []; // Array of meshes that can be clicked212213// Update mouse position214window.addEventListener("mousemove", (event) => {215 mouse.x = (event.clientX / window.innerWidth) * 2 - 1;216 mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;217});218219// Detect clicks220window.addEventListener("click", () => {221 raycaster.setFromCamera(mouse, camera);222 const intersects = raycaster.intersectObjects(clickableObjects);223224 if (intersects.length > 0) {225 const clickedObject = intersects[0].object;226 // Handle click - change color, scale, etc.227 clickedObject.material.color.set(0xff0000);228 }229});230231// Hover effect in animation loop232function animate() {233 requestAnimationFrame(animate);234235 raycaster.setFromCamera(mouse, camera);236 const intersects = raycaster.intersectObjects(clickableObjects);237238 // Reset all objects239 clickableObjects.forEach((obj) => {240 obj.scale.set(1, 1, 1);241 });242243 // Highlight hovered object244 if (intersects.length > 0) {245 intersects[0].object.scale.set(1.2, 1.2, 1.2);246 document.body.style.cursor = "pointer";247 } else {248 document.body.style.cursor = "default";249 }250251 renderer.render(scene, camera);252}253```254255### Particle System256257```javascript258const particlesGeometry = new THREE.BufferGeometry();259const particlesCount = 1000;260const posArray = new Float32Array(particlesCount * 3);261262for (let i = 0; i < particlesCount * 3; i++) {263 posArray[i] = (Math.random() - 0.5) * 10;264}265266particlesGeometry.setAttribute(267 "position",268 new THREE.BufferAttribute(posArray, 3),269);270271const particlesMaterial = new THREE.PointsMaterial({272 size: 0.02,273 color: 0xffffff,274});275276const particlesMesh = new THREE.Points(particlesGeometry, particlesMaterial);277scene.add(particlesMesh);278```279280### User Interaction (Mouse Movement)281282```javascript283let mouseX = 0;284let mouseY = 0;285286document.addEventListener("mousemove", (event) => {287 mouseX = (event.clientX / window.innerWidth) * 2 - 1;288 mouseY = -(event.clientY / window.innerHeight) * 2 + 1;289});290291function animate() {292 requestAnimationFrame(animate);293 camera.position.x = mouseX * 2;294 camera.position.y = mouseY * 2;295 camera.lookAt(scene.position);296 renderer.render(scene, camera);297}298```299300### Loading Textures301302```javascript303const textureLoader = new THREE.TextureLoader();304const texture = textureLoader.load("texture-url.jpg");305306const material = new THREE.MeshStandardMaterial({307 map: texture,308});309```310311## Best Practices312313### Performance314315- **Reuse geometries and materials** when creating multiple similar objects316- **Use `BufferGeometry`** for custom shapes (more efficient)317- **Limit particle counts** to maintain 60fps (start with 1000-5000)318- **Dispose of resources** when removing objects:319 ```javascript320 geometry.dispose();321 material.dispose();322 texture.dispose();323 ```324325### Visual Quality326327- Always set `antialias: true` on renderer for smooth edges328- Use appropriate camera FOV (45-75 degrees typical)329- Position lights thoughtfully - avoid overlapping multiple bright lights330- Add ambient + directional lighting for realistic scenes331332### Code Organization333334- Initialize scene, camera, renderer at the top335- Group related objects (e.g., all particles in one group)336- Keep animation logic in the animate function337- Separate object creation into functions for complex scenes338339### Common Pitfalls to Avoid340341- ❌ Using `THREE.OrbitControls` - not available on CDN342- ❌ Using `THREE.CapsuleGeometry` - requires r142+343- ❌ Forgetting to add objects to scene with `scene.add()`344- ❌ Using lit materials without adding lights345- ❌ Not handling window resize346- ❌ Forgetting to call `renderer.render()` in animation loop347348## Example Workflow349350User: "Create an interactive 3D sphere that responds to mouse movement"3513521. **Setup**: Import Three.js (r128), create scene/camera/renderer3532. **Geometry**: Create `SphereGeometry(1, 32, 32)` for smooth sphere3543. **Material**: Use `MeshStandardMaterial` for realistic look3554. **Lighting**: Add ambient + directional lights3565. **Interaction**: Track mouse position, update camera3576. **Animation**: Rotate sphere, render continuously3587. **Responsive**: Add window resize handler3598. **Result**: Smooth, interactive 3D sphere ✓360361## Troubleshooting362363**Black screen / Nothing renders:**364365- Check if objects added to scene366- Verify camera position isn't inside objects367- Ensure renderer.render() is called368- Add lights if using lit materials369370**Poor performance:**371372- Reduce particle count373- Lower geometry detail (segments)374- Reuse materials/geometries375- Check browser console for errors376377**Objects not visible:**378379- Check object position vs camera position380- Verify material has visible color/properties381- Ensure camera far plane includes objects382- Add lighting if needed383384## Advanced Techniques385386### Visual Polish for Portfolio-Grade Rendering387388**Shadows:**389390```javascript391// Enable shadows on renderer392renderer.shadowMap.enabled = true;393renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Soft shadows394395// Light that casts shadows396const directionalLight = new THREE.DirectionalLight(0xffffff, 1);397directionalLight.position.set(5, 10, 5);398directionalLight.castShadow = true;399400// Configure shadow quality401directionalLight.shadow.mapSize.width = 2048;402directionalLight.shadow.mapSize.height = 2048;403directionalLight.shadow.camera.near = 0.5;404directionalLight.shadow.camera.far = 50;405406scene.add(directionalLight);407408// Objects cast and receive shadows409mesh.castShadow = true;410mesh.receiveShadow = true;411412// Ground plane receives shadows413const groundGeometry = new THREE.PlaneGeometry(20, 20);414const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x808080 });415const ground = new THREE.Mesh(groundGeometry, groundMaterial);416ground.rotation.x = -Math.PI / 2;417ground.receiveShadow = true;418scene.add(ground);419```420421**Environment Maps & Reflections:**422423```javascript424// Create environment map from cubemap425const loader = new THREE.CubeTextureLoader();426const envMap = loader.load([427 "px.jpg",428 "nx.jpg", // positive x, negative x429 "py.jpg",430 "ny.jpg", // positive y, negative y431 "pz.jpg",432 "nz.jpg", // positive z, negative z433]);434435scene.environment = envMap; // Affects all PBR materials436scene.background = envMap; // Optional: use as skybox437438// Or apply to specific materials439const material = new THREE.MeshStandardMaterial({440 metalness: 1.0,441 roughness: 0.1,442 envMap: envMap,443});444```445446**Tone Mapping & Output Encoding:**447448```javascript449// Improve color accuracy and HDR rendering450renderer.toneMapping = THREE.ACESFilmicToneMapping;451renderer.toneMappingExposure = 1.0;452renderer.outputEncoding = THREE.sRGBEncoding;453454// Makes colors more vibrant and realistic455```456457**Fog for Depth:**458459```javascript460// Linear fog461scene.fog = new THREE.Fog(0xcccccc, 10, 50); // color, near, far462463// Or exponential fog (more realistic)464scene.fog = new THREE.FogExp2(0xcccccc, 0.02); // color, density465```466467### Custom Geometry from Vertices468469```javascript470const geometry = new THREE.BufferGeometry();471const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0]);472geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));473```474475### Post-Processing Effects476477While advanced post-processing may not be available in r128 CDN, basic effects can be achieved with shaders and render targets.478479### Group Objects480481```javascript482const group = new THREE.Group();483group.add(mesh1);484group.add(mesh2);485group.rotation.y = Math.PI / 4;486scene.add(group);487```488489## Summary490491Three.js artifacts require systematic setup:4924931. Import correct CDN version (r128)4942. Initialize scene, camera, renderer4953. Create geometry + material = mesh4964. Add lighting if using lit materials4975. Implement animation loop4986. Handle window resize4997. Avoid r128 incompatible features500501Follow these patterns for reliable, performant 3D experiences.502503## Modern Three.js & Production Practices504505While this skill focuses on CDN-based Three.js (r128) for artifact compatibility, here's what you'd do in production environments:506507### Modular Imports with Build Tools508509```javascript510// In production with npm/vite/webpack:511import * as THREE from "three";512import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";513import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";514import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";515```516517**Benefits:**518519- Tree-shaking (smaller bundle sizes)520- Access to full example library (OrbitControls, loaders, etc.)521- Latest Three.js features (r150+)522- TypeScript support523524### Animation Libraries (GSAP Integration)525526```javascript527// Smooth timeline-based animations528import gsap from "gsap";529530// Instead of manual animation loops:531gsap.to(mesh.position, {532 x: 5,533 duration: 2,534 ease: "power2.inOut",535});536537// Complex sequences:538const timeline = gsap.timeline();539timeline540 .to(mesh.rotation, { y: Math.PI * 2, duration: 2 })541 .to(mesh.scale, { x: 2, y: 2, z: 2, duration: 1 }, "-=1");542```543544**Why GSAP:**545546- Professional easing functions547- Timeline control (pause, reverse, scrub)548- Better than manual lerping for complex animations549550### Scroll-Based Interactions551552```javascript553// Sync 3D animations with page scroll554let scrollY = window.scrollY;555556window.addEventListener("scroll", () => {557 scrollY = window.scrollY;558});559560function animate() {561 requestAnimationFrame(animate);562563 // Rotate based on scroll position564 mesh.rotation.y = scrollY * 0.001;565566 // Move camera through scene567 camera.position.y = -(scrollY / window.innerHeight) * 10;568569 renderer.render(scene, camera);570}571```572573**Advanced scroll libraries:**574575- ScrollTrigger (GSAP plugin)576- Locomotive Scroll577- Lenis smooth scroll578579### Performance Optimization in Production580581```javascript582// Level of Detail (LOD)583const lod = new THREE.LOD();584lod.addLevel(highDetailMesh, 0); // Close up585lod.addLevel(mediumDetailMesh, 10); // Medium distance586lod.addLevel(lowDetailMesh, 50); // Far away587scene.add(lod);588589// Instanced meshes for many identical objects590const geometry = new THREE.BoxGeometry();591const material = new THREE.MeshStandardMaterial();592const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);593594// Set transforms for each instance595const matrix = new THREE.Matrix4();596for (let i = 0; i < 1000; i++) {597 matrix.setPosition(598 Math.random() * 100,599 Math.random() * 100,600 Math.random() * 100,601 );602 instancedMesh.setMatrixAt(i, matrix);603}604```605606### Modern Loading Patterns607608```javascript609// In production, load 3D models:610import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";611612const loader = new GLTFLoader();613loader.load("model.gltf", (gltf) => {614 scene.add(gltf.scene);615616 // Traverse and setup materials617 gltf.scene.traverse((child) => {618 if (child.isMesh) {619 child.castShadow = true;620 child.receiveShadow = true;621 }622 });623});624```625626### When to Use What627628**CDN Approach (Current Skill):**629630- Quick prototypes and demos631- Educational content632- Artifacts and embedded experiences633- No build step required634635**Production Build Approach:**636637- Client projects and portfolios638- Complex applications639- Need latest features (r150+)640- Performance-critical applications641- Team collaboration with version control642643### Recommended Production Stack644645```646Three.js (latest) + Vite/Webpack647├── GSAP (animations)648├── React Three Fiber (optional - React integration)649├── Drei (helper components)650├── Leva (debug GUI)651└── Post-processing effects652```653654This skill provides CDN-compatible foundations. In production, you'd layer on these modern tools for professional results.655
Full transparency — inspect the skill content before installing.