关于 improve-threejs
improve-threejs 是用于审查和改进 Three.js 与 React Three Fiber 代码库的技能。它结合 React Doctor 扫描、渲染循环优先级判断和基于证据的视觉检查,定位性能、资源生命周期及场景问题。
主要功能
- 01梳理渲染循环和交互热点
- 02运行 React Doctor 扫描
- 03按帧循环影响排列问题优先级
- 04依据视觉检查表检查场景
- 05修复性能及 GPU 资源问题
- 06验证代码改动和视觉表现
适用场景
- 01审查 Three.js 或 R3F 应用
- 02查找帧回调中的分配或状态更新
- 03依据场景证据诊断视觉缺陷
- 04检查修复是否引入回归并验证渲染行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ millionco/ react-doctor --skill improve-threejs安装后在 Claude Code 中输入/improve-threejs确认已加载。
详细介绍
改进 Three.js
审查 Three.js 或 React Three Fiber(R3F)代码库,并修复影响最大的问题:每帧都会运行的操作、从未释放的 GPU 资源、每次渲染都会重建的场景图对象,以及用户可见的视觉缺陷。React Doctor 提供机器验证的代码扫描;本技能则补充通用 React 扫描器所缺乏的帧循环判断和视觉检查。
核心原则:严重程度取决于渲染循环。useFrame 或 requestAnimationFrame 回调中的代码每秒运行 60 次,因此其中的轻微低效问题也比设置面板中的严重问题更值得优先处理。根据每项问题的运行位置重新排序,而不是照搬规则的默认严重程度。
工作流
第 1 步:侦察
扫描前先确定技术栈:纯 Three.js 还是 R3F、使用了哪些辅助库(drei、postprocessing、rapier),以及渲染循环位于何处(useFrame 钩子、requestAnimationFrame、<Canvas frameloop> 设置)。
绘制热路径图:列出每个 useFrame 函数体、每个 RAF 回调和每个指针移动处理器。第 3 步将对这些文件进行最严格的审查。
第 2 步:扫描
以只读模式运行 React Doctor,收集结构化证据:
npx react-doctor@latest --verbose
进行更改后,可使用 --scope changed 运行回归检查,并确认评分没有下降。
第 3 步:根据帧循环影响重新评估
利用热路径图重新排列扫描器发现的问题,然后查找扫描器无法识别的 Three.js 特有问题。报告前,逐一在对应的 file:line 位置确认每项问题。
高严重程度,每帧运行或导致 GPU 内存泄漏:
- 在
useFrame中分配对象:每帧都创建new Vector3()、new Color(),或传给 Three.js API 的新数组。修复方法:将临时对象提升到模块作用域或放入useMemo,然后直接修改对象 - 在
useFrame中调用setState:每帧都会重新渲染 React 树。修复方法:直接修改 refs;仅在选择或可见性等离散变化时使用状态 - 未释放资源:以命令式方式创建的几何体、材质、纹理或渲染目标从未释放。修复方法:在清理函数中调用
dispose(),或者将对象移入 R3F 声明式树,由其管理生命周期 - 渲染时重建对象:创建几何体或材质实例时未使用
useMemo,或使用了每次渲染都会改变引用的内联args数组,导致 R3F 重建底层对象
中等严重程度,每次渲染或交互都会造成浪费:
- 场景图属性不稳定:将内联
new THREE.Vector3()或新建的材质对象作为属性传入(position={[x, y, z]}这样的普通数组没有问题;R3F 会处理它们) - 缺少实例化渲染:数百个相同的网格分别渲染,而不是通过
<Instances>或InstancedMesh渲染 - 浪费帧:仅在交互时变化的场景使用了
frameloop="always"。修复方法:改用frameloop="demand",并配合invalidate() - 未缓存资源加载:纹理和模型在
useLoader、useTexture或useGLTF之外加载,无法利用缓存和 Suspense 集成
低严重程度,代码卫生问题: React Doctor 对非画布 UI 代码的发现、缺少 <Preload>、纹理尺寸过大。
第 4 步:视觉审查
检查场景实际渲染的内容。每项视觉问题都必须有证据:截图、帧捕获或复现后的观察结果;绝不能仅凭阅读源代码猜测。如果有开发服务器和浏览器可用,就打开应用,捕获第一帧稳定画面,然后在移动摄像机并进行交互后再次捕获。如果没有浏览器,则检查下方列出的代码层面原因,并将每项问题标注为根据源代码推断。
应用此简易评估标准。只有证据表明存在失败情况时,对应条目才算未通过:
| 区域 | 检查 | 失败条件 |
|---|---|---|
| 渲染健全性 | 加载后场景达到稳定帧 | 画布全黑、WebGL 上下文错误,或内容始终未显示 |
| 几何体 | 沿接缝、边缘和边界移动摄像机 | 存在间隙、缺失的面、可见的背面,或两个表面在相同深度闪烁(深度冲突) |
| 透明度和深度 | 穿越重叠或可透光表面的深度排序边界 | 排序错误、光晕、应透光的表面不透明,或掠射角处闪烁 |
| 纹理 | 从近处、远处和掠射角观察贴图表面 | 纹理缺失、拉伸、接缝、摩尔纹、闪烁,或因颜色空间错误导致颜色褪淡 |
| 材质和光照 | 改变受光表面的光照方向和观察方向 | 表面不受光照方向影响,或反射金属没有可供反射的环境 |
| 阴影 | 在其范围内移动投射物、接收面和光源 | 阴影痤疮、分离或悬浮的阴影、静止时闪烁,或投射物移开后阴影仍存在 |
| 摄像机 | 在移动和过渡过程中跟随主要主体 | 主体离开画面、摄像机穿入几何体,或前景遮挡游戏区域 |
| 比例和接触 | 对照周围环境比较物体比例和静置接触情况 | 物体悬浮在支撑表面上方、陷入其中或与之相交,或比例不合理 |
| 图像稳定性 | 在受支持的分辨率下缓慢平移摄像机 | 轮廓、细薄几何体或高光出现爬动、闪烁或残影 |
| 调整大小和 DPR | 更改视口大小、缩放和设备像素比 | 画面变形、模糊、拉伸,或内容超出视口 |
每行检查项都有一小组常见的代码层面原因。某行检查失败时,请先检查以下原因:
- 颜色褪淡或过暗:未设置
renderer.outputColorSpace为SRGBColorSpace,颜色纹理缺少texture.colorSpace = SRGBColorSpace,或数据纹理(法线、粗糙度)被错误标记为 sRGB - 深度冲突:共面几何体需要设置
polygonOffset或微调位置,或者近裁剪面相对于场景比例设置得过小 - 阴影痤疮或悬浮阴影:未调优
shadow.bias和shadow.normalBias,或者阴影摄像机视锥体远大于场景 - 画布模糊或拉伸:渲染器尺寸未与画布 CSS 尺寸同步、从未调用
setPixelRatio,或调整大小的处理程序忘记调用camera.updateProjectionMatrix() - 金属发黑:设置了
metalness: 1,但未设置scene.environment - 透明度排序问题:大型透明网格需要设置
depthWrite: false、手动指定renderOrder,或拆分为更小的网格 - 闪烁和爬动:缺少纹理各向异性、禁用了抗锯齿,或细薄几何体需要加厚
步骤 5:修复
按严重程度顺序修复:先处理 HIGH 性能问题和未通过的视觉检查项。如果某项问题对应 React Doctor 规则,请获取其标准修复方案,而不是自行摸索:
https://www.react.doctor/prompts/rules/<plugin>/<rule>.md
对于 Three.js 特有的问题,请应用分诊列表或上述原因列表中列出的修复方法。
步骤 6:验证
运行 npx react-doctor@latest --verbose --scope changed,确认评分没有下降。使用与原始证据相同的视角和交互方式,重新检查每一项未通过的视觉评估指标,并确认现在已通过。然后验证行为:场景能够渲染,动画能够播放,交互能够响应。如果可以使用浏览器开发者工具,请在空闲场景中环绕查看时监控内存配置;空闲时堆内存持续增长,说明仍存在资源释放泄漏。
扫描器总会漏掉的检查项
每次审查时,都要手动检查以下内容:
- 是否对每个以命令式方式创建的 GPU 资源调用了
dispose() useFrame和 RAF 回调中的内存分配与setState- Canvas 或 window 上未清理的事件监听器和
ResizeObserver - 是否在每次指针移动时都对整个场景进行光线投射,而不是使用经过筛选的目标列表
- 当场景的某一部分需要阴影或后期处理时,是否全局启用了这些效果
- 渲染器和每个颜色纹理的色彩空间配置