iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Examples

A small gallery of three.js patterns you can lift into your own project: a particle field, an orbit-controllable model viewer, an interactive raycaster, and a tween-driven camera path. Each is short, self-contained, and shows the API working together.

Particles, model viewer, raycasting, camera path

EXAMPLE
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader }    from 'three/examples/jsm/loaders/GLTFLoader.js';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(innerWidth, innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
document.body.appendChild(renderer.domElement);

const scene  = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 200);
camera.position.set(0, 1.5, 5);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// 1) Particle field — 10k points scattered in a sphere
const positions = new Float32Array(10_000 * 3);
for (let i = 0; i < positions.length; i++) positions[i] = (Math.random() - .5) * 20;
const particles = new THREE.Points(
  new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(positions, 3)),
  new THREE.PointsMaterial({ size: 0.04, color: 0x88aaff, sizeAttenuation: true })
);
scene.add(particles);

// 2) Model viewer — drop a GLB into ./public/model.glb
const loader = new GLTFLoader();
let model;
loader.load('/model.glb', (gltf) => {
  model = gltf.scene;
  model.position.set(0, 0, 0);
  scene.add(model);
}, undefined, (err) => console.error(err));

scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dir = new THREE.DirectionalLight(0xffffff, 1.2);
dir.position.set(5, 10, 5); scene.add(dir);

// 3) Raycaster — click-to-highlight any object under the cursor
const raycaster = new THREE.Raycaster();
const pointer   = new THREE.Vector2();
let highlighted = null;

addEventListener('pointermove', (e) => {
  pointer.x = (e.clientX / innerWidth)  * 2 - 1;
  pointer.y = -(e.clientY / innerHeight) * 2 + 1;
});

function updateHighlight() {
  raycaster.setFromCamera(pointer, camera);
  const hits = raycaster.intersectObjects(scene.children, true);
  const hit = hits[0]?.object ?? null;
  if (hit !== highlighted) {
    if (highlighted) highlighted.material?.emissive?.setHex(0x000000);
    highlighted = hit;
    if (highlighted?.material?.emissive) highlighted.material.emissive.setHex(0x222288);
  }
}

// 4) Camera path with a Catmull-Rom curve — smooth fly-through
const path = new THREE.CatmullRomCurve3([
  new THREE.Vector3( 5,  2,  5),
  new THREE.Vector3( 0,  3, -3),
  new THREE.Vector3(-5,  2,  5),
  new THREE.Vector3( 0,  6,  0),
], true);

let t = 0;
function flyThrough(dt) {
  t = (t + dt * 0.04) % 1;
  const p = path.getPointAt(t);
  const look = path.getPointAt((t + 0.05) % 1);
  camera.position.lerp(p, 0.05);
  camera.lookAt(look);
}

let last = performance.now();
function flyButton() { /* toggle here */ }

renderer.setAnimationLoop((now) => {
  const dt = (now - last) / 1000; last = now;
  particles.rotation.y += dt * 0.05;
  if (model) model.rotation.y += dt * 0.2;
  updateHighlight();
  // flyThrough(dt);   // uncomment for camera path
  controls.update();
  renderer.render(scene, camera);
});

Why it matters

Set renderer.outputColorSpace = THREE.SRGBColorSpace and renderer.toneMapping = ACESFilmicToneMapping at startup. They make every material, light, and texture in three.js look correct out of the box; without them, lighting looks washed-out and exported PBR materials never look right.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Animated cube, model loader, GUI controls — see lesson body.
Try it Yourself »

Discussion

Loading…