Skip to content
Development
Skill

/improve-threejs

Audit and fix Three.js and React Three Fiber apps for frame-loop performance, GPU memory leaks, scene-graph correctness, and visual defects like z-fighting, shadow acne, wrong color space, and broken resize handling. Uses React Doctor as the scanning engine plus a visual rubric

From plugin
react-doctor
15k4 skills

Claude Code

$ npx -y skills add millionco/react-doctor --skill improve-threejs --agent claude-code

SKILL.md

improve-threejs.SKILL.md
name: improve-threejs
description: Audit and fix Three.js and React Three Fiber apps for frame-loop performance, GPU memory leaks, scene-graph correctness, and visual defects like z-fighting, shadow acne, wrong color space, and broken resize handling. Uses React Doctor as the scanning engine plus a visual rubric checked against rendered output. Use when the user asks to improve, audit, scan, or clean up a Three.js, R3F, react-three-fiber, drei, or WebGL app, or types `/improve-threejs`.

Improve Three.js

Audits a Three.js or React Three Fiber (R3F) codebase and fixes what hurts most: work that runs every frame, GPU resources that never get disposed, scene-graph objects rebuilt on every render, and visual defects the user can see. React Doctor supplies the machine-verified code scan; this skill supplies the frame-loop judgment and the visual inspection a general React scanner lacks.

The core principle: severity follows the render loop. Code inside `useFrame` or a `requestAnimationFrame` callback runs 60 times per second, so a minor inefficiency there outweighs a major one in a settings panel. Rank every finding by where it runs, not by the rule's default severity.

Workflow

Step 1: Recon

Identify the stack before scanning: plain Three.js or R3F, which helper libraries are in use (drei, postprocessing, rapier), and where the render loop lives (`useFrame` hooks, `requestAnimationFrame`, the `<Canvas frameloop>` setting).

Build a hot-path map: every `useFrame` body, every RAF callback, every pointer-move handler. These files get the strictest review in Step 3.

Step 2: Scan

Run React Doctor read-only to collect structured evidence:

npx react-doctor@latest --verbose

For a regression check after making changes, run with `--scope changed` and confirm the score did not drop.

Step 3: Triage by frame-loop leverage

Re-rank the scanner's findings using the hot-path map, then hunt for the Three.js-specific problems the scanner cannot see. Confirm every finding at its `file:line` before reporting it.

**HIGH severity, runs every frame or leaks GPU memory:**

  • **Allocation inside `useFrame`**: `new Vector3()`, `new Color()`, or fresh arrays passed to Three.js APIs each frame. Fix: hoist a scratch object to module scope or `useMemo`, then mutate it in place
  • **`setState` inside `useFrame`**: re-renders the React tree on every frame. Fix: mutate refs directly; reserve state for discrete changes like selection or visibility
  • **Missing disposal**: geometries, materials, textures, or render targets created imperatively and never disposed. Fix: call `dispose()` in the cleanup function, or move the object into R3F's declarative tree so it owns the lifecycle
  • **Object reconstruction in render**: geometry or material instances created without `useMemo`, or inline `args` arrays whose identity changes each render, forcing R3F to rebuild the underlying object

**MEDIUM severity, per-render or per-interaction waste:**

  • **Unstable scene-graph props**: inline `new THREE.Vector3()` or fresh material objects as props (plain arrays like `position={[x, y, z]}` are fine; R3F handles them)
  • **Missing instancing**: hundreds of identical meshes rendered individually instead of through `<Instances>` or `InstancedMesh`
  • **Wasted frames**: `frameloop="always"` on a scene that only changes on interaction. Fix: `frameloop="demand"` plus `invalidate()`
  • **Uncached asset loading**: textures and models loaded outside `useLoader`, `useTexture`, or `useGLTF`, losing caching and Suspense integration

**LOW severity, hygiene:** React Doctor findings on non-canvas UI code, missing `<Preload>`, oversized textures.

Step 4: Visual audit

Inspect what the scene actually renders. Every visual finding needs evidence: a screenshot, a frame capture, or a reproduced observation, never a guess from reading source. When a dev server and browser are available, load the app, capture the first stable frame, then capture again after moving the camera and interacting. When no browser is available, check the code-level causes listed below and label each finding as inferred from source.

Apply the mini rubric. A row fails only when the evidence shows the failure condition:

| Area | Check | Fail when | | ---------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Render sanity | The scene reaches a stable frame after load | Black canvas, WebGL context errors, or content that never appears | | Geometry | Move the camera along seams, edges, and boundaries | Gaps, missing faces, visible backfaces, or two surfaces flickering at the same depth (z-fighting) | | Transparency and depth | Cross depth-order boundaries with overlapping or transmissive surfaces | Wrong sort order, halos, opaque surfaces that should transmit, or flicker at grazing angles | | Textures | View mapped surfaces close, far, and at grazing angles | Missing textures, stretching, seams, moiré, shimmer, or washed-out colors from a wrong color space | | Materials and lighting | Change light and view direction on lit surfaces | Surfaces that ignore light direction, or reflective metals with no environment to reflect | | Shadows | Move casters, receivers, and the light through their range | Acne, detached or floating shadows, flicker at rest, or shadows that outlive their caster | | Camera | Follow the primary subject through movement and transitions | Subject leaves frame, camera clips into geometr

Read more
@millionco
Ships withreact-doctor

Your agent writes bad React. This catches it

Stars on GitHub

Momentum

stars in total
15.1k
Star history of millionco/react-doctor on GitHub, a chart by star-history.com

Other skills on react-doctor.

improve-react

improve-react

Survey a whole React codebase as a senior React engineer, using React Doctor's scan as evidence, then produce a prioritized audit…

performance

performance

Diagnose React runtime performance with React Doctor traces, live render outlines, Long Animation Frames, interaction timing, and…

react-doctor

react-doctor

Use when finishing a feature, fixing a bug, before committing React code, or when the user types `/doctor`, asks to scan, triage,…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about improve-threejs.

Which coding agents can use improve-threejs?
improve-threejs installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.