Skip to main content Home Creators afovea game-dev-skills threejs-geometry
threejs-geometry Three.js geometry — BufferGeometry, 15+ built-in shapes, custom vertex/index data, InstancedMesh for many identical objects, geometry merging, EdgesGeometry, point clouds, morph targets, and InstancedBufferGeometry. Use when creating or modifying 3D geometry, optimising repeated objects, or building procedural meshes. Adapted from CloudAI-X/threejs-skills (MIT).
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/afovea/game-dev-skills --skill threejs-geometryThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository
Art Director persona for visual style, pillars, art bible, cross-discipline visual consistency, art critique, and art QA. Use when a task needs visual direction, style enforcement, or cohesion across concept, environment, character, VFX, and lighting.
Related occupations SOC
Based on SOC occupation classification
name threejs-geometry description Three.js geometry — BufferGeometry, 15+ built-in shapes, custom vertex/index data, InstancedMesh for many identical objects, geometry merging, EdgesGeometry, point clouds, morph targets, and InstancedBufferGeometry. Use when creating or modifying 3D geometry, optimising repeated objects, or building procedural meshes. Adapted from CloudAI-X/threejs-skills (MIT). license MIT compatibility Portable reference skill for agents that support markdown skills or prompt files. Works best alongside project Three.js source files and renderer.info draw-call monitoring. disable-model-invocation true metadata {"owner":"game-delivery","version":"2.0.0","language":"en-GB","category":"web-rendering","upstream_references":["https://github.com/CloudAI-X/threejs-skills (MIT — see NOTICE.md)"],"tags":["three-js","geometry","buffer-geometry","instancing","instanced-mesh","procedural","point-cloud","morph-targets"],"intents":["geometry-creation","instancing","geometry-merging","point-cloud-setup","procedural-mesh"],"output_types":["code-example","api-reference","optimisation-plan"]}
Three.js Geometry
Quick Start
import * as THREE from 'three' ;
const geometry = new THREE .BoxGeometry (1 , 1 , 1 );
const material = new THREE .MeshStandardMaterial ({ color : 0x44aa88 });
const mesh = new THREE .Mesh (geometry, material);
scene.add (mesh);
const custom = new THREE .BufferGeometry ();
const vertices = new Float32Array ([
0 , 1 , 0 ,
-1 , -1 , 0 ,
1 , -1 , 0 ,
]);
custom.setAttribute ('position' , new THREE .BufferAttribute (vertices, 3 ));
scene.add (new . (custom, material));
THREE
Mesh
Built-in Geometry Types
Primitives
new THREE .BoxGeometry (width, height, depth, widthSeg, heightSeg, depthSeg);
new THREE .BoxGeometry (1 , 1 , 1 );
new THREE .SphereGeometry (radius, widthSeg, heightSeg, phiStart, phiLength, thetaStart, thetaLength);
new THREE .SphereGeometry (0.5 , 32 , 32 );
new THREE .PlaneGeometry (width, height, widthSeg, heightSeg);
new THREE .PlaneGeometry (10 , 10 , 64 , 64 );
new THREE .CylinderGeometry (radiusTop, radiusBottom, height, radialSeg, heightSeg, openEnded);
new THREE .CylinderGeometry (0.5 , 0.5 , 2 , 32 );
new THREE .CylinderGeometry (0 , 0.5 , 1 , 32 );
new THREE .TorusGeometry (radius, tube, radialSeg, tubularSeg, arc);
new THREE .TorusGeometry (1 , 0.4 , 16 , 100 );
new THREE .TorusKnotGeometry (radius, tube, tubularSeg, radialSeg, p, q);
new THREE .TorusKnotGeometry (1 , 0.3 , 128 , 16 , 2 , 3 );
new THREE .CircleGeometry (radius, segments, thetaStart, thetaLength);
new THREE .CircleGeometry (0.5 , 32 );
new THREE .RingGeometry (innerRadius, outerRadius, thetaSeg, phiSeg, thetaStart, thetaLength);
new THREE .RingGeometry (0.3 , 0.5 , 32 );
new THREE .CapsuleGeometry (radius, length, capSeg, radialSeg);
new THREE .CapsuleGeometry (0.5 , 1 , 8 , 16 );
new THREE .IcosahedronGeometry (radius, detail);
new THREE .OctahedronGeometry (radius, detail);
Path-Based Shapes
const points = [];
for (let i = 0 ; i < 10 ; i++) {
points.push (new THREE .Vector2 (Math .sin (i * 0.2 ) + 0.5 , i * 0.2 - 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 = {
depth : 0.5 ,
bevelEnabled : true ,
bevelThickness : 0.1 ,
bevelSize : 0.1 ,
bevelSegments : 3 ,
};
new THREE .ExtrudeGeometry (shape, extrudeSettings);
const path = new THREE .CatmullRomCurve3 ([
new THREE .Vector3 (-1 , 0 , 0 ),
new THREE .Vector3 (0 , 1 , 0 ),
new THREE .Vector3 (1 , 0 , 0 ),
]);
new THREE .TubeGeometry (path, 64 , 0.1 , 8 , false );
BufferGeometry The foundation class for all geometry in Three.js — stores data as typed arrays on the GPU.
Custom Geometry const geometry = new THREE .BufferGeometry ();
const positions = new Float32Array ([
0 , 0 , 0 ,
1 , 0 , 0 ,
0 , 1 , 0 ,
1 , 1 , 0 ,
]);
geometry.setAttribute ('position' , new THREE .BufferAttribute (positions, 3 ));
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 ,
0 , 1 ,
1 , 1 ,
]);
geometry.setAttribute ('uv' , new THREE .BufferAttribute (uvs, 2 ));
const indices = new Uint16Array ([0 , 1 , 2 , 1 , 3 , 2 ]);
geometry.setIndex (new THREE .BufferAttribute (indices, 1 ));
const colours = new Float32Array ([
1 , 0 , 0 ,
0 , 1 , 0 ,
0 , 0 , 1 ,
1 , 1 , 0 ,
]);
geometry.setAttribute ('color' , new THREE .BufferAttribute (colours, 3 ));
geometry.computeVertexNormals ();
Runtime Modification const positions = geometry.attributes .position ;
for (let i = 0 ; i < positions.count ; i++) {
const y = Math .sin (positions.getX (i) * 2 + time) * 0.5 ;
positions.setY (i, y);
}
positions.needsUpdate = true ;
geometry.computeBoundingBox ();
geometry.computeBoundingSphere ();
Bounding Volumes geometry.computeBoundingBox ();
geometry.computeBoundingSphere ();
const box = geometry.boundingBox ;
const sphere = geometry.boundingSphere ;
const inside = box.containsPoint (new THREE .Vector3 (0.5 , 0.5 , 0 ));
InstancedMesh — Many Identical Objects Critical for performance. One draw call for thousands of identical meshes.
const count = 10000 ;
const geometry = new THREE .BoxGeometry (0.1 , 0.1 , 0.1 );
const material = new THREE .MeshStandardMaterial ({ color : 0xff0000 });
const instancedMesh = new THREE .InstancedMesh (geometry, material, count);
instancedMesh.castShadow = true ;
instancedMesh.receiveShadow = true ;
const dummy = new THREE .Object3D ();
const colour = new THREE .Color ();
for (let i = 0 ; i < count; i++) {
dummy.position .random ().multiplyScalar (20 );
dummy.rotation .set (
Math .random () * Math .PI ,
Math .random () * Math .PI ,
0 ,
);
dummy.scale .setScalar (0.5 + Math .random () * 0.5 );
dummy.updateMatrix ();
instancedMesh.setMatrixAt (i, dummy.matrix );
colour.setHSL (Math .random (), 0.8 , 0.5 );
instancedMesh.setColorAt (i, colour);
}
instancedMesh.instanceMatrix .needsUpdate = true ;
if (instancedMesh.instanceColor ) instancedMesh.instanceColor .needsUpdate = true ;
scene.add (instancedMesh);
function moveInstance (index, position ) {
dummy.position .copy (position);
dummy.updateMatrix ();
instancedMesh.setMatrixAt (index, dummy.matrix );
instancedMesh.instanceMatrix .needsUpdate = true ;
}
Raycasting on InstancedMesh const raycaster = new THREE .Raycaster ();
function onClick (event ) {
const mouse = new THREE .Vector2 (
(event.clientX / window .innerWidth ) * 2 - 1 ,
-(event.clientY / window .innerHeight ) * 2 + 1 ,
);
raycaster.setFromCamera (mouse, camera);
const intersects = raycaster.intersectObject (instancedMesh);
if (intersects.length > 0 ) {
const id = intersects[0 ].instanceId ;
instancedMesh.getMatrixAt (id, dummy.matrix );
console .log ('Clicked instance:' , id);
}
}
Geometry Merging Combine static meshes into one — eliminates individual draw calls.
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js' ;
const geos = objects.map (o => {
const geo = o.geometry .clone ();
geo.applyMatrix4 (o.matrixWorld );
return geo;
});
const merged = mergeGeometries (geos, false );
const mesh = new THREE .Mesh (merged, sharedMaterial);
scene.add (mesh);
const mergedMulti = mergeGeometries (geos, true );
const meshMulti = new THREE .Mesh (mergedMulti, [mat1, mat2]);
Only merge static geometry. Merged meshes cannot be transformed individually.
Wireframes, Edges, and Points
const wireMat = new THREE .MeshBasicMaterial ({ wireframe : true , color : 0x00ff00 });
const wireMesh = new THREE .Mesh (geometry, wireMat);
const edges = new THREE .EdgesGeometry (geometry, 30 );
const edgeMesh = new THREE .LineSegments (edges, new THREE .LineBasicMaterial ({ color : 0xffffff }));
const wireGeo = new THREE .WireframeGeometry (geometry);
const wireLine = new THREE .LineSegments (wireGeo, new THREE .LineBasicMaterial ({ color : 0x888888 }));
const pointMat = new THREE .PointsMaterial ({ size : 0.02 , color : 0xffffff , sizeAttenuation : true });
const pointMesh = new THREE .Points (geometry, pointMat);
Morph Targets Blend between alternative vertex positions for animation.
const baseGeometry = new THREE .SphereGeometry (1 , 32 , 32 );
const morphGeo = baseGeometry.clone ();
const morphPos = morphGeo.attributes .position ;
for (let i = 0 ; i < morphPos.count ; i++) {
morphPos.setY (i, morphPos.getY (i) * 0.5 );
morphPos.setX (i, morphPos.getX (i) * 1.5 );
}
baseGeometry.morphAttributes .position = [morphPos];
const mesh = new THREE .Mesh (baseGeometry, new THREE .MeshStandardMaterial ({ morphTargets : true }));
scene.add (mesh);
function animate ( ) {
mesh.morphTargetInfluences [0 ] = Math .sin (clock.getElapsedTime ()) * 0.5 + 0.5 ;
requestAnimationFrame (animate);
renderer.render (scene, camera);
}
InstancedBufferGeometry — Custom Per-Instance Attributes For instanced particles or objects needing per-instance shader data beyond transform and colour.
const count = 50000 ;
const geometry = new THREE .PlaneGeometry (0.05 , 0.05 );
const seeds = new Float32Array (count);
const speeds = new Float32Array (count);
for (let i = 0 ; i < count; i++) {
seeds[i] = Math .random ();
speeds[i] = 0.5 + Math .random () * 1.5 ;
}
geometry.setAttribute ('aSeed' , new THREE .InstancedBufferAttribute (seeds, 1 ));
geometry.setAttribute ('aSpeed' , new THREE .InstancedBufferAttribute (speeds, 1 ));
const material = new THREE .ShaderMaterial ({
uniforms : { uTime : { value : 0 } },
vertexShader : `
attribute float aSeed;
attribute float aSpeed;
uniform float uTime;
varying float vSeed;
void main() {
vSeed = aSeed;
vec3 pos = position;
pos.y += mod(aSeed + uTime * aSpeed, 10.0) - 5.0;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
` ,
fragmentShader : `
varying float vSeed;
void main() { gl_FragColor = vec4(vSeed, 0.5, 1.0 - vSeed, 1.0); }
` ,
});
const mesh = new THREE .InstancedMesh (geometry, material, count);
scene.add (mesh);
Performance Tips
InstancedMesh over individual meshes — 100+ identical objects = use instancing
Merge static geometry — buildings, terrain props that never move
Right segment count — 32 segments for spheres; 64×64 for subdivided planes; avoid excess
Index your geometry — shared vertices via index array = smaller GPU buffer
Non-indexed geometry for flat-shaded low-poly — avoids vertex duplication issues
Dispose on removal — geometry.dispose() frees GPU memory
console .log ('Draw calls:' , renderer.info .render .calls );
console .log ('Triangles:' , renderer.info .render .triangles );
console .log ('Geometries:' , renderer.info .memory .geometries );
See Also
threejs-fundamentals — scene setup and Object3D transforms
threejs-materials — materials for geometry
three-js-best-practices — draw-call budget and instancing rules
threejs-animation — morph target animation with AnimationMixer