Skip to content
Back to skills

058 Techniques 22c1ff72

ASecurity

Techniques for fast, smooth 3D experiences.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentjavascriptrustgojavaperformance

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 058-techniques_22c1ff72 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 058 Techniques 22c1ff72?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 058 Techniques 22c1ff72
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-058-techniques-22c1ff72/badge)](https://www.skillsdirectory.com/skills/tools-only-058-techniques-22c1ff72)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Performance Optimization

Techniques for fast, smooth 3D experiences.

## Instancing

Render many copies of same geometry efficiently:

```javascript
// Instead of creating 10,000 individual meshes
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.InstancedMesh(geometry, material, 10000);

// Set transforms for each instance
const matrix = new THREE.Matrix4();
const position = new THREE.Vector3();
const rotation = new THREE.Euler();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3(1, 1, 1);

for (let i = 0; i < 10000; i++) {
  position.set(
    Math.random() * 100 - 50,
    Math.random() * 100 - 50,
    Math.random() * 100 - 50
  );

  rotation.set(
    Math.random() * Math.PI,
    Math.random() * Math.PI,
    Math.random() * Math.PI
  );

  quaternion.setFromEuler(rotation);
  matrix.compose(position, quaternion, scale);
  mesh.setMatrixAt(i, matrix);
}

mesh.instanceMatrix.needsUpdate = true;
scene.add(mesh);

// Per-instance colors
mesh.instanceColor = new THREE.InstancedBufferAttribute(
  new Float32Array(10000 * 3),
  3
);

for (let i = 0; i < 10000; i++) {
  mesh.setColorAt(i, new THREE.Color(Math.random(), Math.random(), Math.random()));
}
```

## Level of Detail (LOD)

Switch between detail levels based on distance:

```javascript
const lod = new THREE.LOD();

// High detail (close)
const geometryHigh = new THREE.IcosahedronGeometry(10, 4);
const meshHigh = new THREE.Mesh(geometryHigh, material);
lod.addLevel(meshHigh, 0);

// Medium detail
const geometryMed = new THREE.IcosahedronGeometry(10, 2);
const meshMed = new THREE.Mesh(geometryMed, material);
lod.addLevel(meshMed, 50);

// Low detail (far)
const geometryLow = new THREE.IcosahedronGeometry(10, 0);
const meshLow = new THREE.Mesh(geometryLow, material);
lod.addLevel(meshLow, 100);

scene.add(lod);

// Update LOD in animation loop
function animate() {
  lod.update(camera);
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}
```

## Frustum Culling

Automatic - objects outside camera view aren't rendered.

```javascript
// Force disable for specific object
object.frustumCulled = false;

// Manually test if in view
const frustum = new THREE.Frustum();
const cameraViewProjectionMatrix = new THREE.Matrix4();
cameraViewProjectionMatrix.multiplyMatrices(
  camera.projectionMatrix,
  camera.matrixWorldInverse
);
frustum.setFromProjectionMatrix(cameraViewProjectionMatrix);

if (frustum.intersectsObject(object)) {
  // Object is visible
}
```

## Geometry Optimization

```javascript
// Merge geometries (reduce draw calls)
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';

const geometries = [geom1, geom2, geom3];
const mergedGeometry = mergeGeometries(geometries);
const mesh = new THREE.Mesh(mergedGeometry, material);

// Dispose old geometries
geometries.forEach(g => g.dispose());

// Simplify geometry
import { SimplifyModifier } from 'three/addons/modifiers/SimplifyModifier.js';

const modifier = new SimplifyModifier();
const simplified = modifier.modify(geometry, Math.floor(geometry.attributes.position.count * 0.5));
```

## Texture Optimization

```javascript
// Use appropriate sizes (power of 2)
// 512x512, 1024x1024, 2048x2048

// Compress textures
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';

// Use mipmaps (auto-generated by default)
texture.generateMipmaps = true;

// Appropriate filtering
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;

// Anisotropic filtering (balance quality/performance)
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

// Dispose unused textures
texture.dispose();
```

## Material Sharing

```javascript
// Share materials between meshes (reduce memory)
const sharedMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });

const mesh1 = new THREE.Mesh(geometry1, sharedMaterial);
const mesh2 = new THREE.Mesh(geometry2, sharedMaterial);
const mesh3 = new THREE.Mesh(geometry3, sharedMaterial);
```

## Shadow Optimization

```javascript
// Reduce shadow map resolution
light.shadow.mapSize.width = 1024;  // instead of 2048
light.shadow.mapSize.height = 1024;

// Limit shadow camera frustum
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 50;  // only cast shadows within this range
light.shadow.camera.left = -10;
light.shadow.camera.right = 10;

// Use fewer shadow-casting objects
object.castShadow = false; // for distant/small objects
object.receiveShadow = false; // for objects that don't need shadows

// Cheaper shadow type
renderer.shadowMap.type = THREE.PCFShadowMap; // instead of PCFSoftShadowMap
```

## Render Target Optimization

```javascript
// Lower resolution for post-processing
const renderTarget = new THREE.WebGLRenderTarget(
  window.innerWidth * 0.5,  // half resolution
  window.innerHeight * 0.5
);

// Appropriate pixel format
renderTarget.texture.format = THREE.RGBAFormat;
renderTarget.texture.type = THREE.UnsignedByteType;

// Dispose when done
renderTarget.dispose();
```

## Object Pooling

```javascript
// Reuse objects instead of creating/destroying
class ObjectPool {
  constructor(factory, initialSize) {
    this.factory = factory;
    this.pool = [];
    for (let i = 0; i < initialSize; i++) {
      this.pool.push(factory());
    }
  }

  get() {
    return this.pool.length > 0 ? this.pool.pop() : this.factory();
  }

  release(obj) {
    this.pool.push(obj);
  }
}

const bulletPool = new ObjectPool(() => {
  return new THREE.Mesh(bulletGeometry, bulletMaterial);
}, 100);

// Use
const bullet = bulletPool.get();
scene.add(bullet);

// Return when done
scene.remove(bullet);
bulletPool.release(bullet);
```

## Monitoring Performance

```javascript
// FPS counter
const stats = new Stats();
document.body.appendChild(stats.dom);

function animate() {
  stats.begin();
  // ... rendering
  stats.end();
  requestAnimationFrame(animate);
}

// Renderer info
console.log(renderer.info);
// Shows: geometries, textures, programs, calls, triangles, points, lines

// GPU timing
const query = renderer.extensions.get('EXT_disjoint_timer_query_webgl2');
```

## General Best Practices

- Limit draw calls (merge geometries, use instancing)
- Reduce polygon count (LOD, simplification)
- Optimize textures (compression, appropriate sizes)
- Share materials and geometries
- Use frustum culling
- Limit number of lights (3-5 max)
- Avoid transparent materials when possible
- Use object pooling for frequently created/destroyed objects
- Profile with browser DevTools
- Test on target devices
- Use WebGL 2 features when available

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.