Three.js Game Development Skill
Comprehensive assistance with Three.js game development using WebGL, covering 3D rendering, game mechanics, physics, animations, and interactive browser-based games.
When to Use This Skill
Activate this skill when:
- Building 3D web games with Three.js
- Implementing game mechanics (player movement, collisions, scoring)
- Setting up cameras, lighting, and scene management
- Loading 3D models (GLTF, OBJ, FBX)
- Handling user input (keyboard, mouse, touch, gamepad)
- Creating animations and character controllers
- Integrating physics engines (Cannon.js, Ammo.js)
- Optimizing 3D game performance
- Working with shaders and materials for game visuals
Quick Reference
Basic Game Setup
javascript
1import * as THREE from 'three';
2
3// Create scene, camera, renderer
4const scene = new THREE.Scene();
5const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
6const renderer = new THREE.WebGLRenderer({ antialias: true });
7renderer.setSize(window.innerWidth, window.innerHeight);
8document.body.appendChild(renderer.domElement);
9
10// Game loop
11function animate(time) {
12 requestAnimationFrame(animate);
13
14 // Update game logic here
15 updatePlayer(time);
16 updateEnemies(time);
17 checkCollisions();
18
19 renderer.render(scene, camera);
20}
21
22animate();
Player Controller (Third-Person)
javascript
1class PlayerController {
2 constructor(camera, target) {
3 this.camera = camera;
4 this.target = target;
5 this.distance = 10;
6 this.height = 5;
7 this.rotationSpeed = 0.005;
8 this.moveSpeed = 0.1;
9 }
10
11 update(input) {
12 // Movement
13 const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.target.quaternion);
14 const right = new THREE.Vector3(1, 0, 0).applyQuaternion(this.target.quaternion);
15
16 if (input.forward) this.target.position.add(forward.multiplyScalar(this.moveSpeed));
17 if (input.backward) this.target.position.add(forward.multiplyScalar(-this.moveSpeed));
18 if (input.left) this.target.position.add(right.multiplyScalar(-this.moveSpeed));
19 if (input.right) this.target.position.add(right.multiplyScalar(this.moveSpeed));
20
21 // Rotation
22 if (input.rotateLeft) this.target.rotation.y += this.rotationSpeed;
23 if (input.rotateRight) this.target.rotation.y -= this.rotationSpeed;
24
25 // Update camera position
26 const offset = new THREE.Vector3(0, this.height, this.distance);
27 offset.applyQuaternion(this.target.quaternion);
28 this.camera.position.copy(this.target.position).add(offset);
29 this.camera.lookAt(this.target.position);
30 }
31}
javascript
1class InputManager {
2 constructor() {
3 this.keys = {};
4 this.mouse = { x: 0, y: 0, buttons: {} };
5
6 window.addEventListener('keydown', (e) => this.keys[e.code] = true);
7 window.addEventListener('keyup', (e) => this.keys[e.code] = false);
8 window.addEventListener('mousemove', (e) => {
9 this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
10 this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
11 });
12 }
13
14 getInput() {
15 return {
16 forward: this.keys['KeyW'] || this.keys['ArrowUp'],
17 backward: this.keys['KeyS'] || this.keys['ArrowDown'],
18 left: this.keys['KeyA'] || this.keys['ArrowLeft'],
19 right: this.keys['KeyD'] || this.keys['ArrowRight'],
20 jump: this.keys['Space'],
21 action: this.keys['KeyE'],
22 rotateLeft: this.keys['KeyQ'],
23 rotateRight: this.keys['KeyE']
24 };
25 }
26}
Collision Detection (Raycasting)
javascript
1function checkCollisions(player, obstacles) {
2 const raycaster = new THREE.Raycaster();
3 const directions = [
4 new THREE.Vector3(1, 0, 0), // right
5 new THREE.Vector3(-1, 0, 0), // left
6 new THREE.Vector3(0, 0, 1), // forward
7 new THREE.Vector3(0, 0, -1), // backward
8 ];
9
10 for (const direction of directions) {
11 raycaster.set(player.position, direction);
12 const intersects = raycaster.intersectObjects(obstacles);
13
14 if (intersects.length > 0 && intersects[0].distance < 1.0) {
15 return {
16 collision: true,
17 object: intersects[0].object,
18 distance: intersects[0].distance,
19 point: intersects[0].point
20 };
21 }
22 }
23
24 return { collision: false };
25}
Loading 3D Models (GLTF)
javascript
1import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
3const loader = new GLTFLoader();
4
5function loadCharacter(path) {
6 return new Promise((resolve, reject) => {
7 loader.load(
8 path,
9 (gltf) => {
10 const model = gltf.scene;
11 model.scale.set(1, 1, 1);
12 scene.add(model);
13
14 // Setup animations if available
15 const mixer = new THREE.AnimationMixer(model);
16 const animations = {};
17 gltf.animations.forEach(clip => {
18 animations[clip.name] = mixer.clipAction(clip);
19 });
20
21 resolve({ model, mixer, animations });
22 },
23 (progress) => {
24 console.log(`Loading: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
25 },
26 (error) => reject(error)
27 );
28 });
29}
30
31// Usage
32const character = await loadCharacter('/models/character.glb');
33character.animations.idle.play();
Basic Physics (Gravity & Jumping)
javascript
1class PhysicsBody {
2 constructor(mesh) {
3 this.mesh = mesh;
4 this.velocity = new THREE.Vector3();
5 this.onGround = false;
6 this.gravity = -9.8;
7 this.jumpPower = 5;
8 }
9
10 update(deltaTime) {
11 // Apply gravity
12 if (!this.onGround) {
13 this.velocity.y += this.gravity * deltaTime;
14 }
15
16 // Apply velocity
17 this.mesh.position.add(this.velocity.clone().multiplyScalar(deltaTime));
18
19 // Ground check
20 if (this.mesh.position.y <= 0) {
21 this.mesh.position.y = 0;
22 this.velocity.y = 0;
23 this.onGround = true;
24 }
25 }
26
27 jump() {
28 if (this.onGround) {
29 this.velocity.y = this.jumpPower;
30 this.onGround = false;
31 }
32 }
33}
Interactive Objects (Picking)
javascript
1const raycaster = new THREE.Raycaster();
2const mouse = new THREE.Vector2();
3
4function onMouseClick(event) {
5 mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
6 mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
7
8 raycaster.setFromCamera(mouse, camera);
9 const intersects = raycaster.intersectObjects(interactableObjects);
10
11 if (intersects.length > 0) {
12 const object = intersects[0].object;
13 object.userData.onInteract?.();
14 }
15}
16
17window.addEventListener('click', onMouseClick);
Health & Damage System
javascript
1class Entity {
2 constructor(mesh, maxHealth) {
3 this.mesh = mesh;
4 this.maxHealth = maxHealth;
5 this.health = maxHealth;
6 this.isDead = false;
7 }
8
9 takeDamage(amount) {
10 if (this.isDead) return;
11
12 this.health = Math.max(0, this.health - amount);
13
14 if (this.health === 0) {
15 this.die();
16 }
17
18 return this.health;
19 }
20
21 heal(amount) {
22 this.health = Math.min(this.maxHealth, this.health + amount);
23 return this.health;
24 }
25
26 die() {
27 this.isDead = true;
28 this.mesh.visible = false;
29 // Trigger death animation, effects, etc.
30 }
31}
Key Concepts
Scene Graph
- Organize game objects hierarchically
- Use groups for complex objects
- Parent-child transformations
Game Loop
- Use
requestAnimationFrame for 60fps
- Calculate delta time for frame-independent movement
- Separate update logic from rendering
Camera Systems
- PerspectiveCamera: First/third-person games
- OrthographicCamera: 2D/isometric games
- Implement camera follow and smooth transitions
Lighting
- AmbientLight: Base illumination
- DirectionalLight: Sun/moonlight with shadows
- PointLight: Torches, explosions
- SpotLight: Flashlights, stage lights
- Use instancing for repeated objects
- Implement frustum culling
- Use LOD (Level of Detail) for distant objects
- Minimize draw calls
- Use texture atlases
- Enable shadow map optimization
Asset Loading
- Preload all assets before game start
- Show loading progress bar
- Use LoadingManager for coordination
- Cache loaded assets
Common Game Patterns
State Machine (Game States)
javascript
1class GameStateMachine {
2 constructor() {
3 this.states = {
4 menu: new MenuState(),
5 playing: new PlayingState(),
6 paused: new PausedState(),
7 gameOver: new GameOverState()
8 };
9 this.currentState = this.states.menu;
10 }
11
12 changeState(stateName) {
13 this.currentState.exit();
14 this.currentState = this.states[stateName];
15 this.currentState.enter();
16 }
17
18 update(deltaTime) {
19 this.currentState.update(deltaTime);
20 }
21}
Object Pooling
javascript
1class ObjectPool {
2 constructor(factory, initialSize = 10) {
3 this.factory = factory;
4 this.available = [];
5 this.inUse = [];
6
7 for (let i = 0; i < initialSize; i++) {
8 this.available.push(factory());
9 }
10 }
11
12 acquire() {
13 let obj = this.available.pop();
14 if (!obj) obj = this.factory();
15 this.inUse.push(obj);
16 return obj;
17 }
18
19 release(obj) {
20 const index = this.inUse.indexOf(obj);
21 if (index > -1) {
22 this.inUse.splice(index, 1);
23 this.available.push(obj);
24 }
25 }
26}
27
28// Usage
29const bulletPool = new ObjectPool(() => createBullet(), 20);
30const bullet = bulletPool.acquire();
31// ... use bullet
32bulletPool.release(bullet);
Reference Files
Detailed documentation organized by topic:
- getting_started.md - Three.js fundamentals, setup, and basic concepts
- game_development.md - Game loop, player controllers, game mechanics
- scene_graph.md - Scene organization, hierarchy, transformations
- materials.md - Material types, shaders, visual effects
- textures.md - Texture loading, UV mapping, atlases
- lighting.md - Light types, shadows, HDR
- cameras.md - Camera types, controls, viewport management
- geometry.md - Built-in geometries, custom geometry, buffers
- loading.md - Asset loading (models, textures, audio)
- animation.md - Animation system, skeletal animation, tweens
- interactivity.md - Raycasting, picking, UI integration
- effects.md - Post-processing, particles, fog
Resources
Official Documentation
Physics Integration
- Cannon.js: Lightweight 3D physics
- Ammo.js: Full Bullet physics engine port
- Rapier: High-performance physics
Useful Libraries
- three-mesh-bvh: Fast raycasting
- three-pathfinding: Navigation meshes
- postprocessing: Advanced effects
Working with This Skill
For Beginners
- Start with basic scene setup
- Learn the coordinate system
- Understand the game loop
- Practice with simple shapes before models
For Game Development
- Plan your game architecture
- Implement input handling first
- Build a simple player controller
- Add gameplay mechanics incrementally
- Optimize performance throughout
For Advanced Features
- Integrate physics engines
- Implement advanced shaders
- Add post-processing effects
- Build multiplayer networking
Notes
- Three.js uses a right-handed coordinate system (X right, Y up, Z out)
- Optimize early: profile regularly, minimize draw calls
- Use development builds for debugging, production builds for release
- Consider WebGL 2 features for modern browsers
- Mobile performance requires careful optimization