threejs-syntax-geometries
Quick Reference
BufferGeometry: Core Properties
| Property |
Type |
Default |
Description |
attributes |
Object |
{} |
Hash map of named BufferAttribute instances |
index |
BufferAttribute | null |
null |
Index buffer for indexed rendering |
morphAttributes |
Object |
{} |
Morph target attribute arrays |
morphTargetsRelative |
Boolean |
false |
If true, morph data = relative offsets |
groups |
Array |
[] |
{ start, count, materialIndex } for multi-material |
drawRange |
Object |
{ start: 0, count: Infinity } |
Portion of geometry to render |
boundingBox |
Box3 | null |
null |
Cached — null until computeBoundingBox() |
boundingSphere |
Sphere | null |
null |
Cached — null until computeBoundingSphere() |
BufferGeometry: Key Methods
| Method |
Returns |
Description |
setAttribute(name, attr) |
this |
Add or replace a named attribute |
getAttribute(name) |
BufferAttribute |
Retrieve attribute by name |
deleteAttribute(name) |
this |
Remove a named attribute |
hasAttribute(name) |
boolean |
Check if attribute exists |
setIndex(attr) |
— |
Set the index buffer |
addGroup(start, count, materialIndex?) |
— |
Define a render group for multi-material |
clearGroups() |
— |
Remove all groups |
setDrawRange(start, count) |
— |
Limit rendered range |
computeVertexNormals() |
— |
Compute smooth normals from face topology |
computeTangents() |
— |
Compute tangent vectors (requires position, normal, uv, index) |
computeBoundingBox() |
— |
Compute and cache AABB |
computeBoundingSphere() |
— |
Compute and cache bounding sphere |
toNonIndexed() |
new geometry |
Create non-indexed copy with duplicated vertices |
translate(x, y, z) |
this |
Translate vertex positions in-place |
rotateX/Y/Z(radians) |
this |
Rotate vertex positions in-place |
scale(x, y, z) |
this |
Scale vertex positions in-place |
center() |
this |
Center geometry at the origin |
dispose() |
— |
Free GPU resources |
BufferAttribute: Constructor and Properties
import * as THREE from 'three';
new THREE.BufferAttribute(array: TypedArray, itemSize: number, normalized?: boolean)
| Property |
Type |
Default |
Description |
array |
TypedArray |
— |
The underlying data |
itemSize |
number |
— |
Values per vertex (1=scalar, 2=UV, 3=position, 4=RGBA) |
count |
number |
computed |
array.length / itemSize |
needsUpdate |
boolean |
false |
Set true to upload changes to GPU |
usage |
number |
StaticDrawUsage |
GPU usage hint |
Typed Convenience Classes
| Class |
Underlying Type |
Use Case |
Float32BufferAttribute |
Float32Array |
Positions, normals, UVs (most common) |
Float16BufferAttribute |
Float16Array |
Memory-optimized attributes |
Uint16BufferAttribute |
Uint16Array |
Index buffers (<65536 vertices) |
Uint32BufferAttribute |
Uint32Array |
Index buffers (>65536 vertices) |
Uint8BufferAttribute |
Uint8Array |
Byte colors (with normalized=true) |
Int8/Int16/Int32BufferAttribute |
Respective arrays |
Signed integer data |
Usage Hints
| Constant |
When to Use |
THREE.StaticDrawUsage |
Data uploaded once, read many times (default) |
THREE.DynamicDrawUsage |
Data updated frequently (particles, animated verts) |
THREE.StreamDrawUsage |
Data updated every frame and read once |
Critical Warnings
NEVER forget attribute.needsUpdate = true after modifying BufferAttribute data via setX/setXY/setXYZ or direct array writes. Without this flag, changes will NOT reach the GPU.
NEVER assume boundingBox or boundingSphere are populated automatically. They are null until you explicitly call computeBoundingBox() / computeBoundingSphere().
ALWAYS call computeVertexNormals() after building custom geometry if you need lighting. Without normals, MeshStandardMaterial and other lit materials render black.
ALWAYS call geometry.dispose() when removing geometry from the scene permanently. Failing to dispose leaks GPU memory. The garbage collector does NOT free GPU-side buffers.
NEVER call translate(), rotateX(), scale(), or other in-place transform methods in an animation loop. These modify the actual vertex data permanently. Use mesh.position, mesh.rotation, and mesh.scale for runtime transforms.
ALWAYS set usage to DynamicDrawUsage BEFORE the first render if you plan to update attribute data every frame. Changing usage after initial upload has no effect on some GPU drivers.
NEVER forget instanceMatrix.needsUpdate = true after calling setMatrixAt() on InstancedMesh. Without this flag, all instances render at the origin.
Indexed vs Non-Indexed Geometry
| Aspect |
Indexed |
Non-Indexed |
| Memory |
Lower (shared vertices) |
Higher (duplicated vertices) |
| GPU cache |
Better (vertex reuse) |
No reuse |
| Flat shading |
Requires duplicated normals |
Natural per-face normals |
| Wireframe |
Clean edges |
May show diagonal lines |
ALWAYS use indexed geometry for smooth-shaded meshes with shared vertices. Use geometry.toNonIndexed() ONLY when you need per-face attributes (flat shading with unique normals).
All 21 Built-in Geometries
Primitives
| Geometry |
Key Parameters |
BoxGeometry |
(width=1, height=1, depth=1, wSeg=1, hSeg=1, dSeg=1) |
SphereGeometry |
(radius=1, wSeg=32, hSeg=16, phiStart, phiLen, thetaStart, thetaLen) |
PlaneGeometry |
(width=1, height=1, wSeg=1, hSeg=1) |
CylinderGeometry |
(radTop=1, radBot=1, height=1, radSeg=32, hSeg=1, open, thetaStart, thetaLen) |
ConeGeometry |
(radius=1, height=1, radSeg=32, hSeg=1, open, thetaStart, thetaLen) |
CapsuleGeometry |
(radius=1, length=1, capSeg=4, radSeg=8) |
TorusGeometry |
(radius=1, tube=0.4, radSeg=12, tubSeg=48, arc=2PI) |
TorusKnotGeometry |
(radius=1, tube=0.4, tubSeg=64, radSeg=8, p=2, q=3) |
CircleGeometry |
(radius=1, seg=32, thetaStart=0, thetaLen=2PI) |
RingGeometry |
(inner=0.5, outer=1, thetaSeg=32, phiSeg=1, thetaStart, thetaLen) |
Polyhedra
All accept (radius=1, detail=0). Detail controls subdivision level.
| Geometry |
Base Faces |
TetrahedronGeometry |
4 |
OctahedronGeometry |
8 |
DodecahedronGeometry |
12 |
IcosahedronGeometry |
20 |
PolyhedronGeometry |
custom (vertices, indices, radius, detail) |
Path-Based
| Geometry |
Description |
ExtrudeGeometry(shapes, options) |
Extrude 2D Shape into 3D |
ShapeGeometry(shapes, curveSegments=12) |
Flat 2D geometry from Shape |
LatheGeometry(points, segments=12, phiStart, phiLength) |
Revolve 2D profile around Y axis |
TubeGeometry(path, tubSeg=64, radius=1, radSeg=8, closed) |
Tube along a Curve3 |
Utility
| Geometry |
Description |
EdgesGeometry(geometry, thresholdAngle=1) |
Edges where angle > threshold (clean outlines) |
WireframeGeometry(geometry) |
ALL triangle edges (debug visualization) |
ExtrudeGeometry Options
| Option |
Type |
Default |
Description |
depth |
number |
1 |
Extrusion depth |
steps |
number |
1 |
Subdivision steps along depth |
bevelEnabled |
boolean |
true |
Enable beveled edges |
bevelThickness |
number |
0.2 |
Bevel depth into shape |
bevelSize |
number |
bevelThickness - 0.1 |
Bevel distance from outline |
bevelOffset |
number |
0 |
Bevel offset from edge |
bevelSegments |
number |
3 |
Bevel resolution |
curveSegments |
number |
12 |
Points on curves |
extrudePath |
Curve |
undefined |
3D path to extrude along |
UVGenerator |
Object |
WorldUVGenerator |
Custom UV generation |
Shape Class: 2D Path Drawing
import * as THREE from 'three';
const shape = new THREE.Shape();
shape.moveTo(x, y);
shape.lineTo(x, y);
shape.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
shape.quadraticCurveTo(cpx, cpy, x, y);
shape.splineThru(points);
shape.arc(aX, aY, radius, startAngle, endAngle, cw);
shape.absarc(aX, aY, radius, startAngle, endAngle, cw);
const holePath = new THREE.Path();
holePath.absarc(0, 0, 0.5, 0, Math.PI * 2);
shape.holes.push(holePath);
Morph Targets
import * as THREE from 'three';
const morphPositions = new Float32Array([]);
geometry.morphAttributes.position = [
new THREE.BufferAttribute(morphPositions, 3)
];
mesh.morphTargetInfluences[0] = 0.5;
mesh.morphTargetDictionary;
Set geometry.morphTargetsRelative = true when morph data represents offsets rather than absolute positions.
InstancedMesh
import * as THREE from 'three';
const mesh = new THREE.InstancedMesh(geometry, material, count);
| Property |
Type |
Description |
instanceMatrix |
InstancedBufferAttribute |
4x4 matrices (16 floats per instance) |
instanceColor |
InstancedBufferAttribute | null |
Per-instance RGB (created on first setColorAt) |
count |
number |
Instance count (read-only after construction) |
| Method |
Description |
setMatrixAt(index, matrix4) |
Set transform for instance |
getMatrixAt(index, matrix4) |
Read transform into target |
setColorAt(index, color) |
Set per-instance color |
getColorAt(index, color) |
Read per-instance color |
Performance Guidelines
| Instance Count |
Recommendation |
| < 10 |
Use individual Mesh objects |
| 10 - 100 |
Either approach; profile your case |
| 100 - 10,000 |
ALWAYS use InstancedMesh |
| > 10,000 |
Use InstancedMesh with spatial subdivision or BatchedMesh (r160+) |
Custom Per-Instance Attributes
import * as THREE from 'three';
const phases = new Float32Array(count);
for (let i = 0; i < count; i++) phases[i] = Math.random();
mesh.geometry.setAttribute('aPhase', new THREE.InstancedBufferAttribute(phases, 1));
Multi-Material with Groups
import * as THREE from 'three';
geometry.addGroup(0, 6, 0);
geometry.addGroup(6, 6, 1);
const mesh = new THREE.Mesh(geometry, [materialA, materialB]);
InterleavedBuffer
For optimal GPU cache performance on large meshes (10,000+ vertices):
import * as THREE from 'three';
const stride = 8;
const buffer = new THREE.InterleavedBuffer(new Float32Array(vertexCount * stride), stride);
geometry.setAttribute('position', new THREE.InterleavedBufferAttribute(buffer, 3, 0));
geometry.setAttribute('normal', new THREE.InterleavedBufferAttribute(buffer, 3, 3));
geometry.setAttribute('uv', new THREE.InterleavedBufferAttribute(buffer, 2, 6));
ALWAYS use separate buffers when individual attributes are updated independently. Use interleaved buffers ONLY when all attributes are static or updated together.
Disposal Rules
- ALWAYS call
geometry.dispose() when removing geometry from the scene permanently
- Shared geometries (used by multiple meshes): dispose ONLY after ALL meshes are removed
- Built-in geometries: dispose when the mesh using them is removed
- The JavaScript garbage collector does NOT free GPU-side vertex buffers
Reference Links
Official Sources