threejs-interaction

Three.js interaction - raycasting, controls, mouse/touch input, object selection. Use when handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences.

By cloudai-x · 9,400 installs

npx skills add cloudai-x/threejs-skills --skill threejs-interaction

Source repository · Upstream listing

Three.js Interaction Targets three.js r186. Examples use WebGLRenderer; the WebGPU and TSL section uses WebGPURenderer. Quick Start Pointer events ( pointerdown , pointermove , pointerup ) cover mouse, touch and pen in one listener set, so no separate touch handlers are needed. Raycasting Faces pointing away from the ray origin are not hit; set material.side = THREE.DoubleSide to catch both sides. A ray that grazes an edge shared by two faces can produce two coincident hits. Invisible meshes are still raycast — the Raycaster tests layers, not visibility — so an invisible simple proxy can stand in for a complex model. What an intersection contains Raycaster configuration Dragging on a plane Camera Controls Every controls class extends Controls and shares one base API: construct with the camera and the DOM element (DragControls takes its array of objects first), and the constructor wires its own listeners; enabled = false to ignore input, disconnect() / connect(element) to detach or move, dispose() on teardown. update() takes a delta in seconds for OrbitControls, FlyControls and FirstPersonControls — pass timer.getDelta() ; call it without arguments for the others. OrbitControls OrbitControls fires change , start and end events. MapControls is an OrbitControls subclass tuned for map navigation: FlyControls FirstPersonControls FirstPersonControls has a drag based look model: press and drag to look (look speed grows with the drag distance and eases through dampingFactor , default 0.1, where 1 disables the easing), WASD or arrows to move, R and F for up and down, hold the left button to fly forward and the right button to fly backward. Touch works through pointer events: one finger moves forward, two fingers move backward. PointerLockControls The controls move the camera passed to the constructor ( controls.object ); it renders without being added to the scene, so scene.add(controls.object) is needed only when the camera has children. TrackballControls TransformControls A gizmo for moving, rotating and scaling objects. The controls object is not an Object3D; the gizmo it renders must be added to the scene separately. DragControls Drags objects directly: left or middle drag moves the object in a plane parallel to the screen, right drag rotates it around the camera's up and right axes. Selection For teardown, keep named handler references so you can removeEventListener them, and call controls.dispose() for every control and timer.dispose() for the timer. Box selection SelectionBox selects the objects whose bounding sphere center falls inside a screen space rectangle; SelectionHelper draws the rectangle and tracks the drag. Screen and World Coordinates WebGPU and TSL Controls and Raycaster are renderer neutral: the picking and camera control code above runs unchanged under WebGPURenderer. Raycaster tests CPU side geometry, so it never sees positionNode displacement — pick against an undisplaced proxy mesh instead. Common Mistakes scene.add(transformControls) → scene.add(transformControls.getHelper()) : TransformControls extends Controls, an EventDispatcher rather than an Object3D, so this logs an error and the gizmo never appears. new OrbitControls(camera) → new OrbitControls(camera, renderer.domElement) : the constructor wires its listeners to the element; without one the controls never receive input. controls.update(clock.getDelta()) → timer.update(); controls.update(timer.getDelta()) : Clock is deprecated in r183; create a Timer, connect it, and update it first thing each frame. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js" → import { OrbitControls } from "three/addons/controls/OrbitControls.js" : the documented import maps point three/addons/ at examples/jsm/ and define no three/examples/ key, so this specifier does not resolve in the browser. requestAnimationFrame(animate) → renderer.setAnimationLoop(animate) : both renderers' docs advise it over a manual loop, and it hands frames to the WebXR session when one starts. flyControls.update() → flyControls.update(timer.getDelta()) : FlyControls and FirstPersonControls scale movement by the delta, so without it the position becomes NaN. orbitControls.update() → orbitControls.update(timer.getDelta()) : without a delta, autoRotate speed depends on the display refresh rate. mesh.layers.set(1) → mesh.layers.enable(1) : set replaces the mask, removing the mesh from layer 0, so the default camera stops rendering it. hit.face instanceof THREE.Face3 → hit.face.normal : the intersection's face is a plain { a, b, c, normal, materialIndex } object; Face3 does not exist. const moveForward = false → let moveForward = false : the keydown handler reassigns the flag, and assigning to a const throws a TypeError. controls.getObject() → controls.object : PointerLockControls.getObject() was removed in r168; the controls manage the camera passed to the constructor. dragControls.getObjects() → dragControls.objects : removed in r168; getRaycaster() became the raycaster property the same way. dragControls.activate() → dragControls.connect(renderer.domElement) : renamed from activate() in r168 (deactivate() became disconnect()), and connect() needs the element: without one it throws a TypeError, as the old names do. firstPersonControls.activeLook = false → firstPersonControls.lookSpeed = 0 : FirstPersonControls has no activeLook property, so assigning it does nothing and drag look stays on. See Also threejs fundamentals scenes, cameras, renderer setup and the animation loop threejs animation animating objects in response to interaction threejs postprocessing outline and bloom effects for selection highlights threejs loaders loading the glTF models you make interactive threejs react three fiber pointer event props and drei controls when the scene is written in React