
Threejs Interaction
Add raycasting, OrbitControls, and mouse or touch input so users can click, select, and navigate interactive 3D scenes in Three.js.
Overview
threejs-interaction is an agent skill for the Build phase that implements Three.js raycasting, OrbitControls, and mouse or touch interaction for clickable 3D experiences.
Install
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-interactionWhat is this skill?
- Quick start with OrbitControls, damping, Raycaster, and normalized device coordinates mouse mapping
- Raycaster from camera (`setFromCamera`) or arbitrary origin and direction (`set`)
- `intersectObjects` with recursive flag; documents distance, point, face, and object on hits
- Patterns for click detection and interactive 3D experiences per skill description
- Uses three/addons OrbitControls import path aligned with modern Three.js module layout
Adoption & trust: 4k installs on skills.sh; 2.3k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Three.js scene renders but users cannot orbit the camera or reliably click objects because picking and controls are not wired correctly.
Who is it for?
Solo builders adding MVP interactivity to a Three.js web app, product viewer, or prototype scene.
Skip if: Projects needing only static renders, or teams standardizing on React Three Fiber without raw Three.js interaction patterns.
When should I use this skill?
Handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences in Three.js.
What do I get? / Deliverables
The scene exposes damped orbit navigation and raycast-based selection with documented intersect payload fields for downstream UI or game logic.
- OrbitControls setup with optional damping on the canvas
- Click or pointer handlers using Raycaster intersection results
Recommended Skills
Journey fit
Interaction code lands while building the product UI layer, before ship-time polish unless you are retrofitting an existing scene. Frontend subphase covers client-side Three.js input, camera controls, and picking—not backend or asset pipeline work.
How it compares
Use for low-level Three.js Raycaster and OrbitControls recipes—not a full game engine input abstraction or Babylon.js equivalent.
Common Questions / FAQ
Who is threejs-interaction for?
Frontend-focused solo builders using Three.js who need camera controls and object picking without reading the entire manual.
When should I use threejs-interaction?
During Build (frontend) when implementing click detection, touch or mouse input, OrbitControls, or interactive selection in a 3D canvas.
Is threejs-interaction safe to install?
It is documentation-style procedural knowledge with no bundled exfiltration logic—still review the Security Audits panel on this Prism page before trusting any skill package.
SKILL.md
READMESKILL.md - Threejs Interaction
# Three.js Interaction ## Quick Start ```javascript import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; // Camera controls const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // Raycasting for click detection const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); function onClick(event) { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { console.log("Clicked:", intersects[0].object); } } window.addEventListener("click", onClick); ``` ## Raycaster ### Basic Raycasting ```javascript const raycaster = new THREE.Raycaster(); // From camera (mouse picking) raycaster.setFromCamera(mousePosition, camera); // From any origin and direction raycaster.set(origin, direction); // origin: Vector3, direction: normalized Vector3 // Get intersections const intersects = raycaster.intersectObjects(objects, recursive); // intersects array contains: // { // distance: number, // Distance from ray origin // point: Vector3, // Intersection point in world coords // face: Face3, // Intersected face // faceIndex: number, // Face index // object: Object3D, // Intersected object // uv: Vector2, // UV coordinates at intersection // uv1: Vector2, // Second UV channel // normal: Vector3, // Interpolated face normal // instanceId: number // For InstancedMesh // } ``` ### Mouse Position Conversion ```javascript const mouse = new THREE.Vector2(); function updateMouse(event) { // For full window mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; } // For specific canvas element function updateMouseCanvas(event, canvas) { const rect = canvas.getBoundingClientRect(); mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; } ``` ### Touch Support ```javascript function onTouchStart(event) { event.preventDefault(); if (event.touches.length === 1) { const touch = event.touches[0]; mouse.x = (touch.clientX / window.innerWidth) * 2 - 1; mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickableObjects); if (intersects.length > 0) { handleSelection(intersects[0]); } } } renderer.domElement.addEventListener("touchstart", onTouchStart); ``` ### Raycaster Options ```javascript const raycaster = new THREE.Raycaster(); // Near/far clipping (default: 0, Infinity) raycaster.near = 0; raycaster.far = 100; // Line/Points precision raycaster.params.Line.threshold = 0.1; raycaster.params.Points.threshold = 0.1; // Layers (only intersect objects on specific layers) raycaster.layers.set(1); ``` ### Efficient Raycasting ```javascript // Only check specific objects const clickables = [mesh1, mesh2, mesh3]; const intersects = raycaster.intersectObjects(clickables, false); // Use layers for filtering mesh1.layers.set(1); // Clickable layer raycaster.layers.set(1); // Throttle raycast for hover effects let lastRaycast = 0; function onMouseMove(event) { const now = Date.now(); if (now - lastRaycast < 50) return; // 20fps max lastRaycast = now; // Raycast here } ``` ## Camera Controls ### OrbitControls ```javascript import { OrbitControls } from "three/addons/controls/OrbitControls.js"; cons