belajarkoding Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.
© 2026 BelajarKoding. All rights reserved.
Bagian dari ekosistem Galih Pratama
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.
JavaScript 9 min read 1.793 kata
Silakan
login atau
daftar untuk membaca cheat sheet ini.
Baca Cheat Sheet Lengkap Login atau daftar akun gratis untuk membaca cheat sheet ini.
Three.js Cheat Sheet - BelajarKoding | BelajarKoding
# Instalasi
# npm
npm install three
# Import maps (browser, tanpa bundler)
# Pakai type="importmap" di 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
import * as THREE from 'three' ;
// 1. Scene
const scene
# Geometry
# Primitive Geometries
// Box
const box = new THREE . BoxGeometry ( 1 , 1 , 1 ); // width, height, depth
const box2
# Common Attributes
// Modify geometry attributes
const geo = new THREE . SphereGeometry ( 1 , 32 , 32 );
// Get position attribute
const positions = geo.attributes.position;
for ( let i
# Materials
# Material Types
// Basic (unlit, flat color)
const basicMat = new THREE . MeshBasicMaterial
# Lights
# Light Types
// Ambient (global illumination)
const ambient = new THREE . AmbientLight ( 0xffffff
# Mesh dan Groups
// Create mesh (geometry + material)
const mesh = new THREE . Mesh (geometry, material);
mesh.position. set ( 0 , 1 , 0 ); // x, y, z
# Cameras
# Perspective Camera
const camera = new THREE . PerspectiveCamera ( 45 , aspect, 0.1 , 1000 );
camera.position. set ( 0 , 10 , 20 );
camera. lookAt ( 0 , 0 ,
# Orthographic Camera
const aspect = window.innerWidth / window.innerHeight;
const frustumSize = 10 ;
const camera = new THREE . OrthographicCamera (
- frustumSize * aspect / 2 ,
# 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.minDistance
# Other Controls
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'
# Animation
# Basic Animation
const clock = new THREE . Clock ();
function animate () {
requestAnimationFrame (animate);
const elapsed = clock. getElapsedTime ();
const delta = clock.
# AnimationMixer (Keyframe/Imported)
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' ;
const loader = new GLTFLoader ();
loader. load ( 'model.glb' , ( gltf ) =>
# Loaders
# GLTF/GLB Loader
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' ;
const loader = new GLTFLoader ();
loader. load (
'model.glb' ,
( gltf ) => {
const model
# Texture Loader
const textureLoader = new THREE . TextureLoader ();
// Single texture
textureLoader. load ( 'diffuse.jpg' , ( texture ) => {
texture.colorSpace = THREE .SRGBColorSpace;
# Raycasting
const raycaster = new THREE . Raycaster ();
const mouse = new THREE . Vector2 ();
window. addEventListener (
# Post-Processing
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
# Performance Tips
// 1. Use InstancedMesh untuk banyak object identik
const instanced = new THREE . InstancedMesh (geometry, material, 1000 );
const dummy = new
# 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).
=
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);
});
=
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 ();
=
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 ();
({
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
});
,
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.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);
0
);
// FOV zoom
camera.fov = 30 ;
camera. updateProjectionMatrix ();
// left
frustumSize * aspect / 2 , // right
frustumSize / 2 , // top
- frustumSize / 2 , // bottom
0.1 , // near
1000 // far
);
=
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);
}
;
// 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'
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 ();
{
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);
}
=
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);
}
);
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' );
'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
);
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 ();
}
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 ();