@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
- # AssetManager
2
-
3
- AssetManager handles loading and caching of 3D assets (FBX, GLB, OBJ) with support for skeletal animation cloning and preloading workflows.
4
-
5
- ## Quick Start
6
-
7
- ```typescript
8
- import { AssetManager } from "@series-ai/rundot-3d-engine/assets"
9
- import * as THREE from "three"
10
-
11
- // Initialize (done automatically by VenusGame)
12
- AssetManager.init(scene, renderer)
13
-
14
- // Preload assets before using them
15
- await AssetManager.preloadAssets([
16
- "models/character.fbx",
17
- "models/environment.glb",
18
- "animations/walk.fbx"
19
- ])
20
-
21
- // Use assets synchronously after preloading
22
- const mesh = AssetManager.getMesh("models/character.fbx")
23
- const animations = AssetManager.getAnimations("animations/walk.fbx")
24
- ```
25
-
26
- ## Common Use Cases
27
-
28
- ### Preloading Game Assets
29
-
30
- ```typescript
31
- class MyGame extends VenusGame {
32
- protected async onStart(): Promise<void> {
33
- // Show loading progress
34
- const assets = [
35
- "models/player.fbx",
36
- "models/enemy.fbx",
37
- "models/level.glb",
38
- "animations/idle.fbx",
39
- "animations/walk.fbx"
40
- ]
41
-
42
- let loaded = 0
43
- await AssetManager.preloadAssets(assets, (progress) => {
44
- loaded++
45
- console.log(`Loading: ${loaded}/${assets.length}`)
46
- })
47
-
48
- // All assets ready - create game objects
49
- this.setupGame()
50
- }
51
- }
52
- ```
53
-
54
- ### Skeletal Character Models
55
-
56
- ```typescript
57
- // Preload skeletal model (for animated characters)
58
- await AssetManager.preloadSkeletalModel("Character/player.fbx")
59
-
60
- // Get properly cloned skeletal model with bone structure
61
- const skeletalClone = AssetManager.getSkeletalClone("Character/player.fbx")
62
-
63
- // Use with animation mixer
64
- const mixer = new THREE.AnimationMixer(skeletalClone)
65
- ```
66
-
67
- ### Getting Meshes
68
-
69
- ```typescript
70
- // Get mesh (returns null if not loaded)
71
- const mesh = AssetManager.getMesh("models/tree.fbx")
72
-
73
- if (mesh) {
74
- scene.add(mesh.clone()) // Clone before using
75
- }
76
- ```
77
-
78
- ### Loading Animations
79
-
80
- ```typescript
81
- // Preload animation file
82
- await AssetManager.preloadAssets(["animations/walk.fbx"])
83
-
84
- // Get animation clip
85
- const clip = AssetManager.getAnimationClip("animations/walk.fbx")
86
-
87
- if (clip) {
88
- const action = mixer.clipAction(clip)
89
- action.play()
90
- }
91
-
92
- // Get all animations from a file
93
- const clips = AssetManager.getAnimations("animations/walk.fbx")
94
- ```
95
-
96
- ### Getting Asset Groups
97
-
98
- ```typescript
99
- // Get entire asset group (meshes, materials, etc.)
100
- const assetGroup = AssetManager.getAssetGroup("models/building.glb")
101
-
102
- if (assetGroup) {
103
- // Access meshes, materials, animations
104
- const meshes = AssetManager.getMeshes("models/building.glb")
105
- const materials = AssetManager.getMaterials("models/building.glb")
106
- }
107
- ```
108
-
109
- ## API Overview
110
-
111
- ### Initialization
112
-
113
- - `AssetManager.init(scene, renderer?)` - Initialize (called by VenusGame)
114
- - `AssetManager.setBaseUrl(url)` - Set base URL for relative paths
115
-
116
- ### Preloading
117
-
118
- - `preloadAssets(paths, progressCallback?): Promise<void>` - Preload multiple assets
119
- - `preloadSkeletalModel(path): Promise<void>` - Preload skeletal model for animation
120
-
121
- ### Accessing Assets
122
-
123
- - `getMesh(path): THREE.Object3D | null` - Get first mesh from asset
124
- - `getMeshes(path): THREE.Mesh[]` - Get all meshes from asset
125
- - `getAssetGroup(path): THREE.Group | null` - Get entire asset group
126
- - `getSkeletalClone(path): THREE.Object3D | null` - Get properly cloned skeletal model
127
- - `getMaterials(path): THREE.Material[]` - Get all materials from asset
128
- - `getAnimationClip(path, index?): THREE.AnimationClip | null` - Get specific animation clip
129
- - `getAnimations(path): THREE.AnimationClip[]` - Get all animation clips
130
- - `getGLTF(path): any | null` - Get raw GLTF data
131
-
132
- ### Utility
133
-
134
- - `isAssetLoaded(path): boolean` - Check if asset is loaded
135
- - `getLoadedAssetPaths(): string[]` - Get all loaded asset paths
136
-
137
- ## Supported Formats
138
-
139
- ### FBX (.fbx)
140
- - 3D models with or without animations
141
- - Skeletal character models
142
- - Animation clips
143
-
144
- ### GLB/GLTF (.glb, .gltf)
145
- - Complete scenes with meshes, materials, animations
146
- - PBR materials with textures
147
- - Optimized for web delivery
148
-
149
- ### OBJ (.obj)
150
- - Static 3D models
151
- - Optional .mtl material files
152
- - No animation support
153
-
154
- ## Patterns & Best Practices
155
-
156
- ### Preload Everything First
157
-
158
- ```typescript
159
- // Good - Preload during initialization
160
- protected async onStart(): Promise<void> {
161
- await AssetManager.preloadAssets([
162
- "all/your/assets.fbx"
163
- ])
164
- // Now use assets synchronously
165
- this.createGameObjects()
166
- }
167
-
168
- // Bad - Load on demand (slower, causes stuttering)
169
- createEnemy() {
170
- AssetManager.preloadAssets(["enemy.fbx"]).then(() => {
171
- const mesh = AssetManager.getMesh("enemy.fbx")
172
- // Delays enemy creation
173
- })
174
- }
175
- ```
176
-
177
- ### Always Clone Meshes
178
-
179
- ```typescript
180
- // Good - Clone before adding to scene
181
- const mesh = AssetManager.getMesh("tree.fbx")
182
- if (mesh) {
183
- scene.add(mesh.clone()) // Fresh copy
184
- }
185
-
186
- // Bad - Reuse same instance
187
- const mesh = AssetManager.getMesh("tree.fbx")
188
- if (mesh) {
189
- scene.add(mesh) // Modifying this affects all references!
190
- }
191
- ```
192
-
193
- ### Use Skeletal Cloning for Characters
194
-
195
- ```typescript
196
- // Good - Proper skeletal cloning
197
- await AssetManager.preloadSkeletalModel("character.fbx")
198
- const skeletalClone = AssetManager.getSkeletalClone("character.fbx")
199
- // Bones work correctly
200
-
201
- // Bad - Regular clone breaks bones
202
- const mesh = AssetManager.getMesh("character.fbx")
203
- const clone = mesh.clone() // Broken bone structure!
204
- ```
205
-
206
- ### Check if Assets are Loaded
207
-
208
- ```typescript
209
- // Good - Check before using
210
- if (AssetManager.isAssetLoaded("model.fbx")) {
211
- const mesh = AssetManager.getMesh("model.fbx")
212
- // Safe to use
213
- }
214
-
215
- // Alternative - null check
216
- const mesh = AssetManager.getMesh("model.fbx")
217
- if (mesh) {
218
- // Safe to use
219
- }
220
- ```
221
-
222
- ### Progress Tracking
223
-
224
- ```typescript
225
- const assets = [...largeAssetList]
226
- let progress = 0
227
-
228
- await AssetManager.preloadAssets(assets, (p) => {
229
- progress = (++progress / assets.length) * 100
230
- console.log(`Loading: ${progress.toFixed(0)}%`)
231
- })
232
- ```
233
-
234
- ## Anti-Patterns
235
-
236
- ### Don't Skip Preloading
237
-
238
- ```typescript
239
- // Bad - Asset won't be loaded
240
- const mesh = AssetManager.getMesh("model.fbx") // null!
241
-
242
- // Good - Preload first
243
- await AssetManager.preloadAssets(["model.fbx"])
244
- const mesh = AssetManager.getMesh("model.fbx") // Available!
245
- ```
246
-
247
- ### Don't Use Regular Cloning for Skeletal Models
248
-
249
- ```typescript
250
- // Bad - Breaks bone hierarchy
251
- const character = AssetManager.getMesh("character.fbx")
252
- const clone = character.clone() // Animations won't work!
253
-
254
- // Good - Use getSkeletalClone
255
- await AssetManager.preloadSkeletalModel("character.fbx")
256
- const clone = AssetManager.getSkeletalClone("character.fbx")
257
- ```
258
-
259
- ### Don't Load Same Asset Multiple Times
260
-
261
- ```typescript
262
- // Bad - Redundant preloading
263
- await AssetManager.preloadAssets(["model.fbx"])
264
- await AssetManager.preloadAssets(["model.fbx"]) // Cached, but unnecessary
265
-
266
- // Good - Check first
267
- if (!AssetManager.isAssetLoaded("model.fbx")) {
268
- await AssetManager.preloadAssets(["model.fbx"])
269
- }
270
- ```
271
-
272
- ## Caching Behavior
273
-
274
- AssetManager caches all loaded assets:
275
- - **First load**: Downloads and parses the file
276
- - **Subsequent access**: Returns cached version (fast!)
277
- - **Memory**: Assets stay in memory until page reload
278
-
279
- ```typescript
280
- // First call - loads from disk
281
- await AssetManager.preloadAssets(["model.fbx"]) // ~100ms
282
-
283
- // Later calls - instant (cached)
284
- const mesh1 = AssetManager.getMesh("model.fbx") // <1ms
285
- const mesh2 = AssetManager.getMesh("model.fbx") // <1ms (same cached instance)
286
- ```
287
-
288
- ## Integration with Renderers
289
-
290
- AssetManager works seamlessly with renderer components:
291
-
292
- ```typescript
293
- // SkeletalRenderer uses AssetManager internally
294
- await AssetManager.preloadSkeletalModel("character.fbx")
295
- const renderer = new SkeletalRenderer("character.fbx")
296
- // SkeletalRenderer calls getSkeletalClone() automatically
297
-
298
- // MeshRenderer uses StowKit (different system)
299
- // For StowKit assets, use MeshRenderer instead
300
- ```
301
-
302
- ## Related Systems
303
-
304
- - [MeshRenderer](MeshRenderer.md) - For StowKit assets (.stow format)
305
- - [SkeletalRenderer](SkeletalRenderer.md) - Uses AssetManager for skeletal models
306
- - [SkeletonCache](../../src/engine/assets/SkeletonCache.ts) - Proper bone cloning
307
- - [VenusGame](../core/VenusGame.md) - Initializes AssetManager
308
-
1
+ # AssetManager
2
+
3
+ AssetManager handles loading and caching of 3D assets (FBX, GLB, OBJ) with support for skeletal animation cloning and preloading workflows.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { AssetManager } from "@series-ai/rundot-3d-engine/assets"
9
+ import * as THREE from "three"
10
+
11
+ // Initialize (done automatically by VenusGame)
12
+ AssetManager.init(scene, renderer)
13
+
14
+ // Preload assets before using them
15
+ await AssetManager.preloadAssets([
16
+ "models/character.fbx",
17
+ "models/environment.glb",
18
+ "animations/walk.fbx"
19
+ ])
20
+
21
+ // Use assets synchronously after preloading
22
+ const mesh = AssetManager.getMesh("models/character.fbx")
23
+ const animations = AssetManager.getAnimations("animations/walk.fbx")
24
+ ```
25
+
26
+ ## Common Use Cases
27
+
28
+ ### Preloading Game Assets
29
+
30
+ ```typescript
31
+ class MyGame extends VenusGame {
32
+ protected async onStart(): Promise<void> {
33
+ // Show loading progress
34
+ const assets = [
35
+ "models/player.fbx",
36
+ "models/enemy.fbx",
37
+ "models/level.glb",
38
+ "animations/idle.fbx",
39
+ "animations/walk.fbx"
40
+ ]
41
+
42
+ let loaded = 0
43
+ await AssetManager.preloadAssets(assets, (progress) => {
44
+ loaded++
45
+ console.log(`Loading: ${loaded}/${assets.length}`)
46
+ })
47
+
48
+ // All assets ready - create game objects
49
+ this.setupGame()
50
+ }
51
+ }
52
+ ```
53
+
54
+ ### Skeletal Character Models
55
+
56
+ ```typescript
57
+ // Preload skeletal model (for animated characters)
58
+ await AssetManager.preloadSkeletalModel("Character/player.fbx")
59
+
60
+ // Get properly cloned skeletal model with bone structure
61
+ const skeletalClone = AssetManager.getSkeletalClone("Character/player.fbx")
62
+
63
+ // Use with animation mixer
64
+ const mixer = new THREE.AnimationMixer(skeletalClone)
65
+ ```
66
+
67
+ ### Getting Meshes
68
+
69
+ ```typescript
70
+ // Get mesh (returns null if not loaded)
71
+ const mesh = AssetManager.getMesh("models/tree.fbx")
72
+
73
+ if (mesh) {
74
+ scene.add(mesh.clone()) // Clone before using
75
+ }
76
+ ```
77
+
78
+ ### Loading Animations
79
+
80
+ ```typescript
81
+ // Preload animation file
82
+ await AssetManager.preloadAssets(["animations/walk.fbx"])
83
+
84
+ // Get animation clip
85
+ const clip = AssetManager.getAnimationClip("animations/walk.fbx")
86
+
87
+ if (clip) {
88
+ const action = mixer.clipAction(clip)
89
+ action.play()
90
+ }
91
+
92
+ // Get all animations from a file
93
+ const clips = AssetManager.getAnimations("animations/walk.fbx")
94
+ ```
95
+
96
+ ### Getting Asset Groups
97
+
98
+ ```typescript
99
+ // Get entire asset group (meshes, materials, etc.)
100
+ const assetGroup = AssetManager.getAssetGroup("models/building.glb")
101
+
102
+ if (assetGroup) {
103
+ // Access meshes, materials, animations
104
+ const meshes = AssetManager.getMeshes("models/building.glb")
105
+ const materials = AssetManager.getMaterials("models/building.glb")
106
+ }
107
+ ```
108
+
109
+ ## API Overview
110
+
111
+ ### Initialization
112
+
113
+ - `AssetManager.init(scene, renderer?)` - Initialize (called by VenusGame)
114
+ - `AssetManager.setBaseUrl(url)` - Set base URL for relative paths
115
+
116
+ ### Preloading
117
+
118
+ - `preloadAssets(paths, progressCallback?): Promise<void>` - Preload multiple assets
119
+ - `preloadSkeletalModel(path): Promise<void>` - Preload skeletal model for animation
120
+
121
+ ### Accessing Assets
122
+
123
+ - `getMesh(path): THREE.Object3D | null` - Get first mesh from asset
124
+ - `getMeshes(path): THREE.Mesh[]` - Get all meshes from asset
125
+ - `getAssetGroup(path): THREE.Group | null` - Get entire asset group
126
+ - `getSkeletalClone(path): THREE.Object3D | null` - Get properly cloned skeletal model
127
+ - `getMaterials(path): THREE.Material[]` - Get all materials from asset
128
+ - `getAnimationClip(path, index?): THREE.AnimationClip | null` - Get specific animation clip
129
+ - `getAnimations(path): THREE.AnimationClip[]` - Get all animation clips
130
+ - `getGLTF(path): any | null` - Get raw GLTF data
131
+
132
+ ### Utility
133
+
134
+ - `isAssetLoaded(path): boolean` - Check if asset is loaded
135
+ - `getLoadedAssetPaths(): string[]` - Get all loaded asset paths
136
+
137
+ ## Supported Formats
138
+
139
+ ### FBX (.fbx)
140
+ - 3D models with or without animations
141
+ - Skeletal character models
142
+ - Animation clips
143
+
144
+ ### GLB/GLTF (.glb, .gltf)
145
+ - Complete scenes with meshes, materials, animations
146
+ - PBR materials with textures
147
+ - Optimized for web delivery
148
+
149
+ ### OBJ (.obj)
150
+ - Static 3D models
151
+ - Optional .mtl material files
152
+ - No animation support
153
+
154
+ ## Patterns & Best Practices
155
+
156
+ ### Preload Everything First
157
+
158
+ ```typescript
159
+ // Good - Preload during initialization
160
+ protected async onStart(): Promise<void> {
161
+ await AssetManager.preloadAssets([
162
+ "all/your/assets.fbx"
163
+ ])
164
+ // Now use assets synchronously
165
+ this.createGameObjects()
166
+ }
167
+
168
+ // Bad - Load on demand (slower, causes stuttering)
169
+ createEnemy() {
170
+ AssetManager.preloadAssets(["enemy.fbx"]).then(() => {
171
+ const mesh = AssetManager.getMesh("enemy.fbx")
172
+ // Delays enemy creation
173
+ })
174
+ }
175
+ ```
176
+
177
+ ### Always Clone Meshes
178
+
179
+ ```typescript
180
+ // Good - Clone before adding to scene
181
+ const mesh = AssetManager.getMesh("tree.fbx")
182
+ if (mesh) {
183
+ scene.add(mesh.clone()) // Fresh copy
184
+ }
185
+
186
+ // Bad - Reuse same instance
187
+ const mesh = AssetManager.getMesh("tree.fbx")
188
+ if (mesh) {
189
+ scene.add(mesh) // Modifying this affects all references!
190
+ }
191
+ ```
192
+
193
+ ### Use Skeletal Cloning for Characters
194
+
195
+ ```typescript
196
+ // Good - Proper skeletal cloning
197
+ await AssetManager.preloadSkeletalModel("character.fbx")
198
+ const skeletalClone = AssetManager.getSkeletalClone("character.fbx")
199
+ // Bones work correctly
200
+
201
+ // Bad - Regular clone breaks bones
202
+ const mesh = AssetManager.getMesh("character.fbx")
203
+ const clone = mesh.clone() // Broken bone structure!
204
+ ```
205
+
206
+ ### Check if Assets are Loaded
207
+
208
+ ```typescript
209
+ // Good - Check before using
210
+ if (AssetManager.isAssetLoaded("model.fbx")) {
211
+ const mesh = AssetManager.getMesh("model.fbx")
212
+ // Safe to use
213
+ }
214
+
215
+ // Alternative - null check
216
+ const mesh = AssetManager.getMesh("model.fbx")
217
+ if (mesh) {
218
+ // Safe to use
219
+ }
220
+ ```
221
+
222
+ ### Progress Tracking
223
+
224
+ ```typescript
225
+ const assets = [...largeAssetList]
226
+ let progress = 0
227
+
228
+ await AssetManager.preloadAssets(assets, (p) => {
229
+ progress = (++progress / assets.length) * 100
230
+ console.log(`Loading: ${progress.toFixed(0)}%`)
231
+ })
232
+ ```
233
+
234
+ ## Anti-Patterns
235
+
236
+ ### Don't Skip Preloading
237
+
238
+ ```typescript
239
+ // Bad - Asset won't be loaded
240
+ const mesh = AssetManager.getMesh("model.fbx") // null!
241
+
242
+ // Good - Preload first
243
+ await AssetManager.preloadAssets(["model.fbx"])
244
+ const mesh = AssetManager.getMesh("model.fbx") // Available!
245
+ ```
246
+
247
+ ### Don't Use Regular Cloning for Skeletal Models
248
+
249
+ ```typescript
250
+ // Bad - Breaks bone hierarchy
251
+ const character = AssetManager.getMesh("character.fbx")
252
+ const clone = character.clone() // Animations won't work!
253
+
254
+ // Good - Use getSkeletalClone
255
+ await AssetManager.preloadSkeletalModel("character.fbx")
256
+ const clone = AssetManager.getSkeletalClone("character.fbx")
257
+ ```
258
+
259
+ ### Don't Load Same Asset Multiple Times
260
+
261
+ ```typescript
262
+ // Bad - Redundant preloading
263
+ await AssetManager.preloadAssets(["model.fbx"])
264
+ await AssetManager.preloadAssets(["model.fbx"]) // Cached, but unnecessary
265
+
266
+ // Good - Check first
267
+ if (!AssetManager.isAssetLoaded("model.fbx")) {
268
+ await AssetManager.preloadAssets(["model.fbx"])
269
+ }
270
+ ```
271
+
272
+ ## Caching Behavior
273
+
274
+ AssetManager caches all loaded assets:
275
+ - **First load**: Downloads and parses the file
276
+ - **Subsequent access**: Returns cached version (fast!)
277
+ - **Memory**: Assets stay in memory until page reload
278
+
279
+ ```typescript
280
+ // First call - loads from disk
281
+ await AssetManager.preloadAssets(["model.fbx"]) // ~100ms
282
+
283
+ // Later calls - instant (cached)
284
+ const mesh1 = AssetManager.getMesh("model.fbx") // <1ms
285
+ const mesh2 = AssetManager.getMesh("model.fbx") // <1ms (same cached instance)
286
+ ```
287
+
288
+ ## Integration with Renderers
289
+
290
+ AssetManager works seamlessly with renderer components:
291
+
292
+ ```typescript
293
+ // SkeletalRenderer uses AssetManager internally
294
+ await AssetManager.preloadSkeletalModel("character.fbx")
295
+ const renderer = new SkeletalRenderer("character.fbx")
296
+ // SkeletalRenderer calls getSkeletalClone() automatically
297
+
298
+ // MeshRenderer uses StowKit (different system)
299
+ // For StowKit assets, use MeshRenderer instead
300
+ ```
301
+
302
+ ## Related Systems
303
+
304
+ - [MeshRenderer](MeshRenderer.md) - For StowKit assets (.stow format)
305
+ - [SkeletalRenderer](SkeletalRenderer.md) - Uses AssetManager for skeletal models
306
+ - [SkeletonCache](../../src/engine/assets/SkeletonCache.ts) - Proper bone cloning
307
+ - [VenusGame](../core/VenusGame.md) - Initializes AssetManager
308
+