threejs-camera
Skill13 starsChanged 7 months agoMITView on GitHub
Configures Three.js cameras and controls — PerspectiveCamera, OrthographicCamera, OrbitControls, FlyControls, PointerLockControls, and first-person setup. Use when the user asks about cameras, controls, orbit, fly, first-person, camera movement, or viewport setup. Trigger keywords: camera, OrbitControls, FlyControls, PointerLockControls, perspective, orthographic, first person, viewport, FOV.
Files
Three.js Camera & Controls
PerspectiveCamera
const camera = new THREE.PerspectiveCamera(
75, // fov — vertical field of view in degrees
window.innerWidth / window.innerHeight, // aspect ratio
0.1, // near clipping plane
1000, // far clipping plane
);
camera.position.set(0, 2, 5);
camera.lookAt(0, 0, 0);
scene.add(camera); // add to scene if it has audio listeners or childrenFOV guidelines: 45–60° cinematic, 75° standard, 90–110° FPS/wide-angle
OrthographicCamera
const aspect = window.innerWidth / window.innerHeight;
const frustumSize = 10;
const camera = new THREE.OrthographicCamera(
(-frustumSize * aspect) / 2, // left
(frustumSize * aspect) / 2, // right
frustumSize / 2, // top
-frustumSize / 2, // bottom
0.1, // near
1000, // far
);
camera.position.set(0, 5, 5);
camera.lookAt(0, 0, 0);
// Resize — must recalculate frustum
window.addEventListener("resize", () => {
const aspect = window.innerWidth / window.innerHeight;
camera.left = (-frustumSize * aspect) / 2;
camera.right = (frustumSize * aspect) / 2;
camera.top = frustumSize / 2;
camera.bottom = -frustumSize / 2;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});OrbitControls
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
const controls = new OrbitControls(camera, renderer.domElement);
// Damping (smooth deceleration) — MUST call controls.update() in loop
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Constraints
controls.minDistance = 2;
controls.maxDistance = 50;
controls.minPolarAngle = 0; // 0 = top
controls.maxPolarAngle = Math.PI / 2; // PI = bottom, PI/2 = equator
controls.minAzimuthAngle = -Math.PI / 4;
controls.maxAzimuthAngle = Math.PI / 4;
// Disable
controls.enableRotate = false;
controls.enableZoom = false;
controls.enablePan = false;
// Target
controls.target.set(0, 1, 0); // orbit around this point
controls.update();
// REQUIRED in render loop when enableDamping: true
function animate() {
requestAnimationFrame(animate);
controls.update(); // ← essential
renderer.render(scene, camera);
}FlyControls
import { FlyControls } from "three/addons/controls/FlyControls.js";
const flyControls = new FlyControls(camera, renderer.domElement);
flyControls.movementSpeed = 10;
flyControls.rollSpeed = Math.PI / 12;
flyControls.autoForward = false;
flyControls.dragToLook = true;
// REQUIRED in loop with delta
function animate() {
const delta = clock.getDelta();
flyControls.update(delta); // delta required
renderer.render(scene, camera);
}PointerLockControls (FPS)
import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
const controls = new PointerLockControls(camera, document.body);
scene.add(controls.object); // controls wraps camera in a parent Object3D
// Lock pointer on click
document.addEventListener("click", () => controls.lock());
controls.addEventListener("lock", () => {
/* hide crosshair UI */
});
controls.addEventListener("unlock", () => {
/* show menu */
});
// WASD movement
const keys = {};
document.addEventListener("keydown", (e) => (keys[e.code] = true));
document.addEventListener("keyup", (e) => (keys[e.code] = false));
function animate() {
const delta = clock.getDelta();
if (controls.isLocked) {
const speed = 5 * delta;
if (keys["KeyW"]) controls.moveForward(speed);
if (keys["KeyS"]) controls.moveForward(-speed);
if (keys["KeyA"]) controls.moveRight(-speed);
if (keys["KeyD"]) controls.moveRight(speed);
}
renderer.render(scene, camera);
}Camera Shake
// Simple procedural camera shake
function shake(camera, intensity = 0.1, duration = 0.5) {
const startTime = clock.getElapsedTime();
const originalPos = camera.position.clone();
function applyShake() {
const elapsed = clock.getElapsedTime() - startTime;
if (elapsed > duration) {
camera.position.copy(originalPos);
return;
}
const decay = 1 - elapsed / duration;
camera.position.x =
originalPos.x + (Math.random() - 0.5) * intensity * decay;
camera.position.y =
originalPos.y + (Math.random() - 0.5) * intensity * decay;
requestAnimationFrame(applyShake);
}
applyShake();
}CameraHelper (debug)
const helper = new THREE.CameraHelper(camera);
scene.add(helper);
// Update each frame if camera moves:
helper.update();Common Gotchas
controls.update()must be called every frame whenenableDamping: true— without it, damping doesn't work- OrthographicCamera resize: recalculate left/right/top/bottom — not just aspect
PointerLockControlswraps camera in a parent — addcontrols.objectto scene, not the camera directlycamera.lookAt()is overridden by controls — don't mix manual lookAt with OrbitControls- FlyControls and PointerLockControls require
deltain update — useclock.getDelta() - Near/far range: keep ratio
far/nearbelow 10,000 to avoid z-fighting. Near=0.01, Far=100 is better than Near=0.001, Far=10000
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 1
- FkennedyFox/claude-skills★ 0100% same
Wrote their own version · 1
- full-stack-skills/threejs-skills★ 9same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository15 other files it gives its agents.
- AGENTS.mdAGENTS.md
- skills/llms.txtllms.txt
- threejs-animationSkill
- threejs-audioSkill
- threejs-coreSkill
- threejs-geometrySkill
- threejs-lightingSkill
- threejs-loadersSkill
- threejs-materialsSkill
- threejs-performanceSkill
- threejs-physicsSkill
- threejs-postprocessingSkill
- threejs-reactSkill
- threejs-shadersSkill
- threejs-xrSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

