@codexo/exojs 0.8.4 → 0.9.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.
Files changed (317) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +26 -5
  3. package/dist/esm/animation/Tween.d.ts +20 -3
  4. package/dist/esm/animation/Tween.js +16 -8
  5. package/dist/esm/animation/Tween.js.map +1 -1
  6. package/dist/esm/animation/TweenManager.d.ts +16 -1
  7. package/dist/esm/animation/TweenManager.js +27 -2
  8. package/dist/esm/animation/TweenManager.js.map +1 -1
  9. package/dist/esm/audio/AudioAnalyser.d.ts +2 -0
  10. package/dist/esm/audio/AudioAnalyser.js +24 -9
  11. package/dist/esm/audio/AudioAnalyser.js.map +1 -1
  12. package/dist/esm/audio/AudioBus.d.ts +1 -0
  13. package/dist/esm/audio/AudioBus.js +8 -4
  14. package/dist/esm/audio/AudioBus.js.map +1 -1
  15. package/dist/esm/audio/AudioListener.d.ts +1 -0
  16. package/dist/esm/audio/AudioListener.js +7 -5
  17. package/dist/esm/audio/AudioListener.js.map +1 -1
  18. package/dist/esm/audio/AudioManager.d.ts +8 -2
  19. package/dist/esm/audio/AudioManager.js +14 -1
  20. package/dist/esm/audio/AudioManager.js.map +1 -1
  21. package/dist/esm/audio/BeatDetector.d.ts +2 -0
  22. package/dist/esm/audio/BeatDetector.js +27 -661
  23. package/dist/esm/audio/BeatDetector.js.map +1 -1
  24. package/dist/esm/audio/Music.d.ts +1 -0
  25. package/dist/esm/audio/Music.js +7 -3
  26. package/dist/esm/audio/Music.js.map +1 -1
  27. package/dist/esm/audio/OscillatorSound.d.ts +1 -0
  28. package/dist/esm/audio/OscillatorSound.js +7 -3
  29. package/dist/esm/audio/OscillatorSound.js.map +1 -1
  30. package/dist/esm/audio/Sound.d.ts +1 -0
  31. package/dist/esm/audio/Sound.js +7 -3
  32. package/dist/esm/audio/Sound.js.map +1 -1
  33. package/dist/esm/audio/audio-context.d.ts +2 -2
  34. package/dist/esm/audio/audio-context.js +4 -4
  35. package/dist/esm/audio/audio-context.js.map +1 -1
  36. package/dist/esm/audio/filters/ChorusFilter.d.ts +1 -0
  37. package/dist/esm/audio/filters/ChorusFilter.js +7 -3
  38. package/dist/esm/audio/filters/ChorusFilter.js.map +1 -1
  39. package/dist/esm/audio/filters/CompressorFilter.d.ts +1 -0
  40. package/dist/esm/audio/filters/CompressorFilter.js +7 -3
  41. package/dist/esm/audio/filters/CompressorFilter.js.map +1 -1
  42. package/dist/esm/audio/filters/DelayFilter.d.ts +1 -0
  43. package/dist/esm/audio/filters/DelayFilter.js +7 -3
  44. package/dist/esm/audio/filters/DelayFilter.js.map +1 -1
  45. package/dist/esm/audio/filters/EqualizerFilter.d.ts +1 -0
  46. package/dist/esm/audio/filters/EqualizerFilter.js +7 -3
  47. package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -1
  48. package/dist/esm/audio/filters/GranularFilter.js +1 -86
  49. package/dist/esm/audio/filters/GranularFilter.js.map +1 -1
  50. package/dist/esm/audio/filters/HighpassFilter.d.ts +1 -0
  51. package/dist/esm/audio/filters/HighpassFilter.js +7 -3
  52. package/dist/esm/audio/filters/HighpassFilter.js.map +1 -1
  53. package/dist/esm/audio/filters/LowpassFilter.d.ts +1 -0
  54. package/dist/esm/audio/filters/LowpassFilter.js +7 -3
  55. package/dist/esm/audio/filters/LowpassFilter.js.map +1 -1
  56. package/dist/esm/audio/filters/PitchShiftFilter.js +1 -71
  57. package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -1
  58. package/dist/esm/audio/filters/ReverbFilter.d.ts +1 -0
  59. package/dist/esm/audio/filters/ReverbFilter.js +7 -3
  60. package/dist/esm/audio/filters/ReverbFilter.js.map +1 -1
  61. package/dist/esm/audio/filters/VocoderFilter.js +1 -89
  62. package/dist/esm/audio/filters/VocoderFilter.js.map +1 -1
  63. package/dist/esm/audio/filters/WorkletFilter.d.ts +2 -0
  64. package/dist/esm/audio/filters/WorkletFilter.js +10 -5
  65. package/dist/esm/audio/filters/WorkletFilter.js.map +1 -1
  66. package/dist/esm/audio/index.d.ts +15 -10
  67. package/dist/esm/audio/worklet/registerWorklet.d.ts +1 -1
  68. package/dist/esm/audio/worklet/registerWorklet.js +2 -2
  69. package/dist/esm/audio/worklet/registerWorklet.js.map +1 -1
  70. package/dist/esm/audio/worklets/beat-detector.worklet.d.ts +1 -0
  71. package/dist/esm/audio/worklets/beat-detector.worklet.js +647 -0
  72. package/dist/esm/audio/worklets/beat-detector.worklet.js.map +1 -0
  73. package/dist/esm/audio/worklets/granular.worklet.d.ts +1 -0
  74. package/dist/esm/audio/worklets/granular.worklet.js +89 -0
  75. package/dist/esm/audio/worklets/granular.worklet.js.map +1 -0
  76. package/dist/esm/audio/worklets/pitch-shift.worklet.d.ts +1 -0
  77. package/dist/esm/audio/worklets/pitch-shift.worklet.js +74 -0
  78. package/dist/esm/audio/worklets/pitch-shift.worklet.js.map +1 -0
  79. package/dist/esm/audio/worklets/vocoder.worklet.d.ts +1 -0
  80. package/dist/esm/audio/worklets/vocoder.worklet.js +92 -0
  81. package/dist/esm/audio/worklets/vocoder.worklet.js.map +1 -0
  82. package/dist/esm/core/Application.d.ts +62 -24
  83. package/dist/esm/core/Application.js +116 -40
  84. package/dist/esm/core/Application.js.map +1 -1
  85. package/dist/esm/core/Color.d.ts +0 -8
  86. package/dist/esm/core/Color.js +0 -24
  87. package/dist/esm/core/Color.js.map +1 -1
  88. package/dist/esm/core/Scene.d.ts +32 -72
  89. package/dist/esm/core/Scene.js +56 -36
  90. package/dist/esm/core/Scene.js.map +1 -1
  91. package/dist/esm/core/SceneManager.d.ts +11 -25
  92. package/dist/esm/core/SceneManager.js +37 -100
  93. package/dist/esm/core/SceneManager.js.map +1 -1
  94. package/dist/esm/core/SceneNode.d.ts +28 -14
  95. package/dist/esm/core/SceneNode.js +66 -33
  96. package/dist/esm/core/SceneNode.js.map +1 -1
  97. package/dist/esm/core/Signal.d.ts +24 -28
  98. package/dist/esm/core/Signal.js +64 -50
  99. package/dist/esm/core/Signal.js.map +1 -1
  100. package/dist/esm/core/Timer.d.ts +1 -0
  101. package/dist/esm/core/Timer.js +3 -0
  102. package/dist/esm/core/Timer.js.map +1 -1
  103. package/dist/esm/debug/BoundingBoxesLayer.js +1 -1
  104. package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
  105. package/dist/esm/debug/HitTestLayer.js +1 -1
  106. package/dist/esm/debug/HitTestLayer.js.map +1 -1
  107. package/dist/esm/debug/PerformanceLayer.js +1 -2
  108. package/dist/esm/debug/PerformanceLayer.js.map +1 -1
  109. package/dist/esm/debug/PointerStackLayer.js +1 -2
  110. package/dist/esm/debug/PointerStackLayer.js.map +1 -1
  111. package/dist/esm/debug/RenderPassInspectorLayer.js +1 -2
  112. package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -1
  113. package/dist/esm/index.js +23 -7
  114. package/dist/esm/index.js.map +1 -1
  115. package/dist/esm/input/InputManager.d.ts +1 -0
  116. package/dist/esm/input/InputManager.js +30 -3
  117. package/dist/esm/input/InputManager.js.map +1 -1
  118. package/dist/esm/input/InteractionManager.d.ts +5 -2
  119. package/dist/esm/input/InteractionManager.js +29 -18
  120. package/dist/esm/input/InteractionManager.js.map +1 -1
  121. package/dist/esm/input/Pointer.js +3 -2
  122. package/dist/esm/input/Pointer.js.map +1 -1
  123. package/dist/esm/input/internal/interactionManagerRegistry.d.ts +9 -0
  124. package/dist/esm/input/internal/interactionManagerRegistry.js +10 -0
  125. package/dist/esm/input/internal/interactionManagerRegistry.js.map +1 -0
  126. package/dist/esm/math/AbstractVector.d.ts +1 -7
  127. package/dist/esm/math/AbstractVector.js +6 -20
  128. package/dist/esm/math/AbstractVector.js.map +1 -1
  129. package/dist/esm/math/Circle.js +0 -2
  130. package/dist/esm/math/Circle.js.map +1 -1
  131. package/dist/esm/math/Collision.d.ts +9 -3
  132. package/dist/esm/math/Ellipse.d.ts +2 -5
  133. package/dist/esm/math/Ellipse.js +10 -7
  134. package/dist/esm/math/Ellipse.js.map +1 -1
  135. package/dist/esm/math/ObservableVector.d.ts +1 -1
  136. package/dist/esm/math/ObservableVector.js +3 -3
  137. package/dist/esm/math/ObservableVector.js.map +1 -1
  138. package/dist/esm/math/Polygon.d.ts +0 -2
  139. package/dist/esm/math/Polygon.js +1 -9
  140. package/dist/esm/math/Polygon.js.map +1 -1
  141. package/dist/esm/math/Rectangle.js +0 -2
  142. package/dist/esm/math/Rectangle.js.map +1 -1
  143. package/dist/esm/math/collision-detection.d.ts +19 -4
  144. package/dist/esm/math/collision-detection.js +61 -4
  145. package/dist/esm/math/collision-detection.js.map +1 -1
  146. package/dist/esm/math/swept-collision.d.ts +16 -12
  147. package/dist/esm/math/swept-collision.js +109 -19
  148. package/dist/esm/math/swept-collision.js.map +1 -1
  149. package/dist/esm/particles/ParticleSystem.js +1 -1
  150. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  151. package/dist/esm/particles/index.d.ts +1 -0
  152. package/dist/esm/rendering/CallbackRenderPass.d.ts +1 -0
  153. package/dist/esm/rendering/CallbackRenderPass.js +1 -0
  154. package/dist/esm/rendering/CallbackRenderPass.js.map +1 -1
  155. package/dist/esm/rendering/Container.d.ts +2 -1
  156. package/dist/esm/rendering/Container.js +17 -16
  157. package/dist/esm/rendering/Container.js.map +1 -1
  158. package/dist/esm/rendering/RenderBackend.d.ts +1 -0
  159. package/dist/esm/rendering/RenderNode.d.ts +1 -3
  160. package/dist/esm/rendering/RenderNode.js +12 -19
  161. package/dist/esm/rendering/RenderNode.js.map +1 -1
  162. package/dist/esm/rendering/RenderPass.d.ts +1 -0
  163. package/dist/esm/rendering/RenderStats.d.ts +9 -0
  164. package/dist/esm/rendering/RenderStats.js +2 -0
  165. package/dist/esm/rendering/RenderStats.js.map +1 -1
  166. package/dist/esm/rendering/RendererRegistry.d.ts +1 -0
  167. package/dist/esm/rendering/RendererRegistry.js +1 -0
  168. package/dist/esm/rendering/RendererRegistry.js.map +1 -1
  169. package/dist/esm/rendering/View.d.ts +23 -0
  170. package/dist/esm/rendering/View.js +42 -0
  171. package/dist/esm/rendering/View.js.map +1 -1
  172. package/dist/esm/rendering/index.d.ts +89 -59
  173. package/dist/esm/rendering/mesh/Mesh.js +1 -1
  174. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  175. package/dist/esm/rendering/mesh/MeshShader.d.ts +1 -0
  176. package/dist/esm/rendering/mesh/MeshShader.js +1 -0
  177. package/dist/esm/rendering/mesh/MeshShader.js.map +1 -1
  178. package/dist/esm/rendering/shader/Shader.d.ts +1 -0
  179. package/dist/esm/rendering/shader/Shader.js +1 -0
  180. package/dist/esm/rendering/shader/Shader.js.map +1 -1
  181. package/dist/esm/rendering/shader/ShaderUniform.d.ts +1 -0
  182. package/dist/esm/rendering/shader/ShaderUniform.js +1 -0
  183. package/dist/esm/rendering/shader/ShaderUniform.js.map +1 -1
  184. package/dist/esm/rendering/sprite/Sprite.d.ts +3 -2
  185. package/dist/esm/rendering/sprite/Sprite.js +15 -13
  186. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  187. package/dist/esm/rendering/text/AbstractText.d.ts +36 -0
  188. package/dist/esm/rendering/text/AbstractText.js +49 -0
  189. package/dist/esm/rendering/text/AbstractText.js.map +1 -0
  190. package/dist/esm/rendering/text/BitmapText.d.ts +97 -0
  191. package/dist/esm/rendering/text/BitmapText.js +220 -0
  192. package/dist/esm/rendering/text/BitmapText.js.map +1 -0
  193. package/dist/esm/rendering/text/BmFont.d.ts +50 -0
  194. package/dist/esm/rendering/text/BmFont.js +24 -0
  195. package/dist/esm/rendering/text/BmFont.js.map +1 -0
  196. package/dist/esm/rendering/text/GlyphAtlas.d.ts +104 -0
  197. package/dist/esm/rendering/text/GlyphAtlas.js +347 -0
  198. package/dist/esm/rendering/text/GlyphAtlas.js.map +1 -0
  199. package/dist/esm/rendering/text/GlyphAtlasPool.d.ts +40 -0
  200. package/dist/esm/rendering/text/GlyphAtlasPool.js +67 -0
  201. package/dist/esm/rendering/text/GlyphAtlasPool.js.map +1 -0
  202. package/dist/esm/rendering/text/GlyphSdf.d.ts +92 -0
  203. package/dist/esm/rendering/text/GlyphSdf.js +220 -0
  204. package/dist/esm/rendering/text/GlyphSdf.js.map +1 -0
  205. package/dist/esm/rendering/text/HTMLText.d.ts +107 -0
  206. package/dist/esm/rendering/text/HTMLText.js +284 -0
  207. package/dist/esm/rendering/text/HTMLText.js.map +1 -0
  208. package/dist/esm/rendering/text/LayoutOptions.d.ts +30 -0
  209. package/dist/esm/rendering/text/Text.d.ts +89 -20
  210. package/dist/esm/rendering/text/Text.js +176 -101
  211. package/dist/esm/rendering/text/Text.js.map +1 -1
  212. package/dist/esm/rendering/text/TextLayout.d.ts +20 -8
  213. package/dist/esm/rendering/text/TextLayout.js +234 -25
  214. package/dist/esm/rendering/text/TextLayout.js.map +1 -1
  215. package/dist/esm/rendering/text/TextStyle.d.ts +154 -87
  216. package/dist/esm/rendering/text/TextStyle.js +257 -203
  217. package/dist/esm/rendering/text/TextStyle.js.map +1 -1
  218. package/dist/esm/rendering/text/types.d.ts +73 -13
  219. package/dist/esm/rendering/texture/Texture.d.ts +1 -0
  220. package/dist/esm/rendering/texture/Texture.js +1 -0
  221. package/dist/esm/rendering/texture/Texture.js.map +1 -1
  222. package/dist/esm/rendering/types.d.ts +3 -1
  223. package/dist/esm/rendering/types.js +2 -0
  224. package/dist/esm/rendering/types.js.map +1 -1
  225. package/dist/esm/rendering/video/Video.d.ts +2 -1
  226. package/dist/esm/rendering/video/Video.js +9 -5
  227. package/dist/esm/rendering/video/Video.js.map +1 -1
  228. package/dist/esm/rendering/webgl2/WebGl2Backend.js +41 -5
  229. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  230. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +4 -4
  231. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
  232. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.d.ts +56 -0
  233. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js +482 -0
  234. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js.map +1 -0
  235. package/dist/esm/rendering/webgl2/glsl/text-color.frag.js +4 -0
  236. package/dist/esm/rendering/webgl2/glsl/text-color.frag.js.map +1 -0
  237. package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js +4 -0
  238. package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js.map +1 -0
  239. package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js +4 -0
  240. package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js.map +1 -0
  241. package/dist/esm/rendering/webgl2/glsl/text.vert.js +4 -0
  242. package/dist/esm/rendering/webgl2/glsl/text.vert.js.map +1 -0
  243. package/dist/esm/rendering/webgpu/WebGpuBackend.js +16 -8
  244. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  245. package/dist/esm/rendering/webgpu/WebGpuBlendState.js +26 -0
  246. package/dist/esm/rendering/webgpu/WebGpuBlendState.js.map +1 -1
  247. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +2 -2
  248. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +23 -15
  249. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
  250. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js +9 -1
  251. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js.map +1 -1
  252. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.d.ts +70 -0
  253. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js +773 -0
  254. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js.map +1 -0
  255. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js +96 -0
  256. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js.map +1 -0
  257. package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js +68 -0
  258. package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js.map +1 -0
  259. package/dist/esm/resources/Asset.d.ts +23 -0
  260. package/dist/esm/resources/Asset.js +23 -0
  261. package/dist/esm/resources/Asset.js.map +1 -0
  262. package/dist/esm/resources/AssetDefinitions.d.ts +137 -0
  263. package/dist/esm/resources/Assets.d.ts +35 -0
  264. package/dist/esm/resources/Assets.js +32 -0
  265. package/dist/esm/resources/Assets.js.map +1 -0
  266. package/dist/esm/resources/IndexedDbDatabase.js +17 -1
  267. package/dist/esm/resources/IndexedDbDatabase.js.map +1 -1
  268. package/dist/esm/resources/IndexedDbStore.js +17 -1
  269. package/dist/esm/resources/IndexedDbStore.js.map +1 -1
  270. package/dist/esm/resources/Loader.d.ts +244 -18
  271. package/dist/esm/resources/Loader.js +456 -50
  272. package/dist/esm/resources/Loader.js.map +1 -1
  273. package/dist/esm/resources/LoadingQueue.d.ts +28 -0
  274. package/dist/esm/resources/LoadingQueue.js +59 -0
  275. package/dist/esm/resources/LoadingQueue.js.map +1 -0
  276. package/dist/esm/resources/factories/BmFontFactory.d.ts +25 -0
  277. package/dist/esm/resources/factories/BmFontFactory.js +96 -0
  278. package/dist/esm/resources/factories/BmFontFactory.js.map +1 -0
  279. package/dist/esm/resources/factories/CsvFactory.d.ts +35 -0
  280. package/dist/esm/resources/factories/CsvFactory.js +87 -0
  281. package/dist/esm/resources/factories/CsvFactory.js.map +1 -0
  282. package/dist/esm/resources/factories/MusicFactory.d.ts +8 -2
  283. package/dist/esm/resources/factories/MusicFactory.js +25 -14
  284. package/dist/esm/resources/factories/MusicFactory.js.map +1 -1
  285. package/dist/esm/resources/factories/SoundFactory.d.ts +2 -2
  286. package/dist/esm/resources/factories/SoundFactory.js.map +1 -1
  287. package/dist/esm/resources/factories/SubtitleFactory.d.ts +28 -0
  288. package/dist/esm/resources/factories/SubtitleFactory.js +203 -0
  289. package/dist/esm/resources/factories/SubtitleFactory.js.map +1 -0
  290. package/dist/esm/resources/factories/SvgFactory.d.ts +18 -1
  291. package/dist/esm/resources/factories/SvgFactory.js +21 -2
  292. package/dist/esm/resources/factories/SvgFactory.js.map +1 -1
  293. package/dist/esm/resources/factories/VideoFactory.d.ts +8 -2
  294. package/dist/esm/resources/factories/VideoFactory.js +27 -20
  295. package/dist/esm/resources/factories/VideoFactory.js.map +1 -1
  296. package/dist/esm/resources/factories/XmlFactory.d.ts +24 -0
  297. package/dist/esm/resources/factories/XmlFactory.js +37 -0
  298. package/dist/esm/resources/factories/XmlFactory.js.map +1 -0
  299. package/dist/esm/resources/index.d.ts +8 -1
  300. package/dist/esm/resources/tokens.d.ts +49 -3
  301. package/dist/esm/resources/tokens.js +50 -4
  302. package/dist/esm/resources/tokens.js.map +1 -1
  303. package/dist/exo.esm.js +6635 -2550
  304. package/dist/exo.esm.js.map +1 -1
  305. package/package.json +16 -4
  306. package/dist/esm/input/interaction-hooks.d.ts +0 -34
  307. package/dist/esm/input/interaction-hooks.js +0 -35
  308. package/dist/esm/input/interaction-hooks.js.map +0 -1
  309. package/dist/esm/rendering/text/DynamicGlyphAtlas.d.ts +0 -33
  310. package/dist/esm/rendering/text/DynamicGlyphAtlas.js +0 -134
  311. package/dist/esm/rendering/text/DynamicGlyphAtlas.js.map +0 -1
  312. package/dist/esm/rendering/text/atlas-singleton.d.ts +0 -7
  313. package/dist/esm/rendering/text/atlas-singleton.js +0 -17
  314. package/dist/esm/rendering/text/atlas-singleton.js.map +0 -1
  315. package/dist/esm/resources/factories/VttFactory.d.ts +0 -24
  316. package/dist/esm/resources/factories/VttFactory.js +0 -158
  317. package/dist/esm/resources/factories/VttFactory.js.map +0 -1
@@ -1,24 +1,31 @@
1
1
  import { Music } from '../audio/Music.js';
2
2
  import { Sound } from '../audio/Sound.js';
3
3
  import { Signal } from '../core/Signal.js';
4
+ import { BmFont } from '../rendering/text/BmFont.js';
4
5
  import { Texture } from '../rendering/texture/Texture.js';
5
6
  import { Video } from '../rendering/video/Video.js';
7
+ import { AssetImpl, Asset } from './Asset.js';
6
8
  import { defineAssetManifest, BundleLoadError } from './AssetManifest.js';
9
+ import { AssetsImpl } from './Assets.js';
7
10
  import { CacheFirstStrategy } from './CacheFirstStrategy.js';
8
11
  import { BinaryFactory } from './factories/BinaryFactory.js';
12
+ import { BmFontLoaderFactory } from './factories/BmFontFactory.js';
13
+ import { CsvFactory } from './factories/CsvFactory.js';
9
14
  import { FontFactory } from './factories/FontFactory.js';
10
15
  import { ImageFactory } from './factories/ImageFactory.js';
11
16
  import { JsonFactory } from './factories/JsonFactory.js';
12
17
  import { MusicFactory } from './factories/MusicFactory.js';
13
18
  import { SoundFactory } from './factories/SoundFactory.js';
19
+ import { SubtitleFactory } from './factories/SubtitleFactory.js';
14
20
  import { SvgFactory } from './factories/SvgFactory.js';
15
21
  import { TextFactory } from './factories/TextFactory.js';
16
22
  import { TextureFactory } from './factories/TextureFactory.js';
17
23
  import { VideoFactory } from './factories/VideoFactory.js';
18
- import { VttFactory } from './factories/VttFactory.js';
19
24
  import { WasmFactory } from './factories/WasmFactory.js';
25
+ import { XmlFactory } from './factories/XmlFactory.js';
20
26
  import { FactoryRegistry } from './FactoryRegistry.js';
21
- import { Json, TextAsset, SvgAsset, VttAsset } from './tokens.js';
27
+ import { LoadingQueue } from './LoadingQueue.js';
28
+ import { FontAsset, Json, TextAsset, SvgAsset, SubtitleAsset, XmlAsset, CsvAsset, BinaryAsset, ImageAsset, WasmAsset } from './tokens.js';
22
29
 
23
30
  // ---------------------------------------------------------------------------
24
31
  // Loader
@@ -45,12 +52,13 @@ import { Json, TextAsset, SvgAsset, VttAsset } from './tokens.js';
45
52
  *
46
53
  * @example
47
54
  * ```ts
48
- * const loader = new Loader({ resourcePath: '/assets/', cache: new IndexedDbStore('game') });
55
+ * const loader = new Loader({ basePath: '/assets/', cache: new IndexedDbStore('game') });
49
56
  * const texture = await loader.load(Texture, 'hero.png');
50
57
  * ```
51
58
  */
52
59
  class Loader {
53
60
  _registry = new FactoryRegistry();
61
+ _assetTypeMap = new Map();
54
62
  _resources = new Map();
55
63
  _manifest = new Map();
56
64
  _bundles = new Map();
@@ -59,8 +67,19 @@ class Loader {
59
67
  _preventStoreKeys = new Set();
60
68
  _stores;
61
69
  _cacheStrategy;
62
- _resourcePath;
63
- _requestOptions;
70
+ // ── Identity / alias tracking for the new Asset API ───────────────────────
71
+ // Maps alias key (`${typeId}:${alias}`) to an identity key (`id:${typeId}:${source}`)
72
+ _aliasKeyToIdentityKey = new Map();
73
+ // Maps identity key to the set of aliases registered under that identity (within same type)
74
+ _identityKeyToAliases = new Map();
75
+ // In-flight promises keyed by identity (source-based) for cross-alias dedup
76
+ _inFlightByIdentity = new Map();
77
+ // Handler entries registered via the handler-based registerAssetType overload
78
+ _handlerFunctions = new Map();
79
+ // Maps lower-case file extensions (without dot) to the constructor to use
80
+ _extensionMap = new Map();
81
+ _basePath;
82
+ _fetchOptions;
64
83
  _concurrency;
65
84
  _nextTypeId = 1;
66
85
  _backgroundQueue = [];
@@ -77,8 +96,8 @@ class Loader {
77
96
  /** Dispatched when an asset fails to load during background or bundle loading. */
78
97
  onError = new Signal();
79
98
  constructor(options = {}) {
80
- this._resourcePath = options.resourcePath ?? '';
81
- this._requestOptions = options.requestOptions ?? {};
99
+ this._basePath = options.basePath ?? '';
100
+ this._fetchOptions = options.fetchOptions ?? {};
82
101
  this._concurrency = options.concurrency ?? 6;
83
102
  this._stores = options.cache ? (Array.isArray(options.cache) ? options.cache : [options.cache]) : [];
84
103
  this._cacheStrategy = options.cacheStrategy ?? new CacheFirstStrategy();
@@ -99,6 +118,47 @@ class Loader {
99
118
  this._registry.register(type, factory);
100
119
  return this;
101
120
  }
121
+ registerAssetType(typeName, ctorOrHandler, factory) {
122
+ if (typeof ctorOrHandler === 'function') {
123
+ this._assetTypeMap.set(typeName, ctorOrHandler);
124
+ if (factory) {
125
+ this._registry.register(ctorOrHandler, factory);
126
+ }
127
+ }
128
+ else {
129
+ // Handler-based form: create a synthetic constructor for type identity
130
+ const syntheticCtor = class {
131
+ };
132
+ Object.defineProperty(syntheticCtor, 'name', { value: typeName });
133
+ this._assetTypeMap.set(typeName, syntheticCtor);
134
+ this._handlerFunctions.set(syntheticCtor, {
135
+ load: (config, ctx) => ctorOrHandler.load(config, ctx),
136
+ getIdentityKey: ctorOrHandler.getIdentityKey?.bind(ctorOrHandler),
137
+ });
138
+ }
139
+ return this;
140
+ }
141
+ // -----------------------------------------------------------------------
142
+ // Extension registration
143
+ // -----------------------------------------------------------------------
144
+ /**
145
+ * Associates a file extension with an asset type so that
146
+ * `loader.load('path.ext')` (the single-string overload) can infer the
147
+ * type automatically.
148
+ *
149
+ * `ext` is matched case-insensitively and the leading dot is optional.
150
+ * The type must already have a registered factory (via {@link register} or
151
+ * {@link registerAssetType}).
152
+ *
153
+ * ```ts
154
+ * loader.registerExtension('tmj', TiledMap);
155
+ * const map = await loader.load('world.tmj'); // TiledMap
156
+ * ```
157
+ */
158
+ registerExtension(ext, type) {
159
+ this._extensionMap.set(ext.replace(/^\./, '').toLowerCase(), type);
160
+ return this;
161
+ }
102
162
  add(type, source) {
103
163
  const ctor = type;
104
164
  if (typeof source === 'string') {
@@ -219,20 +279,120 @@ class Loader {
219
279
  // -----------------------------------------------------------------------
220
280
  // Loading — implementation
221
281
  // -----------------------------------------------------------------------
222
- async load(type, source, options) {
223
- const ctor = type;
224
- if (typeof source === 'string') {
225
- return this._loadSingle(ctor, source, options);
282
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
283
+ load(arg0, arg1, arg2) {
284
+ // 1. Single Asset<T>
285
+ if (arg0 instanceof AssetImpl) {
286
+ const asset = arg0;
287
+ const alias = asset._config.source;
288
+ return this._createLoadingQueue([{ alias, asset }], results => results.get(alias));
289
+ }
290
+ // 2. Assets<M> container
291
+ if (arg0 instanceof AssetsImpl) {
292
+ const container = arg0;
293
+ const items = Object.entries(container.entries).map(([alias, a]) => ({
294
+ alias,
295
+ asset: a,
296
+ }));
297
+ return this._createLoadingQueue(items, results => {
298
+ const out = {};
299
+ for (const { alias } of items) {
300
+ out[alias] = results.get(alias);
301
+ }
302
+ return out;
303
+ });
304
+ }
305
+ // 2b. Extension-based: single path string with no type token
306
+ if (typeof arg0 === 'string' && arg1 === undefined) {
307
+ const path = arg0;
308
+ const ext = path.match(/\.([^./?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
309
+ const ctor = ext ? this._extensionMap.get(ext) : undefined;
310
+ if (ctor === undefined) {
311
+ throw new Error(`Loader: no type registered for extension ".${ext ?? '?'}" in "${path}". ` + 'Register one via loader.registerExtension().');
312
+ }
313
+ // FontAsset requires a family option — infer it from the filename when not provided
314
+ const options = ctor === FontAsset ? { family: (path.split('/').pop()?.split(/[?#]/)[0] ?? '').replace(/\.[^.]+$/, '') } : undefined;
315
+ let notifyFn = null;
316
+ const promise = this._loadSingle(ctor, path, options).then(v => {
317
+ notifyFn?.(true);
318
+ return v;
319
+ }, e => {
320
+ notifyFn?.(false);
321
+ throw e;
322
+ });
323
+ const queue = new LoadingQueue(promise, 1);
324
+ notifyFn = queue._notifyItem.bind(queue);
325
+ return queue;
226
326
  }
227
- if (Array.isArray(source)) {
228
- return Promise.all(source.map(path => this._loadSingle(ctor, path, options)));
327
+ // 3. Old path: first arg is a Loadable constructor
328
+ if (typeof arg0 === 'function') {
329
+ const ctor = arg0;
330
+ const source = arg1;
331
+ const options = arg2;
332
+ if (typeof source === 'string') {
333
+ let notifyFn = null;
334
+ const promise = this._loadSingle(ctor, source, options).then(v => {
335
+ notifyFn?.(true);
336
+ return v;
337
+ }, e => {
338
+ notifyFn?.(false);
339
+ throw e;
340
+ });
341
+ const queue = new LoadingQueue(promise, 1);
342
+ notifyFn = queue._notifyItem.bind(queue);
343
+ return queue;
344
+ }
345
+ if (Array.isArray(source)) {
346
+ const paths = source;
347
+ let notifyFn = null;
348
+ const results = new Array(paths.length);
349
+ const promises = paths.map((path, i) => this._loadSingle(ctor, path, options).then(v => {
350
+ results[i] = v;
351
+ notifyFn?.(true);
352
+ }, e => {
353
+ notifyFn?.(false);
354
+ throw e;
355
+ }));
356
+ const promise = Promise.all(promises).then(() => results);
357
+ const queue = new LoadingQueue(promise, paths.length);
358
+ notifyFn = queue._notifyItem.bind(queue);
359
+ return queue;
360
+ }
361
+ // Record<string, BatchValue>
362
+ const entries = Object.entries(source);
363
+ const result = {};
364
+ let notifyFn = null;
365
+ const promises = entries.map(([alias, pathOrConfig]) => {
366
+ const path = typeof pathOrConfig === 'string' ? pathOrConfig : pathOrConfig.source;
367
+ const itemOptions = typeof pathOrConfig === 'string'
368
+ ? options
369
+ : { ...pathOrConfig, ...(typeof options === 'object' && options !== null ? options : {}) };
370
+ return this._loadSingle(ctor, alias, itemOptions, path).then(v => {
371
+ result[alias] = v;
372
+ notifyFn?.(true);
373
+ }, e => {
374
+ notifyFn?.(false);
375
+ throw e;
376
+ });
377
+ });
378
+ const promise = Promise.all(promises).then(() => result);
379
+ const queue = new LoadingQueue(promise, entries.length);
380
+ notifyFn = queue._notifyItem.bind(queue);
381
+ return queue;
229
382
  }
230
- const entries = Object.entries(source);
231
- const result = {};
232
- await Promise.all(entries.map(async ([alias, path]) => {
233
- result[alias] = await this._loadSingle(ctor, alias, options, path);
383
+ // 4. Plain config map: Record<string, AssetInput>
384
+ const configMap = arg0;
385
+ const items = Object.entries(configMap).map(([alias, value]) => ({
386
+ alias,
387
+ asset: (value instanceof AssetImpl ? value : new Asset(value)),
234
388
  }));
235
- return result;
389
+ return this._createLoadingQueue(items, results => {
390
+ const out = {};
391
+ for (const { alias } of items) {
392
+ out[alias] = results.get(alias);
393
+ }
394
+ return out;
395
+ });
236
396
  }
237
397
  // -----------------------------------------------------------------------
238
398
  // Background loading
@@ -308,22 +468,70 @@ class Loader {
308
468
  const ctor = type;
309
469
  return this._resources.get(ctor)?.has(alias) ?? false;
310
470
  }
311
- // -----------------------------------------------------------------------
312
- // Unload
313
- // -----------------------------------------------------------------------
314
- /**
315
- * Removes a single asset from the in-memory resource store.
316
- *
317
- * If a fetch for this asset is still in flight, the result will be
318
- * discarded once it arrives rather than written to the store, preventing
319
- * a stale value from being committed after an explicit unload.
320
- */
321
- unload(type, alias) {
471
+ unload(arg0, arg1) {
472
+ if (arg0 instanceof AssetImpl) {
473
+ const asset = arg0;
474
+ const ctor = this._assetTypeMap.get(asset.type);
475
+ if (!ctor)
476
+ return this;
477
+ const identityKey = this._resolveAssetIdentityKey(ctor, asset);
478
+ const aliasSet = this._identityKeyToAliases.get(identityKey);
479
+ if (aliasSet && aliasSet.size > 0) {
480
+ // Snapshot the set because _unloadOne modifies it during iteration
481
+ for (const alias of [...aliasSet]) {
482
+ this._unloadOne(ctor, alias);
483
+ }
484
+ }
485
+ else {
486
+ // Asset was loaded without alias-map tracking (e.g. single-asset load).
487
+ // Fall back to using the source as the alias.
488
+ this._unloadOne(ctor, asset._config.source);
489
+ }
490
+ return this;
491
+ }
492
+ if (arg0 instanceof AssetsImpl) {
493
+ const container = arg0;
494
+ for (const [alias, a] of Object.entries(container.entries)) {
495
+ const assetRef = a;
496
+ const ctor = this._assetTypeMap.get(assetRef.type);
497
+ if (!ctor)
498
+ continue;
499
+ const identityKey = this._resolveAssetIdentityKey(ctor, assetRef);
500
+ const aliasSet = this._identityKeyToAliases.get(identityKey);
501
+ if (aliasSet?.has(alias)) {
502
+ // Also remove all other aliases that share this resource identity
503
+ for (const a2 of [...aliasSet]) {
504
+ this._unloadOne(ctor, a2);
505
+ }
506
+ }
507
+ else {
508
+ this._unloadOne(ctor, alias);
509
+ }
510
+ }
511
+ return this;
512
+ }
513
+ return this._unloadOne(arg0, arg1);
514
+ }
515
+ _unloadOne(type, alias) {
322
516
  const ctor = type;
323
- const key = this._key(ctor, alias);
517
+ const aliasKey = this._key(ctor, alias);
324
518
  this._resources.get(ctor)?.delete(alias);
325
- if (this._inFlight.has(key)) {
326
- this._preventStoreKeys.add(key);
519
+ // If a fetch is in flight (via legacy or identity-based map), prevent the
520
+ // result from being written to _resources once it arrives.
521
+ const identityKey = this._aliasKeyToIdentityKey.get(aliasKey);
522
+ if (this._inFlight.has(aliasKey) || (identityKey !== undefined && this._inFlightByIdentity.has(identityKey))) {
523
+ this._preventStoreKeys.add(aliasKey);
524
+ }
525
+ // Clean up alias ↔ identity tracking
526
+ if (identityKey !== undefined) {
527
+ this._aliasKeyToIdentityKey.delete(aliasKey);
528
+ const aliasSet = this._identityKeyToAliases.get(identityKey);
529
+ if (aliasSet) {
530
+ aliasSet.delete(alias);
531
+ if (aliasSet.size === 0) {
532
+ this._identityKeyToAliases.delete(identityKey);
533
+ }
534
+ }
327
535
  }
328
536
  return this;
329
537
  }
@@ -352,21 +560,21 @@ class Loader {
352
560
  * Absolute URLs (starting with `http://`, `https://`, or `//`) are
353
561
  * passed through unchanged.
354
562
  */
355
- get resourcePath() {
356
- return this._resourcePath;
563
+ get basePath() {
564
+ return this._basePath;
357
565
  }
358
- set resourcePath(value) {
359
- this._resourcePath = value;
566
+ set basePath(value) {
567
+ this._basePath = value;
360
568
  }
361
569
  /**
362
570
  * Default `RequestInit` options merged into every `fetch` call.
363
571
  * Override per-load with the `options` argument of {@link load}.
364
572
  */
365
- get requestOptions() {
366
- return this._requestOptions;
573
+ get fetchOptions() {
574
+ return this._fetchOptions;
367
575
  }
368
- set requestOptions(value) {
369
- this._requestOptions = value;
576
+ set fetchOptions(value) {
577
+ this._fetchOptions = value;
370
578
  }
371
579
  // -----------------------------------------------------------------------
372
580
  // Lifecycle
@@ -388,6 +596,10 @@ class Loader {
388
596
  this._bundles.clear();
389
597
  this._inFlight.clear();
390
598
  this._preventStoreKeys.clear();
599
+ this._inFlightByIdentity.clear();
600
+ this._aliasKeyToIdentityKey.clear();
601
+ this._identityKeyToAliases.clear();
602
+ this._handlerFunctions.clear();
391
603
  this._backgroundQueue.length = 0;
392
604
  this.onProgress.destroy();
393
605
  this.onBundleProgress.destroy();
@@ -444,15 +656,166 @@ class Loader {
444
656
  }
445
657
  return this._waitForBackgroundEntry(type, alias);
446
658
  }
659
+ _createLoadingQueue(items, buildResult) {
660
+ const results = new Map();
661
+ let notifyFn = null;
662
+ const itemPromises = items.map(({ alias, asset }) => {
663
+ const ctor = this._assetTypeMap.get(asset.type);
664
+ if (!ctor) {
665
+ // Must call _notifyItem(false) so LoadingProgress doesn't remain stuck.
666
+ return Promise.reject(new Error(`No constructor registered for asset type "${asset.type}". Call registerAssetType() first.`)).then(() => {
667
+ notifyFn?.(true);
668
+ }, error => {
669
+ notifyFn?.(false);
670
+ throw error;
671
+ });
672
+ }
673
+ return this._loadSingleAsset(ctor, alias, asset).then(resource => {
674
+ results.set(alias, resource);
675
+ notifyFn?.(true);
676
+ }, error => {
677
+ notifyFn?.(false);
678
+ throw error;
679
+ });
680
+ });
681
+ const promise = Promise.all(itemPromises).then(() => buildResult(results));
682
+ const queue = new LoadingQueue(promise, items.length);
683
+ notifyFn = queue._notifyItem.bind(queue);
684
+ return queue;
685
+ }
686
+ /**
687
+ * Loads a single asset from an `Asset<T>` reference using identity-based
688
+ * in-flight deduplication.
689
+ *
690
+ * Multiple aliases that point to the same source share a single network
691
+ * fetch. Each alias is stored independently in `_resources` so that
692
+ * `get(type, alias)` works for all of them.
693
+ */
694
+ async _loadSingleAsset(type, alias, asset) {
695
+ if (this._hasResource(type, alias)) {
696
+ return this._resources.get(type)?.get(alias);
697
+ }
698
+ const source = asset.source;
699
+ const rawConfig = asset._config;
700
+ const { type: _type, source: _src, ...extraOnly } = rawConfig;
701
+ // Identity key: use handler's getIdentityKey if provided (config-sensitive dedup),
702
+ // otherwise fall back to source-based identity (correct for URL-only assets).
703
+ const handlerEntry = this._handlerFunctions.get(type);
704
+ const discriminator = handlerEntry?.getIdentityKey?.(rawConfig) ?? source;
705
+ const identityKey = `id:${this._getTypeId(type)}:${discriminator}`;
706
+ const aliasKey = this._key(type, alias);
707
+ // Register alias → identity mapping for unload() semantics
708
+ this._aliasKeyToIdentityKey.set(aliasKey, identityKey);
709
+ let aliasSet = this._identityKeyToAliases.get(identityKey);
710
+ if (!aliasSet) {
711
+ aliasSet = new Set();
712
+ this._identityKeyToAliases.set(identityKey, aliasSet);
713
+ }
714
+ aliasSet.add(alias);
715
+ // Same identity already in flight? Attach to the existing promise.
716
+ const existing = this._inFlightByIdentity.get(identityKey);
717
+ if (existing) {
718
+ return existing.then(resource => {
719
+ this._storeResource(type, alias, resource);
720
+ return resource;
721
+ });
722
+ }
723
+ // Build load promise.
724
+ let fetchPromise;
725
+ if (handlerEntry) {
726
+ const fullConfig = { source, ...extraOnly };
727
+ const context = this._buildHandlerContext(identityKey);
728
+ fetchPromise = this._fetchWithHandler(type, alias, source, fullConfig, handlerEntry.load, context);
729
+ }
730
+ else {
731
+ const options = Object.keys(extraOnly).length > 0 ? extraOnly : undefined;
732
+ fetchPromise = this._fetch(type, alias, source, options);
733
+ }
734
+ const tracked = fetchPromise
735
+ .finally(() => {
736
+ this._inFlightByIdentity.delete(identityKey);
737
+ })
738
+ .then(v => v, error => {
739
+ // On failure, immediately clean up alias ↔ identity tracking so
740
+ // stale entries don't accumulate for assets that never loaded.
741
+ const failedAliases = this._identityKeyToAliases.get(identityKey);
742
+ if (failedAliases) {
743
+ for (const fa of failedAliases) {
744
+ const faKey = this._key(type, fa);
745
+ this._aliasKeyToIdentityKey.delete(faKey);
746
+ this._preventStoreKeys.delete(faKey);
747
+ }
748
+ this._identityKeyToAliases.delete(identityKey);
749
+ }
750
+ throw error;
751
+ });
752
+ this._inFlightByIdentity.set(identityKey, tracked);
753
+ return tracked;
754
+ }
755
+ /**
756
+ * Calls a handler-based custom asset loader and stores the result.
757
+ *
758
+ * Unlike `_fetch`, this does NOT automatically bypass caching — the handler
759
+ * controls caching by calling `context.fetchText` / `context.fetchArrayBuffer`
760
+ * / `context.fetchJson`, which route through the loader's cache strategy.
761
+ */
762
+ async _fetchWithHandler(type, alias, source, fullConfig, handler, context) {
763
+ const url = this._resolveUrl(source);
764
+ try {
765
+ const resource = await handler(fullConfig, context);
766
+ this._storeResource(type, alias, resource);
767
+ return resource;
768
+ }
769
+ catch (error) {
770
+ const message = error instanceof Error ? error.message : String(error);
771
+ throw new Error(`Failed to load "${alias}" from "${url}": ${message}`, { cause: error });
772
+ }
773
+ }
774
+ /**
775
+ * Builds an {@link AssetLoaderContext} for a handler invocation.
776
+ *
777
+ * The `fetch*` helpers on the returned context route through the loader's
778
+ * configured cache strategy and IDB stores, using `source` as the IDB key
779
+ * (so the same URL is never fetched twice regardless of the asset alias).
780
+ */
781
+ _buildHandlerContext(identityKey) {
782
+ const ctx = {
783
+ loader: this,
784
+ identityKey,
785
+ fetchText: (source) => this._contextFetch(source, '__ctx_text', r => r.text()),
786
+ fetchArrayBuffer: (source) => this._contextFetch(source, '__ctx_binary', r => r.arrayBuffer()),
787
+ fetchJson: (source) => this._contextFetch(source, '__ctx_json', r => r.json()),
788
+ };
789
+ return ctx;
790
+ }
791
+ /**
792
+ * Fetches `source` through the loader's cache strategy with an inline
793
+ * pass-through factory, using `source` as the IDB key.
794
+ *
795
+ * `process` converts the raw `Response` to the storable intermediate form
796
+ * (e.g. `r.text()`, `r.arrayBuffer()`, `r.json()`). `create` is always the
797
+ * identity function — the cached value is returned unchanged.
798
+ */
799
+ _contextFetch(source, storageName, process) {
800
+ const url = this._resolveUrl(source);
801
+ const factory = {
802
+ storageName,
803
+ process,
804
+ create: data => Promise.resolve(data),
805
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
806
+ destroy() { },
807
+ };
808
+ return this._cacheStrategy.resolve({ storageName, key: source, url, requestOptions: this._fetchOptions, factory, options: undefined }, this._stores);
809
+ }
447
810
  async _fetch(type, alias, path, options) {
448
811
  const factory = this._registry.resolve(type);
449
812
  const url = this._resolveUrl(path);
450
813
  try {
451
814
  const resource = await this._cacheStrategy.resolve({
452
815
  storageName: factory.storageName,
453
- key: alias,
816
+ key: path, // source-path as IDB key so same resource is not cached multiple times under different aliases
454
817
  url,
455
- requestOptions: this._requestOptions,
818
+ requestOptions: this._fetchOptions,
456
819
  factory,
457
820
  options,
458
821
  }, this._stores);
@@ -665,19 +1028,38 @@ class Loader {
665
1028
  typeResources.set(alias, resource);
666
1029
  this.onLoaded.dispatch(type, alias, resource);
667
1030
  }
668
- _key(type, alias) {
1031
+ _getTypeId(type) {
669
1032
  let typeId = this._typeIds.get(type);
670
1033
  if (typeId === undefined) {
671
1034
  typeId = this._nextTypeId++;
672
1035
  this._typeIds.set(type, typeId);
673
1036
  }
674
- return `${typeId}:${alias}`;
1037
+ return typeId;
1038
+ }
1039
+ _key(type, alias) {
1040
+ return `${this._getTypeId(type)}:${alias}`;
1041
+ }
1042
+ _identityKey(type, source) {
1043
+ return `id:${this._getTypeId(type)}:${source}`;
1044
+ }
1045
+ /**
1046
+ * Resolves the effective identity key for an `Asset<T>` reference, mirroring
1047
+ * the logic used in `_loadSingleAsset`.
1048
+ *
1049
+ * For handler types with `getIdentityKey`, the config-sensitive discriminator
1050
+ * is used; otherwise source is the discriminator (same as `_identityKey`).
1051
+ */
1052
+ _resolveAssetIdentityKey(type, asset) {
1053
+ const rawConfig = asset._config;
1054
+ const handlerEntry = this._handlerFunctions.get(type);
1055
+ const discriminator = handlerEntry?.getIdentityKey?.(rawConfig) ?? asset.source;
1056
+ return `id:${this._getTypeId(type)}:${discriminator}`;
675
1057
  }
676
1058
  _resolveUrl(path) {
677
1059
  if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('//')) {
678
1060
  return path;
679
1061
  }
680
- return `${this._resourcePath}${path}`;
1062
+ return `${this._basePath}${path}`;
681
1063
  }
682
1064
  // -----------------------------------------------------------------------
683
1065
  // Internal — built-in factory registration
@@ -690,16 +1072,40 @@ class Loader {
690
1072
  this._registry.register(Json, new JsonFactory());
691
1073
  this._registry.register(TextAsset, new TextFactory());
692
1074
  this._registry.register(SvgAsset, new SvgFactory());
693
- this._registry.register(VttAsset, new VttFactory());
694
- this._registry.register(ArrayBuffer, new BinaryFactory());
1075
+ this._registry.register(SubtitleAsset, new SubtitleFactory());
1076
+ this._registry.register(XmlAsset, new XmlFactory());
1077
+ this._registry.register(CsvAsset, new CsvFactory());
1078
+ this._registry.register(BinaryAsset, new BinaryFactory());
1079
+ this._assetTypeMap.set('texture', Texture);
1080
+ this._assetTypeMap.set('sound', Sound);
1081
+ this._assetTypeMap.set('music', Music);
1082
+ this._assetTypeMap.set('json', Json);
1083
+ this._assetTypeMap.set('video', Video);
1084
+ this._assetTypeMap.set('text', TextAsset);
1085
+ this._assetTypeMap.set('svg', SvgAsset);
1086
+ this._assetTypeMap.set('vtt', SubtitleAsset);
1087
+ this._assetTypeMap.set('srt', SubtitleAsset);
1088
+ this._assetTypeMap.set('xml', XmlAsset);
1089
+ this._assetTypeMap.set('csv', CsvAsset);
1090
+ this._assetTypeMap.set('binary', BinaryAsset);
1091
+ this._registry.register(BmFont, new BmFontLoaderFactory(this));
1092
+ this._assetTypeMap.set('bmFont', BmFont);
1093
+ this._extensionMap.set('fnt', BmFont);
695
1094
  if (typeof FontFace !== 'undefined') {
696
- this._registry.register(FontFace, new FontFactory());
1095
+ this._registry.register(FontAsset, new FontFactory());
1096
+ this._assetTypeMap.set('font', FontAsset);
1097
+ this._extensionMap.set('woff', FontAsset);
1098
+ this._extensionMap.set('woff2', FontAsset);
1099
+ this._extensionMap.set('ttf', FontAsset);
1100
+ this._extensionMap.set('otf', FontAsset);
697
1101
  }
698
1102
  if (typeof HTMLImageElement !== 'undefined') {
699
- this._registry.register(HTMLImageElement, new ImageFactory());
1103
+ this._registry.register(ImageAsset, new ImageFactory());
1104
+ this._assetTypeMap.set('image', ImageAsset);
700
1105
  }
701
1106
  if (typeof WebAssembly !== 'undefined') {
702
- this._registry.register(WebAssembly.Module, new WasmFactory());
1107
+ this._registry.register(WasmAsset, new WasmFactory());
1108
+ this._assetTypeMap.set('wasm', WasmAsset);
703
1109
  }
704
1110
  }
705
1111
  }