Skip to main content Accueil Créateurs beko2210 firstbrain threejs-interaction
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.
Aller à l'installation Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Métiers associés SOC
Basé sur la classification professionnelle SOC
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/BEKO2210/Firstbrain --skill threejs-interactionLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... name threejs-interaction description 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. type skill created 2026-02-27T00:00:00.000Z domain design-creative category 3d-animation risk unknown source community tags ["skill","design-creative","3d-animation","threejs","interaction"]
Three.js Interaction
When to Use
You need user interaction inside a Three.js scene.
The task involves raycasting, object picking, pointer handling, touch input, or camera controls.
You are building an interactive 3D experience rather than a passive render.
Quick Start
import * as THREE from "three" ;
import { OrbitControls } from "three/addons/controls/OrbitControls.js" ;
const controls = new OrbitControls (camera, renderer.domElement );
controls.enableDamping = true ;
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. );
(intersects. > ) {
. ( , intersects[ ]. );
}
}
. ( , onClick);
children
if
length
0
console
log
"Clicked:"
0
object
window
addEventListener
"click"
Raycaster
Basic Raycasting const raycaster = new THREE .Raycaster ();
raycaster.setFromCamera (mousePosition, camera);
raycaster.set (origin, direction);
const intersects = raycaster.intersectObjects (objects, recursive);
Mouse Position Conversion const mouse = new THREE .Vector2 ();
function updateMouse (event ) {
mouse.x = (event.clientX / window .innerWidth ) * 2 - 1 ;
mouse.y = -(event.clientY / window .innerHeight ) * 2 + 1 ;
}
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 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 const raycaster = new THREE .Raycaster ();
raycaster.near = 0 ;
raycaster.far = 100 ;
raycaster.params .Line .threshold = 0.1 ;
raycaster.params .Points .threshold = 0.1 ;
raycaster.layers .set (1 );
Efficient Raycasting
const clickables = [mesh1, mesh2, mesh3];
const intersects = raycaster.intersectObjects (clickables, false );
mesh1.layers .set (1 );
raycaster.layers .set (1 );
let lastRaycast = 0 ;
function onMouseMove (event ) {
const now = Date .now ();
if (now - lastRaycast < 50 ) return ;
lastRaycast = now;
}
Camera Controls
OrbitControls import { OrbitControls } from "three/addons/controls/OrbitControls.js" ;
const controls = new OrbitControls (camera, renderer.domElement );
controls.enableDamping = true ;
controls.dampingFactor = 0.05 ;
controls.minPolarAngle = 0 ;
controls.maxPolarAngle = Math .PI / 2 ;
controls.minAzimuthAngle = -Math .PI / 4 ;
controls.maxAzimuthAngle = Math .PI / 4 ;
controls.minDistance = 2 ;
controls.maxDistance = 50 ;
controls.enableRotate = true ;
controls.enableZoom = true ;
controls.enablePan = true ;
controls.autoRotate = true ;
controls.autoRotateSpeed = 2.0 ;
controls.target .set (0 , 1 , 0 );
function animate ( ) {
controls.update ();
renderer.render (scene, camera);
}
OrbitControls Programmatic Methods (r183)
controls.dolly (1.5 );
controls.pan (deltaX, deltaY);
controls.rotate (deltaAzimuth, deltaPolar);
controls.cursorStyle = { orbit : "grab" , pan : "move" , dolly : "zoom-in" };
FlyControls import { FlyControls } from "three/addons/controls/FlyControls.js" ;
const controls = new FlyControls (camera, renderer.domElement );
controls.movementSpeed = 10 ;
controls.rollSpeed = Math .PI / 24 ;
controls.dragToLook = true ;
function animate ( ) {
controls.update (clock.getDelta ());
renderer.render (scene, camera);
}
FirstPersonControls import { FirstPersonControls } from "three/addons/controls/FirstPersonControls.js" ;
const controls = new FirstPersonControls (camera, renderer.domElement );
controls.movementSpeed = 10 ;
controls.lookSpeed = 0.1 ;
controls.lookVertical = true ;
controls.constrainVertical = true ;
controls.verticalMin = Math .PI / 4 ;
controls.verticalMax = (Math .PI * 3 ) / 4 ;
function animate ( ) {
controls.update (clock.getDelta ());
}
PointerLockControls import { PointerLockControls } from "three/addons/controls/PointerLockControls.js" ;
const controls = new PointerLockControls (camera, document .body );
document .addEventListener ("click" , () => {
controls.lock ();
});
controls.addEventListener ("lock" , () => {
console .log ("Pointer locked" );
});
controls.addEventListener ("unlock" , () => {
console .log ("Pointer unlocked" );
});
const velocity = new THREE .Vector3 ();
const direction = new THREE .Vector3 ();
const moveForward = false ;
const moveBackward = false ;
document .addEventListener ("keydown" , (event ) => {
switch (event.code ) {
case "KeyW" :
moveForward = true ;
break ;
case "KeyS" :
moveBackward = true ;
break ;
}
});
function animate ( ) {
if (controls.isLocked ) {
direction.z = Number (moveForward) - Number (moveBackward);
direction.normalize ();
velocity.z -= direction.z * 0.1 ;
velocity.z *= 0.9 ;
controls.moveForward (-velocity.z );
}
}
TrackballControls import { TrackballControls } from "three/addons/controls/TrackballControls.js" ;
const controls = new TrackballControls (camera, renderer.domElement );
controls.rotateSpeed = 2.0 ;
controls.zoomSpeed = 1.2 ;
controls.panSpeed = 0.8 ;
controls.staticMoving = true ;
function animate ( ) {
controls.update ();
}
MapControls import { MapControls } from "three/addons/controls/MapControls.js" ;
const controls = new MapControls (camera, renderer.domElement );
controls.enableDamping = true ;
controls.dampingFactor = 0.05 ;
controls.screenSpacePanning = false ;
controls.maxPolarAngle = Math .PI / 2 ;
TransformControls Gizmo for moving/rotating/scaling objects.
import { TransformControls } from "three/addons/controls/TransformControls.js" ;
const transformControls = new TransformControls (camera, renderer.domElement );
scene.add (transformControls);
transformControls.attach (selectedMesh);
transformControls.setMode ("translate" );
transformControls.setSpace ("local" );
transformControls.setSize (1 );
transformControls.addEventListener ("dragging-changed" , (event ) => {
orbitControls.enabled = !event.value ;
});
transformControls.addEventListener ("change" , () => {
renderer.render (scene, camera);
});
window .addEventListener ("keydown" , (event ) => {
switch (event.key ) {
case "g" :
transformControls.setMode ("translate" );
break ;
case "r" :
transformControls.setMode ("rotate" );
break ;
case "s" :
transformControls.setMode ("scale" );
break ;
case "Escape" :
transformControls.detach ();
break ;
}
});
DragControls import { DragControls } from "three/addons/controls/DragControls.js" ;
const draggableObjects = [mesh1, mesh2, mesh3];
const dragControls = new DragControls (
draggableObjects,
camera,
renderer.domElement ,
);
dragControls.addEventListener ("dragstart" , (event ) => {
orbitControls.enabled = false ;
event.object .material .emissive .set (0xaaaaaa );
});
dragControls.addEventListener ("drag" , (event ) => {
event.object .position .y = 0 ;
});
dragControls.addEventListener ("dragend" , (event ) => {
orbitControls.enabled = true ;
event.object .material .emissive .set (0x000000 );
});
Selection System
Click to Select const raycaster = new THREE .Raycaster ();
const mouse = new THREE .Vector2 ();
let selectedObject = null ;
function onMouseDown (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 (selectableObjects);
if (selectedObject) {
selectedObject.material .emissive .set (0x000000 );
}
if (intersects.length > 0 ) {
selectedObject = intersects[0 ].object ;
selectedObject.material .emissive .set (0x444444 );
} else {
selectedObject = null ;
}
}
Box Selection import { SelectionBox } from "three/addons/interactive/SelectionBox.js" ;
import { SelectionHelper } from "three/addons/interactive/SelectionHelper.js" ;
const selectionBox = new SelectionBox (camera, scene);
const selectionHelper = new SelectionHelper (renderer, "selectBox" );
document .addEventListener ("pointerdown" , (event ) => {
selectionBox.startPoint .set (
(event.clientX / window .innerWidth ) * 2 - 1 ,
-(event.clientY / window .innerHeight ) * 2 + 1 ,
0.5 ,
);
});
document .addEventListener ("pointermove" , (event ) => {
if (selectionHelper.isDown ) {
selectionBox.endPoint .set (
(event.clientX / window .innerWidth ) * 2 - 1 ,
-(event.clientY / window .innerHeight ) * 2 + 1 ,
0.5 ,
);
}
});
document .addEventListener ("pointerup" , (event ) => {
selectionBox.endPoint .set (
(event.clientX / window .innerWidth ) * 2 - 1 ,
-(event.clientY / window .innerHeight ) * 2 + 1 ,
0.5 ,
);
const selected = selectionBox.select ();
console .log ("Selected objects:" , selected);
});
Hover Effects const raycaster = new THREE .Raycaster ();
const mouse = new THREE .Vector2 ();
let hoveredObject = null ;
function onMouseMove (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 (hoverableObjects);
if (hoveredObject) {
hoveredObject.material .color .set (hoveredObject.userData .originalColor );
document .body .style .cursor = "default" ;
}
if (intersects.length > 0 ) {
hoveredObject = intersects[0 ].object ;
if (!hoveredObject.userData .originalColor ) {
hoveredObject.userData .originalColor =
hoveredObject.material .color .getHex ();
}
hoveredObject.material .color .set (0xff6600 );
document .body .style .cursor = "pointer" ;
} else {
hoveredObject = null ;
}
}
window .addEventListener ("mousemove" , onMouseMove);
Keyboard Input const keys = {};
document .addEventListener ("keydown" , (event ) => {
keys[event.code ] = true ;
});
document .addEventListener ("keyup" , (event ) => {
keys[event.code ] = false ;
});
function update ( ) {
const speed = 0.1 ;
if (keys["KeyW" ]) player.position .z -= speed;
if (keys["KeyS" ]) player.position .z += speed;
if (keys["KeyA" ]) player.position .x -= speed;
if (keys["KeyD" ]) player.position .x += speed;
if (keys["Space" ]) player.position .y += speed;
if (keys["ShiftLeft" ]) player.position .y -= speed;
}
World-Screen Coordinate Conversion
World to Screen function worldToScreen (position, camera ) {
const vector = position.clone ();
vector.project (camera);
return {
x : ((vector.x + 1 ) / 2 ) * window .innerWidth ,
y : (-(vector.y - 1 ) / 2 ) * window .innerHeight ,
};
}
const screenPos = worldToScreen (mesh.position , camera);
element.style .left = screenPos.x + "px" ;
element.style .top = screenPos.y + "px" ;
Screen to World function screenToWorld (screenX, screenY, camera, targetZ = 0 ) {
const vector = new THREE .Vector3 (
(screenX / window .innerWidth ) * 2 - 1 ,
-(screenY / window .innerHeight ) * 2 + 1 ,
0.5 ,
);
vector.unproject (camera);
const dir = vector.sub (camera.position ).normalize ();
const distance = (targetZ - camera.position .z ) / dir.z ;
return camera.position .clone ().add (dir.multiplyScalar (distance));
}
Ray-Plane Intersection function getRayPlaneIntersection (mouse, camera, plane ) {
const raycaster = new THREE .Raycaster ();
raycaster.setFromCamera (mouse, camera);
const intersection = new THREE .Vector3 ();
raycaster.ray .intersectPlane (plane, intersection);
return intersection;
}
const groundPlane = new THREE .Plane (new THREE .Vector3 (0 , 1 , 0 ), 0 );
const worldPos = getRayPlaneIntersection (mouse, camera, groundPlane);
Event Handling Best Practices class InteractionManager {
constructor (camera, renderer, scene ) {
this .camera = camera;
this .renderer = renderer;
this .scene = scene;
this .raycaster = new THREE .Raycaster ();
this .mouse = new THREE .Vector2 ();
this .clickables = [];
this .bindEvents ();
}
bindEvents ( ) {
const canvas = this .renderer .domElement ;
canvas.addEventListener ("click" , (e ) => this .onClick (e));
canvas.addEventListener ("mousemove" , (e ) => this .onMouseMove (e));
canvas.addEventListener ("touchstart" , (e ) => this .onTouchStart (e));
}
updateMouse (event ) {
const rect = this .renderer .domElement .getBoundingClientRect ();
this .mouse .x = ((event.clientX - rect.left ) / rect.width ) * 2 - 1 ;
this .mouse .y = -((event.clientY - rect.top ) / rect.height ) * 2 + 1 ;
}
getIntersects ( ) {
this .raycaster .setFromCamera (this .mouse , this .camera );
return this .raycaster .intersectObjects (this .clickables , true );
}
onClick (event ) {
this .updateMouse (event);
const intersects = this .getIntersects ();
if (intersects.length > 0 ) {
const object = intersects[0 ].object ;
if (object.userData .onClick ) {
object.userData .onClick (intersects[0 ]);
}
}
}
addClickable (object, callback ) {
this .clickables .push (object);
object.userData .onClick = callback;
}
dispose ( ) {
}
}
const interaction = new InteractionManager (camera, renderer, scene);
interaction.addClickable (mesh, (intersect ) => {
console .log ("Clicked at:" , intersect.point );
});
Performance Tips
Limit raycasts : Throttle mousemove handlers
Use layers : Filter raycast targets
Simple collision meshes : Use invisible simpler geometry for raycasting
Disable controls when not needed : controls.enabled = false
Batch updates : Group interaction checks
const complexMesh = loadedModel;
const collisionMesh = new THREE .Mesh (
new THREE .BoxGeometry (1 , 1 , 1 ),
new THREE .MeshBasicMaterial ({ visible : false }),
);
collisionMesh.userData .target = complexMesh;
clickables.push (collisionMesh);
See Also
threejs-fundamentals - Camera and scene setup
threejs-animation - Animating interactions
threejs-shaders - Visual feedback effects
Connections
Domain: [[Design & Kreativitaet]]
Kategorie: [[3D & Animation]]
Navigation: [[Skills Uebersicht]], [[Home]]