Claude-skill-registry dev-performance-performance-basics

Core R3F/Three.js performance optimization principles. Use when FPS drops below 60.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dev-performance-performance-basics" ~/.claude/skills/majiayu000-claude-skill-registry-dev-performance-performance-basics && rm -rf "$T"
manifest: skills/data/dev-performance-performance-basics/SKILL.md
source content

Performance Optimization Basics

"Optimize for mobile, scale up for desktop – 60 FPS is the goal."

When to Use

Use when:

  • FPS drops below 60
  • Debugging performance issues
  • Starting optimization work

The 16ms Budget (60 FPS)

SystemBudgetNotes
Input~1msEvent handling
Physics~3msRapier/Cannon updates
Game Logic~4msState, AI, animations
Render~5msThree.js draw calls
Buffer~3msSafety margin
Total16.67ms60 FPS target

Quick Start Canvas Config

// Performance-optimized Canvas
<Canvas
  dpr={[1, 2]} // Limit pixel ratio
  performance={{ min: 0.5 }} // Auto-reduce quality
  gl={{ antialias: false }} // Disable for mobile
>
  <Suspense fallback={null}>
    <Scene />
  </Suspense>
</Canvas>

Decision Framework

SymptomLikely CauseSolution
Low FPS everywhereToo many draw callsInstancing, merging
FPS drops on zoomLOD not implementedAdd LOD system
Mobile slowDPR too highLimit to 1.5
Memory growsDispose missingAdd cleanup
StutteringGC pressureObject pooling

Progressive Optimizations

Level 1: Basic

// Limit device pixel ratio
<Canvas dpr={Math.min(window.devicePixelRatio, 2)}>

// Disable expensive features on mobile
const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);

<Canvas
  shadows={!isMobile}
  gl={{
    antialias: !isMobile,
    powerPreference: 'high-performance',
  }}
>

Level 2: Object Reuse

// Reuse Vector3, Quaternion instances
const position = useRef(new THREE.Vector3());
const rotation = useRef(new THREE.Quaternion());

useFrame(() => {
  position.current.set(0, 0, 0); // Reuse, don't create
});

Level 3: Memory Management

// CRITICAL: Dispose of Three.js objects
useEffect(() => {
  const geometry = new THREE.BoxGeometry();
  const material = new THREE.MeshStandardMaterial();

  return () => {
    geometry.dispose();
    material.dispose();
    if (material.map) material.map.dispose();
  };
}, []);

Performance Monitoring

import { useFrame } from '@react-three/fiber';
import { useRef } from 'react';

function PerformanceMonitor() {
  const frameCount = useRef(0);
  const lastTime = useRef(performance.now());

  useFrame(() => {
    frameCount.current++;

    const now = performance.now();
    if (now - lastTime.current >= 1000) {
      console.log(`FPS: ${frameCount.current}`);
      frameCount.current = 0;
      lastTime.current = now;
    }
  });

  return null;
}

Anti-Patterns

DON'T:

  • Create objects inside useFrame
  • Skip dispose() calls
  • Use shadows on mobile without testing
  • Render invisible objects
  • Use uncompressed textures

DO:

  • Reuse Vector3, Quaternion instances
  • Always dispose geometries and materials
  • Profile before and after optimizations
  • Compress textures (WebP, Basis)

Checklist

  • DPR limited appropriately
  • No object creation in useFrame
  • Dispose called on cleanup
  • Shadows disabled on mobile
  • Textures compressed
  • FPS stable at 60

Common Performance Killers

  1. Too many draw calls → Use Instances
  2. High polygon count → Use LOD
  3. Unoptimized textures → Compress, resize
  4. No frustum culling → Enable frustumCulled
  5. Memory leaks → Call dispose()
  6. GC pressure → Object pooling

Reference