用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/feliperyba/ralph-orchestra --skill dev-patterns-object-pooling命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Complete Developer workflow orchestration - task research sequence, implementation flow, validation gates, PRD synchronization, exit conditions.
Complete Game Designer workflow - skill invocation protocol, GDD creation, playtest flow with GDD review, design sessions. MUST load before starting assignments.
Complete PM Coordinator workflow - task assignment, project orchestration, PRD management, worker coordination. Use proactively when starting PM agent work.
正在显示 SKILL.md
基于 SOC 职业分类
| name | dev-patterns-object-pooling |
| description | Object pooling for high-performance R3F components (decals, particles, projectiles) |
| category | patterns |
"Pre-allocate, reuse, recycle – eliminate runtime GC pauses."
Use when:
// Basic object pool pattern
const POOL_SIZE = 500;
const MAX_ACTIVE = 200;
interface PoolSlot<T> {
obj: T;
active: boolean;
lastUsed: number;
}
function useObjectPool<T>(
create: () => T,
activate: (obj: T) => void,
deactivate: (obj: T) => void
) {
const poolRef = useRef<PoolSlot<T>[]>([]);
// Initialize pool on mount
useEffect(() => {
poolRef.current = Array.from({ length: POOL_SIZE }, () => ({
obj: create(),
active: false,
lastUsed: 0,
}));
return () => {
// Cleanup
poolRef.current.forEach(slot => {
if (slot.obj?.dispose) slot.obj.dispose();
});
};
}, []);
const acquire = useCallback(() => {
const pool = poolRef.current;
// Find inactive slot
let slot = pool.find(s => !s.active);
// If pool full, recycle LRU
if (!slot) {
slot = pool.reduce((oldest, s) =>
s.lastUsed < oldest.lastUsed ? s : oldest
);
deactivate(slot.obj);
}
slot.active = true;
slot.lastUsed = performance.now();
activate(slot.obj);
return slot.obj;
}, [activate]);
const release = useCallback((obj: T) => {
const slot = poolRef.current.find(s => s.obj === obj);
if (slot) slot.active = false;
}, []);
return { acquire, release };
}
| Scenario | Use Pool? | Reason |
|---|---|---|
| Bullets (max ~100 active) | Yes | High create/destroy rate |
| Decals (max ~200 visible) | Yes | Geometry allocation costly |
| Particles (max ~500) | Yes | Per-frame creation |
| UI overlays (dynamic count) | No | Unpredictable count |
| Player characters (1-32) | No | Low churn, complex init |
| Static props | No | Never destroyed |
When the pool is full, evict the Least Recently Used item:
// LRU recycling
let slot = pool.find(s => !s.active);
if (!slot) {
// Pool exhausted - recycle oldest decal
slot = pool.reduce((oldest, s) =>
s.lastUsed < oldest.lastUsed ? s : oldest
);
// Fade out before recycling
fadeOutDecal(slot.obj);
}
Why LRU?
// BAD: Creates new objects every frame
useFrame(() => {
const position = new Vector3();
const quaternion = new Quaternion();
// ... do work
});
// GOOD: Reuse temp objects
const _tempVec = useRef(new Vector3()).current;
const _tempQuat = useRef(new Quaternion()).current;
useFrame(() => {
_tempVec.set(0, 0, 0); // Reset, don't reallocate
_tempQuat.identity();
// ... do work
});
| Object Type | Suggested Pool Size | Max Active | Rationale |
|---|---|---|---|
| Bullets | 200 | 100 | Fast fire rate ~10/sec |
| Particles | 1000 | 500 | Explosions spawn many at once |
| Decals | 500 | 200 | Persist 60s, but limited visibility |
| Audio sources | 32 | 16 | WebAudio limit |
Rule of thumb: poolSize = maxActive * 2 to maxActive * 3
active flag to track in-use slotslastUsed timestamp for LRU evictionuseRef or class fieldsfrustumCulled={false} for small objects| Pitfall | Symptom | Fix |
|---|---|---|
| Sharing material across slots | All decals same color | Create unique material per slot |
| Forgetting to reset state | Stale data on reuse | Reset all props in activate() |
| Pool too small | Visible popping | Increase pool or maxActive |
| No disposal in useEffect | Memory leak | Add cleanup function |
Using new in useFrame | GC stutter | Use temp refs |
See: src/components/game/effects/PaintDecalManager.tsx
Key sections: