| name | threejs-geometry |
| allowed-tools | Read, Glob |
| description | Three.js geometry creation - built-in shapes, BufferGeometry, custom geometry, instancing. Use when creating 3D shapes, working with vertices, building custom meshes, or optimizing with instanced rendering. |
Three.js Geometry
Iron Law
Never mutate BufferGeometry attributes without setting needsUpdate = true on the BufferAttribute — stale GPU buffers will silently render the old mesh.
Quick Start
import * as THREE from "three";
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(box, material);
scene.add(mesh);
Built-in Geometries
Basic Shapes
new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
new THREE.SphereGeometry(1, 32, 32);
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI);
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI);
new THREE.PlaneGeometry(10, 10, 1, 1);
new THREE.CircleGeometry(1, 32);
new THREE.CircleGeometry(1, 32, 0, Math.PI);
new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
new THREE.CylinderGeometry(0, 1, 2, 32);
new THREE.CylinderGeometry(1, 1, 2, 6);
new THREE.ConeGeometry(1, 2, 32, 1, false);
new THREE.TorusGeometry(1, 0.4, 16, 100);
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);
new THREE.RingGeometry(0.5, 1, 32, 1);
Advanced Shapes
new THREE.CapsuleGeometry(0.5, 1, 4, 8);
new THREE.DodecahedronGeometry(1, 0);
new THREE.IcosahedronGeometry(1, 0);
new THREE.OctahedronGeometry(1, 0);
new THREE.TetrahedronGeometry(1, 0);
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
new THREE.PolyhedronGeometry(vertices, indices, 1, 0);
Path-Based Shapes
const points = [
new THREE.Vector2(0, 0),
new THREE.Vector2(0.5, 0),
new THREE.Vector2(0.5, 1),
new THREE.Vector2(0, 1),
];
new THREE.LatheGeometry(points, 32);
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(1, 0);
shape.lineTo(1, 1);
shape.lineTo(0, 1);
shape.lineTo(0, 0);
const extrudeSettings = {
steps: 2,
depth: 1,
bevelEnabled: true,
bevelThickness: 0.1,
bevelSize: 0.1,
bevelSegments: 3,
};
new THREE.ExtrudeGeometry(shape, extrudeSettings);
const curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0),
]);
new THREE.TubeGeometry(curve, 64, 0.2, 8, false);
Text Geometry
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
const loader = new FontLoader();
loader.load("fonts/helvetiker_regular.typeface.json", (font) => {
const geometry = new TextGeometry("Hello", {
font: font,
size: 1,
depth: 0.2,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelSegments: 5,
});
geometry.computeBoundingBox();
geometry.center();
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});
BufferGeometry
The base class for all geometries. Stores data as typed arrays for GPU efficiency.
Custom BufferGeometry
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1,
-1,
0,
1,
-1,
0,
1,
1,
0,
-1,
1,
0,
]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([
0,
1,
2,
0,
2,
3,
]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
const colors = new Float32Array([
1,
0,
0,
0,
1,
0,
0,
0,
1,
1,
1,
0,
]);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
Modifying BufferGeometry
const positions = geometry.attributes.position;
positions.setXYZ(index, x, y, z);
const x = positions.getX(index);
const y = positions.getY(index);
const z = positions.getZ(index);
positions.needsUpdate = true;
geometry.computeVertexNormals();
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
EdgesGeometry & WireframeGeometry
const edges = new THREE.EdgesGeometry(boxGeometry, 15);
const edgeMesh = new THREE.LineSegments(
edges,
new THREE.LineBasicMaterial({ color: 0xffffff }),
);
const wireframe = new THREE.WireframeGeometry(boxGeometry);
const wireMesh = new THREE.LineSegments(
wireframe,
new THREE.LineBasicMaterial({ color: 0xffffff }),
);
Points
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(1000 * 3);
for (let i = 0; i < 1000; i++) {
positions[i * 3] = (Math.random() - 0.5) * 10;
positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
}
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
const material = new THREE.PointsMaterial({
size: 0.1,
sizeAttenuation: true,
color: 0xffffff,
});
const points = new THREE.Points(geometry, material);
scene.add(points);
Lines
const points = [
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0),
];
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const line = new THREE.Line(
geometry,
new THREE.LineBasicMaterial({ color: 0xff0000 }),
);
const loop = new THREE.LineLoop(geometry, material);
const segmentsGeometry = new THREE.BufferGeometry();
segmentsGeometry.setAttribute(
"position",
new THREE.BufferAttribute(
new Float32Array([
-1,
0,
0,
0,
1,
0,
0,
1,
0,
1,
0,
0,
]),
3,
),
);
const segments = new THREE.LineSegments(segmentsGeometry, material);
InstancedMesh
Efficiently render many copies of the same geometry.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
const matrix = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
);
dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
dummy.scale.setScalar(0.5 + Math.random());
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;
instancedMesh.instanceColor = new THREE.InstancedBufferAttribute(
new Float32Array(count * 3),
3,
);
for (let i = 0; i < count; i++) {
instancedMesh.setColorAt(
i,
new THREE.Color(Math.random(), Math.random(), Math.random()),
);
}
instancedMesh.instanceColor.needsUpdate = true;
scene.add(instancedMesh);
Update Instance at Runtime
const matrix = new THREE.Matrix4();
instancedMesh.getMatrixAt(index, matrix);
instancedMesh.setMatrixAt(index, matrix);
instancedMesh.instanceMatrix.needsUpdate = true;
const intersects = raycaster.intersectObject(instancedMesh);
if (intersects.length > 0) {
const instanceId = intersects[0].instanceId;
}
Common Patterns
Center Geometry
geometry.computeBoundingBox();
geometry.center();
Scale to Fit
geometry.computeBoundingBox();
const size = new THREE.Vector3();
geometry.boundingBox.getSize(size);
const maxDim = Math.max(size.x, size.y, size.z);
geometry.scale(1 / maxDim, 1 / maxDim, 1 / maxDim);
Clone and Transform
const clone = geometry.clone();
clone.rotateX(Math.PI / 2);
clone.translate(0, 1, 0);
clone.scale(2, 2, 2);
References
references/advanced-patterns.md — Interleaved buffers, InstancedBufferGeometry, morph targets, BufferAttribute type guide, geometry utilities, and performance optimization detail
See Also
threejs-fundamentals - Scene setup and Object3D
threejs-materials - Material types for meshes
threejs-shaders - Custom vertex manipulation