BelajarKoding Logobelajarkoding

Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.

Navigasi

  • Artikel
  • Cheat Sheets
  • Roadmap
  • Challenges
  • Pricing
  • Search

Produk Lain

  • JagoHermes
  • KelasClaude
  • KilatKoding
  • BelajarVibeCoding
  • JualanKoding

Support

  • Privacy Policy
  • Terms of Service
  • Email

© 2026 BelajarKoding. All rights reserved.

Galih PratamaBagian dari ekosistem Galih Pratama
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade

Daftar Isi

InstalasiScene SetupBasic SceneGeometryPrimitive GeometriesCommon AttributesMaterialsMaterial TypesLightsLight TypesMesh dan GroupsCamerasPerspective CameraOrthographic CameraControlsOrbitControlsOther ControlsAnimationBasic AnimationAnimationMixer (Keyframe/Imported)LoadersGLTF/GLB LoaderTexture LoaderRaycastingPost-ProcessingPerformance TipsGlossary
Three.js3DWebGLJavaScript

Three.js Cheat Sheet

Referensi cepat Three.js untuk 3D web graphics. Scene, camera, renderer, geometry, materials, lights, animation, dan controls. Perfect buat developer yang bangun 3D visual di browser.

JavaScript9 min read1.793 kata
Silakan login atau daftar untuk membaca cheat sheet ini.

#Instalasi

bash
# npm
npm install three
 
# Import maps (browser, tanpa bundler)
# Pakai type="importmap" di HTML
html
<script type="importmap">
{
  "imports": {
    "three": "https://unpkg.com/three@0.170.0/build/three.module.js",
    "three/addons/": "https://unpkg.com/three@0.170.0/examples/jsm/"
  }
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
</script>

#Scene Setup

#Basic Scene

javascript
import * as THREE from 'three';
 
// 1. Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
scene.fog = new THREE.Fog(0x1a1a2e, 10, 50);
 
// 2. Camera
const camera = new THREE.PerspectiveCamera(
  75,                                    // FOV (degrees)
  window.innerWidth / window.innerHeight, // aspect ratio
  0.1,                                    // near clipping plane
  1000                                    // far clipping plane
);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);
 
// 3. Renderer
const renderer = new THREE.WebGLRenderer({
  antialias: true,
  alpha: true,                    // transparent background
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;
document.body.appendChild(renderer.domElement);
 
// 4. Animation loop
function animate() {
  requestAnimationFrame(animate);
  // Update objects here
  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();
 
// 5. Handle resize
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

#Geometry

#Primitive Geometries

javascript
// Box
const box = new THREE.BoxGeometry(1, 1, 1);           // width, height, depth
const box2 = new THREE.BoxGeometry(2, 2, 2, 4, 4, 4); // segmented
 
// Sphere
const sphere = new THREE.SphereGeometry(1, 32, 32);    // radius, widthSeg, heightSeg
 
// Plane
const plane = new THREE.PlaneGeometry(10, 10, 10, 10);
 
// Cylinder
const cylinder = new THREE.CylinderGeometry(1, 1, 2, 32); // topR, botR, height, seg
 
// Cone
const cone = new THREE.ConeGeometry(1, 2, 32);
 
// Torus (donut)
const torus = new THREE.TorusGeometry(1, 0.3, 16, 100); // radius, tube, radialSeg, tubularSeg
 
// Ring
const ring = new THREE.RingGeometry(1, 2, 32);
 
// Buffer Geometry (custom)
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -1, -1,  0,   // vertex 1
   1, -1,  0,   // vertex 2
   0,  1,  0,   // vertex 3
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.computeVertexNormals();

#Common Attributes

javascript
// Modify geometry attributes
const geo = new THREE.SphereGeometry(1, 32, 32);
 
// Get position attribute
const positions = geo.attributes.position;
for (let i = 0; i < positions.count; i++) {
  const x = positions.getX(i);
  const y = positions.getY(i);
  const z = positions.getZ(i);
  // Modify vertex
  positions.setZ(i, z + Math.sin(x * 5) * 0.1);
}
positions.needsUpdate = true;
geo.computeVertexNormals();

#Materials

#Material Types

javascript
// Basic (unlit, flat color)
const basicMat = new THREE.MeshBasicMaterial({
  color: 0x44aa44,
  wireframe: false,
  transparent: true,
  opacity: 0.8,
});
 
// Lambert (diffuse, no specular)
const lambertMat = new THREE.MeshLambertMaterial({
  color: 0xff0000,
  emissive: 0x110000,
});
 
// Phong (specular highlights)
const phongMat = new THREE.MeshPhongMaterial({
  color: 0x00ff00,
  specular: 0xffffff,
  shininess: 100,
  flatShading: false,
});
 
// Standard (PBR: metalness + roughness)
const stdMat = new THREE.MeshStandardMaterial({
  color: 0x2194ce,
  metalness: 0.7,        // 0 = dielectric, 1 = metal
  roughness: 0.3,        // 0 = mirror, 1 = fully diffuse
  envMapIntensity: 1.0,
});
 
// Physical (advanced PBR)
const physMat = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0.5,
  roughness: 0.2,
  clearcoat: 1.0,         // glossy coating
  clearcoatRoughness: 0.1,
  transmission: 0.9,      // glass-like
  thickness: 0.5,
  ior: 1.5,               // index of refraction
});
 
// Normal (show normals as colors, debug)
const normalMat = new THREE.MeshNormalMaterial();
 
// Texture material
const texture = new THREE.TextureLoader().load('texture.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
 
const texMat = new THREE.MeshStandardMaterial({
  map: texture,               // diffuse color map
  normalMap: normalTexture,    // surface detail
  roughnessMap: roughTexture,  // surface roughness
  metalnessMap: metalTexture,  // metallic areas
});

#Lights

#Light Types

javascript
// Ambient (global illumination)
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
 
// Directional (sun-like, parallel rays)
const directional = new THREE.DirectionalLight(0xffffff, 1.0);
directional.position.set(5, 10, 5);
directional.castShadow = true;
directional.shadow.mapSize.width = 2048;
directional.shadow.mapSize.height = 2048;
directional.shadow.camera.near = 0.5;
directional.shadow.camera.far = 50;
directional.shadow.camera.left = -10;
directional.shadow.camera.right = 10;
directional.shadow.camera.top = 10;
directional.shadow.camera.bottom = -10;
scene.add(directional);
 
// Point (omnidirectional, like a bulb)
const point = new THREE.PointLight(0xff9000, 1.0, 10, 2); // color, intensity, distance, decay
point.position.set(0, 3, 0);
point.castShadow = true;
scene.add(point);
 
// Spot (cone of light)
const spot = new THREE.SpotLight(0xffffff, 1.0, 20, Math.PI / 6, 0.5, 1);
spot.position.set(0, 10, 0);
spot.target.position.set(0, 0, 0);
scene.add(spot);
scene.add(spot.target);
 
// Hemisphere (sky + ground)
const hemi = new THREE.HemisphereLight(0x87ceeb, 0x36290e, 0.6); // skyColor, groundColor
scene.add(hemi);
 
// RectArea (flat panel light)
import { RectAreaLightUniformsLib } from 'three/addons/lights/RectAreaLightUniformsLib.js';
RectAreaLightUniformsLib.init();
const rect = new THREE.RectAreaLight(0xffffff, 5, 4, 2); // color, intensity, width, height
rect.position.set(0, 5, 0);
rect.lookAt(0, 0, 0);
scene.add(rect);

#Mesh dan Groups

javascript
// Create mesh (geometry + material)
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 1, 0);         // x, y, z
mesh.rotation.set(0, Math.PI / 4, 0); // Euler angles
mesh.scale.set(1, 1, 1);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
 
// Group multiple objects
const group = new THREE.Group();
const cube = new THREE.Mesh(boxGeo, mat);
cube.position.x = -2;
const sphere = new THREE.Mesh(sphereGeo, mat);
sphere.position.x = 2;
group.add(cube, sphere);
group.position.y = 1;
scene.add(group);
 
// Clone mesh
const mesh2 = mesh.clone();
mesh2.position.x = 3;
 
// Traverse scene
scene.traverse((obj) => {
  if (obj.isMesh) {
    obj.rotation.x += 0.01;
  }
});
 
// Dispose (memory management)
mesh.geometry.dispose();
mesh.material.dispose();
scene.remove(mesh);

#Cameras

#Perspective Camera

javascript
const camera = new THREE.PerspectiveCamera(45, aspect, 0.1, 1000);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
 
// FOV zoom
camera.fov = 30;
camera.updateProjectionMatrix();

#Orthographic Camera

javascript
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
);

#Controls

#OrbitControls

javascript
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 5;
controls.maxDistance = 50;
controls.maxPolarAngle = Math.PI / 2;  // prevent below ground
controls.autoRotate = true;
controls.autoRotateSpeed = 1.0;
controls.target.set(0, 1, 0);
 
// Must update in animation loop when damping is enabled
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

#Other Controls

javascript
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
import { FlyControls } from 'three/addons/controls/FlyControls.js';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';
 
// TransformControls (gizmo for editing)
const transformControl = new TransformControls(camera, renderer.domElement);
transformControl.addEventListener('dragging-changed', (e) => {
  orbitControls.enabled = !e.value;
});
scene.add(transformControl);
transformControl.attach(mesh);
 
// Switch modes
transformControl.setMode('translate'); // 'translate' | 'rotate' | 'scale'

#Animation

#Basic Animation

javascript
const clock = new THREE.Clock();
 
function animate() {
  requestAnimationFrame(animate);
  const elapsed = clock.getElapsedTime();
  const delta = clock.getDelta();
 
  // Rotate
  mesh.rotation.y += delta * 0.5;
 
  // Bounce
  mesh.position.y = Math.sin(elapsed * 2) * 0.5 + 1;
 
  // Scale pulse
  const scale = 1 + Math.sin(elapsed * 3) * 0.1;
  mesh.scale.set(scale, scale, scale);
 
  controls.update();
  renderer.render(scene, camera);
}
animate();

#AnimationMixer (Keyframe/Imported)

javascript
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
 
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
  const model = gltf.scene;
  scene.add(model);
 
  // Play animation
  const mixer = new THREE.AnimationMixer(model);
  const clips = gltf.animations;
 
  // Play first clip
  const action = mixer.clipAction(clips[0]);
  action.play();
 
  // Play specific clip by name
  const walk = mixer.clipAction(THREE.AnimationClip.findByName(clips, 'Walk'));
  walk.play();
 
  // Store mixer for update
  animMixers.push(mixer);
});
 
// Update in animation loop
const clock = new THREE.Clock();
function animate() {
  const delta = clock.getDelta();
  animMixers.forEach(mixer => mixer.update(delta));
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

#Loaders

#GLTF/GLB Loader

javascript
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
 
const loader = new GLTFLoader();
loader.load(
  'model.glb',
  (gltf) => {
    const model = gltf.scene;
    model.position.set(0, 0, 0);
    model.scale.set(1, 1, 1);
    scene.add(model);
  },
  (progress) => {
    console.log(`Loaded: ${(progress.loaded / progress.total * 100).toFixed(0)}%`);
  },
  (error) => {
    console.error('Load error:', error);
  }
);

#Texture Loader

javascript
const textureLoader = new THREE.TextureLoader();
 
// Single texture
textureLoader.load('diffuse.jpg', (texture) => {
  texture.colorSpace = THREE.SRGBColorSpace;
  material.map = texture;
  material.needsUpdate = true;
});
 
// Load manager (track multiple)
const manager = new THREE.LoadingManager();
manager.onLoad = () => console.log('All loaded');
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);
manager.onError = (url) => console.error('Error:', url);
 
const loader = new THREE.TextureLoader(manager);
loader.load('tex1.jpg');
loader.load('tex2.jpg');

#Raycasting

javascript
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
 
window.addEventListener('click', (event) => {
  // NDC coordinates (-1 to 1)
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
 
  raycaster.setFromCamera(mouse, camera);
 
  // Check intersection with objects
  const intersects = raycaster.intersectObjects(scene.children, true);
 
  if (intersects.length > 0) {
    const hit = intersects[0];
    console.log('Hit:', hit.object.name);
    console.log('Point:', hit.point);
    console.log('Distance:', hit.distance);
    console.log('Face:', hit.face);  // { a, b, c, normal }
  }
});
 
// Ray from custom origin
raycaster.set(
  new THREE.Vector3(0, 0, 0),   // origin
  new THREE.Vector3(0, 0, -1)   // direction
);

#Post-Processing

javascript
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
 
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
 
const bloomPass = new UnrealBloomPass(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  0.8,   // strength
  0.4,   // radius
  0.85   // threshold
);
composer.addPass(bloomPass);
 
// Render with composer instead of renderer
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  composer.render();
}

#Performance Tips

javascript
// 1. Use InstancedMesh untuk banyak object identik
const instanced = new THREE.InstancedMesh(geometry, material, 1000);
const dummy = new THREE.Object3D();
for (let i = 0; i < 1000; i++) {
  dummy.position.set(
    Math.random() * 100 - 50,
    Math.random() * 100 - 50,
    Math.random() * 100 - 50,
  );
  dummy.updateMatrix();
  instanced.setMatrixAt(i, dummy.matrix);
}
scene.add(instanced);
 
// 2. Frustum culling (otomatis, tapi bisa di-disable)
mesh.frustumCulled = true;
 
// 3. Merge geometries
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
const merged = mergeGeometries([geo1, geo2, geo3]);
 
// 4. LOD (Level of Detail)
import { LOD } from 'three';
const lod = new LOD();
lod.addLevel(highDetailMesh, 0);    // visible when distance < 10
lod.addLevel(mediumDetailMesh, 10); // visible when 10-30
lod.addLevel(lowDetailMesh, 30);    // visible when > 30
scene.add(lod);
 
// 5. Pixel ratio cap
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
 
// 6. Dispose unused resources
geometry.dispose();
material.dispose();
texture.dispose();

#Glossary

  • Scene: Container untuk semua 3D objects, lights, dan cameras.
  • Mesh: 3D object yang terdiri dari geometry (shape) dan material (surface).
  • Geometry: Definisi shape (vertices, faces, normals). Contoh: box, sphere, plane.
  • Material: Surface properties (color, texture, how it reacts to light).
  • PBR: Physically Based Rendering. Pendekatan rendering yang simulasi cahaya secara fisik (MeshStandardMaterial).
  • Texture: Image yang dipetakan ke surface mesh buat detail (color, normal, roughness).
  • Raycaster: Menentukan object apa yang di-click/hover dengan menembak ray dari camera.
  • Normal: Vector arah permukaan (tegak lurus dengan face). Dipake untuk lighting calculations.
  • Shadow Map: Technique buat render shadows. Texture yang store depth dari perspective light.
  • Shader: Program GPU (GLSL/WGSL) yang proses vertices dan pixels. Vertex shader + Fragment shader.
  • AnimationMixer: Controller untuk play/stop/blend keyframe animations pada model.
  • LOD: Level of Detail. Swap ke geometry lebih simple saat object jauh dari camera buat hemat performance.
  • InstancedMesh: Render ribuan mesh identik dengan satu draw call. Sangat efisien.
  • Post-processing: Effects yang diaplikasikan setelah render (bloom, SSAO, depth of field, dll).

Baca Cheat Sheet Lengkap

Login atau daftar akun gratis untuk membaca cheat sheet ini.

LoginDaftar Gratis
Share: