### Reference Code Example in Docs
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md
Reference a code example in your documentation using the component with the 'path' prop. The 'path' prop is the directory path relative to src/examples.
```html
```
```markdown
| Prop | Type | Default | Description |
| ---------------- | ------- | -------- | --------------------------------------- |
| `path` | string | required | Directory path relative to src/examples |
| `hideCode` | boolean | `false` | Hides the source code section |
| `hidePreview` | boolean | `false` | Hides the example preview |
| `hideStackblitz` | boolean | `false` | Hides "Open in Stackblitz" button |
```
--------------------------------
### Install via npm
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx
Use this command to install the package using npm.
```sh
npm install @three.ez/instanced-mesh
```
--------------------------------
### Create Code Example
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md
Create a new example directory and write your Three.js code in index.ts. Maximum 2 levels of nesting are allowed.
```bash
code src/examples/myExample/index.ts
```
```typescript
import { Scene, PerspectiveCamera } from 'three';
// Your Three.js example code here
```
--------------------------------
### Install @three.ez/instanced-mesh
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Install the InstancedMesh2 package and its peer dependency, three.js. CDN importmap is also provided.
```bash
npm install @three.ez/instanced-mesh
# peer dependency
npm install three
```
```html
```
--------------------------------
### Install via pnpm
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx
Use this command to install the package using pnpm.
```sh
pnpm add @three.ez/instanced-mesh
```
--------------------------------
### Install via yarn
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx
Use this command to install the package using yarn.
```sh
yarn add @three.ez/instanced-mesh
```
--------------------------------
### Set and Get Instance Opacity
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Demonstrates setting and getting per-instance opacity values (0-1) using `setOpacityAt` and `getOpacityAt`. Requires a transparent material and `sortObjects = true` for correct rendering.
```typescript
import { MeshStandardMaterial } from 'three';
const iMesh = new InstancedMesh2(
geometry,
new MeshStandardMaterial({ transparent: true }),
{ capacity: 200 }
);
iMesh.addInstances(200, (obj, i) => {
obj.position.set(i * 1.2, 0, 0);
});
iMesh.sortObjects = true; // required for correct transparency
iMesh.setOpacityAt(0, 0.1);
iMesh.setOpacityAt(1, 0.5);
iMesh.setOpacityAt(2, 1.0);
console.log(iMesh.getOpacityAt(0)); // 0.1
```
--------------------------------
### Add Documentation Pages
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md
Specify the directory based on content type (guides, reference, tutorials, concepts) and include required frontmatter with title and description.
```bash
src/content/docs/guides/ # For how-to guides
src/content/docs/reference/ # For technical reference
src/content/docs/tutorials/ # For tutorials
src/content/docs/concepts/ # For explanations
```
```markdown
---
title: Your Page Title
description: Brief description
---
```
--------------------------------
### Set and Get Instance Matrix
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Demonstrates low-level manipulation of an instance's transform using `setMatrixAt` and `getMatrixAt` with `Matrix4`.
```typescript
import { Matrix4, Vector3, Quaternion } from 'three';
const m = new Matrix4();
m.compose(
new Vector3(5, 0, 0),
new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 4),
new Vector3(2, 2, 2)
);
iMesh.setMatrixAt(0, m);
// Read back
const readback = new Matrix4();
iMesh.getMatrixAt(0, readback);
console.log(readback.elements[12]); // 5 (translation X)
```
--------------------------------
### Set and Get Instance Color
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Shows how to set and retrieve per-instance colors using various formats (CSS string, hex, `Color` instance) with `setColorAt` and `getColorAt`.
```typescript
import { Color } from 'three';
// Set colors during creation
iMesh.addInstances(3, (obj, i) => {
obj.color = ['red', 'lime', 'blue'][i]; // CSS color string
});
// Update individual instance color later
iMesh.setColorAt(1, 0x00ff00);
iMesh.setColorAt(2, new Color(0, 0, 1));
// Read
const col = new Color();
iMesh.getColorAt(0, col);
console.log(col.getHexString()); // 'ff0000'
```
--------------------------------
### Install via CDN with Import Map
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx
Include this script tag in your HTML file to load the library directly from a CDN. This sets up import aliases for three.js and related libraries.
```html
```
--------------------------------
### Development Scripts
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md
Run development and build scripts using npm. 'npm run dev' provides hot reload, 'npm run start' for production preview, and 'npm run build' for production build.
```bash
npm run dev # Dev mode with hot reload
npm run start # Production preview
npm run build # Production build
```
--------------------------------
### Set and Get Instance Visibility
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Explains how to hide or show individual instances using `setVisibilityAt` and `getVisibilityAt` without removing them from the mesh.
```typescript
// Hide every other instance
for (let i = 0; i < iMesh.instancesCount; i += 2) {
iMesh.setVisibilityAt(i, false);
}
// Re-show instance 4
iMesh.setVisibilityAt(4, true);
console.log(iMesh.getVisibilityAt(4)); // true
console.log(iMesh.getVisibilityAt(0)); // false
```
--------------------------------
### Tweening Instanced Entity Properties
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/04-tween.mdx
This example demonstrates how to apply tween animations to properties of instanced entities. It assumes you have already created an array of instances. Note that the 'color' property cannot be tweened.
```javascript
```
--------------------------------
### setMatrixAt and getMatrixAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Low-level methods for directly setting or getting the Matrix4 transformation for a specific instance by its ID.
```APIDOC
## setMatrixAt(id, matrix) / getMatrixAt(id, matrix?)
### Description
Provides low-level access to read or write the `Matrix4` for a specific instance using its ID. Useful for migrating from `InstancedMesh` or when transforms are computed externally.
### Parameters
- **id** (number): The ID of the instance.
- **matrix** (Matrix4): The `Matrix4` object to set or read.
### Usage
#### `setMatrixAt(id, matrix)`
Sets the transformation matrix for the specified instance.
```ts
import { Matrix4, Vector3, Quaternion } from 'three';
const m = new Matrix4();
m.compose(
new Vector3(5, 0, 0),
new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 4),
new Vector3(2, 2, 2)
);
iMesh.setMatrixAt(0, m);
```
#### `getMatrixAt(id, matrix?)`
Reads the transformation matrix of the specified instance. If a `matrix` object is provided, it will be populated with the instance's matrix; otherwise, a new `Matrix4` will be returned.
```ts
const readback = new Matrix4();
iMesh.getMatrixAt(0, readback);
console.log(readback.elements[12]); // 5 (translation X)
```
```
--------------------------------
### initSkeleton and setBonesAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Enables GPU skeletal animation for instances. `initSkeleton` sets up the necessary structures, and `setBonesAt` updates the bone matrices for individual instances.
```APIDOC
## `initSkeleton(skeleton)` / `setBonesAt(id, updateBonesMatrices?)`
### Description
Enables GPU skeletal animation across all instances. Each instance can be posed independently by calling `setBonesAt` with the current animation state. Bone matrices are stored per-instance in a `boneTexture`.
### Method
`initSkeleton`, `setBonesAt`
### Parameters
#### `initSkeleton`
- **skeleton** (Skeleton) - The skeleton to use for animation.
#### `setBonesAt`
- **id** (number) - The index of the instance.
- **updateBonesMatrices** (boolean, optional) - Whether to update the bone matrices.
### Request Example
```ts
import { InstancedMesh2, createInstancedMesh2From } from '@three.ez/instanced-mesh';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { AnimationMixer, Clock } from 'three';
const loader = new GLTFLoader();
const gltf = await loader.loadAsync('character.glb');
const skinnedMesh = gltf.scene.getObjectByProperty('isSkinnedMesh', true);
// createInstancedMesh2From detects SkinnedMesh and calls initSkeleton automatically
const iMesh = createInstancedMesh2From(skinnedMesh, {
capacity: 3000,
createEntities: true,
});
const mixer = new AnimationMixer(skinnedMesh);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
const clock = new Clock();
iMesh.addInstances(3000, (obj, i) => {
obj.position.set((i % 50) * 2, 0, Math.floor(i / 50) * 2);
});
// Frustum enter: update only visible instances' bones
iMesh.onFrustumEnter = (index) => {
iMesh.setBonesAt(index, true); // snapshot current skeleton pose to this instance
return true;
};
renderer.setAnimationLoop(() => {
const delta = clock.getDelta();
mixer.update(delta); // advance animation on shared skeleton
renderer.render(scene, camera);
});
scene.add(iMesh);
```
```
--------------------------------
### initUniformsPerInstance, setUniformAt, and getUniformAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Manages per-instance GPU shader uniforms. `initUniformsPerInstance` defines the schema for uniforms, while `setUniformAt` and `getUniformAt` allow individual instance uniform manipulation.
```APIDOC
## `initUniformsPerInstance(schema)` / `setUniformAt(id, name, value)` / `getUniformAt(id, name)`
### Description
Assigns per-instance GPU shader uniforms stored in a `SquareDataTexture`. The `schema` defines which uniforms live in the `vertex` and/or `fragment` shader stage and their GLSL type (`'float'`, `'vec2'`, `'vec3'`, `'vec4'`, `'mat3'`, `'mat4'`). Uniforms are automatically injected into the material's shader.
### Method
`initUniformsPerInstance`, `setUniformAt`, `getUniformAt`
### Parameters
#### `initUniformsPerInstance`
- **schema** (object) - Defines the uniforms and their types for vertex and/or fragment shaders.
#### `setUniformAt`
- **id** (number) - The index of the instance.
- **name** (string) - The name of the uniform.
- **value** (any) - The value to set for the uniform.
#### `getUniformAt`
- **id** (number) - The index of the instance.
- **name** (string) - The name of the uniform.
### Request Example
```ts
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { BoxGeometry, MeshLambertMaterial, Vector2, Color } from 'three';
const iMesh = new InstancedMesh2(
new BoxGeometry(),
new MeshLambertMaterial(),
{ capacity: 256 * 256 }
);
// Define per-instance uniforms: a UV offset (vec2) and metalness (float)
iMesh.initUniformsPerInstance({
fragment: {
offset: 'vec2',
metalness: 'float',
emissive: 'vec3',
},
});
iMesh.addInstances(256 * 256, (obj, i) => {
obj.position.set(i % 256, 0, Math.floor(i / 256));
obj.setUniform('offset', new Vector2(Math.random(), Math.random()));
obj.setUniform('metalness', Math.random());
obj.setUniform('emissive', new Color(Math.random(), Math.random(), Math.random()));
});
// Read a uniform back
const uv = iMesh.getUniformAt(0, 'offset') as Vector2;
console.log(uv.x, uv.y);
// Update a single instance's uniform later
iMesh.setUniformAt(42, 'metalness', 0.9);
```
```
--------------------------------
### Initialize Skeleton and Set Bones
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Apply skeletal animations to instances by initializing the skeleton and then setting the bones for each instance. The mixer needs to be updated with time for animations to progress.
```typescript
myInstancedMesh.initSkeleton(skeleton);
mixer.update(time);
myInstancedMesh.setBonesAt(index);
```
--------------------------------
### Instantiate and Add Instances with InstancedMesh2
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Initialize InstancedMesh2 with geometry and material, then add a specified number of instances, configuring each instance's properties using a callback function.
```typescript
const myInstancedMesh = new InstancedMesh2(geometry, material);
myInstancedMesh.addInstances(count, (obj, index) => {
obj.position.x = index;
});
```
--------------------------------
### Initialize InstancedMesh2
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/02-first-instancedmesh2.mdx
Create a new InstancedMesh2 instance. Requires a geometry and a material.
```typescript
const iMesh = new InstancedMesh2(geometry, material);
```
--------------------------------
### createInstancedMesh2From
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Factory utility to create an InstancedMesh2 from an existing Mesh, InstancedMesh, or SkinnedMesh. It copies geometry, material, matrices, colors, and skeleton.
```APIDOC
## `createInstancedMesh2From(mesh, params?)`
Factory utility that creates an `InstancedMesh2` from an existing `Mesh`, `InstancedMesh`, or `SkinnedMesh`, copying geometry, material, matrices, colors, and skeleton.
### Parameters
- **mesh** (Mesh | InstancedMesh | SkinnedMesh) - The source mesh to copy from.
- **params** (object, optional) - Configuration options for the new InstancedMesh2.
- **capacity** (number) - The maximum number of instances.
- **createEntities** (boolean) - Whether to create entity objects for each instance.
```
--------------------------------
### Create and Animate Instanced Entities
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Initializes an InstancedMesh2 with entity creation enabled and demonstrates animating individual instances by updating their transforms and calling `updateMatrix()`.
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { TorusKnotGeometry, MeshStandardMaterial } from 'three';
const iMesh = new InstancedMesh2(
new TorusKnotGeometry(),
new MeshStandardMaterial(),
{ createEntities: true, capacity: 100 }
);
iMesh.addInstances(100, (obj, i) => {
obj.position.set(i * 3, 0, 0);
obj.color = 0xff0000 + i * 100;
});
// Animate in render loop
function animate() {
requestAnimationFrame(animate);
for (const instance of iMesh.instances) {
if (!instance.active) continue;
instance.rotateY(0.01);
instance.translateX(0.001);
instance.updateMatrix(); // flush to matricesTexture
}
renderer.render(scene, camera);
}
animate();
// Toggle visibility
iMesh.instances[10].visible = false;
// Adjust opacity (requires sorting + transparent material for best results)
iMesh.instances[20].opacity = 0.4;
// Remove via entity
iMesh.instances[30].remove();
```
--------------------------------
### Create InstancedMesh2 Instance
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Basic construction of InstancedMesh2 with optional parameters for capacity, entity creation, and renderer injection. The renderer must be injected if the index buffer needs to initialize immediately.
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import {
WebGLRenderer, Scene, PerspectiveCamera,
BoxGeometry, MeshStandardMaterial, DirectionalLight
} from 'three';
const renderer = new WebGLRenderer({ antialias: true });
document.body.appendChild(renderer.domElement);
const scene = new Scene();
const camera = new PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000);
camera.position.set(0, 20, 60);
// Basic construction — capacity defaults to 1000
const iMesh = new InstancedMesh2(
new BoxGeometry(),
new MeshStandardMaterial({ color: 0x44aa88 }),
{
capacity: 10000, // pre-allocate for 10k instances
createEntities: false, // no per-instance Object3D wrappers (lower memory)
renderer, // inject renderer so index buffer initialises immediately
}
);
scene.add(iMesh, new DirectionalLight('white', 2));
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
```
--------------------------------
### Initialize Per-Instance Uniforms for Shaders
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Define and assign custom shader uniforms that vary per instance using `initUniformsPerInstance`, `setUniformAt`, and `getUniformAt`. This allows for per-instance color, UV offsets, or other data.
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { BoxGeometry, MeshLambertMaterial, Vector2, Color } from 'three';
const iMesh = new InstancedMesh2(
new BoxGeometry(),
new MeshLambertMaterial(),
{ capacity: 256 * 256 }
);
// Define per-instance uniforms: a UV offset (vec2) and metalness (float)
iMesh.initUniformsPerInstance({
fragment: {
offset: 'vec2',
metalness: 'float',
emissive: 'vec3',
},
});
iMesh.addInstances(256 * 256, (obj, i) => {
obj.position.set(i % 256, 0, Math.floor(i / 256));
obj.setUniform('offset', new Vector2(Math.random(), Math.random()));
obj.setUniform('metalness', Math.random());
obj.setUniform('emissive', new Color(Math.random(), Math.random(), Math.random()));
});
// Read a uniform back
const uv = iMesh.getUniformAt(0, 'offset') as Vector2;
console.log(uv.x, uv.y);
// Update a single instance's uniform later
iMesh.setUniformAt(42, 'metalness', 0.9);
```
--------------------------------
### Add Custom Data to Instances (JavaScript)
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/05-custom-data.mdx
This JavaScript snippet demonstrates how to assign custom data, such as a UUID, to each instance during creation with `addInstances`.
```javascript
const iMesh = new InstancedMesh2(geo, mat, { createEntities: true });
iMesh.addInstances(count, (obj, index) => {
obj.uuid = MathUtils.generateUUID();
});
```
--------------------------------
### updateInstances and updateInstancesPosition
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
These methods provide a convenient way to iterate over all active instances, apply a callback function, and automatically handle matrix updates.
```APIDOC
## updateInstances(onUpdate) / updateInstancesPosition(onUpdate)
### Description
Iterates through all active instances, applies a callback function to each, and automatically calls `updateMatrix()` or `updateMatrixPosition()`.
### Parameters
- **onUpdate** (function): A callback function that receives the instance object as an argument.
### Usage
#### `updateInstances(onUpdate)`
Use this when you need to update transforms (position, rotation, scale).
```ts
iMesh.updateInstances((obj) => {
obj.rotateY(0.01);
// updateMatrix() is called automatically
});
```
#### `updateInstancesPosition(onUpdate)`
Use this when you only need to update the position. This is faster as it skips rotation and scale recalculations.
```ts
iMesh.updateInstancesPosition((obj) => {
obj.position.y = Math.sin(Date.now() * 0.001 + obj.id * 0.1);
// updateMatrixPosition() is called automatically
});
```
```
--------------------------------
### Animate All Instances using updateInstances
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/02-animation.mdx
The recommended method for animating all active instances. This method automatically handles matrix updates. Be aware that if instances are not created as an array, transformations might reset.
```typescript
this.updateInstances((obj) => {
instance.scale.x += 0.1;
});
```
--------------------------------
### InstancedMesh2 Constructor
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Creates a new InstancedMesh2 instance. It requires a geometry and material, and accepts an optional params object to configure initial capacity, entity creation, and renderer injection.
```APIDOC
## new InstancedMesh2(geometry, material, params?)
### Description
Creates an instanced mesh. `geometry` and `material` are mandatory (same types as three.js `Mesh`). The optional `params` object (`InstancedMesh2Params`) controls initial capacity, entity creation, Euler support, and renderer injection.
### Parameters
- **geometry** (THREE.BufferGeometry) - The geometry to be instanced.
- **material** (THREE.Material) - The material to be used for the instances.
- **params** (InstancedMesh2Params, optional) - Configuration options for the InstancedMesh2.
- **capacity** (number, optional) - The initial capacity for instances. Defaults to 1000.
- **createEntities** (boolean, optional) - Whether to create per-instance Object3D wrappers. Defaults to true.
- **renderer** (THREE.WebGLRenderer, optional) - The renderer to inject for immediate index buffer initialization.
### Request Example
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import {
WebGLRenderer, Scene, PerspectiveCamera,
BoxGeometry, MeshStandardMaterial, DirectionalLight
} from 'three';
const renderer = new WebGLRenderer({ antialias: true });
document.body.appendChild(renderer.domElement);
const scene = new Scene();
const camera = new PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000);
camera.position.set(0, 20, 60);
// Basic construction — capacity defaults to 1000
const iMesh = new InstancedMesh2(
new BoxGeometry(),
new MeshStandardMaterial({ color: 0x44aa88 }),
{
capacity: 10000, // pre-allocate for 10k instances
createEntities: false, // no per-instance Object3D wrappers (lower memory)
renderer, // inject renderer so index buffer initialises immediately
}
);
scene.add(iMesh, new DirectionalLight('white', 2));
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
```
```
--------------------------------
### `computeBVH(params?)` / `disposeBVH()`
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Builds a dynamic Bounding Volume Hierarchy (BVH) for efficient frustum culling and raycasting. The BVH updates automatically when instances move if `autoUpdateBVH` is true.
```APIDOC
## `computeBVH(params?)` / `disposeBVH()`
Builds a dynamic Bounding Volume Hierarchy (BVH) over all instances for O(log n) frustum culling and raycasting instead of O(n) linear scans. The BVH updates automatically when instances move (`autoUpdateBVH = true`). Call after populating instances for best build quality.
```ts
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { OctahedronGeometry, MeshLambertMaterial, Vector3 } from 'three';
type Data = { dir: Vector3 };
const iMesh = new InstancedMesh2(
new OctahedronGeometry(1, 2),
new MeshLambertMaterial(),
{ capacity: 50000, createEntities: true }
);
iMesh.addInstances(50000, (obj) => {
obj.dir = new Vector3().randomDirection();
obj.position.randomDirection().multiplyScalar(Math.random() * 3000);
obj.scale.setScalar(1 + Math.random() * 4);
});
// Build BVH after all instances are placed
iMesh.computeBVH({
margin: 75, // tolerance for moving objects (0 = static)
getBBoxFromBSphere: true, // faster bbox approx (geometry must be origin-centered)
accurateCulling: true, // re-check margin nodes precisely
});
// Animate — BVH nodes update automatically via updateMatrixPosition
renderer.setAnimationLoop((delta) => {
for (const obj of iMesh.instances) {
if (!obj.active) continue;
obj.position.addScaledVector(obj.dir, delta * 10);
obj.updateMatrixPosition(); // triggers bvh.move(id) internally
}
renderer.render(scene, camera);
});
// Intersect a box with the BVH
import { Box3 } from 'three';
const queryBox = new Box3().setFromCenterAndSize(
new Vector3(0, 0, 0),
new Vector3(100, 100, 100)
);
iMesh.bvh.intersectBox(queryBox, (id) => {
console.log('Instance inside box:', id);
return true; // continue iterating
});
// Teardown
iMesh.disposeBVH();
```
```
--------------------------------
### Initialize InstancedMesh2 with Capacity
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/00-add-remove.mdx
Set the initial buffer capacity when creating a new InstancedMesh2 to pre-allocate memory. Buffers expand automatically if capacity is not specified.
```typescript
const iMesh = new InstancedMesh2(geo, mat, { capacity: 10000 });
```
--------------------------------
### Enable GPU Skeletal Animation for Instanced Meshes
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Use `createInstancedMesh2From` with a `SkinnedMesh` or manually call `initSkeleton` to enable GPU skeletal animation. `setBonesAt` updates bone matrices per instance, and `onFrustumEnter` can optimize updates for visible instances.
```typescript
import { InstancedMesh2, createInstancedMesh2From } from '@three.ez/instanced-mesh';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { AnimationMixer, Clock } from 'three';
const loader = new GLTFLoader();
const gltf = await loader.loadAsync('character.glb');
const skinnedMesh = gltf.scene.getObjectByProperty('isSkinnedMesh', true);
// createInstancedMesh2From detects SkinnedMesh and calls initSkeleton automatically
const iMesh = createInstancedMesh2From(skinnedMesh, {
capacity: 3000,
createEntities: true,
});
const mixer = new AnimationMixer(skinnedMesh);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
const clock = new Clock();
iMesh.addInstances(3000, (obj, i) => {
obj.position.set((i % 50) * 2, 0, Math.floor(i / 50) * 2);
});
// Frustum enter: update only visible instances' bones
iMesh.onFrustumEnter = (index) => {
iMesh.setBonesAt(index, true); // snapshot current skeleton pose to this instance
return true;
};
renderer.setAnimationLoop(() => {
const delta = clock.getDelta();
mixer.update(delta); // advance animation on shared skeleton
renderer.render(scene, camera);
});
scene.add(iMesh);
```
--------------------------------
### addInstances
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Adds a specified number of new instances to the mesh. An optional callback function can be provided to configure each new instance upon creation. Buffers will automatically expand if the current capacity is exceeded.
```APIDOC
## addInstances(count, onCreation?)
### Description
Adds `count` new instances to the mesh. The optional `onCreation` callback receives a temporary `InstancedEntity` (`obj`) and the instance `index`; set transforms and custom data here. Buffers expand automatically if capacity is exceeded.
### Parameters
- **count** (number) - The number of instances to add.
- **onCreation** (function, optional) - A callback function executed for each newly created instance. It receives the `InstancedEntity` object and its `index`.
- **obj** (InstancedEntity) - The temporary entity object for the instance.
- **index** (number) - The index of the newly created instance.
### Request Example
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { SphereGeometry, MeshLambertMaterial } from 'three';
type CustomData = { speed: number };
const iMesh = new InstancedMesh2(
new SphereGeometry(0.5, 16, 8),
new MeshLambertMaterial(),
{ capacity: 5000, createEntities: true }
);
// Add 5000 instances; obj is InstancedEntity & CustomData
iMesh.addInstances(5000, (obj, index) => {
// Position in a grid
obj.position.set(
(index % 100) * 2 - 100,
0,
Math.floor(index / 100) * 2 - 50
);
obj.quaternion.random();
obj.scale.setScalar(0.5 + Math.random());
obj.color = Math.random() * 0xffffff;
obj.speed = Math.random() * 2; // custom field
// updateMatrix() is called automatically after onCreation returns
});
console.log(iMesh.instancesCount); // 5000
```
```
--------------------------------
### setOpacityAt and getOpacityAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Methods for setting and retrieving the per-instance opacity. Opacity is stored in the alpha channel of the colors texture and requires specific material and sorting settings for correct rendering.
```APIDOC
## setOpacityAt(id, value) / getOpacityAt(id)
### Description
Sets per-instance opacity (0–1). Stored in the alpha channel of `colorsTexture`. For correct visual output, combine with `sortObjects = true` and a transparent material.
### Parameters
- **id** (number): The ID of the instance.
- **value** (number): The opacity value (0.0 to 1.0).
### Usage
#### `setOpacityAt(id, value)`
Sets the opacity for the specified instance.
```ts
import { MeshStandardMaterial } from 'three';
const iMesh = new InstancedMesh2(
geometry,
new MeshStandardMaterial({ transparent: true }),
{ capacity: 200 }
);
iMesh.addInstances(200, (obj, i) => {
obj.position.set(i * 1.2, 0, 0);
});
iMesh.sortObjects = true; // required for correct transparency
iMesh.setOpacityAt(0, 0.1);
iMesh.setOpacityAt(1, 0.5);
iMesh.setOpacityAt(2, 1.0);
```
#### `getOpacityAt(id)`
Retrieves the opacity of the specified instance.
```ts
console.log(iMesh.getOpacityAt(0)); // 0.1
```
```
--------------------------------
### Initialize and Set Per-Instance Uniforms
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Assign unique shader uniforms to each instance. This works with all materials. Uniforms can be initialized for fragment or vertex shaders and then set per instance by index or directly on the instance object.
```typescript
myInstancedMesh.initUniformsPerInstance({ fragment: { metalness: 'float', roughness: 'float', emissive: 'vec3' } });
myInstancedMesh.setUniformAt(index, 'metalness', 0.5);
myInstancedMesh.instances[0].setUniform('emissive', new Color('white')); // if instances array is created
```
--------------------------------
### setColorAt and getColorAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Methods for setting and retrieving the per-instance color. Supports various color representations and initializes a colors texture if needed.
```APIDOC
## setColorAt(id, color) / getColorAt(id, color?)
### Description
Sets or reads the per-instance color. Accepts any `ColorRepresentation` (hex number, CSS string, `Color` instance). Internally initializes a `colorsTexture` on first use.
### Parameters
- **id** (number): The ID of the instance.
- **color** (ColorRepresentation): The color to set. Can be a hex number, CSS string, or `THREE.Color` instance.
- **color?** (Color): Optional `THREE.Color` instance to read the color into.
### Usage
#### `setColorAt(id, color)`
Sets the color for the specified instance.
```ts
import { Color } from 'three';
// Set colors during creation
iMesh.addInstances(3, (obj, i) => {
obj.color = ['red', 'lime', 'blue'][i]; // CSS color string
});
// Update individual instance color later
iMesh.setColorAt(1, 0x00ff00);
iMesh.setColorAt(2, new Color(0, 0, 1));
```
#### `getColorAt(id, color?)`
Reads the color of the specified instance. If a `Color` object is provided, it will be populated with the instance's color; otherwise, a new `Color` instance will be returned.
```ts
const col = new Color();
iMesh.getColorAt(0, col);
console.log(col.getHexString()); // 'ff0000'
```
```
--------------------------------
### Custom Frustum Enter Callback
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/06-frustum-culling.mdx
Implement a callback function that is executed for each instance entering the camera's frustum. Return true to render the instance; this is useful for conditional rendering based on distance.
```typescript
iMesh.onFrustumEnter = (index, camera) => {
// render only if not too far away
return iMesh.getPositionAt(index).distanceTo(camera.position) <= maxDistance;
};
```
--------------------------------
### InstancedMesh2 with Dynamic Capacity
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Instantiate InstancedMesh2 with a specified capacity. Use addInstances to add new instances, which will expand the buffer if necessary. removeInstances and clearInstances manage existing instances.
```typescript
const myInstancedMesh = new InstancedMesh2(geometry, material, { capacity: count });
myInstancedMesh.addInstances(count, (obj, index) => { ... }); // add instances and expand buffer if necessary
myInstancedMesh.removeInstances(id0, id1, ...);
myInstancedMesh.clearInstances(); // remove all instances
```
--------------------------------
### Create InstancedMesh2 from Existing Mesh
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Use this factory utility to upgrade an existing InstancedMesh, Mesh, or SkinnedMesh to InstancedMesh2, copying geometry, material, and instance data. Set 'capacity' for the new mesh and 'createEntities' if per-instance access is needed.
```typescript
import { createInstancedMesh2From } from '@three.ez/instanced-mesh';
import { InstancedMesh, BoxGeometry, MeshStandardMaterial, Matrix4 } from 'three';
// Existing InstancedMesh with 500 pre-placed instances
const old = new InstancedMesh(new BoxGeometry(), new MeshStandardMaterial(), 500);
for (let i = 0; i < 500; i++) {
const m = new Matrix4().makeTranslation(i, 0, 0);
old.setMatrixAt(i, m);
old.setColorAt(i, { r: Math.random(), g: Math.random(), b: Math.random() });
}
old.instanceMatrix.needsUpdate = true;
// Upgrade to InstancedMesh2 — matrices and colors are copied
const iMesh = createInstancedMesh2From(old, {
capacity: 1000,
createEntities: true,
});
// Now has all InstancedMesh2 features
iMesh.computeBVH();
iMesh.sortObjects = true;
console.log(iMesh.instancesCount); // 500
```
--------------------------------
### Enable InstancedEntity Creation
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/01-Instancedentity.mdx
Set the `createEntities` flag to `true` in the InstancedMesh2 constructor parameters to automatically generate InstancedEntity objects for each instance.
```typescript
const iMesh = new InstancedMesh2(geo, mat, { createEntities: true });
```
--------------------------------
### copyTo
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Copies an instance's world-space transform into a standard three.js Object3D (position, quaternion, scale).
```APIDOC
## `copyTo(id, target)` / `InstancedEntity.copyTo(target)`
Copies an instance's world-space transform into a standard three.js `Object3D` (position, quaternion, scale).
### Parameters
- **id** (number) - The index of the instance to copy.
- **target** (Object3D) - The target Object3D to copy the transform to.
### Usage
```ts
import { Object3D } from 'three';
const dummy = new Object3D();
// Copy instance 7's transform to dummy
iMesh.copyTo(7, dummy);
console.log(dummy.position);
// Via entity (if createEntities: true)
iMesh.instances[7].copyTo(dummy);
```
```
--------------------------------
### setVisibilityAt and getVisibilityAt
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Methods to control the visibility of individual instances, allowing them to be hidden or shown without removal.
```APIDOC
## setVisibilityAt(id, visible) / getVisibilityAt(id)
### Description
Hides or shows individual instances without removing them. Hidden instances are excluded from the render index every frame.
### Parameters
- **id** (number): The ID of the instance.
- **visible** (boolean): `true` to show the instance, `false` to hide it.
### Usage
#### `setVisibilityAt(id, visible)`
Sets the visibility state for the specified instance.
```ts
// Hide every other instance
for (let i = 0; i < iMesh.instancesCount; i += 2) {
iMesh.setVisibilityAt(i, false);
}
// Re-show instance 4
iMesh.setVisibilityAt(4, true);
```
#### `getVisibilityAt(id)`
Retrieves the visibility state of the specified instance.
```ts
console.log(iMesh.getVisibilityAt(4)); // true
console.log(iMesh.getVisibilityAt(0)); // false
```
```
--------------------------------
### InstancedEntity Properties and Methods
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Each instance in InstancedMesh2 (when createEntities is true) is an InstancedEntity object with transform properties (position, scale, quaternion, rotation), visibility, color, opacity, and helper methods. Remember to call updateMatrix() or updateMatrixPosition() after changing transforms.
```APIDOC
## InstancedEntity
### Description
Object3D-like instance manipulation for individual entities within an InstancedMesh.
### Properties
- **position** (Vector3): The position of the instance.
- **scale** (Vector3): The scale of the instance.
- **quaternion** (Quaternion): The quaternion representing the rotation of the instance.
- **rotation** (Euler): The Euler rotation of the instance (optional).
- **visible** (boolean): Whether the instance is visible.
- **color** (ColorRepresentation): The color of the instance.
- **opacity** (number): The opacity of the instance (0-1).
### Methods
- **updateMatrix()**: Updates the instance's transformation matrix. Call after changing transforms.
- **updateMatrixPosition()**: Updates only the position part of the transformation matrix. Faster when only position changes.
- **remove()**: Removes the instance.
### Example Usage
```ts
iMesh.instances[id].position.set(x, y, z);
iMesh.instances[id].rotateY(0.01);
iMesh.instances[id].updateMatrix();
iMesh.instances[id].visible = false;
iMesh.instances[id].color = 0xff0000;
iMesh.instances[id].opacity = 0.5;
iMesh.instances[id].remove();
```
```
--------------------------------
### Set Per-Instance Opacity
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Adjust the opacity of individual instances. For best results, enable instance sorting and disable depth writing on the material.
```typescript
myInstancedMesh.setOpacityAt(index, 0.5);
myInstancedMesh.instances[0].opacity = 0.5; // if instances array is created
```
--------------------------------
### Compute and Dispose BVH for InstancedMesh2
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Build a dynamic Bounding Volume Hierarchy (BVH) for efficient frustum culling and raycasting. The BVH updates automatically if `autoUpdateBVH` is true. Call `computeBVH` after populating instances. Use `disposeBVH` for cleanup.
```typescript
import { InstancedMesh2 } from '@three.ez/instanced-mesh';
import { OctahedronGeometry, MeshLambertMaterial, Vector3 } from 'three';
type Data = { dir: Vector3 };
const iMesh = new InstancedMesh2(
new OctahedronGeometry(1, 2),
new MeshLambertMaterial(),
{ capacity: 50000, createEntities: true }
);
iMesh.addInstances(50000, (obj) => {
obj.dir = new Vector3().randomDirection();
obj.position.randomDirection().multiplyScalar(Math.random() * 3000);
obj.scale.setScalar(1 + Math.random() * 4);
});
// Build BVH after all instances are placed
iMesh.computeBVH({
margin: 75, // tolerance for moving objects (0 = static)
getBBoxFromBSphere: true, // faster bbox approx (geometry must be origin-centered)
accurateCulling: true, // re-check margin nodes precisely
});
// Animate — BVH nodes update automatically via updateMatrixPosition
renderer.setAnimationLoop((delta) => {
for (const obj of iMesh.instances) {
if (!obj.active) continue;
obj.position.addScaledVector(obj.dir, delta * 10);
obj.updateMatrixPosition(); // triggers bvh.move(id) internally
}
renderer.render(scene, camera);
});
// Intersect a box with the BVH
import { Box3 } from 'three';
const queryBox = new Box3().setFromCenterAndSize(
new Vector3(0, 0, 0),
new Vector3(100, 100, 100)
);
iMesh.bvh.intersectBox(queryBox, (id) => {
console.log('Instance inside box:', id);
return true; // continue iterating
});
// Teardown
iMesh.disposeBVH();
```
--------------------------------
### InstancedMesh2 with Object3D-like Instances
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Create InstancedMesh2 with entities that mimic Object3D behavior. Transformations on these entities require an explicit call to updateMatrix().
```typescript
const myInstancedMesh = new InstancedMesh2(geometry, material, { createEntities: true });
myInstancedMesh.instances[0].customData = {};
myInstancedMesh.instances[0].position.random();
myInstancedMesh.instances[0].rotateX(Math.PI);
myInstancedMesh.instances[0].updateMatrix(); // necessary after transformations
```
--------------------------------
### dispose
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Releases all GPU resources (textures) allocated by the InstancedMesh2.
```APIDOC
## `dispose()`
Releases all GPU resources (textures) allocated by the `InstancedMesh2`.
### Usage
```ts
// Cleanup on scene teardown
iMesh.dispose();
scene.remove(iMesh);
```
```
--------------------------------
### Update All Instances with Callback
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Uses `updateInstances` to apply a transformation to all active instances, automatically calling `updateMatrix()`.
```typescript
// Rotate all instances every frame
scene.addEventListener('before-render', () => {
iMesh.updateInstances((obj) => {
obj.rotateY(0.01);
// updateMatrix() is called automatically
});
});
```
--------------------------------
### `sortObjects` / `createRadixSort(target)`
Source: https://context7.com/agargaro/instanced-mesh/llms.txt
Enables depth-based sorting before each render, which is useful for transparency and overdraw reduction. `createRadixSort` provides a faster sort implementation.
```APIDOC
## `sortObjects` / `createRadixSort(target)`
`sortObjects` (default `false`) enables depth-based sorting before each render — useful for transparency and overdraw reduction. `createRadixSort` provides a faster sort implementation based on three.js's radix sort utility.
```ts
import { InstancedMesh2, createRadixSort } from '@three.ez/instanced-mesh';
import { MeshStandardMaterial, SphereGeometry } from 'three';
const iMesh = new InstancedMesh2(
new SphereGeometry(1),
new MeshStandardMaterial({ transparent: true, opacity: 0.6 }),
{ capacity: 5000 }
);
iMesh.sortObjects = true;
iMesh.customSort = createRadixSort(iMesh); // ~3× faster than default sort
iMesh.addInstances(5000, (obj, i) => {
obj.position.set(
Math.random() * 100 - 50,
Math.random() * 100 - 50,
Math.random() * 100 - 50
);
obj.color = Math.random() * 0xffffff;
});
```
```
--------------------------------
### Enable Instance Sorting
Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/07-sorting.mdx
Set `iMesh.sortObjects` to `true` to enable automatic sorting of instances. This is useful for avoiding GPU overdraw and correctly rendering transparent objects. The default value is `false`.
```typescript
iMesh.sortObjects = true; // default is false
```
--------------------------------
### Add Shadow Level of Detail (LOD)
Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md
Optimize shadow rendering by adding simplified geometries for instances that cast shadows, based on their distance from the camera.
```typescript
myInstancedMesh.addShadowLOD(geometryMid);
myInstancedMesh.addShadowLOD(geometryLow, 100);
```