ChatGPT Claude Codex CLI Cohere Cursor DeepSeek Gemini GitHub Copilot GLM Grok Kimi Llama MiniMax Mistral OpenAI opencode Skill

threejs-geometry

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.

LLM Mart · 0 points · 16 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download sickn33-agentic-awesome-skills-skills_threejs-geometry-286166a.zip · 4 KB
Part of sickn33/agentic-awesome-skills — 427 skills
This skill couldn't be refreshed from GitHub on the last check — you're seeing the last imported snapshot.

Install

skills CLI npx skills add https://github.com/sickn33/agentic-awesome-skills/tree/main/skills/threejs-geometry
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install sickn33-agentic-awesome-skills@llmmart
Git git clone https://github.com/sickn33/agentic-awesome-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole sickn33/agentic-awesome-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Three.js Geometry

When to Use

  • You need to create or optimize geometry in Three.js.
  • The task involves built-in shapes, custom BufferGeometry, vertices, or instanced rendering.
  • You are working on mesh structure rather than scene setup or materials alone.

Quick Start

import * as THREE from "three";

// Built-in geometry
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);

// Create mesh
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(box, material);
scene.add(mesh);

Built-in Geometries

Basic Shapes

// Box - width, height, depth, widthSegments, heightSegments, depthSegments
new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);

// Sphere - radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength
new THREE.SphereGeometry(1, 32, 32);
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // Full sphere
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // Hemisphere

// Plane - width, height, widthSegments, heightSegments
new THREE.PlaneGeometry(10, 10, 1, 1);

// Circle - radius, segments, thetaStart, thetaLength
new THREE.CircleGeometry(1, 32);
new THREE.CircleGeometry(1, 32, 0, Math.PI); // Semicircle

// Cylinder - radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded
new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
new THREE.CylinderGeometry(0, 1, 2, 32); // Cone
new THREE.CylinderGeometry(1, 1, 2, 6); // Hexagonal prism

// Cone - radius, height, radialSegments, heightSegments, openEnded
new THREE.ConeGeometry(1, 2, 32, 1, false);

// Torus - radius, tube, radialSegments, tubularSegments, arc
new THREE.TorusGeometry(1, 0.4, 16, 100);

// TorusKnot - radius, tube, tubularSegments, radialSegments, p, q
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);

// Ring - innerRadius, outerRadius, thetaSegments, phiSegments
new THREE.RingGeometry(0.5, 1, 32, 1);

Advanced Shapes

// Capsule - radius, length, capSegments, radialSegments
new THREE.CapsuleGeometry(0.5, 1, 4, 8);

// Dodecahedron - radius, detail
new THREE.DodecahedronGeometry(1, 0);

// Icosahedron - radius, detail (0 = 20 faces, higher = smoother)
new THREE.IcosahedronGeometry(1, 0);

// Octahedron - radius, detail
new THREE.OctahedronGeometry(1, 0);

// Tetrahedron - radius, detail
new THREE.TetrahedronGeometry(1, 0);

// Polyhedron - vertices, indices, radius, detail
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

// Lathe - points[], segments, phiStart, phiLength
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);

// Extrude - shape, options
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);

// Tube - path, tubularSegments, radius, radialSegments, closed
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, // Was 'height' in older versions
    curveSegments: 12,
    bevelEnabled: true,
    bevelThickness: 0.03,
    bevelSize: 0.02,
    bevelSegments: 5,
  });

  // Center text
  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();

// Vertices (3 floats per vertex: x, y, z)
const vertices = new Float32Array([
  -1,
  -1,
  0, // vertex 0
  1,
  -1,
  0, // vertex 1
  1,
  1,
  0, // vertex 2
  -1,
  1,
  0, // vertex 3
]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));

// Indices (for indexed geometry - reuse vertices)
const indices = new Uint16Array([
  0,
  1,
  2, // triangle 1
  0,
  2,
  3, // triangle 2
]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// Normals (required for lighting)
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));

// UVs (for texturing)
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));

// Colors (per-vertex colors)
const colors = new Float32Array([
  1,
  0,
  0, // red
  0,
  1,
  0, // green
  0,
  0,
  1, // blue
  1,
  1,
  0, // yellow
]);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
// Use with: material.vertexColors = true

BufferAttribute Types

// Common attribute types
new THREE.BufferAttribute(array, itemSize);

// Typed array options
new Float32Array(count * itemSize); // Positions, normals, UVs
new Uint16Array(count); // Indices (up to 65535 vertices)
new Uint32Array(count); // Indices (larger meshes)
new Uint8Array(count * itemSize); // Colors (0-255 range)

// Item sizes
// Position: 3 (x, y, z)
// Normal: 3 (x, y, z)
// UV: 2 (u, v)
// Color: 3 (r, g, b) or 4 (r, g, b, a)
// Index: 1

Modifying BufferGeometry

const positions = geometry.attributes.position;

// Modify vertex
positions.setXYZ(index, x, y, z);

// Access vertex
const x = positions.getX(index);
const y = positions.getY(index);
const z = positions.getZ(index);

// Flag for GPU update
positions.needsUpdate = true;

// Recompute normals after position changes
geometry.computeVertexNormals();

// Recompute bounding box/sphere after changes
geometry.computeBoundingBox();
geometry.computeBoundingSphere();

Interleaved Buffers (Advanced)

// More efficient memory layout for large meshes
const interleavedBuffer = new THREE.InterleavedBuffer(
  new Float32Array([
    // pos.x, pos.y, pos.z, uv.u, uv.v (repeated per vertex)
    -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1,
  ]),
  5, // stride (floats per vertex)
);

geometry.setAttribute(
  "position",
  new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0),
); // size 3, offset 0
geometry.setAttribute(
  "uv",
  new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3),
); // size 2, offset 3

EdgesGeometry & WireframeGeometry

// Edge lines (only hard edges)
const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = threshold angle
const edgeMesh = new THREE.LineSegments(
  edges,
  new THREE.LineBasicMaterial({ color: 0xffffff }),
);

// Wireframe (all triangles)
const wireframe = new THREE.WireframeGeometry(boxGeometry);
const wireMesh = new THREE.LineSegments(
  wireframe,
  new THREE.LineBasicMaterial({ color: 0xffffff }),
);

Points

// Create point cloud
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, // Size decreases with distance
  color: 0xffffff,
});

const points = new THREE.Points(geometry, material);
scene.add(points);

Lines

// Line (connected points)
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 }),
);

// LineLoop (closed loop)
const loop = new THREE.LineLoop(geometry, material);

// LineSegments (pairs of points)
const segmentsGeometry = new THREE.BufferGeometry();
segmentsGeometry.setAttribute(
  "position",
  new THREE.BufferAttribute(
    new Float32Array([
      -1,
      0,
      0,
      0,
      1,
      0, // segment 1
      0,
      1,
      0,
      1,
      0,
      0, // segment 2
    ]),
    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);

// Set transforms for each instance
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);
}

// Flag for GPU update
instancedMesh.instanceMatrix.needsUpdate = true;

// Optional: per-instance colors
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

// Update single instance
const matrix = new THREE.Matrix4();
instancedMesh.getMatrixAt(index, matrix);
// Modify matrix...
instancedMesh.setMatrixAt(index, matrix);
instancedMesh.instanceMatrix.needsUpdate = true;

// Raycasting with instanced mesh
const intersects = raycaster.intersectObject(instancedMesh);
if (intersects.length > 0) {
  const instanceId = intersects[0].instanceId;
}

InstancedBufferGeometry (Advanced)

For custom per-instance attributes beyond transform/color.

const geometry = new THREE.InstancedBufferGeometry();
geometry.copy(new THREE.BoxGeometry(1, 1, 1));

// Add per-instance attribute
const offsets = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
  offsets[i * 3] = Math.random() * 10;
  offsets[i * 3 + 1] = Math.random() * 10;
  offsets[i * 3 + 2] = Math.random() * 10;
}
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));

// Use in shader
// attribute vec3 offset;
// vec3 transformed = position + offset;

Geometry Utilities

import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";

// Merge geometries (must have same attributes)
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]);

// Merge with groups (for multi-material)
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true);

// Compute tangents (required for normal maps)
BufferGeometryUtils.computeTangents(geometry);

// Interleave attributes for better performance
const interleaved = BufferGeometryUtils.interleaveAttributes([
  geometry.attributes.position,
  geometry.attributes.normal,
  geometry.attributes.uv,
]);

Common Patterns

Center Geometry

geometry.computeBoundingBox();
geometry.center(); // Move vertices so center is at origin

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);

Morph Targets

// Base geometry
const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);

// Create morph target
const morphPositions = geometry.attributes.position.array.slice();
for (let i = 0; i < morphPositions.length; i += 3) {
  morphPositions[i] *= 2; // Scale X
  morphPositions[i + 1] *= 0.5; // Squash Y
}

geometry.morphAttributes.position = [
  new THREE.BufferAttribute(new Float32Array(morphPositions), 3),
];

const mesh = new THREE.Mesh(geometry, material);
mesh.morphTargetInfluences[0] = 0.5; // 50% blend

Performance Tips

  1. Use indexed geometry: Reuse vertices with indices
  2. Merge static meshes: Reduce draw calls with mergeGeometries
  3. Use InstancedMesh: For many identical objects
  4. Choose appropriate segment counts: More segments = smoother but slower
  5. Dispose unused geometry: geometry.dispose()
// Good segment counts for common uses
new THREE.SphereGeometry(1, 32, 32); // Good quality
new THREE.SphereGeometry(1, 64, 64); // High quality
new THREE.SphereGeometry(1, 16, 16); // Performance mode

// Dispose when done
geometry.dispose();

BatchedMesh (r183)

BatchedMesh is a higher-level alternative to InstancedMesh that supports multiple geometries in a single draw call. As of r183, it supports per-instance opacity and per-instance wireframe.

const batchedMesh = new THREE.BatchedMesh(maxGeometryCount, maxVertexCount, maxIndexCount);
batchedMesh.sortObjects = true; // Enable depth sorting for transparency

// Add different geometries
const boxId = batchedMesh.addGeometry(new THREE.BoxGeometry(1, 1, 1));
const sphereId = batchedMesh.addGeometry(new THREE.SphereGeometry(0.5, 16, 16));

// Add instances of those geometries
const instance1 = batchedMesh.addInstance(boxId);
const instance2 = batchedMesh.addInstance(sphereId);

// Set transforms
const matrix = new THREE.Matrix4();
matrix.setPosition(2, 0, 0);
batchedMesh.setMatrixAt(instance1, matrix);

// Per-instance opacity (r183)
batchedMesh.setOpacityAt(instance1, 0.5);

// Per-instance visibility
batchedMesh.setVisibleAt(instance2, false);

scene.add(batchedMesh);

See Also

  • threejs-fundamentals - Scene setup and Object3D
  • threejs-materials - Material types for meshes
  • threejs-shaders - Custom vertex manipulation

Limitations

  • Use this skill only when the task clearly matches the scope described above.
  • Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
  • Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
Files (agentic-awesome-skills)
  • SKILL.md 15.1 KB
    ---
    name: threejs-geometry
    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.
    risk: critical
    source: community
    ---
    
    # Three.js Geometry
    
    ## When to Use
    - You need to create or optimize geometry in Three.js.
    - The task involves built-in shapes, custom `BufferGeometry`, vertices, or instanced rendering.
    - You are working on mesh structure rather than scene setup or materials alone.
    
    ## Quick Start
    
    ```javascript
    import * as THREE from "three";
    
    // Built-in geometry
    const box = new THREE.BoxGeometry(1, 1, 1);
    const sphere = new THREE.SphereGeometry(0.5, 32, 32);
    const plane = new THREE.PlaneGeometry(10, 10);
    
    // Create mesh
    const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
    const mesh = new THREE.Mesh(box, material);
    scene.add(mesh);
    ```
    
    ## Built-in Geometries
    
    ### Basic Shapes
    
    ```javascript
    // Box - width, height, depth, widthSegments, heightSegments, depthSegments
    new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
    
    // Sphere - radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength
    new THREE.SphereGeometry(1, 32, 32);
    new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // Full sphere
    new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // Hemisphere
    
    // Plane - width, height, widthSegments, heightSegments
    new THREE.PlaneGeometry(10, 10, 1, 1);
    
    // Circle - radius, segments, thetaStart, thetaLength
    new THREE.CircleGeometry(1, 32);
    new THREE.CircleGeometry(1, 32, 0, Math.PI); // Semicircle
    
    // Cylinder - radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded
    new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
    new THREE.CylinderGeometry(0, 1, 2, 32); // Cone
    new THREE.CylinderGeometry(1, 1, 2, 6); // Hexagonal prism
    
    // Cone - radius, height, radialSegments, heightSegments, openEnded
    new THREE.ConeGeometry(1, 2, 32, 1, false);
    
    // Torus - radius, tube, radialSegments, tubularSegments, arc
    new THREE.TorusGeometry(1, 0.4, 16, 100);
    
    // TorusKnot - radius, tube, tubularSegments, radialSegments, p, q
    new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);
    
    // Ring - innerRadius, outerRadius, thetaSegments, phiSegments
    new THREE.RingGeometry(0.5, 1, 32, 1);
    ```
    
    ### Advanced Shapes
    
    ```javascript
    // Capsule - radius, length, capSegments, radialSegments
    new THREE.CapsuleGeometry(0.5, 1, 4, 8);
    
    // Dodecahedron - radius, detail
    new THREE.DodecahedronGeometry(1, 0);
    
    // Icosahedron - radius, detail (0 = 20 faces, higher = smoother)
    new THREE.IcosahedronGeometry(1, 0);
    
    // Octahedron - radius, detail
    new THREE.OctahedronGeometry(1, 0);
    
    // Tetrahedron - radius, detail
    new THREE.TetrahedronGeometry(1, 0);
    
    // Polyhedron - vertices, indices, radius, detail
    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
    
    ```javascript
    // Lathe - points[], segments, phiStart, phiLength
    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);
    
    // Extrude - shape, options
    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);
    
    // Tube - path, tubularSegments, radius, radialSegments, closed
    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
    
    ```javascript
    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, // Was 'height' in older versions
        curveSegments: 12,
        bevelEnabled: true,
        bevelThickness: 0.03,
        bevelSize: 0.02,
        bevelSegments: 5,
      });
    
      // Center text
      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
    
    ```javascript
    const geometry = new THREE.BufferGeometry();
    
    // Vertices (3 floats per vertex: x, y, z)
    const vertices = new Float32Array([
      -1,
      -1,
      0, // vertex 0
      1,
      -1,
      0, // vertex 1
      1,
      1,
      0, // vertex 2
      -1,
      1,
      0, // vertex 3
    ]);
    geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
    
    // Indices (for indexed geometry - reuse vertices)
    const indices = new Uint16Array([
      0,
      1,
      2, // triangle 1
      0,
      2,
      3, // triangle 2
    ]);
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));
    
    // Normals (required for lighting)
    const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
    geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
    
    // UVs (for texturing)
    const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
    geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
    
    // Colors (per-vertex colors)
    const colors = new Float32Array([
      1,
      0,
      0, // red
      0,
      1,
      0, // green
      0,
      0,
      1, // blue
      1,
      1,
      0, // yellow
    ]);
    geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
    // Use with: material.vertexColors = true
    ```
    
    ### BufferAttribute Types
    
    ```javascript
    // Common attribute types
    new THREE.BufferAttribute(array, itemSize);
    
    // Typed array options
    new Float32Array(count * itemSize); // Positions, normals, UVs
    new Uint16Array(count); // Indices (up to 65535 vertices)
    new Uint32Array(count); // Indices (larger meshes)
    new Uint8Array(count * itemSize); // Colors (0-255 range)
    
    // Item sizes
    // Position: 3 (x, y, z)
    // Normal: 3 (x, y, z)
    // UV: 2 (u, v)
    // Color: 3 (r, g, b) or 4 (r, g, b, a)
    // Index: 1
    ```
    
    ### Modifying BufferGeometry
    
    ```javascript
    const positions = geometry.attributes.position;
    
    // Modify vertex
    positions.setXYZ(index, x, y, z);
    
    // Access vertex
    const x = positions.getX(index);
    const y = positions.getY(index);
    const z = positions.getZ(index);
    
    // Flag for GPU update
    positions.needsUpdate = true;
    
    // Recompute normals after position changes
    geometry.computeVertexNormals();
    
    // Recompute bounding box/sphere after changes
    geometry.computeBoundingBox();
    geometry.computeBoundingSphere();
    ```
    
    ### Interleaved Buffers (Advanced)
    
    ```javascript
    // More efficient memory layout for large meshes
    const interleavedBuffer = new THREE.InterleavedBuffer(
      new Float32Array([
        // pos.x, pos.y, pos.z, uv.u, uv.v (repeated per vertex)
        -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1,
      ]),
      5, // stride (floats per vertex)
    );
    
    geometry.setAttribute(
      "position",
      new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0),
    ); // size 3, offset 0
    geometry.setAttribute(
      "uv",
      new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3),
    ); // size 2, offset 3
    ```
    
    ## EdgesGeometry & WireframeGeometry
    
    ```javascript
    // Edge lines (only hard edges)
    const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = threshold angle
    const edgeMesh = new THREE.LineSegments(
      edges,
      new THREE.LineBasicMaterial({ color: 0xffffff }),
    );
    
    // Wireframe (all triangles)
    const wireframe = new THREE.WireframeGeometry(boxGeometry);
    const wireMesh = new THREE.LineSegments(
      wireframe,
      new THREE.LineBasicMaterial({ color: 0xffffff }),
    );
    ```
    
    ## Points
    
    ```javascript
    // Create point cloud
    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, // Size decreases with distance
      color: 0xffffff,
    });
    
    const points = new THREE.Points(geometry, material);
    scene.add(points);
    ```
    
    ## Lines
    
    ```javascript
    // Line (connected points)
    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 }),
    );
    
    // LineLoop (closed loop)
    const loop = new THREE.LineLoop(geometry, material);
    
    // LineSegments (pairs of points)
    const segmentsGeometry = new THREE.BufferGeometry();
    segmentsGeometry.setAttribute(
      "position",
      new THREE.BufferAttribute(
        new Float32Array([
          -1,
          0,
          0,
          0,
          1,
          0, // segment 1
          0,
          1,
          0,
          1,
          0,
          0, // segment 2
        ]),
        3,
      ),
    );
    const segments = new THREE.LineSegments(segmentsGeometry, material);
    ```
    
    ## InstancedMesh
    
    Efficiently render many copies of the same geometry.
    
    ```javascript
    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);
    
    // Set transforms for each instance
    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);
    }
    
    // Flag for GPU update
    instancedMesh.instanceMatrix.needsUpdate = true;
    
    // Optional: per-instance colors
    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
    
    ```javascript
    // Update single instance
    const matrix = new THREE.Matrix4();
    instancedMesh.getMatrixAt(index, matrix);
    // Modify matrix...
    instancedMesh.setMatrixAt(index, matrix);
    instancedMesh.instanceMatrix.needsUpdate = true;
    
    // Raycasting with instanced mesh
    const intersects = raycaster.intersectObject(instancedMesh);
    if (intersects.length > 0) {
      const instanceId = intersects[0].instanceId;
    }
    ```
    
    ## InstancedBufferGeometry (Advanced)
    
    For custom per-instance attributes beyond transform/color.
    
    ```javascript
    const geometry = new THREE.InstancedBufferGeometry();
    geometry.copy(new THREE.BoxGeometry(1, 1, 1));
    
    // Add per-instance attribute
    const offsets = new Float32Array(count * 3);
    for (let i = 0; i < count; i++) {
      offsets[i * 3] = Math.random() * 10;
      offsets[i * 3 + 1] = Math.random() * 10;
      offsets[i * 3 + 2] = Math.random() * 10;
    }
    geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));
    
    // Use in shader
    // attribute vec3 offset;
    // vec3 transformed = position + offset;
    ```
    
    ## Geometry Utilities
    
    ```javascript
    import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
    
    // Merge geometries (must have same attributes)
    const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]);
    
    // Merge with groups (for multi-material)
    const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true);
    
    // Compute tangents (required for normal maps)
    BufferGeometryUtils.computeTangents(geometry);
    
    // Interleave attributes for better performance
    const interleaved = BufferGeometryUtils.interleaveAttributes([
      geometry.attributes.position,
      geometry.attributes.normal,
      geometry.attributes.uv,
    ]);
    ```
    
    ## Common Patterns
    
    ### Center Geometry
    
    ```javascript
    geometry.computeBoundingBox();
    geometry.center(); // Move vertices so center is at origin
    ```
    
    ### Scale to Fit
    
    ```javascript
    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
    
    ```javascript
    const clone = geometry.clone();
    clone.rotateX(Math.PI / 2);
    clone.translate(0, 1, 0);
    clone.scale(2, 2, 2);
    ```
    
    ### Morph Targets
    
    ```javascript
    // Base geometry
    const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);
    
    // Create morph target
    const morphPositions = geometry.attributes.position.array.slice();
    for (let i = 0; i < morphPositions.length; i += 3) {
      morphPositions[i] *= 2; // Scale X
      morphPositions[i + 1] *= 0.5; // Squash Y
    }
    
    geometry.morphAttributes.position = [
      new THREE.BufferAttribute(new Float32Array(morphPositions), 3),
    ];
    
    const mesh = new THREE.Mesh(geometry, material);
    mesh.morphTargetInfluences[0] = 0.5; // 50% blend
    ```
    
    ## Performance Tips
    
    1. **Use indexed geometry**: Reuse vertices with indices
    2. **Merge static meshes**: Reduce draw calls with `mergeGeometries`
    3. **Use InstancedMesh**: For many identical objects
    4. **Choose appropriate segment counts**: More segments = smoother but slower
    5. **Dispose unused geometry**: `geometry.dispose()`
    
    ```javascript
    // Good segment counts for common uses
    new THREE.SphereGeometry(1, 32, 32); // Good quality
    new THREE.SphereGeometry(1, 64, 64); // High quality
    new THREE.SphereGeometry(1, 16, 16); // Performance mode
    
    // Dispose when done
    geometry.dispose();
    ```
    
    ## BatchedMesh (r183)
    
    `BatchedMesh` is a higher-level alternative to `InstancedMesh` that supports multiple geometries in a single draw call. As of r183, it supports **per-instance opacity** and **per-instance wireframe**.
    
    ```javascript
    const batchedMesh = new THREE.BatchedMesh(maxGeometryCount, maxVertexCount, maxIndexCount);
    batchedMesh.sortObjects = true; // Enable depth sorting for transparency
    
    // Add different geometries
    const boxId = batchedMesh.addGeometry(new THREE.BoxGeometry(1, 1, 1));
    const sphereId = batchedMesh.addGeometry(new THREE.SphereGeometry(0.5, 16, 16));
    
    // Add instances of those geometries
    const instance1 = batchedMesh.addInstance(boxId);
    const instance2 = batchedMesh.addInstance(sphereId);
    
    // Set transforms
    const matrix = new THREE.Matrix4();
    matrix.setPosition(2, 0, 0);
    batchedMesh.setMatrixAt(instance1, matrix);
    
    // Per-instance opacity (r183)
    batchedMesh.setOpacityAt(instance1, 0.5);
    
    // Per-instance visibility
    batchedMesh.setVisibleAt(instance2, false);
    
    scene.add(batchedMesh);
    ```
    
    ## See Also
    
    - `threejs-fundamentals` - Scene setup and Object3D
    - `threejs-materials` - Material types for meshes
    - `threejs-shaders` - Custom vertex manipulation
    
    ## Limitations
    - Use this skill only when the task clearly matches the scope described above.
    - Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
    - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related