一键导入
webgl-performance-optimizer
Optimize Three.js and WebGL performance, reduce GPU load, suggest fallback UI strategies, and maintain 60fps experience.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Optimize Three.js and WebGL performance, reduce GPU load, suggest fallback UI strategies, and maintain 60fps experience.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Agent-to-Agent (A2A) messaging system for direct communication between Cloud and Local agents. Replaces file-based handoffs with real-time messaging while maintaining vault as audit record. Supports task delegation, status updates, approval requests, and result delivery between distributed AI Employee instances. Use when coordinating multiple Claude Code agents across cloud and local environments.
Implements the core Customer Success Agent using OpenAI Agents SDK. Manages the orchestration of tool calls (search, ticket creation, etc.), conversation logic, and state management. Use when Claude needs to create or modify Customer Success Agent implementations with OpenAI Agents SDK, orchestrate multiple tools, manage conversation flows, or handle persistent state across interactions.
Generate valid AGENTS.md files for repositories according to AAIF standards. Use when Claude needs to create or update AGENTS.md files that document AI agents in a repository following standard format and best practices.
Design learning experiences for AI-native software development, integrating the Three Roles Framework (AI as Teacher/Student/Co-Worker), co-learning partnership pedagogy, and "Specs Are the New Syntax" paradigm into programming curriculum. Use this skill when educators need to prepare students for professional AI-driven development workflows, teach effective specification-first collaboration, or balance AI assistance with foundational learning goals. This skill helps create lessons that leverage AI tools appropriately while ensuring students build independent capability, bidirectional learning patterns, and ethical AI use practices. Aligned with Constitution v4.0.1.
Expert in LLM integration (Claude/GPT), RAG systems for self-learning, and WhatsApp Business API for remote approval workflows. Use when: (1) Designing prompts for Claude or GPT models with system prompts and few-shot learning, (2) Implementing multi-agent orchestration with specialized agent prompts, (3) Setting up RAG systems with vector databases (Pinecone, ChromaDB, Weaviate), (4) Implementing document chunking, embedding generation, and retrieval strategies, (5) Building WhatsApp approval workflows with interactive messages and buttons, (6) Integrating feedback loops for continuous learning, (7) Optimizing LLM API calls with error handling and retries, (8) Creating message templates for WhatsApp Business API. Provides prompt templates, RAG implementation patterns, WhatsApp message templates, and comprehensive reference documentation.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
| name | webgl-performance-optimizer |
| description | Optimize Three.js and WebGL performance, reduce GPU load, suggest fallback UI strategies, and maintain 60fps experience. |
WebGL performance optimization is about intelligent resource management - knowing when to render, what to render, and how to render efficiently. Every frame has a budget of ~16.67ms to maintain 60fps. Your job is to ensure the GPU never exceeds this budget through smart geometry, texture, and draw call management.
Key Principles:
Use webgl-performance-optimizer when:
// Add Stats.js for real-time monitoring
import Stats from 'three/examples/jsm/libs/stats.module'
const StatsMonitor = () => {
const statsRef = useRef<Stats>()
useEffect(() => {
const stats = new Stats()
stats.showPanel(0) // 0: fps, 1: ms, 2: mb
stats.dom.style.position = 'absolute'
stats.dom.style.top = '0'
stats.dom.style.left = '0'
document.body.appendChild(stats.dom)
statsRef.current = stats
return () => document.body.removeChild(stats.dom)
}, [])
useFrame(() => {
statsRef.current?.update()
})
return null
}
// Usage in Canvas
<Canvas>
<StatsMonitor />
{/* Your scene */}
</Canvas>
Chrome DevTools GPU Profiling:
Problem: Each mesh = 1 draw call. Too many objects = GPU bottleneck.
Solution 1: Instanced Rendering
// Bad: 1000 draw calls for 1000 spheres
{particles.map((pos, i) => (
<mesh key={i} position={pos}>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="cyan" />
</mesh>
))}
// Good: 1 draw call for 1000 spheres using instancing
import { Instances, Instance } from '@react-three/drei'
<Instances limit={1000}>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="cyan" />
{particles.map((pos, i) => (
<Instance key={i} position={pos} />
))}
</Instances>
Solution 2: Geometry Merging
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils'
// Merge static geometries into single mesh
const MergedStaticObjects = () => {
const mergedGeometry = useMemo(() => {
const geometries = staticObjects.map(obj => {
const geo = new BoxGeometry(obj.size, obj.size, obj.size)
geo.translate(obj.position.x, obj.position.y, obj.position.z)
return geo
})
return mergeBufferGeometries(geometries)
}, [staticObjects])
return (
<mesh geometry={mergedGeometry}>
<meshStandardMaterial />
</mesh>
)
}
Reduce Polygon Count:
// Bad: High poly sphere (2400 triangles)
<sphereGeometry args={[1, 64, 64]} />
// Good: Low poly sphere (300 triangles) - visually similar with proper lighting
<sphereGeometry args={[1, 16, 16]} />
// Better: Adaptive detail based on screen size
const DetailedSphere = ({ radius, screenSize }) => {
const segments = screenSize > 1920 ? 32 : screenSize > 1280 ? 24 : 16
return <sphereGeometry args={[radius, segments, segments]} />
}
Use LOD (Level of Detail):
import { LOD } from 'three'
const AdaptiveMesh = ({ position }) => {
const lodRef = useRef<LOD>()
useEffect(() => {
const lod = new LOD()
// High detail (close)
const highGeo = new SphereGeometry(1, 32, 32)
const highMesh = new Mesh(highGeo, material)
lod.addLevel(highMesh, 0)
// Medium detail
const medGeo = new SphereGeometry(1, 16, 16)
const medMesh = new Mesh(medGeo, material)
lod.addLevel(medMesh, 10)
// Low detail (far)
const lowGeo = new SphereGeometry(1, 8, 8)
const lowMesh = new Mesh(lowGeo, material)
lod.addLevel(lowMesh, 20)
lodRef.current = lod
}, [])
return <primitive object={lodRef.current} position={position} />
}
Texture Compression and Sizing:
import { useTexture } from '@react-three/drei'
// Bad: 4K uncompressed texture (64MB memory)
const texture = useTexture('/texture-4k.png')
// Good: Compressed, appropriately sized texture (4MB memory)
const OptimizedTexture = () => {
const texture = useTexture('/texture-1k-compressed.jpg')
// Enable mipmaps for better performance at distance
texture.generateMipmaps = true
texture.minFilter = THREE.LinearMipmapLinearFilter
texture.magFilter = THREE.LinearFilter
// Anisotropic filtering (2-4 is usually enough)
texture.anisotropy = 2
return <meshStandardMaterial map={texture} />
}
Texture Atlasing:
// Bad: 10 separate textures = 10 texture binds per frame
materials.map(mat => <meshBasicMaterial map={mat.texture} />)
// Good: 1 texture atlas = 1 texture bind
// Combine multiple textures into single atlas, use UV offsets
const AtlasMaterial = ({ uvOffset, uvScale }) => {
const atlas = useTexture('/texture-atlas.jpg')
return (
<meshBasicMaterial
map={atlas}
map-offset={uvOffset}
map-repeat={uvScale}
/>
)
}
Avoid Expensive Operations:
// Bad: Expensive operations in fragment shader
varying vec3 vNormal;
varying vec3 vPosition;
void main() {
// Normalize in fragment shader (runs per-pixel)
vec3 normal = normalize(vNormal);
// Expensive calculations per pixel
float pattern = sin(vPosition.x * 100.0) * cos(vPosition.y * 100.0);
gl_FragColor = vec4(normal * pattern, 1.0);
}
// Good: Move calculations to vertex shader (runs per-vertex)
// Vertex Shader
attribute vec3 position;
attribute vec3 normal;
varying vec3 vNormal;
varying float vPattern;
void main() {
vNormal = normalize(normalMatrix * normal); // Normalize once per vertex
vPattern = sin(position.x * 100.0) * cos(position.y * 100.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
// Fragment Shader
varying vec3 vNormal;
varying float vPattern;
void main() {
gl_FragColor = vec4(vNormal * vPattern, 1.0);
}
Shader Precision:
// Use appropriate precision for mobile
precision mediump float; // Good for mobile (saves GPU power)
precision highp float; // Use only when necessary
// Mix precisions for optimal performance
varying lowp vec4 vColor; // Color doesn't need high precision
varying mediump vec2 vUv; // UVs need medium precision
varying highp vec3 vPosition; // Positions may need high precision
import { useThree } from '@react-three/fiber'
const FrustumCulledObject = ({ position, children }) => {
const { camera } = useThree()
const meshRef = useRef()
const [visible, setVisible] = useState(true)
useFrame(() => {
if (!meshRef.current) return
// Check if object is in camera frustum
const frustum = new THREE.Frustum()
const matrix = new THREE.Matrix4().multiplyMatrices(
camera.projectionMatrix,
camera.matrixWorldInverse
)
frustum.setFromProjectionMatrix(matrix)
const isVisible = frustum.intersectsObject(meshRef.current)
setVisible(isVisible)
})
return visible ? (
<group ref={meshRef} position={position}>
{children}
</group>
) : null
}
const PerformanceAdaptiveScene = () => {
const [quality, setQuality] = useState<'high' | 'medium' | 'low'>('high')
const fpsRef = useRef(60)
useFrame((state, delta) => {
// Monitor FPS
const currentFps = 1 / delta
fpsRef.current = fpsRef.current * 0.9 + currentFps * 0.1 // Smooth average
// Adaptive quality
if (fpsRef.current < 30 && quality !== 'low') {
setQuality('low')
} else if (fpsRef.current < 50 && quality === 'high') {
setQuality('medium')
} else if (fpsRef.current > 55 && quality !== 'high') {
setQuality('high')
}
})
return (
<>
{quality === 'high' && <HighQualityEffects />}
{quality === 'medium' && <MediumQualityEffects />}
{quality === 'low' && <MinimalEffects />}
<Instances limit={quality === 'high' ? 1000 : quality === 'medium' ? 500 : 200}>
{/* Adaptive particle count */}
</Instances>
</>
)
}
// Dispose of geometries and materials when unmounting
const ManagedMesh = () => {
const meshRef = useRef<THREE.Mesh>()
useEffect(() => {
return () => {
// Clean up on unmount
if (meshRef.current) {
meshRef.current.geometry.dispose()
if (Array.isArray(meshRef.current.material)) {
meshRef.current.material.forEach(mat => mat.dispose())
} else {
meshRef.current.material.dispose()
}
}
}
}, [])
return <mesh ref={meshRef}>{/* ... */}</mesh>
}
// Dispose textures
const textureRef = useRef<THREE.Texture>()
useEffect(() => {
return () => {
textureRef.current?.dispose()
}
}, [])
const WebGLDetector = () => {
const [webglAvailable, setWebglAvailable] = useState(true)
useEffect(() => {
const canvas = document.createElement('canvas')
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
setWebglAvailable(!!gl)
}, [])
if (!webglAvailable) {
return (
<div className="fallback-ui">
<h2>3D View Unavailable</h2>
<p>Your browser doesn't support WebGL. Here's a 2D alternative:</p>
<StaticImageFallback />
</div>
)
}
return <Canvas>{/* 3D Scene */}</Canvas>
}
const AdaptiveVisualization = () => {
const [mode, setMode] = useState<'3d' | '2d' | 'minimal'>('3d')
const performanceRef = useRef({ fps: 60, memory: 0 })
// Monitor performance and switch modes
useEffect(() => {
const checkPerformance = () => {
const { fps, memory } = performanceRef.current
if (fps < 20 || memory > 500) {
setMode('minimal')
} else if (fps < 40 || memory > 300) {
setMode('2d')
}
}
const interval = setInterval(checkPerformance, 5000)
return () => clearInterval(interval)
}, [])
return (
<>
{mode === '3d' && <Full3DScene />}
{mode === '2d' && <Simplified2DView />}
{mode === 'minimal' && <StaticFallback />}
</>
)
}
const QualitySettings = () => {
const [userQuality, setUserQuality] = useState<'auto' | 'high' | 'low'>('auto')
return (
<div className="quality-controls">
<select value={userQuality} onChange={e => setUserQuality(e.target.value)}>
<option value="auto">Auto</option>
<option value="high">High Quality</option>
<option value="low">Performance Mode</option>
</select>
<Canvas dpr={userQuality === 'low' ? [1, 1] : [1, 2]}>
<PerformanceOptimizedScene quality={userQuality} />
</Canvas>
</div>
)
}
<Canvas
// Limit pixel ratio for performance
dpr={[1, 2]} // Max 2x pixel ratio
// Performance-focused GL settings
gl={{
antialias: false, // Disable AA for performance (use FXAA in post if needed)
alpha: false, // Disable transparency if not needed
stencil: false, // Disable stencil buffer if not needed
depth: true, // Keep depth buffer for proper rendering
powerPreference: 'high-performance', // Request discrete GPU
failIfMajorPerformanceCaveat: true, // Fail on software rendering
}}
// Frame loop control
frameloop="demand" // Only render when needed (for static scenes)
// frameloop="always" // Use for animated scenes
// Camera settings
camera={{
fov: 50, // Narrower FOV = less to render
near: 0.1,
far: 100, // Tighter far plane = less depth buffer precision needed
}}
>
{/* Your scene */}
</Canvas>
dpr={[1, 2]} to limit pixel ratioframeloop="demand" for static scenesSee /references directory for:
optimization-techniques.md - Advanced optimization methodsfallback-strategies.md - Progressive enhancement approachesperformance-monitoring.md - Profiling and debugging tools"Premature optimization is the root of all evil, but so is premature de-optimization." - Profile first, optimize based on data, not assumptions. Always maintain 60fps on desktop and 30fps on mobile as your baseline targets.
threejs-react-ui-specialist — Build the Three.js scenes that this optimizer improvescanvas-design — Canvas 2D alternative for less demanding visual requirementsalgorithmic-art — Optimize generative art algorithms using WebGL performance techniques