mcpField
T
threejs-syntax-geometries

threejs-syntax-geometries

github.com/impertio-studioDevelopment23136 installsUpdated 30w ago
Repository

About threejs-syntax-geometries

threejs-syntax-geometries is a Three.js geometry reference for developers creating and managing mesh data. It explains BufferGeometry, attributes, built-in shapes, instancing, and resource handling.

Key features

  1. 01BufferGeometry and BufferAttribute APIs
  2. 02Built-in geometry catalog
  3. 03Custom paths and extrusion
  4. 04InstancedMesh usage
  5. 05Geometry updates and disposal

Use cases

  1. 01Creating custom meshes
  2. 02Choosing a built-in primitive
  3. 03Rendering repeated objects efficiently
  4. 04Updating vertex data safely

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/impertio-studio/three.js-claude-skill-package --skill threejs-syntax-geometries

After installing, type/threejs-syntax-geometriesin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

Details

From the project README

threejs-syntax-geometries

Quick Reference

BufferGeometry: Core Properties
PropertyTypeDefaultDescription
attributesObject{}Hash map of named BufferAttribute instances
indexBufferAttribute | nullnullIndex buffer for indexed rendering
morphAttributesObject{}Morph target attribute arrays
morphTargetsRelativeBooleanfalseIf true, morph data = relative offsets
groupsArray[]{ start, count, materialIndex } for multi-material
drawRangeObject{ start: 0, count: Infinity }Portion of geometry to render
boundingBoxBox3 | nullnullCached — null until computeBoundingBox()
boundingSphereSphere | nullnullCached — null until computeBoundingSphere()
BufferGeometry: Key Methods
MethodReturnsDescription
setAttribute(name, attr)thisAdd or replace a named attribute
getAttribute(name)BufferAttributeRetrieve attribute by name
deleteAttribute(name)thisRemove a named attribute
hasAttribute(name)booleanCheck 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 geometryCreate non-indexed copy with duplicated vertices
translate(x, y, z)thisTranslate vertex positions in-place
rotateX/Y/Z(radians)thisRotate vertex positions in-place
scale(x, y, z)thisScale vertex positions in-place
center()thisCenter 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)
PropertyTypeDefaultDescription
arrayTypedArray—The underlying data
itemSizenumber—Values per vertex (1=scalar, 2=UV, 3=position, 4=RGBA)
countnumbercomputedarray.length / itemSize
needsUpdatebooleanfalseSet true to upload changes to GPU
usagenumberStaticDrawUsageGPU usage hint
Typed Convenience Classes
ClassUnderlying TypeUse Case
Float32BufferAttributeFloat32ArrayPositions, normals, UVs (most common)
Float16BufferAttributeFloat16ArrayMemory-optimized attributes
Uint16BufferAttributeUint16ArrayIndex buffers (<65536 vertices)
Uint32BufferAttributeUint32ArrayIndex buffers (>65536 vertices)
Uint8BufferAttributeUint8ArrayByte colors (with normalized=true)
Int8/Int16/Int32BufferAttributeRespective arraysSigned integer data
Usage Hints
ConstantWhen to Use
THREE.StaticDrawUsageData uploaded once, read many times (default)
THREE.DynamicDrawUsageData updated frequently (particles, animated verts)
THREE.StreamDrawUsageData 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

AspectIndexedNon-Indexed
MemoryLower (shared vertices)Higher (duplicated vertices)
GPU cacheBetter (vertex reuse)No reuse
Flat shadingRequires duplicated normalsNatural per-face normals
WireframeClean edgesMay 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
GeometryKey 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.

GeometryBase Faces
TetrahedronGeometry4
OctahedronGeometry8
DodecahedronGeometry12
IcosahedronGeometry20
PolyhedronGeometrycustom (vertices, indices, radius, detail)
Path-Based
GeometryDescription
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
GeometryDescription
EdgesGeometry(geometry, thresholdAngle=1)Edges where angle > threshold (clean outlines)
WireframeGeometry(geometry)ALL triangle edges (debug visualization)

ExtrudeGeometry Options

OptionTypeDefaultDescription
depthnumber1Extrusion depth
stepsnumber1Subdivision steps along depth
bevelEnabledbooleantrueEnable beveled edges
bevelThicknessnumber0.2Bevel depth into shape
bevelSizenumberbevelThickness - 0.1Bevel distance from outline
bevelOffsetnumber0Bevel offset from edge
bevelSegmentsnumber3Bevel resolution
curveSegmentsnumber12Points on curves
extrudePathCurveundefined3D path to extrude along
UVGeneratorObjectWorldUVGeneratorCustom UV generation

Shape Class: 2D Path Drawing

import * as THREE from 'three';

const shape = new THREE.Shape();
shape.moveTo(x, y);                                    // Start new subpath
shape.lineTo(x, y);                                    // Straight line
shape.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);   // Cubic Bezier
shape.quadraticCurveTo(cpx, cpy, x, y);                // Quadratic Bezier
shape.splineThru(points);                               // Smooth spline through Vector2[]
shape.arc(aX, aY, radius, startAngle, endAngle, cw);   // Relative arc
shape.absarc(aX, aY, radius, startAngle, endAngle, cw); // Absolute arc

// Holes
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';

// Define morph target positions
const morphPositions = new Float32Array([/* ... */]);
geometry.morphAttributes.position = [
  new THREE.BufferAttribute(morphPositions, 3)
];

// Control on the mesh
mesh.morphTargetInfluences[0] = 0.5; // 50% blend toward morph target 0

// Named morph targets (from glTF)
mesh.morphTargetDictionary; // { "smile": 0, "frown": 1 }

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);
PropertyTypeDescription
instanceMatrixInstancedBufferAttribute4x4 matrices (16 floats per instance)
instanceColorInstancedBufferAttribute | nullPer-instance RGB (created on first setColorAt)
countnumberInstance count (read-only after construction)
MethodDescription
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 CountRecommendation
< 10Use individual Mesh objects
10 - 100Either approach; profile your case
100 - 10,000ALWAYS use InstancedMesh
> 10,000Use 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));
// Access in vertex shader: attribute float aPhase;

Multi-Material with Groups

import * as THREE from 'three';

geometry.addGroup(0, 6, 0);    // First 6 indices -> material[0]
geometry.addGroup(6, 6, 1);    // Next 6 indices  -> material[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; // 3 (position) + 3 (normal) + 2 (uv)
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

Comments

Markdown supported