threejs-fundamentals
Three.js scene setup guidance for cameras, renderer configuration, object hierarchy, and transforms.
Install
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-fundamentalsThree.js Fundamentals
Targets three.js r186. Examples use WebGLRenderer; the WebGPU and TSL section uses WebGPURenderer.
Quick Start
Without a bundler, the browser loads three.js as ES modules through an import map; this is the map for the WebGLRenderer examples above:
For WebGPURenderer work, map all four keys — three.tsl.js imports three/webgpu, so the map fails without that entry:
Scene
scene.backgroundalso accepts aCubeTexture, or aTexturewhosemappingisTHREE.EquirectangularReflectionMapping; a plain unmapped texture is drawn as a flat screen-filling quad, not a skybox.scene.environmentlightsMeshStandardMaterialandMeshPhysicalMaterialon both renderers, andMeshLambertMaterialandMeshPhongMaterialon WebGLRenderer only.scene.environmentIntensityscales it —material.envMapIntensityscales onlymaterial.envMap. See threejs-loaders for HDR environments.
Cameras
PerspectiveCamera
OrthographicCamera
ArrayCamera
CubeCamera
With WebGPURenderer, build the target with CubeRenderTarget from three/webgpu instead of WebGLCubeRenderTarget.
WebGLRenderer
Objects
Object3D
Base class of Mesh, Group, Light and Camera.
Group and Mesh
Coordinate System
Right-handed, +Y up: +X right, +Y up, +Z toward the viewer. A camera at the origin with no rotation looks down −Z.
Math Utilities
Vector3
Matrix4, Quaternion, Euler
Color
MathUtils
Loading Manager
Cleanup
Object3D.dispose() releases per-object renderer state (WebGPURenderer bindings, WebGLRenderer instanced-mesh buffers); it does not visit children or free geometry, material or textures. To tear down a subtree, traverse it and dispose each mesh as above. A custom Object3D subclass that overrides dispose() calls super.dispose(). timer.dispose() disconnects a connected timer.
Performance
- Frustum culling tests a bounding sphere, not the bounding box:
geometry.boundingSpherefor a plain mesh, the object's ownboundingSpherefor InstancedMesh, SkinnedMesh and BatchedMesh. Both are computed once, so after editing positions callgeometry.computeBoundingSphere(), and after moving instances or bones far from where they started callobject.computeBoundingSphere(), or visible objects get culled. - Merge static geometry that shares a material into one mesh, and use
InstancedMeshfor many copies of one object (threejs-geometry). - Switch meshes by distance with
LOD; the renderer callsupdate(camera)for you each frame. - On WebGLRenderer,
renderer.info.render.callscounts the draw calls of the lastrender()call (with several passes per frame, setrenderer.info.autoReset = falseand callrenderer.info.reset()once per frame), andrenderer.info.memorythe live geometries and textures; check them after merging meshes or disposing objects.
WebGPU and TSL
renderer.render()throws untilawait renderer.init()has completed.setAnimationLoopwould run the init too, but awaitinit()right after construction, before setup code touches the renderer: the WebGL 2 fallback replacesrenderer.backendduringinit().- WebGPURenderer falls back to WebGL 2 by itself when WebGPU is unavailable;
new THREE.WebGPURenderer({ forceWebGL: true })forces the fallback, and afterawait renderer.init(),renderer.backend.isWebGPUBackendreports which backend runs. - Node materials and TSL target WebGPURenderer (either backend). WebGLRenderer renders them only through the
WebGLNodesHandleraddon (three/addons/tsl/WebGLNodesHandler.js, passed torenderer.setNodesHandler()), a migration aid without VSM shadows, MRT, transmission or the WebGPU post-processing stack. ShaderMaterial andonBeforeCompileare WebGLRenderer-only. Custom shading starts in threejs-shaders. - Built-in materials such as
MeshStandardMaterialare converted to their node versions automatically; use the*NodeMaterialclasses when you set node slots. - There is no
renderer.capabilitiesobject here: anisotropy comes fromrenderer.getMaxAnisotropy(). - GPU readback stays asynchronous:
await renderer.getArrayBufferAsync(attribute).
Common Mistakes
renderer.shadowMap.type = THREE.PCFSoftShadowMap→renderer.shadowMap.type = THREE.PCFShadowMap: deprecated in r182; both renderers now warn and fall back to PCFShadowMap, which is already soft.const clock = new THREE.Clock()→const timer = new THREE.Timer(); timer.connect(document);: Clock is deprecated in r183 and warns on construction; calltimer.update()once per frame beforetimer.getDelta()ortimer.getElapsed().requestAnimationFrame(animate)→renderer.setAnimationLoop(animate): both renderers' docs advise it over a manual loop, WebXR frames run only through it, and on WebGPURendererrender()throws before the async init thatsetAnimationLoopperforms.subCamera.viewport = new THREE.Vector4(0, 0, 0.5, 0.5)→subCamera.viewport = new THREE.Vector4(x * dpr, y * dpr, width * dpr, height * dpr): ArrayCamera viewports are drawing-buffer pixels under WebGLRenderer (WebGPURenderer scales CSS pixels by the pixel ratio itself), so fractions draw nothing.cubeCamera.update(renderer, scene)→mesh.visible = false; cubeCamera.update(renderer, scene); mesh.visible = true;: a visible reflective mesh is rendered into the very cube map its material samples.scene.background = texture→texture.mapping = THREE.EquirectangularReflectionMapping; scene.background = texture: without an equirect or cube mapping the texture draws as a flat screen-filling quad, not a skybox.import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js"→import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js": thethree/examples/jsm/specifier does not resolve under the standard import map, which mapsthree/addons/instead.<script src="three.min.js"></script>→<script type="module">import * as THREE from "three";</script>:build/three.jsandbuild/three.min.jswere removed in r161, so in the browser three.js loads as an ES module behind an import map.mesh.layers.set(1)→mesh.layers.enable(1):setreplaces the layer mask and takes the mesh off layer 0, where the default camera and lights live.renderer.outputEncoding = THREE.sRGBEncoding→renderer.outputColorSpace = THREE.SRGBColorSpace: the encoding API no longer exists, and the color-space property already defaults toSRGBColorSpace, so the assignment is usually unnecessary.renderer.physicallyCorrectLights = true→const bulb = new THREE.PointLight(0xffffff, 100): physically based light units are always on and thephysicallyCorrectLightsanduseLegacyLightsswitches no longer exist, so delete the line and give point and spot lights candela intensities that suit their distance (threejs-lighting).material.envMapIntensity = 0.5→scene.environmentIntensity = 0.5:envMapIntensityscales only the material's ownenvMap, notscene.environment.mesh.dispose()→mesh.dispose(); mesh.geometry.dispose(); for (const value of Object.values(mesh.material)) if (value?.isTexture) value.dispose(); mesh.material.dispose();: the object-level dispose frees only per-object renderer state, never the geometry, material or textures, and material.dispose() leaves the textures alone too.import { WebGLCubeRenderTarget } from "three/webgpu"→import { CubeRenderTarget } from "three/webgpu":three/webgpudoes not export WebGLCubeRenderTarget, which does not work with WebGPURenderer; keep it for WebGLRenderer.await renderer.renderAsync(scene, camera)→await renderer.init(); renderer.render(scene, camera): the async render methods are deprecated in r181; initialize once, then render synchronously in the loop.
See Also
threejs-geometry— creating and editing BufferGeometry, instancing, merging, bounding volumes.threejs-materials— choosing and configuring materials and their texture slots.threejs-textures— loading textures, color spaces, UV channels.threejs-lighting— light types, units, and shadow configuration.threejs-animation— the AnimationMixer and clip system for keyframed motion.threejs-interaction— raycasting, pointer events, and camera controls.threejs-loaders— glTF and other file loaders, async loading patterns.threejs-shaders— ShaderMaterial and GLSL on WebGLRenderer, TSL node materials on WebGPURenderer.threejs-postprocessing— EffectComposer passes and the WebGPU render pipeline.threejs-performance— measuring frame cost and cutting draw calls, memory and fill rate.threejs-react-three-fiber— the same scene graph written as React components.