Skip to main content Início Criadores 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.
Ir para a instalação Skills Marketplace Descubra e explore skills de IA criadas pela comunidade.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Copiar promptMostrar detalhes do prompt Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
npx skills add https://github.com/BEKO2210/Firstbrain --skill threejs-interactionO comando permanece em uma só linha. Role horizontalmente para revisá-lo antes de copiar.
Prefere uma cópia local? Baixe os arquivos disponíveis atualmente no SkillsMP.
Baixar Zip Baixando... Ocupações relacionadas SOC
Baseado na classificação ocupacional SOC
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]]