Reorganize: Move all skills to skills/ folder
- Created skills/ directory - Moved 272 skills to skills/ subfolder - Kept agents/ at root level - Kept installation scripts and docs at root level Repository structure: - skills/ - All 272 skills from skills.sh - agents/ - Agent definitions - *.sh, *.ps1 - Installation scripts - README.md, etc. - Documentation Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,230 +0,0 @@
|
||||
---
|
||||
name: r3f-best-practices
|
||||
description: React Three Fiber (R3F) and Poimandres ecosystem best practices. Use when writing, reviewing, or optimizing R3F code. Triggers on tasks involving @react-three/fiber, @react-three/drei, zustand, @react-three/postprocessing, @react-three/rapier, or leva.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: three-agent-skills
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# React Three Fiber Best Practices
|
||||
|
||||
Comprehensive guide for React Three Fiber and the Poimandres ecosystem. Contains 60+ rules across 11 categories, prioritized by impact.
|
||||
|
||||
## When to Apply
|
||||
|
||||
Reference these guidelines when:
|
||||
- Writing new R3F components
|
||||
- Optimizing R3F performance (re-renders are the #1 issue)
|
||||
- Using Drei helpers correctly
|
||||
- Managing state with Zustand
|
||||
- Implementing post-processing or physics
|
||||
|
||||
## Ecosystem Coverage
|
||||
|
||||
- **@react-three/fiber** - React renderer for Three.js
|
||||
- **@react-three/drei** - Useful helpers and abstractions
|
||||
- **@react-three/postprocessing** - Post-processing effects
|
||||
- **@react-three/rapier** - Physics engine
|
||||
- **zustand** - State management
|
||||
- **leva** - Debug GUI
|
||||
|
||||
## Rule Categories by Priority
|
||||
|
||||
| Priority | Category | Impact | Prefix |
|
||||
|----------|----------|--------|--------|
|
||||
| 1 | Performance & Re-renders | CRITICAL | `perf-` |
|
||||
| 2 | useFrame & Animation | CRITICAL | `frame-` |
|
||||
| 3 | Component Patterns | HIGH | `component-` |
|
||||
| 4 | Canvas & Setup | HIGH | `canvas-` |
|
||||
| 5 | Drei Helpers | MEDIUM-HIGH | `drei-` |
|
||||
| 6 | Loading & Suspense | MEDIUM-HIGH | `loading-` |
|
||||
| 7 | State Management | MEDIUM | `state-` |
|
||||
| 8 | Events & Interaction | MEDIUM | `events-` |
|
||||
| 9 | Post-processing | MEDIUM | `postpro-` |
|
||||
| 10 | Physics (Rapier) | LOW-MEDIUM | `physics-` |
|
||||
| 11 | Leva (Debug GUI) | LOW | `leva-` |
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### 1. Performance & Re-renders (CRITICAL)
|
||||
|
||||
- `perf-never-set-state-in-useframe` - NEVER call setState in useFrame
|
||||
- `perf-isolate-state` - Isolate components that need React state
|
||||
- `perf-zustand-selectors` - Use Zustand selectors, not entire store
|
||||
- `perf-transient-subscriptions` - Use transient subscriptions for continuous values
|
||||
- `perf-memo-components` - Memoize expensive components
|
||||
- `perf-keys-for-lists` - Use stable keys for dynamic lists
|
||||
- `perf-avoid-inline-objects` - Avoid creating objects/arrays in JSX
|
||||
- `perf-dispose-auto` - Understand R3F auto-dispose behavior
|
||||
|
||||
### 2. useFrame & Animation (CRITICAL)
|
||||
|
||||
- `frame-priority` - Use priority for execution order
|
||||
- `frame-delta-time` - Always use delta for animations
|
||||
- `frame-conditional-subscription` - Disable useFrame when not needed
|
||||
- `frame-destructure-state` - Destructure only what you need
|
||||
- `frame-render-on-demand` - Use invalidate() for on-demand rendering
|
||||
- `frame-avoid-heavy-computation` - Move heavy work outside useFrame
|
||||
|
||||
### 3. Component Patterns (HIGH)
|
||||
|
||||
- `component-jsx-elements` - Use JSX for Three.js objects
|
||||
- `component-attach-prop` - Use attach for non-standard properties
|
||||
- `component-primitive` - Use primitive for existing objects
|
||||
- `component-extend` - Use extend() for custom classes
|
||||
- `component-forwardref` - Use forwardRef for reusable components
|
||||
- `component-dispose-null` - Set dispose={null} on shared resources
|
||||
|
||||
### 4. Canvas & Setup (HIGH)
|
||||
|
||||
- `canvas-size-container` - Canvas fills parent container
|
||||
- `canvas-camera-default` - Configure camera via prop
|
||||
- `canvas-gl-config` - Configure WebGL context
|
||||
- `canvas-shadows` - Enable shadows at Canvas level
|
||||
- `canvas-frameloop` - Choose appropriate frameloop mode
|
||||
- `canvas-events` - Configure event handling
|
||||
- `canvas-linear-flat` - Use linear/flat for correct colors
|
||||
|
||||
### 5. Drei Helpers (MEDIUM-HIGH)
|
||||
|
||||
- `drei-use-gltf` - useGLTF with preloading
|
||||
- `drei-use-texture` - useTexture for texture loading
|
||||
- `drei-environment` - Environment for realistic lighting
|
||||
- `drei-orbit-controls` - OrbitControls from Drei
|
||||
- `drei-html` - Html for DOM overlays
|
||||
- `drei-text` - Text for 3D text
|
||||
- `drei-instances` - Instances for optimized instancing
|
||||
- `drei-use-helper` - useHelper for debug visualization
|
||||
- `drei-bounds` - Bounds to fit camera
|
||||
- `drei-center` - Center to center objects
|
||||
- `drei-float` - Float for floating animation
|
||||
|
||||
### 6. Loading & Suspense (MEDIUM-HIGH)
|
||||
|
||||
- `loading-suspense` - Wrap async components in Suspense
|
||||
- `loading-preload` - Preload assets with useGLTF.preload
|
||||
- `loading-use-progress` - useProgress for loading UI
|
||||
- `loading-lazy-components` - Lazy load heavy components
|
||||
- `loading-error-boundary` - Handle loading errors
|
||||
|
||||
### 7. State Management (MEDIUM)
|
||||
|
||||
- `state-zustand-store` - Create focused Zustand stores
|
||||
- `state-avoid-objects-in-store` - Be careful with Three.js objects
|
||||
- `state-subscribeWithSelector` - Fine-grained subscriptions
|
||||
- `state-persist` - Persist state when needed
|
||||
- `state-separate-concerns` - Separate stores by concern
|
||||
|
||||
### 8. Events & Interaction (MEDIUM)
|
||||
|
||||
- `events-pointer-events` - Use pointer events on meshes
|
||||
- `events-stop-propagation` - Prevent event bubbling
|
||||
- `events-cursor-pointer` - Change cursor on hover
|
||||
- `events-raycast-filter` - Filter raycasting
|
||||
- `events-event-data` - Understand event data structure
|
||||
|
||||
### 9. Post-processing (MEDIUM)
|
||||
|
||||
- `postpro-effect-composer` - Use EffectComposer
|
||||
- `postpro-common-effects` - Common effects reference
|
||||
- `postpro-selective-bloom` - SelectiveBloom for optimized glow
|
||||
- `postpro-custom-shader` - Create custom effects
|
||||
- `postpro-performance` - Optimize post-processing
|
||||
|
||||
### 10. Physics Rapier (LOW-MEDIUM)
|
||||
|
||||
- `physics-setup` - Basic Rapier setup
|
||||
- `physics-body-types` - dynamic, fixed, kinematic
|
||||
- `physics-colliders` - Choose appropriate colliders
|
||||
- `physics-events` - Handle collision events
|
||||
- `physics-api-ref` - Use ref for physics API
|
||||
- `physics-performance` - Optimize physics
|
||||
|
||||
### 11. Leva (LOW)
|
||||
|
||||
- `leva-basic` - Basic Leva usage
|
||||
- `leva-folders` - Organize with folders
|
||||
- `leva-conditional` - Hide in production
|
||||
|
||||
## How to Use
|
||||
|
||||
Read individual rule files for detailed explanations and code examples:
|
||||
|
||||
```
|
||||
rules/perf-never-set-state-in-useframe.md
|
||||
rules/drei-use-gltf.md
|
||||
rules/state-zustand-selectors.md
|
||||
```
|
||||
|
||||
## Full Compiled Document
|
||||
|
||||
For the complete guide with all rules expanded: `../R3F_BEST_PRACTICES.md`
|
||||
|
||||
## Critical Patterns
|
||||
|
||||
### NEVER setState in useFrame
|
||||
|
||||
```jsx
|
||||
// BAD - 60 re-renders per second!
|
||||
function BadComponent() {
|
||||
const [position, setPosition] = useState(0);
|
||||
useFrame(() => {
|
||||
setPosition(p => p + 0.01); // NEVER DO THIS
|
||||
});
|
||||
return <mesh position-x={position} />;
|
||||
}
|
||||
|
||||
// GOOD - Mutate refs directly
|
||||
function GoodComponent() {
|
||||
const meshRef = useRef();
|
||||
useFrame(() => {
|
||||
meshRef.current.position.x += 0.01;
|
||||
});
|
||||
return <mesh ref={meshRef} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Zustand Selectors
|
||||
|
||||
```jsx
|
||||
// BAD - Re-renders on ANY store change
|
||||
const store = useGameStore();
|
||||
|
||||
// GOOD - Only re-renders when playerX changes
|
||||
const playerX = useGameStore(state => state.playerX);
|
||||
|
||||
// BETTER - No re-renders, direct mutation
|
||||
useFrame(() => {
|
||||
const { value } = useStore.getState();
|
||||
ref.current.position.x = value;
|
||||
});
|
||||
```
|
||||
|
||||
### Drei useGLTF
|
||||
|
||||
```jsx
|
||||
import { useGLTF } from '@react-three/drei';
|
||||
|
||||
function Model() {
|
||||
const { scene } = useGLTF('/model.glb');
|
||||
return <primitive object={scene} />;
|
||||
}
|
||||
|
||||
// Preload for instant loading
|
||||
useGLTF.preload('/model.glb');
|
||||
```
|
||||
|
||||
### Suspense Loading
|
||||
|
||||
```jsx
|
||||
function App() {
|
||||
return (
|
||||
<Canvas>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Model />
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
);
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user