Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when building a 3D web game with three.js, Babylon.js or PlayCanvas - render loop and delta per library, fixed-step physics with Rapier or Havok, explicit dispose of GPU resources, instancing and draw-call budgets, glTF with Draco/meshopt/KTX2, pixel ratio and resize, WebGPU opt-in, React Three Fiber notes, and headless testing.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
three.js is a rendering library with a huge ecosystem; Babylon.js is a full engine (physics plugin, GUI, inspector, a NullEngine for headless tests); PlayCanvas is an engine built around its hosted editor, also usable engine-only. All three hand you the GPU directly — and with it the job of freeing what you allocate, keeping draw calls low, and staying inside a mobile browser's memory.
Core principle: Simulate on a fixed step, render every frame, dispose every GPU resource you create, and count draw calls.
// three.js — Timer replaces the deprecated Clock (r183+); setAnimationLoop also drives WebXR
const timer = new THREE.Timer();
timer.connect(document); // ignores the huge delta after a hidden tab
renderer.setAnimationLoop((t) => {
timer.update(t);
const dt = Math.min(timer.getDelta(), 0.25); // seconds
stepFixed(dt); // accumulator: physics + rules at 1/60 (game-loop-and-time)
renderer.render(scene, camera);
});
// Babylon.js — getDeltaTime() is milliseconds
scene.onBeforeRenderObservable.add(() => stepFixed(Math.min(engine.getDeltaTime() / 1000, 0.25)));
engine.runRenderLoop(() => scene.render());
window.addEventListener("resize", () => engine.resize());
// PlayCanvas (engine API / ESM scripts) — dt in seconds
export class Spin extends Script {
static scriptName = "spin";
speed = 90;
update(dt: number) { this.entity.rotate(0, this.speed * dt, 0); }
}
await RAPIER.init(), world.timestep = 1 / 60, call world.step() from the accumulator, copy body transforms to meshes with interpolation. The deterministic build exists for lockstep/rollback.new HavokPlugin(true, await HavokPhysics())); keep its fixed timestep consistent across devices.mesh.position; set velocities/impulses or use kinematic bodies.// ❌ removing from the scene does not free GPU memory
scene.remove(level);
// ✅ free geometry, materials and textures explicitly (unless shared with something still alive)
level.traverse((o) => {
if (o instanceof THREE.Mesh) {
o.geometry.dispose();
for (const m of Array.isArray(o.material) ? o.material : [o.material]) {
for (const v of Object.values(m)) if (v instanceof THREE.Texture) v.dispose();
m.dispose();
}
}
});
scene.remove(level);
console.assert(renderer.info.memory.geometries <= baseline.geometries);
PMREMGenerator outputs, and the renderer itself on teardown. renderer.info.memory before and after a level change is the leak test.mesh.dispose(false, true) frees materials and textures too; load levels into an AssetContainer and dispose() it on exit; scene.dispose() / engine.dispose() on teardown.entity.destroy(), and asset.unload() for assets no longer used.THREE.InstancedMesh (setMatrixAt + instanceMatrix.needsUpdate = true, count for the live number) or Babylon thin instances (mesh.thinInstanceAdd(matrix)).BufferGeometryUtils.mergeGeometries, Babylon Mesh.MergeMeshes) and share materials.renderer.info.render.calls, Babylon Inspector's statistics) before and after.castShadow only where it shows; bake lighting for static scenes.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); resize from the canvas size, not the window, with a ResizeObserver.GLTFLoader + DRACOLoader / MeshoptDecoder + KTX2Loader (decoder files served from the app's own path); Babylon's glTF loader with its Draco/KTX2 support; LoadAssetContainerAsync to keep a level's assets disposable together.npx @gltf-transform/cli optimize) and keep originals out of the shipped bundle (game-asset-pipeline).three.js WebGPURenderer (from three/webgpu, falling back to WebGL2) and Babylon WebGPUEngine are usable; adopt them only when the repository or task opts in — shader code, post-processing and some materials differ between the paths.
useFrame((state, delta) => ...) mutates refs; never setState per frame. Dispose is automatic for objects R3F created declaratively, not for ones you created imperatively. <Instances> / <instancedMesh> for repetition.
new NullEngine() + new Scene(engine) runs scene logic headless in Vitest (no pixels).scene.remove without dispose — memory grows every level.new THREE.Vector3() in the frame loop instead of reusing module-level temporaries.THREE.Clock in new code on a revision that deprecated it.dispose() call anywhere in a project that loads more than one level.renderer.info.render.calls in the thousands on a mobile target.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
日本語の概要は準備中です。原文の説明を表示しています。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
日本語の概要は準備中です。原文の説明を表示しています。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
日本語の概要は準備中です。原文の説明を表示しています。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
日本語の概要は準備中です。原文の説明を表示しています。
Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。