@lark-apaas/coding-steering 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -13
- package/steering/html/skills/rich-interactive-design/SKILL.md +5 -2
- package/steering/html/skills/rich-interactive-design/references/tasks/interactive-scene.md +1 -0
- package/steering/vite-react/skills/react-three-fiber/SKILL.md +214 -0
- package/steering/vite-react/skills/react-three-fiber/references/animation.md +1001 -0
- package/steering/vite-react/skills/react-three-fiber/references/fundamentals.md +877 -0
- package/steering/vite-react/skills/react-three-fiber/references/geometry.md +717 -0
- package/steering/vite-react/skills/react-three-fiber/references/interaction.md +880 -0
- package/steering/vite-react/skills/react-three-fiber/references/lighting.md +668 -0
- package/steering/vite-react/skills/react-three-fiber/references/loaders.md +607 -0
- package/steering/vite-react/skills/react-three-fiber/references/materials.md +601 -0
- package/steering/vite-react/skills/react-three-fiber/references/physics.md +820 -0
- package/steering/vite-react/skills/react-three-fiber/references/postprocessing.md +754 -0
- package/steering/vite-react/skills/react-three-fiber/references/shaders.md +874 -0
- package/steering/vite-react/skills/react-three-fiber/references/textures.md +635 -0
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/coding-steering",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Stack-specific steering content for miaoda-coding templates",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"files": [
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
"files": ["steering"],
|
|
7
|
+
"scripts": {
|
|
8
|
+
"lint:md": "markdownlint 'steering/**/*.md'"
|
|
9
|
+
},
|
|
9
10
|
"devDependencies": {
|
|
10
11
|
"markdownlint-cli": "^0.47.0"
|
|
11
12
|
},
|
|
@@ -13,12 +14,6 @@
|
|
|
13
14
|
"access": "public",
|
|
14
15
|
"registry": "https://registry.npmjs.org/"
|
|
15
16
|
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
],
|
|
20
|
-
"license": "MIT",
|
|
21
|
-
"scripts": {
|
|
22
|
-
"lint:md": "markdownlint 'steering/**/*.md'"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
17
|
+
"keywords": ["miaoda", "coding-steering"],
|
|
18
|
+
"license": "MIT"
|
|
19
|
+
}
|
|
@@ -71,6 +71,7 @@ plan 中说明「主类 X,包含 Y 模块」即可。
|
|
|
71
71
|
- 不区分桌面 / 移动端输入(PC 只 keydown / 移动端只 click)
|
|
72
72
|
- 加载完成无 fade-in 过渡,首帧突现
|
|
73
73
|
- 模拟 / 3D 场景里大面积装饰性紫蓝渐变背景(科幻味的廉价 AI 审美)
|
|
74
|
+
- Canvas 2D 字符串颜色用 CSS Level 4 空格分隔语法(`hsl(200 90% 65%)` / `hsla(...)`)—— `addColorStop` / `fillStyle` / `strokeStyle` 只解析 Level 3 逗号分隔,空格分隔抛 `could not be parsed as a color`;CSS 上下文(`style.color` / CSS 变量 / Tailwind 配置)两种语法都支持,但写入 Canvas API 字符串参数(含模板字符串拼接)必须用逗号分隔 `hsla(200, 90%, 65%, 0.9)`
|
|
74
75
|
|
|
75
76
|
### 5.2 默认设计倾向
|
|
76
77
|
|
|
@@ -85,8 +86,10 @@ plan 中说明「主类 X,包含 Y 模块」即可。
|
|
|
85
86
|
|
|
86
87
|
### 5.3 资产策略
|
|
87
88
|
|
|
88
|
-
-
|
|
89
|
-
-
|
|
89
|
+
- **路径按视觉目标选**(不分主次):
|
|
90
|
+
- 抽象 / 程式化 / 卡通 → 程序化(SVG / Canvas / Three.js Geometry / Web Audio)
|
|
91
|
+
- 写实复刻"在用户脑子里有视觉标准答案"的真实物体(地球、人体、汽车……)→ CDN 贴图 + PBR + 真实模型(jsDelivr / threejs.org examples);程序化几何模拟这类物体一定假
|
|
92
|
+
- 原创艺术内容(角色 sprite、风格化场景、封面)→ GenerateImage 兜底;详见各 task 文件
|
|
90
93
|
- **图标**:禁止 emoji 充当功能性图标(导航 / 按钮 / 状态指示),用 Lucide 风格 inline SVG
|
|
91
94
|
- **`<img>` alt**:每个 `<img>` 的 `alt` 必须有意义(描述图片内容),不要空 alt 或填文件名
|
|
92
95
|
- **占位图**:禁用 placeholder.com 等外链占位服务;需要时用纯 CSS 占位框或程序化生成
|
|
@@ -217,6 +217,7 @@ const hits = raycaster.intersectObjects(targets, false);
|
|
|
217
217
|
- **白屏到首帧突现**——没有 loading 进度
|
|
218
218
|
- **纯 AmbientLight 全亮**——画面扁平如纸片
|
|
219
219
|
- **MeshBasicMaterial 当主材质**——无光照响应,看着像未渲染
|
|
220
|
+
- **Canvas 2D / 程序化生成写实物体纹理(地球、月球、人脸、汽车、知名建筑等"用户脑中有真实标准答案"的物体)**——一定会被识破为假;必须用 CDN 真实贴图
|
|
220
221
|
- **不 dispose**——切场景内存爆炸,几次后 crash
|
|
221
222
|
- **`setPixelRatio(devicePixelRatio)`**——高 dpr 手机直接卡死
|
|
222
223
|
- **OrbitControls 不限制 polarAngle**——用户翻到地下看到悬空模型
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-three-fiber
|
|
3
|
+
description: "Use when 实现 3D 场景 / 3D 游戏 / 3D 数据可视化, 用到 react-three-fiber (R3F) / three.js / @react-three/drei / @react-three/rapier / @react-three/postprocessing 时. 触发词:3D, R3F, react-three-fiber, three.js, threejs, Canvas, useFrame, useThree, OrbitControls, drei, mesh, geometry, useGLTF, GLTF, GLB, 3D 模型, 3D 场景, 3D 游戏, 3D 地球, shader, GLSL, 物理引擎, rapier, postprocessing, Bloom, 后处理, 着色器, 立体, 透视, 视角, 飞行射击, 空战, 探索"
|
|
4
|
+
steering: true
|
|
5
|
+
steering-topic: react_three_fiber
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# React Three Fiber (R3F) 编码指南
|
|
9
|
+
|
|
10
|
+
实现 3D 场景 / 3D 游戏 / 3D 数据可视化时, MUST 用 **react-three-fiber + drei** 声明式栈, 严禁用 React + CSS / SVG / `transform: rotateX` 伪 3D.
|
|
11
|
+
|
|
12
|
+
## ⚠️ 妙搭沙箱适配铁律 (React 19 + 严格模式, 不遵守 → 黑屏)
|
|
13
|
+
|
|
14
|
+
妙搭沙箱跑 React 19 + React Compiler 严格 lint. 下列写法 commit 时报错, 且**运行时部分组件会被 React 跳过编译 / 严格模式重复挂载抛错 → Canvas 内部黑屏 (只剩 HUD)**.
|
|
15
|
+
|
|
16
|
+
### 铁律 1: `Math.random()` / `Date.now()` 严禁 render 期间直接调用
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// ❌ React 19 报 "Math.random is an impure function during render"
|
|
20
|
+
{enemies.map((_, i) => <group position={[Math.random() * 10, 0, 0]}>...</group>)}
|
|
21
|
+
|
|
22
|
+
// ✅ useMemo 一次性算好, deps=[]
|
|
23
|
+
const enemyPositions = useMemo(
|
|
24
|
+
() => Array.from({ length: 8 }, () => [Math.random() * 10, 0, Math.random() * 10]),
|
|
25
|
+
[]
|
|
26
|
+
)
|
|
27
|
+
{enemyPositions.map((pos, i) => <group key={i} position={pos as [number, number, number]}>...</group>)}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 铁律 2: 动画 / 位置更新优先用 drei 高阶组件, 严禁 render 里读写 ref.current
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// ❌ render 期间访问 ref.current — React 19 报 "Cannot access refs during render"
|
|
34
|
+
<mesh rotation={[ref.current?.rotation.y + 0.01 || 0, 0, 0]} />
|
|
35
|
+
|
|
36
|
+
// ✅ 优先用 drei 高阶组件让库帮你驱动动画 (推荐)
|
|
37
|
+
<OrbitControls autoRotate autoRotateSpeed={0.4} enableDamping />
|
|
38
|
+
<Float speed={1.5} rotationIntensity={1} floatIntensity={2}>
|
|
39
|
+
<mesh>...</mesh>
|
|
40
|
+
</Float>
|
|
41
|
+
|
|
42
|
+
// ✅ 必须自己写 useFrame 时, ref 操作只在 useFrame 内, 不进 render JSX
|
|
43
|
+
function Earth() {
|
|
44
|
+
const ref = useRef<THREE.Mesh>(null)
|
|
45
|
+
useFrame(() => { if (ref.current) ref.current.rotation.y += 0.005 })
|
|
46
|
+
return <mesh ref={ref}><sphereGeometry /><meshStandardMaterial /></mesh>
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 铁律 3: useEffect 里 setState 加 if 条件 / 用 setter 函数, 防级联渲染
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// ❌ React 19 报 "Calling setState synchronously within an effect can trigger cascading renders"
|
|
54
|
+
useEffect(() => { setHealth(100) }, [gameState])
|
|
55
|
+
|
|
56
|
+
// ✅ 加条件或 setter 函数
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (gameState === 'playing') {
|
|
59
|
+
setHealth((h) => (h > 0 ? h : 100))
|
|
60
|
+
}
|
|
61
|
+
}, [gameState])
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 铁律 4: Canvas 外必须包 ErrorBoundary, Suspense 不吞 Error
|
|
65
|
+
|
|
66
|
+
`<Canvas>` 内部 mesh / geometry / material 抛 runtime error 时, **Suspense fallback 只吞 Promise (异步加载), 不吞 Error**. 没 ErrorBoundary → 整个 Canvas 黑屏, 控制台报错被吞, 用户看到只剩 HUD.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// ❌ 只有 Suspense, Canvas 内部错误 → 整片黑
|
|
70
|
+
<Canvas>
|
|
71
|
+
<Suspense fallback={null}>
|
|
72
|
+
<Scene />
|
|
73
|
+
</Suspense>
|
|
74
|
+
</Canvas>
|
|
75
|
+
|
|
76
|
+
// ✅ ErrorBoundary 包 Canvas, fallback 显示降级 UI 而不是黑屏
|
|
77
|
+
import { ErrorBoundary } from 'react-error-boundary'
|
|
78
|
+
|
|
79
|
+
<ErrorBoundary fallback={<div className="p-8 text-center">3D 场景加载失败, 请刷新重试</div>}>
|
|
80
|
+
<Canvas camera={{ position: [0, 0, 5] }}>
|
|
81
|
+
<Suspense fallback={null}>
|
|
82
|
+
<Scene />
|
|
83
|
+
</Suspense>
|
|
84
|
+
</Canvas>
|
|
85
|
+
</ErrorBoundary>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 铁律 5: 黑屏必查清单 (3D 场景空白时按顺序排查)
|
|
89
|
+
|
|
90
|
+
| 项 | 要求 |
|
|
91
|
+
|----|------|
|
|
92
|
+
| Canvas 父容器有显式高度 | `h-screen` / `h-[800px]`, **不要** `h-full` 链断 (Canvas 默认会撑满, 父容器无高度 → Canvas 0px) |
|
|
93
|
+
| 至少 1 个 `<ambientLight intensity≥0.3>` | 没灯 = 全黑 |
|
|
94
|
+
| `<directionalLight position={[5,5,5]} intensity≥0.5>` | 主光源 |
|
|
95
|
+
| Camera position 跟 mesh 有距离 (5-20 单位) | `<Canvas camera={{ position: [0, 0, 5] }}>` |
|
|
96
|
+
| 至少 1 个 mesh 在 `[0, 0, 0]` 附近 | 调试时放原点确认场景渲染 |
|
|
97
|
+
| 浏览器 Console 看有无红字 Error | 看 R3F 抛了什么 (没 ErrorBoundary 时只有 Console 看得到) |
|
|
98
|
+
|
|
99
|
+
## 核心写法原则
|
|
100
|
+
|
|
101
|
+
1. **优先 drei 高阶 API, 不要自己写低阶**: drei 已经帮你处理了交互 / 动画 / 控制器 / 加载状态等. 自己写 useFrame / useState 60fps + ref + 碰撞容易踩 React 19 严格规则.
|
|
102
|
+
2. **JSX 声明式描述场景, 不用命令式**: R3F 在 React 树里描述场景图, 不要 `scene.add(mesh)` 这种 imperative 写法.
|
|
103
|
+
3. **小写元素 = three.js 类**: `<mesh>` / `<boxGeometry>` / `<ambientLight>` 是 R3F 内置 (small-case = three.js constructor).
|
|
104
|
+
4. **大写元素 = React 组件**: `<OrbitControls>` / `<Float>` / `<Stars>` 是 drei 提供的封装.
|
|
105
|
+
|
|
106
|
+
## Reference 文档索引 — 按需读取
|
|
107
|
+
|
|
108
|
+
各 reference 文档在以下场景**必须先读取再编写代码**, 避免凭训练数据写过时 API:
|
|
109
|
+
|
|
110
|
+
### references/fundamentals.md
|
|
111
|
+
|
|
112
|
+
- 第一次写 R3F 代码 / 不确定 Canvas / useFrame / useThree 怎么用时
|
|
113
|
+
- 设置 Canvas (camera / dpr / shadows / gl 参数)
|
|
114
|
+
- 使用 hooks: useFrame (render loop) / useThree (scene/camera/gl/size)
|
|
115
|
+
- 监听 mesh 事件 (onClick / onPointerOver / onPointerMissed)
|
|
116
|
+
- 处理 refs (THREE.Object3D / Group / Mesh ref 类型)
|
|
117
|
+
|
|
118
|
+
### references/geometry.md
|
|
119
|
+
|
|
120
|
+
- 决定用哪种 geometry: boxGeometry / sphereGeometry / planeGeometry / coneGeometry / cylinderGeometry / torusGeometry 等
|
|
121
|
+
- 创建自定义 BufferGeometry (顶点 / 法线 / UV)
|
|
122
|
+
- 大量重复 mesh (≥100 个) 需要 instancing 时 — 用 drei `<Instances>` / `<Merged>`
|
|
123
|
+
|
|
124
|
+
### references/materials.md
|
|
125
|
+
|
|
126
|
+
- 配置 material: meshStandardMaterial (默认 PBR) / meshPhysicalMaterial (高级 PBR) / meshBasicMaterial (无光照)
|
|
127
|
+
- PBR 参数: metalness / roughness / envMapIntensity
|
|
128
|
+
- 透明 / blending / depthWrite
|
|
129
|
+
- 自定义 shaderMaterial (简单需求, 复杂走 references/shaders.md)
|
|
130
|
+
|
|
131
|
+
### references/lighting.md
|
|
132
|
+
|
|
133
|
+
- 配光: ambientLight (环境光) / directionalLight (定向光, 模拟太阳) / pointLight (点光源) / spotLight (聚光灯)
|
|
134
|
+
- shadow 配置 (castShadow / receiveShadow / shadow-mapSize)
|
|
135
|
+
- drei `<Environment>` 加 HDRI 环境贴图 (城市 / sunset / studio 等预设)
|
|
136
|
+
|
|
137
|
+
### references/textures.md
|
|
138
|
+
|
|
139
|
+
- 加载贴图: drei `useTexture('/img.jpg')` 或 R3F `useLoader(TextureLoader, ...)`
|
|
140
|
+
- 多张贴图组合 (normalMap / roughnessMap / aoMap / displacementMap)
|
|
141
|
+
- 贴图配置: repeat / wrapS / wrapT / anisotropy / colorSpace
|
|
142
|
+
- 环境贴图 `useEnvironment`
|
|
143
|
+
|
|
144
|
+
### references/loaders.md
|
|
145
|
+
|
|
146
|
+
- 加载 GLTF / GLB 3D 模型 (drei `useGLTF` 推荐)
|
|
147
|
+
- 资源预加载 (`useGLTF.preload(...)`)
|
|
148
|
+
- Suspense fallback / 加载进度 (`useProgress`)
|
|
149
|
+
- DRACO / meshopt 压缩模型解码
|
|
150
|
+
- 加载 fbx / obj 等其他格式 (`useFBX` / `useLoader`)
|
|
151
|
+
|
|
152
|
+
### references/animation.md
|
|
153
|
+
|
|
154
|
+
- 用 `useFrame` 写 render loop 动画 (旋转 / 移动 / 缩放)
|
|
155
|
+
- 加载 GLTF 骨骼动画 `useAnimations`
|
|
156
|
+
- drei 内置动画组件: `<Float>` / `<OrbitControls autoRotate>` / `<Sparkles>` 等
|
|
157
|
+
- spring 物理动画 (react-spring / framer-motion-3d)
|
|
158
|
+
|
|
159
|
+
### references/shaders.md
|
|
160
|
+
|
|
161
|
+
- 写自定义 GLSL shader (vertex / fragment)
|
|
162
|
+
- drei `shaderMaterial` 助手 (类型化 uniforms + 自动 hot reload)
|
|
163
|
+
- uniforms / varying / attributes 写法
|
|
164
|
+
- 时间驱动的视觉效果 (波纹 / 噪声 / 渐变)
|
|
165
|
+
|
|
166
|
+
### references/postprocessing.md
|
|
167
|
+
|
|
168
|
+
- 加后处理 Bloom (辉光) / DepthOfField (景深) / ChromaticAberration (色散) / Vignette (暗角) / ToneMapping
|
|
169
|
+
- `<EffectComposer>` 编排多个 effect
|
|
170
|
+
- 性能注意 (后处理消耗很大, mobile 慎用)
|
|
171
|
+
|
|
172
|
+
### references/interaction.md
|
|
173
|
+
|
|
174
|
+
- 鼠标 / 触摸交互 (pointer events)
|
|
175
|
+
- 相机控制: drei `<OrbitControls>` (轨道) / `<PointerLockControls>` (第一人称) / `<FirstPersonControls>` / `<TrackballControls>`
|
|
176
|
+
- 键盘输入: drei `<KeyboardControls>` + `useKeyboardControls`
|
|
177
|
+
- 拖拽: drei `<TransformControls>` (gizmo) / `<PivotControls>`
|
|
178
|
+
- 自定义 raycasting 选中物体
|
|
179
|
+
|
|
180
|
+
### references/physics.md
|
|
181
|
+
|
|
182
|
+
- 用 `@react-three/rapier` 加物理引擎
|
|
183
|
+
- `<Physics>` provider 包场景
|
|
184
|
+
- `<RigidBody>` (动态 / 运动 / 固定) + collider (cuboid / ball / capsule / trimesh / convex)
|
|
185
|
+
- 力 / 冲量 / 关节 / 传感器
|
|
186
|
+
- 碰撞检测 (`onCollisionEnter` / `onIntersectionEnter`)
|
|
187
|
+
|
|
188
|
+
## 快速决策表 (按场景选 reference)
|
|
189
|
+
|
|
190
|
+
| 业务场景 | 必读 references |
|
|
191
|
+
|---------|-----------------|
|
|
192
|
+
| 3D 商品 / 地球仪 / 模型展示 (可旋转看) | fundamentals + geometry + materials + lighting + interaction (OrbitControls autoRotate) |
|
|
193
|
+
| 加载真实 3D 模型 (GLTF) 来展示 | fundamentals + loaders + materials + lighting + (可选) animation |
|
|
194
|
+
| 3D 飞行射击 / 跑酷 / 动作游戏 | fundamentals + geometry + animation + interaction (KeyboardControls) + physics (rapier) + ⚠️ 妙搭沙箱铁律 (60fps 动画必踩 React 19) |
|
|
195
|
+
| 3D 数据可视化 (柱状图 / 散点云) | fundamentals + geometry + materials + (可选 instancing) |
|
|
196
|
+
| 写酷炫视觉 (波纹 / 粒子 / 渐变) | fundamentals + shaders + postprocessing (Bloom) |
|
|
197
|
+
| 第一人称 3D 探索 | fundamentals + loaders + interaction (PointerLockControls / KeyboardControls) + physics |
|
|
198
|
+
|
|
199
|
+
## 依赖装包速查
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# 基础 (设计指南选了 R3F 必装)
|
|
203
|
+
npm install three @react-three/fiber @react-three/drei
|
|
204
|
+
|
|
205
|
+
# 按需扩展
|
|
206
|
+
npm install @react-three/postprocessing # 后处理
|
|
207
|
+
npm install @react-three/rapier # 物理引擎
|
|
208
|
+
npm install react-error-boundary # 必装! Canvas 外包 ErrorBoundary
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## See Also
|
|
212
|
+
|
|
213
|
+
- `client-coding-guide` - vite-react 通用编码规范
|
|
214
|
+
- `component-conventions` - React 组件命名 / 文件结构
|