Communitygithub.com

phido0410/threejs-3d

基于 Three.js、React Three Fiber(R3F)、Drei 辅助库、Rapier 物理引擎(@react-three/rapier)和后处理特效(@react-three/postprocessing)的 3D 开发技能。适用于构建 Web 或视频的 3D 场景,涵盖模型(GLTF)、灯光、相机、环境贴图、物理、泛光/暗角/景深等。若在 Remotion 中使用,还需遵循 remotion-markup/3d.md。

threejs-3d 是什么?

phido0410/threejs-3d 是一个为 AI 代理(如 Claude Code、Cursor、Codex)提供完整 Three.js 3D 堆栈配置和编码规范的技能。它基于 2026-10 月验证的版本:three 0.186、@react-three/fiber 9.8、@react-three/drei 10.7、@react-three/rapier 2.2、@react-three/postprocessing 3.2,且要求 React 19。该技能涵盖基础场景搭建、Rapier 物理引擎(包括刚体、碰撞体和手动步进)、后处理特效(Bloom、Vignette、DepthOfField 等)以及视频场景的特殊处理。在 Remotion 中,它建议避免使用基于 `useFrame` 和内部时钟的 Drei 辅助组件,改用 `useCurrentFrame` 驱动,并对物理模拟进行预烘焙以获得确定性输出。技能提供了可复制的代码片段、import 语句和最佳实践,帮助开发者快速构建 Web 或视频 3D 场景。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/phido0410/claude-video-skills/tree/HEAD/skills/threejs-3d

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Three.js 3D 堆栈

2026-10 月验证:three 0.186,@react-three/fiber 9.8,@react-three/drei 10.7,@react-three/rapier 2.2,@react-three/postprocessing 3.2(+ postprocessing 6.39)。Fiber 9 / Drei 10 / Rapier 2 / postprocessing 3 需要 React 19(fiber 9.8 peer: react >=19 <19.4)。

npm i three @react-three/fiber @react-three/drei
npm i @react-three/rapier                         # 物理引擎
npm i @react-three/postprocessing postprocessing  # 特效
npm i -D @types/three

基础场景(Web)

import { useRef, Suspense } from 'react'
import * as THREE from 'three'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls, Environment, ContactShadows } from '@react-three/drei'

function Box() {
  const ref = useRef<THREE.Mesh>(null!)
  useFrame((_, delta) => { ref.current.rotation.y += delta }) // 每帧修改 ref,绝不使用 setState
  return (
    <mesh ref={ref} castShadow>
      <boxGeometry />
      <meshStandardMaterial color="#4a9eff" />
    </mesh>
  )
}

<Canvas camera={{ position: [3, 2, 5], fov: 45 }} dpr={[1, 2]} shadows>
  <ambientLight intensity={0.3} />
  <directionalLight position={[5, 5, 5]} castShadow />
  <Suspense fallback={null}>
    <Box />
    <Environment preset="city" />
  </Suspense>
  <ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
  <OrbitControls />
</Canvas>

规则:

  • 所有异步操作(useGLTF、useTexture、Environment、Text 字体、Physics WASM)都应放在 <Suspense> 下。
  • 首次渲染即需加载的模型,在模块级别使用 useGLTF.preload(url)。
  • 场景尺寸保持在 1–10 单位左右;过大或过小的比例会破坏阴影和控制器。
  • MeshStandardMaterial 需要光源或 <Environment>;否则渲染为黑色。

Drei(按需选用)

  • 相机/控制器:OrbitControls、CameraControls、PerspectiveCamera makeDefault
  • 资源:useGLTF、useTexture、Environment(预设:apartment、city、dawn、forest、lobby、night、park、studio、sunset、warehouse)、Center、Bounds
  • 布景:ContactShadows、AccumulativeShadows、Stage、Float、Sparkles、Stars、Cloud
  • 材质:MeshTransmissionMaterial(玻璃)、MeshReflectorMaterial(反射地面)
  • 文字:Text(SDF,支持任意字体 URL)、Text3D(需要 typeface JSON)、Html(DOM 覆盖层)

Rapier 物理引擎

import { Physics, RigidBody, CuboidCollider, type RapierRigidBody } from '@react-three/rapier'

<Suspense>
  <Physics gravity={[0, -9.81, 0]} /* debug */>
    <RigidBody colliders="hull" restitution={0.6} ref={bodyRef}>
      <mesh><torusGeometry /><meshStandardMaterial /></mesh>
    </RigidBody>
    <RigidBody type="fixed">
      <CuboidCollider args={[10, 0.1, 10]} /> {/* 半长宽高 */}
    </RigidBody>
  </Physics>
</Suspense>
// bodyRef.current?.applyImpulse({ x: 0, y: 5, z: 0 }, true)
  • colliders:"cuboid"(默认)、"ball"、"hull"、"trimesh"、false(自行添加碰撞体组件)。
  • type:"dynamic"(默认)、"fixed"、"kinematicPosition"、"kinematicVelocity"。
  • timeStep 默认为固定的 1/60。timeStep="vary" 不确定。手动步进:useRapier().step(1 / 60)。
  • 在 <Physics> 上添加 debug 可绘制碰撞体。

后处理特效

import { EffectComposer, Bloom, Vignette, DepthOfField, Noise } from '@react-three/postprocessing'

<EffectComposer>{/* 作为 <Canvas> 的最后一个子元素 */}
  <Bloom luminanceThreshold={0.9} intensity={1.2} mipmapBlur />
  <Vignette offset={0.1} darkness={0.9} />
</EffectComposer>
  • Bloom 仅捕获高于 luminanceThreshold 的像素。若要让某个对象发光:使用 emissive 颜色 + emissiveIntensity > 1,并在其材质上设置 toneMapped={false}。
  • 每个特效消耗一次全屏渲染;2–4 个特效足矣。

视频场景

Remotion(参见 remotion-markup/3d.md):使用 @remotion/three 中的 <ThreeCanvas width height>;不要使用 useFrame;所有运动来自 useCurrentFrame()。此外:

  • 不使用 OrbitControls——从 frame 移动相机(使用 interpolate / spring)。
  • 依赖自身时钟动画的 Drei 辅助组件(Float、Sparkles、Stars、Cloud、MeshWobbleMaterial)在渲染中会闪烁。要么删除,要么用 frame 重新实现运动。
  • 物理引擎:Remotion 跨标签页乱序渲染帧,因此实时模拟无法匹配。需要烘焙:初始化 @dimforge/rapier3d-compat(@react-three/rapier 底层引擎)一次,对每一帧使用 world.step() 步进,timestep = 1 / fps,存储每个刚体每帧的位置 + 旋转,然后在帧索引 frame 处渲染变换。

在 Remotion 之外(屏幕录制、GSAP 驱动):useFrame 是可以的;当需要镜头可重复时,使用时间线时间(tl.time())驱动,而非 delta。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

相关技能