diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..be0643d1 Binary files /dev/null and b/.DS_Store differ diff --git a/CATALOG.md b/CATALOG.md index 55cd66e3..285554f2 100644 --- a/CATALOG.md +++ b/CATALOG.md @@ -570,7 +570,7 @@ TRIGGER: "shopify", "shopify app", "checkout extension",... | shopify | shopify, | `subagent-driven-development` | Use when executing implementation plans with independent tasks in the current session | subagent, driven | subagent, driven, development, executing, plans, independent, tasks, current, session | | `superpowers-lab` | Lab environment for Claude superpowers | superpowers, lab | superpowers, lab, environment, claude | | `theme-factory` | Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors... | theme, factory | theme, factory, toolkit, styling, artifacts, these, slides, docs, reportings, html, landing, pages | -| `threejs-skills` | Three.js skills for creating 3D elements and interactive experiences | threejs, skills | threejs, skills, three, js, creating, 3d, elements, interactive, experiences | +| `threejs-skills` | Create 3D scenes, interactive experiences, and visual effects using Three.js. Use when user requests 3D graphics, WebGL experiences, 3D visualizations, anima... | threejs, skills | threejs, skills, 3d, scenes, interactive, experiences, visual, effects, three, js, user, requests | | `turborepo-caching` | Configure Turborepo for efficient monorepo builds with local and remote caching. Use when setting up Turborepo, optimizing build pipelines, or implementing d... | turborepo, caching | turborepo, caching, configure, efficient, monorepo, local, remote, setting, up, optimizing, pipelines, implementing | | `tutorial-engineer` | Creates step-by-step tutorials and educational content from code. Transforms complex concepts into progressive learning experiences with hands-on examples. U... | tutorial | tutorial, engineer, creates, step, tutorials, educational, content, code, transforms, complex, concepts, progressive | | `ui-skills` | Opinionated, evolving constraints to guide agents when building interfaces | ui, skills | ui, skills, opinionated, evolving, constraints, agents, building, interfaces | diff --git a/data/catalog.json b/data/catalog.json index 5c98eb37..c7cd3dda 100644 --- a/data/catalog.json +++ b/data/catalog.json @@ -19332,7 +19332,7 @@ { "id": "threejs-skills", "name": "threejs-skills", - "description": "Three.js skills for creating 3D elements and interactive experiences", + "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.", "category": "general", "tags": [ "threejs", @@ -19341,13 +19341,16 @@ "triggers": [ "threejs", "skills", + "3d", + "scenes", + "interactive", + "experiences", + "visual", + "effects", "three", "js", - "creating", - "3d", - "elements", - "interactive", - "experiences" + "user", + "requests" ], "path": "skills/threejs-skills/SKILL.md" }, diff --git a/skills/threejs-skills/SKILL.md b/skills/threejs-skills/SKILL.md index 3a27a00e..6680ac59 100644 --- a/skills/threejs-skills/SKILL.md +++ b/skills/threejs-skills/SKILL.md @@ -1,6 +1,8 @@ --- 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. +source: https://github.com/CloudAI-X/threejs-skills +risk: safe --- # Three.js Skills @@ -23,7 +25,7 @@ Systematically create high-quality 3D scenes and interactive experiences using T Always use the correct CDN version (r128): ```javascript -import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js'; +import * as THREE from "https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"; ``` **CRITICAL**: Do NOT use example imports like `THREE.OrbitControls` - they won't work on the CDN. @@ -38,10 +40,10 @@ const scene = new THREE.Scene(); // Camera - defines viewing perspective const camera = new THREE.PerspectiveCamera( - 75, // Field of view + 75, // Field of view window.innerWidth / window.innerHeight, // Aspect ratio - 0.1, // Near clipping plane - 1000 // Far clipping plane + 0.1, // Near clipping plane + 1000, // Far clipping plane ); camera.position.z = 5; @@ -58,11 +60,11 @@ Use requestAnimationFrame for smooth rendering: ```javascript function animate() { requestAnimationFrame(animate); - + // Update object transformations here mesh.rotation.x += 0.01; mesh.rotation.y += 0.01; - + renderer.render(scene, camera); } animate(); @@ -84,6 +86,7 @@ Start by identifying: Choose appropriate geometry types: **Basic Shapes:** + - `BoxGeometry` - cubes, rectangular prisms - `SphereGeometry` - spheres, planets - `CylinderGeometry` - cylinders, tubes @@ -93,6 +96,7 @@ Choose appropriate geometry types: **IMPORTANT**: Do NOT use `CapsuleGeometry` (introduced in r142, not available in r128) **Alternatives for capsules:** + - Combine `CylinderGeometry` + 2 `SphereGeometry` - Use `SphereGeometry` with adjusted parameters - Create custom geometry with vertices @@ -102,6 +106,7 @@ Choose appropriate geometry types: Choose materials based on visual needs: **Common Materials:** + - `MeshBasicMaterial` - unlit, flat colors (no lighting needed) - `MeshStandardMaterial` - physically-based, realistic (needs lighting) - `MeshPhongMaterial` - shiny surfaces with specular highlights @@ -111,7 +116,7 @@ Choose materials based on visual needs: const material = new THREE.MeshStandardMaterial({ color: 0x00ff00, metalness: 0.5, - roughness: 0.5 + roughness: 0.5, }); ``` @@ -137,7 +142,7 @@ scene.add(directionalLight); Always add window resize handling: ```javascript -window.addEventListener('resize', () => { +window.addEventListener("resize", () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); @@ -165,31 +170,31 @@ Since `THREE.OrbitControls` isn't available on CDN, implement custom controls: let isDragging = false; let previousMousePosition = { x: 0, y: 0 }; -renderer.domElement.addEventListener('mousedown', () => { +renderer.domElement.addEventListener("mousedown", () => { isDragging = true; }); -renderer.domElement.addEventListener('mouseup', () => { +renderer.domElement.addEventListener("mouseup", () => { isDragging = false; }); -renderer.domElement.addEventListener('mousemove', (event) => { +renderer.domElement.addEventListener("mousemove", (event) => { if (isDragging) { const deltaX = event.clientX - previousMousePosition.x; const deltaY = event.clientY - previousMousePosition.y; - + // Rotate camera around scene const rotationSpeed = 0.005; camera.position.x += deltaX * rotationSpeed; camera.position.y -= deltaY * rotationSpeed; camera.lookAt(scene.position); } - + previousMousePosition = { x: event.clientX, y: event.clientY }; }); // Zoom with mouse wheel -renderer.domElement.addEventListener('wheel', (event) => { +renderer.domElement.addEventListener("wheel", (event) => { event.preventDefault(); camera.position.z += event.deltaY * 0.01; camera.position.z = Math.max(2, Math.min(20, camera.position.z)); // Clamp @@ -206,16 +211,16 @@ const mouse = new THREE.Vector2(); const clickableObjects = []; // Array of meshes that can be clicked // Update mouse position -window.addEventListener('mousemove', (event) => { +window.addEventListener("mousemove", (event) => { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; }); // Detect clicks -window.addEventListener('click', () => { +window.addEventListener("click", () => { raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickableObjects); - + if (intersects.length > 0) { const clickedObject = intersects[0].object; // Handle click - change color, scale, etc. @@ -226,23 +231,23 @@ window.addEventListener('click', () => { // Hover effect in animation loop function animate() { requestAnimationFrame(animate); - + raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickableObjects); - + // Reset all objects - clickableObjects.forEach(obj => { + clickableObjects.forEach((obj) => { obj.scale.set(1, 1, 1); }); - + // Highlight hovered object if (intersects.length > 0) { intersects[0].object.scale.set(1.2, 1.2, 1.2); - document.body.style.cursor = 'pointer'; + document.body.style.cursor = "pointer"; } else { - document.body.style.cursor = 'default'; + document.body.style.cursor = "default"; } - + renderer.render(scene, camera); } ``` @@ -259,13 +264,13 @@ for (let i = 0; i < particlesCount * 3; i++) { } particlesGeometry.setAttribute( - 'position', - new THREE.BufferAttribute(posArray, 3) + "position", + new THREE.BufferAttribute(posArray, 3), ); const particlesMaterial = new THREE.PointsMaterial({ size: 0.02, - color: 0xffffff + color: 0xffffff, }); const particlesMesh = new THREE.Points(particlesGeometry, particlesMaterial); @@ -278,7 +283,7 @@ scene.add(particlesMesh); let mouseX = 0; let mouseY = 0; -document.addEventListener('mousemove', (event) => { +document.addEventListener("mousemove", (event) => { mouseX = (event.clientX / window.innerWidth) * 2 - 1; mouseY = -(event.clientY / window.innerHeight) * 2 + 1; }); @@ -296,10 +301,10 @@ function animate() { ```javascript const textureLoader = new THREE.TextureLoader(); -const texture = textureLoader.load('texture-url.jpg'); +const texture = textureLoader.load("texture-url.jpg"); const material = new THREE.MeshStandardMaterial({ - map: texture + map: texture, }); ``` @@ -356,18 +361,21 @@ User: "Create an interactive 3D sphere that responds to mouse movement" ## Troubleshooting **Black screen / Nothing renders:** + - Check if objects added to scene - Verify camera position isn't inside objects - Ensure renderer.render() is called - Add lights if using lit materials **Poor performance:** + - Reduce particle count - Lower geometry detail (segments) - Reuse materials/geometries - Check browser console for errors **Objects not visible:** + - Check object position vs camera position - Verify material has visible color/properties - Ensure camera far plane includes objects @@ -416,19 +424,22 @@ scene.add(ground); // Create environment map from cubemap const loader = new THREE.CubeTextureLoader(); const envMap = loader.load([ - 'px.jpg', 'nx.jpg', // positive x, negative x - 'py.jpg', 'ny.jpg', // positive y, negative y - 'pz.jpg', 'nz.jpg' // positive z, negative z + "px.jpg", + "nx.jpg", // positive x, negative x + "py.jpg", + "ny.jpg", // positive y, negative y + "pz.jpg", + "nz.jpg", // positive z, negative z ]); scene.environment = envMap; // Affects all PBR materials -scene.background = envMap; // Optional: use as skybox +scene.background = envMap; // Optional: use as skybox // Or apply to specific materials const material = new THREE.MeshStandardMaterial({ metalness: 1.0, roughness: 0.1, - envMap: envMap + envMap: envMap, }); ``` @@ -457,12 +468,8 @@ scene.fog = new THREE.FogExp2(0xcccccc, 0.02); // color, density ```javascript const geometry = new THREE.BufferGeometry(); -const vertices = new Float32Array([ - -1, -1, 0, - 1, -1, 0, - 1, 1, 0 -]); -geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); +const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0]); +geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3)); ``` ### Post-Processing Effects @@ -482,6 +489,7 @@ scene.add(group); ## Summary Three.js artifacts require systematic setup: + 1. Import correct CDN version (r128) 2. Initialize scene, camera, renderer 3. Create geometry + material = mesh @@ -500,13 +508,14 @@ While this skill focuses on CDN-based Three.js (r128) for artifact compatibility ```javascript // In production 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 * 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"; ``` **Benefits:** + - Tree-shaking (smaller bundle sizes) - Access to full example library (OrbitControls, loaders, etc.) - Latest Three.js features (r150+) @@ -516,23 +525,24 @@ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer ```javascript // Smooth timeline-based animations -import gsap from 'gsap'; +import gsap from "gsap"; // Instead of manual animation loops: gsap.to(mesh.position, { x: 5, duration: 2, - ease: 'power2.inOut' + ease: "power2.inOut", }); // Complex sequences: const timeline = gsap.timeline(); timeline .to(mesh.rotation, { y: Math.PI * 2, duration: 2 }) - .to(mesh.scale, { x: 2, y: 2, z: 2, duration: 1 }, '-=1'); + .to(mesh.scale, { x: 2, y: 2, z: 2, duration: 1 }, "-=1"); ``` **Why GSAP:** + - Professional easing functions - Timeline control (pause, reverse, scrub) - Better than manual lerping for complex animations @@ -543,24 +553,25 @@ timeline // Sync 3D animations with page scroll let scrollY = window.scrollY; -window.addEventListener('scroll', () => { +window.addEventListener("scroll", () => { scrollY = window.scrollY; }); function animate() { requestAnimationFrame(animate); - + // Rotate based on scroll position mesh.rotation.y = scrollY * 0.001; - + // Move camera through scene camera.position.y = -(scrollY / window.innerHeight) * 10; - + renderer.render(scene, camera); } ``` **Advanced scroll libraries:** + - ScrollTrigger (GSAP plugin) - Locomotive Scroll - Lenis smooth scroll @@ -570,9 +581,9 @@ function animate() { ```javascript // Level of Detail (LOD) const lod = new THREE.LOD(); -lod.addLevel(highDetailMesh, 0); // Close up +lod.addLevel(highDetailMesh, 0); // Close up lod.addLevel(mediumDetailMesh, 10); // Medium distance -lod.addLevel(lowDetailMesh, 50); // Far away +lod.addLevel(lowDetailMesh, 50); // Far away scene.add(lod); // Instanced meshes for many identical objects @@ -583,7 +594,11 @@ const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000); // Set transforms for each instance const matrix = new THREE.Matrix4(); for (let i = 0; i < 1000; i++) { - matrix.setPosition(Math.random() * 100, Math.random() * 100, Math.random() * 100); + matrix.setPosition( + Math.random() * 100, + Math.random() * 100, + Math.random() * 100, + ); instancedMesh.setMatrixAt(i, matrix); } ``` @@ -592,12 +607,12 @@ for (let i = 0; i < 1000; i++) { ```javascript // In production, load 3D models: -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; const loader = new GLTFLoader(); -loader.load('model.gltf', (gltf) => { +loader.load("model.gltf", (gltf) => { scene.add(gltf.scene); - + // Traverse and setup materials gltf.scene.traverse((child) => { if (child.isMesh) { @@ -611,12 +626,14 @@ loader.load('model.gltf', (gltf) => { ### When to Use What **CDN Approach (Current Skill):** + - Quick prototypes and demos - Educational content - Artifacts and embedded experiences - No build step required **Production Build Approach:** + - Client projects and portfolios - Complex applications - Need latest features (r150+) diff --git a/skills_index.json b/skills_index.json index 34f366d8..a11795ae 100644 --- a/skills_index.json +++ b/skills_index.json @@ -7006,7 +7006,7 @@ "path": "skills/threejs-skills", "category": "uncategorized", "name": "threejs-skills", - "description": "Three.js skills for creating 3D elements and interactive experiences", + "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.", "risk": "safe", "source": "https://github.com/CloudAI-X/threejs-skills" },