{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/threejs-skills",
  "version": "1.0.0",
  "name": "Threejs Skills",
  "description": "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.",
  "system_prompt_fragment": "# Three.js Skills\n\nSystematically create high-quality 3D scenes and interactive experiences using Three.js best practices.\n\n## When to Use\n\n- Requests 3D visualizations or graphics (\"create a 3D model\", \"show in 3D\")\n- Wants interactive 3D experiences (\"rotating cube\", \"explorable scene\")\n- Needs WebGL or canvas-based rendering\n- Asks for animations, particles, or visual effects\n- Mentions Three.js, WebGL, or 3D rendering\n- Wants to visualize data in 3D space\n\n## Core Setup Pattern\n\n### 1. Essential Three.js Imports\n\nAlways use the correct CDN version (r128):\n\n```javascript\nimport * as THREE from \"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\";\n```\n\n**CRITICAL**: Do NOT use example imports like `THREE.OrbitControls` - they won't work on the CDN.\n\n### 2. Scene Initialization\n\nEvery Three.js artifact needs these core components:\n\n```javascript\n// Scene - contains all 3D objects\nconst scene = new THREE.Scene();\n\n// Camera - defines viewing perspective\nconst camera = new THREE.PerspectiveCamera(\n  75, // Field of view\n  window.innerWidth / window.innerHeight, // Aspect ratio\n  0.1, // Near clipping plane\n  1000, // Far clipping plane\n);\ncamera.position.z = 5;\n\n// Renderer - draws the scene\nconst renderer = new THREE.WebGLRenderer({ antialias: true });\nrenderer.setSize(window.innerWidth, window.innerHeight);\ndocument.body.appendChild(renderer.domElement);\n```\n\n### 3. Animation Loop\n\nUse requestAnimationFrame for smooth rendering:\n\n```javascript\nfunction animate() {\n  requestAnimationFrame(animate);\n\n  // Update object transformations here\n  mesh.rotation.x += 0.01;\n  mesh.rotation.y += 0.01;\n\n  renderer.render(scene, camera);\n}\nanimate();\n```\n\n## Systematic Development Process\n\n### 1. Define the Scene\n\nStart by identifying:\n\n- **What objects** need to be rendered\n- **Camera position** and field of view\n- **Lighting setup** required\n- **Interaction model** (static, rotating, user-controlled)\n\n### 2. Build Geometry\n\nChoose appropriate geometry types:\n\n**Basic Shapes:**\n\n- `BoxGeometry` - cubes, rectangular prisms\n- `SphereGeometry` - spheres, planets\n- `CylinderGeometry` - cylinders, tubes\n- `PlaneGeometry` - flat surfaces, ground planes\n- `TorusGeometry` - donuts, rings\n\n**IMPORTANT**: Do NOT use `CapsuleGeometry` (introduced in r142, not available in r128)\n\n**Alternatives for capsules:**\n\n- Combine `CylinderGeometry` + 2 `SphereGeometry`\n- Use `SphereGeometry` with adjusted parameters\n- Create custom geometry with vertices\n\n### 3. Apply Materials\n\nChoose materials based on visual needs:\n\n**Common Materials:**\n\n- `MeshBasicMaterial` - unlit, flat colors (no lighting needed)\n- `MeshStandardMaterial` - physically-based, realistic (needs lighting)\n- `MeshPhongMaterial` - shiny surfaces with specular highlights\n- `MeshLambertMaterial` - matte surfaces, diffuse reflection\n\n```javascript\nconst material = new THREE.MeshStandardMaterial({\n  color: 0x00ff00,\n  metalness: 0.5,\n  roughness: 0.5,\n});\n```\n\n### 4. Add Lighting\n\n**If using lit materials** (Standard, Phong, Lambert), add lights:\n\n```javascript\n// Ambient light - general illumination\nconst ambientLight = new THREE.AmbientLight(0xffffff, 0.5);\nscene.add(ambientLight);\n\n// Directional light - like sunlight\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\ndirectionalLight.position.set(5, 5, 5);\nscene.add(directionalLight);\n```\n\n**Skip lighting** if using `MeshBasicMaterial` - it's unlit by design.\n\n### 5. Handle Responsiveness\n\nAlways add window resize handling:\n\n```javascript\nwindow.addEventListener(\"resize\", () => {\n  camera.aspect = window.innerWidth / window.innerHeight;\n  camera.updateProjectionMatrix();\n  renderer.setSize(window.innerWidth, window.innerHeight);\n});\n```\n\n## Common Patterns\n\n### Rotating Object\n\n```javascript\nfunction animate() {\n  requestAnimationFrame(animate);\n  mesh.rotation.x += 0.01;\n  mesh.rotation.y += 0.01;\n  renderer.render(scene, camera);\n}\n```\n\n### Custom Camera Controls (OrbitControls Alternative)\n\nSince `THREE.OrbitControls` isn't available on CDN, implement custom controls:\n\n```javascript\nlet isDragging = false;\nlet previousMousePosition = { x: 0, y: 0 };\n\nrenderer.domElement.addEventListener(\"mousedown\", () => {\n  isDragging = true;\n});\n\nrenderer.domElement.addEventListener(\"mouseup\", () => {\n  isDragging = false;\n});\n\nrenderer.domElement.addEventListener(\"mousemove\", (event) => {\n  if (isDragging) {\n    const deltaX = event.clientX - previousMousePosition.x;\n    const deltaY = event.clientY - previousMousePosition.y;\n\n    // Rotate camera around scene\n    const rotationSpeed = 0.005;\n    camera.position.x += deltaX * rotationSpeed;\n    camera.position.y -= deltaY * rotationSpeed;\n    camera.lookAt(scene.position);\n  }\n\n  previousMousePosition = { x: event.clientX, y: event.clientY };\n});\n\n// Zoom with mouse wheel\nrenderer.domElement.addEventListener(\"wheel\", (event) => {\n  event.preventDefault();\n  camera.position.z += event.deltaY * 0.01;\n  camera.position.z = Math.max(2, Math.min(20, camera.position.z)); // Clamp\n});\n```\n\n### Raycasting for Object Selection\n\nDetect mouse clicks and hovers on 3D objects:\n\n```javascript\nconst raycaster = new THREE.Raycaster();\nconst mouse = new THREE.Vector2();\nconst clickableObjects = []; // Array of meshes that can be clicked\n\n// Update mouse position\nwindow.addEventListener(\"mousemove\", (event) => {\n  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;\n  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;\n});\n\n// Detect clicks\nwindow.addEventListener(\"click\", () => {\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(clickableObjects);\n\n  if (intersects.length > 0) {\n    const clickedObject = intersects[0].object;\n    // Handle click - change color, scale, etc.\n    clickedObject.material.color.set(0xff0000);\n  }\n});\n\n// Hover effect in animation loop\nfunction animate() {\n  requestAnimationFrame(animate);\n\n  raycaster.setFromCamera(mouse, camera);\n  const intersects = raycaster.intersectObjects(clickableObjects);\n\n  // Reset all objects\n  clickableObjects.forEach((obj) => {\n    obj.scale.set(1, 1, 1);\n  });\n\n  // Highlight hovered object\n  if (intersects.length > 0) {\n    intersects[0].object.scale.set(1.2, 1.2, 1.2);\n    document.body.style.cursor = \"pointer\";\n  } else {\n    document.body.style.cursor = \"default\";\n  }\n\n  renderer.render(scene, camera);\n}\n```\n\n### Particle System\n\n```javascript\nconst particlesGeometry = new THREE.BufferGeometry();\nconst particlesCount = 1000;\nconst posArray = new Float32Array(particlesCount * 3);\n\nfor (let i = 0; i < particlesCount * 3; i++) {\n  posArray[i] = (Math.random() - 0.5) * 10;\n}\n\nparticlesGeometry.setAttribute(\n  \"position\",\n  new THREE.BufferAttribute(posArray, 3),\n);\n\nconst particlesMaterial = new THREE.PointsMaterial({\n  size: 0.02,\n  color: 0xffffff,\n});\n\nconst particlesMesh = new THREE.Points(particlesGeometry, particlesMaterial);\nscene.add(particlesMesh);\n```\n\n### User Interaction (Mouse Movement)\n\n```javascript\nlet mouseX = 0;\nlet mouseY = 0;\n\ndocument.addEventListener(\"mousemove\", (event) => {\n  mouseX = (event.clientX / window.innerWidth) * 2 - 1;\n  mouseY = -(event.clientY / window.innerHeight) * 2 + 1;\n});\n\nfunction animate() {\n  requestAnimationFrame(animate);\n  camera.position.x = mouseX * 2;\n  camera.position.y = mouseY * 2;\n  camera.lookAt(scene.position);\n  renderer.render(scene, camera);\n}\n```\n\n### Loading Textures\n\n```javascript\nconst textureLoader = new THREE.TextureLoader();\nconst texture = textureLoader.load(\"texture-url.jpg\");\n\nconst material = new THREE.MeshStandardMaterial({\n  map: texture,\n});\n```\n\n## Best Practices\n\n### Performance\n\n- **Reuse geometries and materials** when creating multiple similar objects\n- **Use `BufferGeometry`** for custom shapes (more efficient)\n- **Limit particle counts** to maintain 60fps (start with 1000-5000)\n- **Dispose of resources** when removing objects:\n  ```javascript\n  geometry.dispose();\n  material.dispose();\n  texture.dispose();\n  ```\n\n### Visual Quality\n\n- Always set `antialias: true` on renderer for smooth edges\n- Use appropriate camera FOV (45-75 degrees typical)\n- Position lights thoughtfully - avoid overlapping multiple bright lights\n- Add ambient + directional lighting for realistic scenes\n\n### Code Organization\n\n- Initialize scene, camera, renderer at the top\n- Group related objects (e.g., all particles in one group)\n- Keep animation logic in the animate function\n- Separate object creation into functions for complex scenes\n\n### Common Pitfalls to Avoid\n\n- ❌ Using `THREE.OrbitControls` - not available on CDN\n- ❌ Using `THREE.CapsuleGeometry` - requires r142+\n- ❌ Forgetting to add objects to scene with `scene.add()`\n- ❌ Using lit materials without adding lights\n- ❌ Not handling window resize\n- ❌ Forgetting to call `renderer.render()` in animation loop\n\n## Example Workflow\n\nUser: \"Create an interactive 3D sphere that responds to mouse movement\"\n\n1. **Setup**: Import Three.js (r128), create scene/camera/renderer\n2. **Geometry**: Create `SphereGeometry(1, 32, 32)` for smooth sphere\n3. **Material**: Use `MeshStandardMaterial` for realistic look\n4. **Lighting**: Add ambient + directional lights\n5. **Interaction**: Track mouse position, update camera\n6. **Animation**: Rotate sphere, render continuously\n7. **Responsive**: Add window resize handler\n8. **Result**: Smooth, interactive 3D sphere ✓\n\n## Troubleshooting\n\n**Black screen / Nothing renders:**\n\n- Check if objects added to scene\n- Verify camera position isn't inside objects\n- Ensure renderer.render() is called\n- Add lights if using lit materials\n\n**Poor performance:**\n\n- Reduce particle count\n- Lower geometry detail (segments)\n- Reuse materials/geometries\n- Check browser console for errors\n\n**Objects not visible:**\n\n- Check object position vs camera position\n- Verify material has visible color/properties\n- Ensure camera far plane includes objects\n- Add lighting if needed\n\n## Advanced Techniques\n\n### Visual Polish for Portfolio-Grade Rendering\n\n**Shadows:**\n\n```javascript\n// Enable shadows on renderer\nrenderer.shadowMap.enabled = true;\nrenderer.shadowMap.type = THREE.PCFSoftShadowMap; // Soft shadows\n\n// Light that casts shadows\nconst directionalLight = new THREE.DirectionalLight(0xffffff, 1);\ndirectionalLight.position.set(5, 10, 5);\ndirectionalLight.castShadow = true;\n\n// Configure shadow quality\ndirectionalLight.shadow.mapSize.width = 2048;\ndirectionalLight.shadow.mapSize.height = 2048;\ndirectionalLight.shadow.camera.near = 0.5;\ndirectionalLight.shadow.camera.far = 50;\n\nscene.add(directionalLight);\n\n// Objects cast and receive shadows\nmesh.castShadow = true;\nmesh.receiveShadow = true;\n\n// Ground plane receives shadows\nconst groundGeometry = new THREE.PlaneGeometry(20, 20);\nconst groundMaterial = new THREE.MeshStandardMaterial({ color: 0x808080 });\nconst ground = new THREE.Mesh(groundGeometry, groundMaterial);\nground.rotation.x = -Math.PI / 2;\nground.receiveShadow = true;\nscene.add(ground);\n```\n\n**Environment Maps & Reflections:**\n\n```javascript\n// Create environment map from cubemap\nconst loader = new THREE.CubeTextureLoader();\nconst envMap = loader.load([\n  \"px.jpg\",\n  \"nx.jpg\", // positive x, negative x\n  \"py.jpg\",\n  \"ny.jpg\", // positive y, negative y\n  \"pz.jpg\",\n  \"nz.jpg\", // positive z, negative z\n]);\n\nscene.environment = envMap; // Affects all PBR materials\nscene.background = envMap; // Optional: use as skybox\n\n// Or apply to specific materials\nconst material = new THREE.MeshStandardMaterial({\n  metalness: 1.0,\n  roughness: 0.1,\n  envMap: envMap,\n});\n```\n\n**Tone Mapping & Output Encoding:**\n\n```javascript\n// Improve color accuracy and HDR rendering\nrenderer.toneMapping = THREE.ACESFilmicToneMapping;\nrenderer.toneMappingExposure = 1.0;\nrenderer.outputEncoding = THREE.sRGBEncoding;\n\n// Makes colors more vibrant and realistic\n```\n\n**Fog for Depth:**\n\n```javascript\n// Linear fog\nscene.fog = new THREE.Fog(0xcccccc, 10, 50); // color, near, far\n\n// Or exponential fog (more realistic)\nscene.fog = new THREE.FogExp2(0xcccccc, 0.02); // color, density\n```\n\n### Custom Geometry from Vertices\n\n```javascript\nconst geometry = new THREE.BufferGeometry();\nconst vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0]);\ngeometry.setAttribute(\"position\", new THREE.BufferAttribute(vertices, 3));\n```\n\n### Post-Processing Effects\n\nWhile advanced post-processing may not be available in r128 CDN, basic effects can be achieved with shaders and render targets.\n\n### Group Objects\n\n```javascript\nconst group = new THREE.Group();\ngroup.add(mesh1);\ngroup.add(mesh2);\ngroup.rotation.y = Math.PI / 4;\nscene.add(group);\n```\n\n## Summary\n\nThree.js artifacts require systematic setup:\n\n1. Import correct CDN version (r128)\n2. Initialize scene, camera, renderer\n3. Create geometry + material = mesh\n4. Add lighting if using lit materials\n5. Implement animation loop\n6. Handle window resize\n7. Avoid r128 incompatible features\n\nFollow these patterns for reliable, performant 3D experiences.\n\n## Modern Three.js & Production Practices\n\nWhile this skill focuses on CDN-based Three.js (r128) for artifact compatibility, here's what you'd do in production environments:\n\n### Modular Imports with Build Tools\n\n```javascript\n// In production with npm/vite/webpack:\nimport * as THREE from \"three\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader\";\nimport { EffectComposer } from \"three/examples/jsm/postprocessing/EffectComposer\";\n```\n\n**Benefits:**\n\n- Tree-shaking (smaller bundle sizes)\n- Access to full example library (OrbitControls, loaders, etc.)\n- Latest Three.js features (r150+)\n- TypeScript support\n\n### Animation Libraries (GSAP Integration)\n\n```javascript\n// Smooth timeline-based animations\nimport gsap from \"gsap\";\n\n// Instead of manual animation loops:\ngsap.to(mesh.position, {\n  x: 5,\n  duration: 2,\n  ease: \"power2.inOut\",\n});\n\n// Complex sequences:\nconst timeline = gsap.timeline();\ntimeline\n  .to(mesh.rotation, { y: Math.PI * 2, duration: 2 })\n  .to(mesh.scale, { x: 2, y: 2, z: 2, duration: 1 }, \"-=1\");\n```\n\n**Why GSAP:**\n\n- Professional easing functions\n- Timeline control (pause, reverse, scrub)\n- Better than manual lerping for complex animations\n\n### Scroll-Based Interactions\n\n```javascript\n// Sync 3D animations with page scroll\nlet scrollY = window.scrollY;\n\nwindow.addEventListener(\"scroll\", () => {\n  scrollY = window.scrollY;\n});\n\nfunction animate() {\n  requestAnimationFrame(animate);\n\n  // Rotate based on scroll position\n  mesh.rotation.y = scrollY * 0.001;\n\n  // Move camera through scene\n  camera.position.y = -(scrollY / window.innerHeight) * 10;\n\n  renderer.render(scene, camera);\n}\n```\n\n**Advanced scroll libraries:**\n\n- ScrollTrigger (GSAP plugin)\n- Locomotive Scroll\n- Lenis smooth scroll\n\n### Performance Optimization in Production\n\n```javascript\n// Level of Detail (LOD)\nconst lod = new THREE.LOD();\nlod.addLevel(highDetailMesh, 0); // Close up\nlod.addLevel(mediumDetailMesh, 10); // Medium distance\nlod.addLevel(lowDetailMesh, 50); // Far away\nscene.add(lod);\n\n// Instanced meshes for many identical objects\nconst geometry = new THREE.BoxGeometry();\nconst material = new THREE.MeshStandardMaterial();\nconst instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);\n\n// Set transforms for each instance\nconst matrix = new THREE.Matrix4();\nfor (let i = 0; i < 1000; i++) {\n  matrix.setPosition(\n    Math.random() * 100,\n    Math.random() * 100,\n    Math.random() * 100,\n  );\n  instancedMesh.setMatrixAt(i, matrix);\n}\n```\n\n### Modern Loading Patterns\n\n```javascript\n// In production, load 3D models:\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader\";\n\nconst loader = new GLTFLoader();\nloader.load(\"model.gltf\", (gltf) => {\n  scene.add(gltf.scene);\n\n  // Traverse and setup materials\n  gltf.scene.traverse((child) => {\n    if (child.isMesh) {\n      child.castShadow = true;\n      child.receiveShadow = true;\n    }\n  });\n});\n```\n\n### When to Use What\n\n**CDN Approach (Current Skill):**\n\n- Quick prototypes and demos\n- Educational content\n- Artifacts and embedded experiences\n- No build step required\n\n**Production Build Approach:**\n\n- Client projects and portfolios\n- Complex applications\n- Need latest features (r150+)\n- Performance-critical applications\n- Team collaboration with version control\n\n### Recommended Production Stack\n\n```\nThree.js (latest) + Vite/Webpack\n├── GSAP (animations)\n├── React Three Fiber (optional - React integration)\n├── Drei (helper components)\n├── Leva (debug GUI)\n└── Post-processing effects\n```\n\nThis skill provides CDN-compatible foundations. In production, you'd layer on these modern tools for professional results.",
  "applicable_domains": [
    "other"
  ],
  "category": "other",
  "invocation": [
    "/threejs-skills"
  ],
  "authored_by": "claudeskills.in community",
  "source_url": "https://claudeskills.in/skill/threejs-skills",
  "provenance": {
    "source": "claudeskills.in",
    "source_url": "https://claudeskills.in/skill/threejs-skills",
    "license": "unknown",
    "imported_at": "2026-09-03",
    "notes": "Aggregated by claudeskills.in from community GitHub lists. Upstream as recorded by the aggregator: https://github.com/CloudAI-X/threejs-skills."
  },
  "tags": [
    "claudeskills",
    "other",
    "risk-reviewed"
  ],
  "lifecycle": "draft"
}