@series-inc/rundot-3d-engine 0.3.0 → 0.4.0

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.
@@ -1,308 +1,308 @@
1
- # SkeletalRenderer
2
-
3
- SkeletalRenderer loads and displays animated character meshes with skeletal animations. It properly clones bone structures and works with the animation system.
4
-
5
- ## Quick Start
6
-
7
- ```typescript
8
- import { GameObject, SkeletalRenderer } from "@series-ai/rundot-3d-engine"
9
- import { AssetManager } from "@series-ai/rundot-3d-engine/assets"
10
-
11
- // 1. Preload skeletal model
12
- await AssetManager.preloadSkeletalModel("Character/character_main.fbx")
13
-
14
- // 2. Create character with skeletal renderer
15
- const character = new GameObject("Character")
16
- const renderer = new SkeletalRenderer("Character/character_main.fbx")
17
- character.addComponent(renderer)
18
-
19
- // 3. Access skeletal model for animation
20
- const skeletalModel = renderer.getSkeletalModel()
21
- // Use with AnimationSystem
22
- ```
23
-
24
- ## Common Use Cases
25
-
26
- ### Basic Character Setup
27
-
28
- ```typescript
29
- class Character extends Component {
30
- private skeletalRenderer?: SkeletalRenderer
31
-
32
- protected async onCreate(): Promise<void> {
33
- // Must preload first
34
- await AssetManager.preloadSkeletalModel("Character/character_main.fbx")
35
-
36
- // Add renderer
37
- this.skeletalRenderer = new SkeletalRenderer("Character/character_main.fbx")
38
- this.gameObject.addComponent(this.skeletalRenderer)
39
- }
40
- }
41
- ```
42
-
43
- ### With Custom Material
44
-
45
- ```typescript
46
- import * as THREE from "three"
47
-
48
- // Create custom material
49
- const characterMaterial = new THREE.MeshStandardMaterial({
50
- color: 0xff0000,
51
- metalness: 0.1,
52
- roughness: 0.8
53
- })
54
-
55
- // Apply to skeletal renderer
56
- const renderer = new SkeletalRenderer(
57
- "Character/character_main.fbx",
58
- characterMaterial
59
- )
60
- ```
61
-
62
- ### Integration with Animation System
63
-
64
- ```typescript
65
- import { AnimationControllerComponent } from "@series-ai/rundot-3d-engine/systems"
66
-
67
- class AnimatedCharacter extends Component {
68
- protected async onCreate(): Promise<void> {
69
- // Preload model and animations
70
- await AssetManager.preloadSkeletalModel("Character/character.fbx")
71
- await AssetManager.preloadAssets([
72
- "Animations/walk.fbx",
73
- "Animations/run.fbx",
74
- "Animations/idle.fbx"
75
- ])
76
-
77
- // Add skeletal renderer
78
- const renderer = new SkeletalRenderer("Character/character.fbx")
79
- this.gameObject.addComponent(renderer)
80
-
81
- // Add animation controller
82
- const animController = new AnimationControllerComponent()
83
- this.gameObject.addComponent(animController)
84
-
85
- // Get skeletal model for animation setup
86
- const model = renderer.getSkeletalModel()
87
- if (model) {
88
- // Animation controller will find and use this model
89
- animController.setTarget(model)
90
- }
91
- }
92
- }
93
- ```
94
-
95
- ### Accessing Model for Custom Animation
96
-
97
- ```typescript
98
- class CustomAnimatedCharacter extends Component {
99
- private mixer?: THREE.AnimationMixer
100
- private renderer?: SkeletalRenderer
101
-
102
- protected onCreate(): void {
103
- this.renderer = new SkeletalRenderer("Character/character.fbx")
104
- this.gameObject.addComponent(this.renderer)
105
-
106
- const model = this.renderer.getSkeletalModel()
107
- if (model) {
108
- // Set up custom animation mixer
109
- this.mixer = new THREE.AnimationMixer(model)
110
-
111
- // Load and play animation
112
- const clip = AssetManager.getAnimationClip("Animations/walk.fbx")
113
- if (clip) {
114
- const action = this.mixer.clipAction(clip)
115
- action.play()
116
- }
117
- }
118
- }
119
-
120
- public update(deltaTime: number): void {
121
- this.mixer?.update(deltaTime)
122
- }
123
- }
124
- ```
125
-
126
- ## API Overview
127
-
128
- ### Constructor
129
-
130
- ```typescript
131
- new SkeletalRenderer(
132
- assetPath: string,
133
- material?: THREE.Material
134
- )
135
- ```
136
-
137
- ### Methods
138
-
139
- - `getGroup(): THREE.Group | null` - Get wrapper group (attached to GameObject)
140
- - `getSkeletalModel(): THREE.Object3D | null` - Get skeletal model for animation
141
- - `getAssetPath(): string` - Get asset path being rendered
142
- - `getMaterial(): THREE.Material | null` - Get custom material if set
143
- - `setMaterial(material: THREE.Material): void` - Change material at runtime
144
-
145
- ### Shadow Behavior
146
-
147
- SkeletalRenderer always:
148
- - Casts shadows (`castShadow: true`)
149
- - Receives shadows (`receiveShadow: true`)
150
- - These cannot be disabled (characters always interact with lighting)
151
-
152
- ## Patterns & Best Practices
153
-
154
- ### Always Preload Before Using
155
-
156
- ```typescript
157
- // Good - Preload in game initialization
158
- class MyGame extends VenusGame {
159
- protected async onStart(): Promise<void> {
160
- // Preload all character models
161
- await AssetManager.preloadSkeletalModel("Character/player.fbx")
162
- await AssetManager.preloadSkeletalModel("Character/enemy.fbx")
163
-
164
- // Now safe to use
165
- this.createCharacters()
166
- }
167
- }
168
-
169
- // Bad - Don't use without preloading
170
- const renderer = new SkeletalRenderer("Character/player.fbx") // Error!
171
- ```
172
-
173
- ### Use with AnimationControllerComponent
174
-
175
- ```typescript
176
- // Good - Let AnimationController manage animations
177
- const renderer = new SkeletalRenderer("Character/char.fbx")
178
- this.gameObject.addComponent(renderer)
179
-
180
- const animController = new AnimationControllerComponent()
181
- this.gameObject.addComponent(animController)
182
- // AnimationController finds and uses the skeletal model
183
- ```
184
-
185
- ### Material Customization
186
-
187
- ```typescript
188
- // Apply game-specific materials to characters
189
- const toonMaterial = MaterialUtils.createToonMaterial(0xff5500)
190
-
191
- const renderer = new SkeletalRenderer(
192
- "Character/character.fbx",
193
- toonMaterial
194
- )
195
- ```
196
-
197
- ## Anti-Patterns
198
-
199
- ### Don't Use for Static Meshes
200
-
201
- ```typescript
202
- // Bad - SkeletalRenderer is for animated characters only
203
- const tree = new SkeletalRenderer("tree.fbx")
204
-
205
- // Good - Use MeshRenderer for static objects
206
- const renderer = new MeshRenderer("tree")
207
- const treeObj = new GameObject("TreeMesh")
208
- treeObj.addComponent(renderer)
209
- this.gameObject.add(treeObj)
210
- ```
211
-
212
- ### Don't Forget Preloading
213
-
214
- ```typescript
215
- // Bad - Throws error "No skeletal model found"
216
- const renderer = new SkeletalRenderer("Character/player.fbx")
217
- this.gameObject.addComponent(renderer) // ERROR!
218
-
219
- // Good - Preload first
220
- await AssetManager.preloadSkeletalModel("Character/player.fbx")
221
- const renderer = new SkeletalRenderer("Character/player.fbx")
222
- this.gameObject.addComponent(renderer) // Works!
223
- ```
224
-
225
- ### Don't Clone Manually
226
-
227
- ```typescript
228
- // Bad - Manual cloning breaks bones
229
- const model = AssetManager.getAssetGroup("Character/char.fbx")
230
- const clone = model.clone() // Broken bones!
231
-
232
- // Good - Use SkeletalRenderer (uses SkeletonCache)
233
- const renderer = new SkeletalRenderer("Character/char.fbx")
234
- // Properly clones with bone structure intact
235
- ```
236
-
237
- ## Character Setup Workflow
238
-
239
- Typical workflow for setting up animated characters:
240
-
241
- ```typescript
242
- class CharacterSetup {
243
- static async preloadAssets(): Promise<void> {
244
- // 1. Preload character model
245
- await AssetManager.preloadSkeletalModel("Character/player.fbx")
246
-
247
- // 2. Preload animations
248
- await AssetManager.preloadAssets([
249
- "Animations/idle.fbx",
250
- "Animations/walk.fbx",
251
- "Animations/run.fbx",
252
- "Animations/jump.fbx"
253
- ])
254
- }
255
-
256
- static create(): GameObject {
257
- // 3. Create GameObject
258
- const character = new GameObject("Player")
259
-
260
- // 4. Add SkeletalRenderer
261
- const renderer = new SkeletalRenderer("Character/player.fbx")
262
- character.addComponent(renderer)
263
-
264
- // 5. Add AnimationController
265
- const animController = new AnimationControllerComponent()
266
- character.addComponent(animController)
267
-
268
- // 6. Set up animation states
269
- animController.addState("idle", "Animations/idle.fbx")
270
- animController.addState("walk", "Animations/walk.fbx")
271
- animController.setState("idle")
272
-
273
- return character
274
- }
275
- }
276
- ```
277
-
278
- ## Performance Considerations
279
-
280
- ### Skeletal Animation Cost
281
-
282
- Skeletal rendering is more expensive than static meshes:
283
- - Bone calculations per frame
284
- - Animation blending
285
- - Skin weights processing
286
-
287
- ### Optimization Tips
288
-
289
- ```typescript
290
- // Reduce character LOD distance
291
- VenusGame.getAnimationCulling().setDistanceCullingEnabled(true)
292
- VenusGame.getAnimationCulling().setMaxDistance(50) // Units
293
-
294
- // Use frustum culling
295
- VenusGame.setAnimationCullingCamera(camera, 1.2)
296
-
297
- // Limit active characters
298
- // Pool inactive characters instead of creating/destroying
299
- ```
300
-
301
- ## Related Systems
302
-
303
- - [AssetManager](AssetManager.md) - Preloading skeletal models
304
- - [AnimationControllerComponent](../systems/AnimationSystem.md) - Animation management
305
- - [MeshRenderer](MeshRenderer.md) - For non-animated meshes
306
- - [GameObject](../core/GameObject.md) - Entity class
307
- - [Component](../core/Component.md) - Base component class
308
-
1
+ # SkeletalRenderer
2
+
3
+ SkeletalRenderer loads and displays animated character meshes with skeletal animations. It properly clones bone structures and works with the animation system.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { GameObject, SkeletalRenderer } from "@series-ai/rundot-3d-engine"
9
+ import { AssetManager } from "@series-ai/rundot-3d-engine/assets"
10
+
11
+ // 1. Preload skeletal model
12
+ await AssetManager.preloadSkeletalModel("Character/character_main.fbx")
13
+
14
+ // 2. Create character with skeletal renderer
15
+ const character = new GameObject("Character")
16
+ const renderer = new SkeletalRenderer("Character/character_main.fbx")
17
+ character.addComponent(renderer)
18
+
19
+ // 3. Access skeletal model for animation
20
+ const skeletalModel = renderer.getSkeletalModel()
21
+ // Use with AnimationSystem
22
+ ```
23
+
24
+ ## Common Use Cases
25
+
26
+ ### Basic Character Setup
27
+
28
+ ```typescript
29
+ class Character extends Component {
30
+ private skeletalRenderer?: SkeletalRenderer
31
+
32
+ protected async onCreate(): Promise<void> {
33
+ // Must preload first
34
+ await AssetManager.preloadSkeletalModel("Character/character_main.fbx")
35
+
36
+ // Add renderer
37
+ this.skeletalRenderer = new SkeletalRenderer("Character/character_main.fbx")
38
+ this.gameObject.addComponent(this.skeletalRenderer)
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### With Custom Material
44
+
45
+ ```typescript
46
+ import * as THREE from "three"
47
+
48
+ // Create custom material
49
+ const characterMaterial = new THREE.MeshStandardMaterial({
50
+ color: 0xff0000,
51
+ metalness: 0.1,
52
+ roughness: 0.8
53
+ })
54
+
55
+ // Apply to skeletal renderer
56
+ const renderer = new SkeletalRenderer(
57
+ "Character/character_main.fbx",
58
+ characterMaterial
59
+ )
60
+ ```
61
+
62
+ ### Integration with Animation System
63
+
64
+ ```typescript
65
+ import { AnimationControllerComponent } from "@series-ai/rundot-3d-engine/systems"
66
+
67
+ class AnimatedCharacter extends Component {
68
+ protected async onCreate(): Promise<void> {
69
+ // Preload model and animations
70
+ await AssetManager.preloadSkeletalModel("Character/character.fbx")
71
+ await AssetManager.preloadAssets([
72
+ "Animations/walk.fbx",
73
+ "Animations/run.fbx",
74
+ "Animations/idle.fbx"
75
+ ])
76
+
77
+ // Add skeletal renderer
78
+ const renderer = new SkeletalRenderer("Character/character.fbx")
79
+ this.gameObject.addComponent(renderer)
80
+
81
+ // Add animation controller
82
+ const animController = new AnimationControllerComponent()
83
+ this.gameObject.addComponent(animController)
84
+
85
+ // Get skeletal model for animation setup
86
+ const model = renderer.getSkeletalModel()
87
+ if (model) {
88
+ // Animation controller will find and use this model
89
+ animController.setTarget(model)
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ### Accessing Model for Custom Animation
96
+
97
+ ```typescript
98
+ class CustomAnimatedCharacter extends Component {
99
+ private mixer?: THREE.AnimationMixer
100
+ private renderer?: SkeletalRenderer
101
+
102
+ protected onCreate(): void {
103
+ this.renderer = new SkeletalRenderer("Character/character.fbx")
104
+ this.gameObject.addComponent(this.renderer)
105
+
106
+ const model = this.renderer.getSkeletalModel()
107
+ if (model) {
108
+ // Set up custom animation mixer
109
+ this.mixer = new THREE.AnimationMixer(model)
110
+
111
+ // Load and play animation
112
+ const clip = AssetManager.getAnimationClip("Animations/walk.fbx")
113
+ if (clip) {
114
+ const action = this.mixer.clipAction(clip)
115
+ action.play()
116
+ }
117
+ }
118
+ }
119
+
120
+ public update(deltaTime: number): void {
121
+ this.mixer?.update(deltaTime)
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## API Overview
127
+
128
+ ### Constructor
129
+
130
+ ```typescript
131
+ new SkeletalRenderer(
132
+ assetPath: string,
133
+ material?: THREE.Material
134
+ )
135
+ ```
136
+
137
+ ### Methods
138
+
139
+ - `getGroup(): THREE.Group | null` - Get wrapper group (attached to GameObject)
140
+ - `getSkeletalModel(): THREE.Object3D | null` - Get skeletal model for animation
141
+ - `getAssetPath(): string` - Get asset path being rendered
142
+ - `getMaterial(): THREE.Material | null` - Get custom material if set
143
+ - `setMaterial(material: THREE.Material): void` - Change material at runtime
144
+
145
+ ### Shadow Behavior
146
+
147
+ SkeletalRenderer always:
148
+ - Casts shadows (`castShadow: true`)
149
+ - Receives shadows (`receiveShadow: true`)
150
+ - These cannot be disabled (characters always interact with lighting)
151
+
152
+ ## Patterns & Best Practices
153
+
154
+ ### Always Preload Before Using
155
+
156
+ ```typescript
157
+ // Good - Preload in game initialization
158
+ class MyGame extends VenusGame {
159
+ protected async onStart(): Promise<void> {
160
+ // Preload all character models
161
+ await AssetManager.preloadSkeletalModel("Character/player.fbx")
162
+ await AssetManager.preloadSkeletalModel("Character/enemy.fbx")
163
+
164
+ // Now safe to use
165
+ this.createCharacters()
166
+ }
167
+ }
168
+
169
+ // Bad - Don't use without preloading
170
+ const renderer = new SkeletalRenderer("Character/player.fbx") // Error!
171
+ ```
172
+
173
+ ### Use with AnimationControllerComponent
174
+
175
+ ```typescript
176
+ // Good - Let AnimationController manage animations
177
+ const renderer = new SkeletalRenderer("Character/char.fbx")
178
+ this.gameObject.addComponent(renderer)
179
+
180
+ const animController = new AnimationControllerComponent()
181
+ this.gameObject.addComponent(animController)
182
+ // AnimationController finds and uses the skeletal model
183
+ ```
184
+
185
+ ### Material Customization
186
+
187
+ ```typescript
188
+ // Apply game-specific materials to characters
189
+ const toonMaterial = MaterialUtils.createToonMaterial(0xff5500)
190
+
191
+ const renderer = new SkeletalRenderer(
192
+ "Character/character.fbx",
193
+ toonMaterial
194
+ )
195
+ ```
196
+
197
+ ## Anti-Patterns
198
+
199
+ ### Don't Use for Static Meshes
200
+
201
+ ```typescript
202
+ // Bad - SkeletalRenderer is for animated characters only
203
+ const tree = new SkeletalRenderer("tree.fbx")
204
+
205
+ // Good - Use MeshRenderer for static objects
206
+ const renderer = new MeshRenderer("tree")
207
+ const treeObj = new GameObject("TreeMesh")
208
+ treeObj.addComponent(renderer)
209
+ this.gameObject.add(treeObj)
210
+ ```
211
+
212
+ ### Don't Forget Preloading
213
+
214
+ ```typescript
215
+ // Bad - Throws error "No skeletal model found"
216
+ const renderer = new SkeletalRenderer("Character/player.fbx")
217
+ this.gameObject.addComponent(renderer) // ERROR!
218
+
219
+ // Good - Preload first
220
+ await AssetManager.preloadSkeletalModel("Character/player.fbx")
221
+ const renderer = new SkeletalRenderer("Character/player.fbx")
222
+ this.gameObject.addComponent(renderer) // Works!
223
+ ```
224
+
225
+ ### Don't Clone Manually
226
+
227
+ ```typescript
228
+ // Bad - Manual cloning breaks bones
229
+ const model = AssetManager.getAssetGroup("Character/char.fbx")
230
+ const clone = model.clone() // Broken bones!
231
+
232
+ // Good - Use SkeletalRenderer (uses SkeletonCache)
233
+ const renderer = new SkeletalRenderer("Character/char.fbx")
234
+ // Properly clones with bone structure intact
235
+ ```
236
+
237
+ ## Character Setup Workflow
238
+
239
+ Typical workflow for setting up animated characters:
240
+
241
+ ```typescript
242
+ class CharacterSetup {
243
+ static async preloadAssets(): Promise<void> {
244
+ // 1. Preload character model
245
+ await AssetManager.preloadSkeletalModel("Character/player.fbx")
246
+
247
+ // 2. Preload animations
248
+ await AssetManager.preloadAssets([
249
+ "Animations/idle.fbx",
250
+ "Animations/walk.fbx",
251
+ "Animations/run.fbx",
252
+ "Animations/jump.fbx"
253
+ ])
254
+ }
255
+
256
+ static create(): GameObject {
257
+ // 3. Create GameObject
258
+ const character = new GameObject("Player")
259
+
260
+ // 4. Add SkeletalRenderer
261
+ const renderer = new SkeletalRenderer("Character/player.fbx")
262
+ character.addComponent(renderer)
263
+
264
+ // 5. Add AnimationController
265
+ const animController = new AnimationControllerComponent()
266
+ character.addComponent(animController)
267
+
268
+ // 6. Set up animation states
269
+ animController.addState("idle", "Animations/idle.fbx")
270
+ animController.addState("walk", "Animations/walk.fbx")
271
+ animController.setState("idle")
272
+
273
+ return character
274
+ }
275
+ }
276
+ ```
277
+
278
+ ## Performance Considerations
279
+
280
+ ### Skeletal Animation Cost
281
+
282
+ Skeletal rendering is more expensive than static meshes:
283
+ - Bone calculations per frame
284
+ - Animation blending
285
+ - Skin weights processing
286
+
287
+ ### Optimization Tips
288
+
289
+ ```typescript
290
+ // Reduce character LOD distance
291
+ VenusGame.getAnimationCulling().setDistanceCullingEnabled(true)
292
+ VenusGame.getAnimationCulling().setMaxDistance(50) // Units
293
+
294
+ // Use frustum culling
295
+ VenusGame.setAnimationCullingCamera(camera, 1.2)
296
+
297
+ // Limit active characters
298
+ // Pool inactive characters instead of creating/destroying
299
+ ```
300
+
301
+ ## Related Systems
302
+
303
+ - [AssetManager](AssetManager.md) - Preloading skeletal models
304
+ - [AnimationControllerComponent](../systems/AnimationSystem.md) - Animation management
305
+ - [MeshRenderer](MeshRenderer.md) - For non-animated meshes
306
+ - [GameObject](../core/GameObject.md) - Entity class
307
+ - [Component](../core/Component.md) - Base component class
308
+