@haiyue/extensions 0.1.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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/animation/Animation2DComponent.d.ts +46 -0
  4. package/dist/animation/Animation2DExtensionRegistry.d.ts +27 -0
  5. package/dist/animation/Animation2DRenderSystem.d.ts +89 -0
  6. package/dist/animation/Animation2DRuntime.d.ts +99 -0
  7. package/dist/animation/Animation2DStateMachine.d.ts +13 -0
  8. package/dist/animation/Animation2DStateMachineComponent.d.ts +54 -0
  9. package/dist/animation/Animation2DStateMachineRuntime.d.ts +30 -0
  10. package/dist/animation/Animation2DStateMachineSystem.d.ts +14 -0
  11. package/dist/animation/Animation2DStateMachineVisualRuntime.d.ts +27 -0
  12. package/dist/animation/Animation2DSystem.d.ts +14 -0
  13. package/dist/animation/AnimationAssetLoader.d.ts +9 -0
  14. package/dist/animation/AnimationAudioClip.d.ts +26 -0
  15. package/dist/animation/AnimationPathTessellator.d.ts +52 -0
  16. package/dist/animation/AnimationTextRasterizer.d.ts +21 -0
  17. package/dist/animation/AnimationVisual2D.d.ts +68 -0
  18. package/dist/animation/HyaAnimation2DClipAdapter.d.ts +16 -0
  19. package/dist/animation/Particle2DDescriptorAdapter.d.ts +5 -0
  20. package/dist/animation/runtime/mixer/Action.d.ts +150 -0
  21. package/dist/animation/runtime/mixer/Mixer.d.ts +54 -0
  22. package/dist/animation/runtime/mixer/PoseBuffer.d.ts +23 -0
  23. package/dist/animation/runtime/mixer/Sampler.d.ts +17 -0
  24. package/dist/animation/runtime/mixer/Types.d.ts +101 -0
  25. package/dist/animation/runtime/mixer/index.d.ts +6 -0
  26. package/dist/animation-state-machine/AnimationStateMachine.d.ts +111 -0
  27. package/dist/animation-state-machine/AnimationStateMachineChannels.d.ts +23 -0
  28. package/dist/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.d.ts +51 -0
  29. package/dist/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.d.ts +14 -0
  30. package/dist/animation-state-machine/runtime/AnimationStateMachineCompiler.d.ts +109 -0
  31. package/dist/animation-state-machine/runtime/AnimationStateMachineController.d.ts +103 -0
  32. package/dist/animation-state-machine/runtime/AnimationStateMachineMixerPort.d.ts +35 -0
  33. package/dist/animation-state-machine/runtime/index.d.ts +7 -0
  34. package/dist/animation.d.ts +15 -0
  35. package/dist/animation.js +1171 -0
  36. package/dist/animation3d/Animation3DAction.d.ts +46 -0
  37. package/dist/animation3d/Animation3DBinding.d.ts +85 -0
  38. package/dist/animation3d/Animation3DClip.d.ts +20 -0
  39. package/dist/animation3d/Animation3DError.d.ts +13 -0
  40. package/dist/animation3d/Animation3DMixer.d.ts +27 -0
  41. package/dist/animation3d/Animation3DPose.d.ts +40 -0
  42. package/dist/animation3d/Animation3DPoseBuffer.d.ts +24 -0
  43. package/dist/animation3d/Animation3DResource.d.ts +28 -0
  44. package/dist/animation3d/Animation3DStateMachine.d.ts +95 -0
  45. package/dist/animation3d/Animation3DStateMachineRuntime.d.ts +70 -0
  46. package/dist/animation3d/Animation3DTrack.d.ts +19 -0
  47. package/dist/animation3d/hya/HyaAnimation3DRuntime.d.ts +73 -0
  48. package/dist/animation3d/hya/HyaAnimation3DStateMachineRuntime.d.ts +65 -0
  49. package/dist/animation3d/hya/HyaAnimation3DTypes.d.ts +170 -0
  50. package/dist/animation3d/hya/index.d.ts +4 -0
  51. package/dist/animation3d/index.d.ts +14 -0
  52. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.d.ts +81 -0
  53. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.d.ts +39 -0
  54. package/dist/animation3d/runtime/integration/index.d.ts +2 -0
  55. package/dist/animation3d/runtime/mixer/Action.d.ts +150 -0
  56. package/dist/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.d.ts +6 -0
  57. package/dist/animation3d/runtime/mixer/Mixer.d.ts +59 -0
  58. package/dist/animation3d/runtime/mixer/PoseBuffer.d.ts +1 -0
  59. package/dist/animation3d/runtime/mixer/TrackSampler.d.ts +24 -0
  60. package/dist/animation3d/runtime/mixer/index.d.ts +4 -0
  61. package/dist/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.d.ts +1 -0
  62. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.d.ts +1 -0
  63. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineController.d.ts +1 -0
  64. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.d.ts +1 -0
  65. package/dist/animation3d/runtime/state-machine/index.d.ts +6 -0
  66. package/dist/animation3d.d.ts +5 -0
  67. package/dist/animation3d.js +1708 -0
  68. package/dist/benchmark.d.ts +30 -0
  69. package/dist/benchmark.js +119 -0
  70. package/dist/canvas-text/CanvasText2DRenderSystem.d.ts +24 -0
  71. package/dist/canvas-text/CanvasTextComponent.d.ts +18 -0
  72. package/dist/canvas-text.d.ts +4 -0
  73. package/dist/canvas-text.js +276 -0
  74. package/dist/chunks/2d-ui-animation-2d.generated-D4aHzFU2.js +4 -0
  75. package/dist/chunks/2d-ui-canvas-text-2d.generated-C0Eaej2m.js +4 -0
  76. package/dist/chunks/2d-ui-spine2d.generated-CUUi8xjl.js +4 -0
  77. package/dist/chunks/2d-ui-tilemap2d.generated-gebw4mX7.js +4 -0
  78. package/dist/chunks/Animation2DStateMachine-9IonguNa.js +3245 -0
  79. package/dist/chunks/AnimationStateMachineController-BIcAh-sT.js +1438 -0
  80. package/dist/chunks/GltfAnimation3DAdapter-Cu3rQQsW.js +2240 -0
  81. package/dist/chunks/GltfAnimationRuntime-CRHsLycN.js +631 -0
  82. package/dist/chunks/RenderSystem2DBase-DDT61dAu.js +227 -0
  83. package/dist/chunks/Spine2DRuntime-D9M9LAQR.js +3056 -0
  84. package/dist/chunks/SpineAssetParser-BSDmPge1.js +378 -0
  85. package/dist/chunks/gltfLoader-Dm22jLYB.js +2085 -0
  86. package/dist/chunks/pluginUtils-CvwroRMd.js +33 -0
  87. package/dist/experimental-gltf-worker.d.ts +4 -0
  88. package/dist/experimental-gltf-worker.js +138 -0
  89. package/dist/experimental-spine-worker.d.ts +4 -0
  90. package/dist/experimental-spine-worker.js +110 -0
  91. package/dist/gltf/GltfAccessorReader.d.ts +7 -0
  92. package/dist/gltf/GltfAnimation3DAdapter.d.ts +47 -0
  93. package/dist/gltf/GltfAnimationRuntime.d.ts +10 -0
  94. package/dist/gltf/GltfAssetWorkerClient.d.ts +20 -0
  95. package/dist/gltf/GltfCompatibilityReport.d.ts +70 -0
  96. package/dist/gltf/GltfConservativeBounds.d.ts +18 -0
  97. package/dist/gltf/GltfDracoDecoder.d.ts +4 -0
  98. package/dist/gltf/GltfExtensionAdapter.d.ts +54 -0
  99. package/dist/gltf/GltfLoaderContract.d.ts +249 -0
  100. package/dist/gltf/GltfLoaderErrors.d.ts +4 -0
  101. package/dist/gltf/GltfMaterialDescriptor.d.ts +23 -0
  102. package/dist/gltf/GltfMaterialEncoder.d.ts +20 -0
  103. package/dist/gltf/GltfMaterialLoader.d.ts +6 -0
  104. package/dist/gltf/GltfModelComponent.d.ts +72 -0
  105. package/dist/gltf/GltfModelSystem.d.ts +37 -0
  106. package/dist/gltf/GltfPlugin.d.ts +6 -0
  107. package/dist/gltf/GltfSchema.d.ts +225 -0
  108. package/dist/gltf/GltfUvSemanticPlanner.d.ts +33 -0
  109. package/dist/gltf/gltfLoader.d.ts +9 -0
  110. package/dist/gltf-animation3d.d.ts +3 -0
  111. package/dist/gltf-animation3d.js +8 -0
  112. package/dist/gltf-worker-runtime.d.ts +7 -0
  113. package/dist/gltf-worker-runtime.js +6981 -0
  114. package/dist/gltf.d.ts +12 -0
  115. package/dist/gltf.js +517 -0
  116. package/dist/grid/Grid2DComponent.d.ts +25 -0
  117. package/dist/grid.d.ts +2 -0
  118. package/dist/grid.js +56 -0
  119. package/dist/hya-state-machine.d.ts +7 -0
  120. package/dist/hya-state-machine.js +2934 -0
  121. package/dist/index.d.ts +2 -0
  122. package/dist/index.js +7 -0
  123. package/dist/internal/2d-ui-shader-artifact.js +870 -0
  124. package/dist/plugins/pluginUtils.d.ts +20 -0
  125. package/dist/plugins.d.ts +6 -0
  126. package/dist/shaders/generated/2d-ui-artifact.generated.d.ts +658 -0
  127. package/dist/spine/Spine2DComponent.d.ts +116 -0
  128. package/dist/spine/Spine2DGpuRenderer.d.ts +65 -0
  129. package/dist/spine/Spine2DRenderSystem.d.ts +27 -0
  130. package/dist/spine/Spine2DRuntime.d.ts +103 -0
  131. package/dist/spine/SpineAnimationBoneTimelines.d.ts +8 -0
  132. package/dist/spine/SpineAssetParser.d.ts +18 -0
  133. package/dist/spine/SpineAssetWorkerClient.d.ts +19 -0
  134. package/dist/spine/SpineAssetWorkerContract.d.ts +6 -0
  135. package/dist/spine/SpineAtlasParser.d.ts +21 -0
  136. package/dist/spine/SpineFloatBuilder.d.ts +15 -0
  137. package/dist/spine/SpinePathConstraintSolver.d.ts +32 -0
  138. package/dist/spine/SpinePlugin.d.ts +8 -0
  139. package/dist/spine/SpineSkeletonRuntime.d.ts +185 -0
  140. package/dist/spine/SpineSlotAnimation.d.ts +17 -0
  141. package/dist/spine/SpineTimelineRuntime.d.ts +25 -0
  142. package/dist/spine/SpineVertexBuilder.d.ts +61 -0
  143. package/dist/spine.d.ts +7 -0
  144. package/dist/spine.js +578 -0
  145. package/dist/tilemap/Tilemap2DComponent.d.ts +110 -0
  146. package/dist/tilemap/Tilemap2DRenderSystem.d.ts +11 -0
  147. package/dist/tilemap/Tilemap2DRenderer.d.ts +24 -0
  148. package/dist/tilemap/TilemapPlugin.d.ts +8 -0
  149. package/dist/tilemap.d.ts +6 -0
  150. package/dist/tilemap.js +535 -0
  151. package/dist/tween/Tween2DComponent.d.ts +70 -0
  152. package/dist/tween/Tween2DSystem.d.ts +12 -0
  153. package/dist/tween.d.ts +4 -0
  154. package/dist/tween.js +138 -0
  155. package/dist/utils/RenderSystem2DBase.d.ts +42 -0
  156. package/dist/utils/arrayAccess.d.ts +4 -0
  157. package/dist/utils/camera2d.d.ts +12 -0
  158. package/dist/utils/render2dGpu.d.ts +32 -0
  159. package/package.json +124 -0
  160. package/src/animation/Animation2DComponent.ts +135 -0
  161. package/src/animation/Animation2DExtensionRegistry.ts +52 -0
  162. package/src/animation/Animation2DRenderSystem.ts +1026 -0
  163. package/src/animation/Animation2DRuntime.ts +1326 -0
  164. package/src/animation/Animation2DStateMachine.ts +39 -0
  165. package/src/animation/Animation2DStateMachineComponent.ts +228 -0
  166. package/src/animation/Animation2DStateMachineRuntime.ts +141 -0
  167. package/src/animation/Animation2DStateMachineSystem.ts +60 -0
  168. package/src/animation/Animation2DStateMachineVisualRuntime.ts +282 -0
  169. package/src/animation/Animation2DSystem.ts +72 -0
  170. package/src/animation/AnimationAssetLoader.ts +84 -0
  171. package/src/animation/AnimationAudioClip.ts +140 -0
  172. package/src/animation/AnimationPathTessellator.ts +691 -0
  173. package/src/animation/AnimationTextRasterizer.ts +340 -0
  174. package/src/animation/AnimationVisual2D.ts +153 -0
  175. package/src/animation/HyaAnimation2DClipAdapter.ts +845 -0
  176. package/src/animation/Particle2DDescriptorAdapter.ts +35 -0
  177. package/src/animation/runtime/mixer/Action.ts +876 -0
  178. package/src/animation/runtime/mixer/Mixer.ts +505 -0
  179. package/src/animation/runtime/mixer/PoseBuffer.ts +105 -0
  180. package/src/animation/runtime/mixer/Sampler.ts +252 -0
  181. package/src/animation/runtime/mixer/Types.ts +138 -0
  182. package/src/animation/runtime/mixer/index.ts +31 -0
  183. package/src/animation-state-machine/AnimationStateMachine.ts +146 -0
  184. package/src/animation-state-machine/AnimationStateMachineChannels.ts +116 -0
  185. package/src/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.ts +197 -0
  186. package/src/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.ts +503 -0
  187. package/src/animation-state-machine/runtime/AnimationStateMachineCompiler.ts +763 -0
  188. package/src/animation-state-machine/runtime/AnimationStateMachineController.ts +987 -0
  189. package/src/animation-state-machine/runtime/AnimationStateMachineMixerPort.ts +54 -0
  190. package/src/animation-state-machine/runtime/index.ts +47 -0
  191. package/src/animation.ts +33 -0
  192. package/src/animation3d/Animation3DAction.ts +73 -0
  193. package/src/animation3d/Animation3DBinding.ts +116 -0
  194. package/src/animation3d/Animation3DClip.ts +22 -0
  195. package/src/animation3d/Animation3DError.ts +34 -0
  196. package/src/animation3d/Animation3DMixer.ts +82 -0
  197. package/src/animation3d/Animation3DPose.ts +100 -0
  198. package/src/animation3d/Animation3DPoseBuffer.ts +85 -0
  199. package/src/animation3d/Animation3DResource.ts +49 -0
  200. package/src/animation3d/Animation3DStateMachine.ts +126 -0
  201. package/src/animation3d/Animation3DStateMachineRuntime.ts +191 -0
  202. package/src/animation3d/Animation3DTrack.ts +29 -0
  203. package/src/animation3d/hya/HyaAnimation3DRuntime.ts +756 -0
  204. package/src/animation3d/hya/HyaAnimation3DStateMachineRuntime.ts +618 -0
  205. package/src/animation3d/hya/HyaAnimation3DTypes.ts +168 -0
  206. package/src/animation3d/hya/index.ts +10 -0
  207. package/src/animation3d/index.ts +76 -0
  208. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.ts +325 -0
  209. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.ts +158 -0
  210. package/src/animation3d/runtime/integration/index.ts +9 -0
  211. package/src/animation3d/runtime/mixer/Action.ts +833 -0
  212. package/src/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.ts +26 -0
  213. package/src/animation3d/runtime/mixer/Mixer.ts +562 -0
  214. package/src/animation3d/runtime/mixer/PoseBuffer.ts +1 -0
  215. package/src/animation3d/runtime/mixer/TrackSampler.ts +399 -0
  216. package/src/animation3d/runtime/mixer/index.ts +8 -0
  217. package/src/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.ts +4 -0
  218. package/src/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.ts +1 -0
  219. package/src/animation3d/runtime/state-machine/Animation3DStateMachineController.ts +1 -0
  220. package/src/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.ts +1 -0
  221. package/src/animation3d/runtime/state-machine/index.ts +45 -0
  222. package/src/animation3d.ts +5 -0
  223. package/src/benchmark.ts +168 -0
  224. package/src/canvas-text/CanvasText2DRenderSystem.ts +292 -0
  225. package/src/canvas-text/CanvasTextComponent.ts +47 -0
  226. package/src/canvas-text.ts +4 -0
  227. package/src/experimental-gltf-worker.ts +18 -0
  228. package/src/experimental-spine-worker.ts +9 -0
  229. package/src/gltf/GltfAccessorReader.ts +271 -0
  230. package/src/gltf/GltfAnimation3DAdapter.ts +680 -0
  231. package/src/gltf/GltfAnimationRuntime.ts +392 -0
  232. package/src/gltf/GltfAssetWorkerClient.ts +136 -0
  233. package/src/gltf/GltfCompatibilityReport.ts +214 -0
  234. package/src/gltf/GltfConservativeBounds.ts +219 -0
  235. package/src/gltf/GltfDracoDecoder.ts +251 -0
  236. package/src/gltf/GltfExtensionAdapter.ts +340 -0
  237. package/src/gltf/GltfLoaderContract.ts +333 -0
  238. package/src/gltf/GltfLoaderErrors.ts +59 -0
  239. package/src/gltf/GltfMaterialDescriptor.ts +134 -0
  240. package/src/gltf/GltfMaterialEncoder.ts +173 -0
  241. package/src/gltf/GltfMaterialLoader.ts +293 -0
  242. package/src/gltf/GltfModelComponent.ts +115 -0
  243. package/src/gltf/GltfModelSystem.ts +208 -0
  244. package/src/gltf/GltfPlugin.ts +84 -0
  245. package/src/gltf/GltfSchema.ts +229 -0
  246. package/src/gltf/GltfUvSemanticPlanner.ts +166 -0
  247. package/src/gltf/gltfLoader.ts +910 -0
  248. package/src/gltf-animation3d.ts +10 -0
  249. package/src/gltf-worker-runtime.ts +10 -0
  250. package/src/gltf.ts +56 -0
  251. package/src/grid/Grid2DComponent.ts +69 -0
  252. package/src/grid.ts +2 -0
  253. package/src/hya-state-machine.ts +19 -0
  254. package/src/index.ts +2 -0
  255. package/src/plugins/pluginUtils.ts +50 -0
  256. package/src/plugins.ts +6 -0
  257. package/src/shaders/generated/2d-ui-animation-2d.generated.wgsl +242 -0
  258. package/src/shaders/generated/2d-ui-artifact.generated.ts +867 -0
  259. package/src/shaders/generated/2d-ui-canvas-text-2d.generated.wgsl +38 -0
  260. package/src/shaders/generated/2d-ui-spine2d.generated.wgsl +41 -0
  261. package/src/shaders/generated/2d-ui-tilemap2d.generated.wgsl +36 -0
  262. package/src/spine/Spine2DComponent.ts +168 -0
  263. package/src/spine/Spine2DGpuRenderer.ts +449 -0
  264. package/src/spine/Spine2DRenderSystem.ts +199 -0
  265. package/src/spine/Spine2DRuntime.ts +1529 -0
  266. package/src/spine/SpineAnimationBoneTimelines.ts +30 -0
  267. package/src/spine/SpineAssetParser.ts +20 -0
  268. package/src/spine/SpineAssetWorkerClient.ts +112 -0
  269. package/src/spine/SpineAssetWorkerContract.ts +4 -0
  270. package/src/spine/SpineAtlasParser.ts +127 -0
  271. package/src/spine/SpineFloatBuilder.ts +66 -0
  272. package/src/spine/SpinePathConstraintSolver.ts +582 -0
  273. package/src/spine/SpinePlugin.ts +76 -0
  274. package/src/spine/SpineSkeletonRuntime.ts +521 -0
  275. package/src/spine/SpineSlotAnimation.ts +195 -0
  276. package/src/spine/SpineTimelineRuntime.ts +453 -0
  277. package/src/spine/SpineVertexBuilder.ts +686 -0
  278. package/src/spine.ts +7 -0
  279. package/src/tilemap/Tilemap2DComponent.ts +232 -0
  280. package/src/tilemap/Tilemap2DRenderSystem.ts +58 -0
  281. package/src/tilemap/Tilemap2DRenderer.ts +289 -0
  282. package/src/tilemap/TilemapPlugin.ts +75 -0
  283. package/src/tilemap.ts +6 -0
  284. package/src/tween/Tween2DComponent.ts +83 -0
  285. package/src/tween/Tween2DSystem.ts +78 -0
  286. package/src/tween.ts +4 -0
  287. package/src/types/earcut.d.ts +7 -0
  288. package/src/types/wgsl.d.ts +4 -0
  289. package/src/utils/RenderSystem2DBase.ts +164 -0
  290. package/src/utils/arrayAccess.ts +17 -0
  291. package/src/utils/camera2d.ts +68 -0
  292. package/src/utils/render2dGpu.ts +132 -0
  293. package/test/fixtures/gltf/animation-characterization.gltf +344 -0
@@ -0,0 +1,680 @@
1
+ import { Component, type Entity } from '@haiyue/engine';
2
+ import { createAbortError } from '@haiyue/engine/experimental/async';
3
+ import type {
4
+ Animation3DBinding,
5
+ Animation3DBindingResolver,
6
+ Animation3DResolvedBinding,
7
+ } from '../animation3d/Animation3DBinding';
8
+ import type { Animation3DClip } from '../animation3d/Animation3DClip';
9
+ import { Animation3DMixer } from '../animation3d/Animation3DMixer';
10
+ import type { Animation3DPose } from '../animation3d/Animation3DPose';
11
+ import { Animation3DPoseBuffer } from '../animation3d/Animation3DPoseBuffer';
12
+ import type { Animation3DTrack } from '../animation3d/Animation3DTrack';
13
+ import {
14
+ applyMorphWeights,
15
+ composeTrsMatrix,
16
+ updateSkinnedPrimitive,
17
+ } from './GltfAnimationRuntime';
18
+ import type {
19
+ GltfAnimationChannelRuntime,
20
+ GltfAnimationClip,
21
+ GltfAnimationPath,
22
+ GltfAnimationTarget,
23
+ GltfSkinnedPrimitiveRuntime,
24
+ LoadedGltfModel,
25
+ } from './GltfLoaderContract';
26
+
27
+ export interface GltfAnimation3DRuntimeOptions {
28
+ /** Cancels and destroys the adapter without taking ownership of the glTF model. */
29
+ readonly signal?: AbortSignal;
30
+ /** Stable prefix used when several glTF models share a higher-level clip registry. */
31
+ readonly clipIdPrefix?: string;
32
+ }
33
+
34
+ export type GltfAnimation3DRuntimeState = 'active' | 'destroyed';
35
+
36
+ type GltfAnimation3DBindingPath =
37
+ | 'transform.translation'
38
+ | 'transform.rotation'
39
+ | 'transform.scale'
40
+ | 'morph.weights';
41
+
42
+ interface GltfAnimation3DTargetState {
43
+ readonly target: GltfAnimationTarget;
44
+ readonly nodePath: readonly string[];
45
+ readonly nodeKey: string;
46
+ readonly baseTranslation: Float32Array;
47
+ readonly baseRotation: Float32Array;
48
+ readonly baseScale: Float32Array;
49
+ readonly baseWeights: Float32Array;
50
+ readonly translation: Float32Array;
51
+ readonly rotation: Float32Array;
52
+ readonly scale: Float32Array;
53
+ readonly weights: Float32Array;
54
+ readonly matrix: Float32Array<ArrayBuffer>;
55
+ seenGeneration: number;
56
+ touchedTransform: boolean;
57
+ touchedWeights: boolean;
58
+ appliedTransform: boolean;
59
+ appliedWeights: boolean;
60
+ }
61
+
62
+ interface GltfAnimation3DAdapterContext {
63
+ readonly targetStates: Map<GltfAnimationTarget, GltfAnimation3DTargetState>;
64
+ readonly endpoints: Map<string, GltfAnimation3DResolvedEndpoint>;
65
+ readonly skinnedPrimitives: readonly GltfSkinnedPrimitiveRuntime[];
66
+ }
67
+
68
+ class GltfAnimation3DResolvedEndpoint implements Animation3DResolvedBinding {
69
+ readonly binding: Animation3DBinding;
70
+ readonly state: GltfAnimation3DTargetState;
71
+ readonly path: GltfAnimation3DBindingPath;
72
+ private readonly _onDirectWrite: () => void;
73
+
74
+ constructor(
75
+ binding: Animation3DBinding,
76
+ state: GltfAnimation3DTargetState,
77
+ path: GltfAnimation3DBindingPath,
78
+ onDirectWrite: () => void,
79
+ ) {
80
+ this.binding = binding;
81
+ this.state = state;
82
+ this.path = path;
83
+ this._onDirectWrite = onDirectWrite;
84
+ }
85
+
86
+ read(out: Float32Array): void {
87
+ copyValues(this.baseValue(), out, this.binding.valueSize);
88
+ }
89
+
90
+ write(value: ArrayLike<number>): void {
91
+ this.writeCurrent(value);
92
+ commitTargetState(this.state, this.path.startsWith('transform.'), this.path === 'morph.weights');
93
+ this._onDirectWrite();
94
+ }
95
+
96
+ resetCurrentFromBase(): void {
97
+ this.state.translation.set(this.state.baseTranslation);
98
+ this.state.rotation.set(this.state.baseRotation);
99
+ this.state.scale.set(this.state.baseScale);
100
+ this.state.weights.set(this.state.baseWeights);
101
+ }
102
+
103
+ writeCurrent(value: ArrayLike<number>): void {
104
+ switch (this.path) {
105
+ case 'transform.translation':
106
+ copyValues(value, this.state.translation, 3);
107
+ this.state.touchedTransform = true;
108
+ break;
109
+ case 'transform.rotation':
110
+ copyValues(value, this.state.rotation, 4);
111
+ normalizeQuaternion(this.state.rotation);
112
+ this.state.touchedTransform = true;
113
+ break;
114
+ case 'transform.scale':
115
+ copyValues(value, this.state.scale, 3);
116
+ this.state.touchedTransform = true;
117
+ break;
118
+ case 'morph.weights':
119
+ copyValues(value, this.state.weights, this.binding.valueSize);
120
+ this.state.touchedWeights = true;
121
+ break;
122
+ }
123
+ }
124
+
125
+ private baseValue(): Float32Array {
126
+ switch (this.path) {
127
+ case 'transform.translation': return this.state.baseTranslation;
128
+ case 'transform.rotation': return this.state.baseRotation;
129
+ case 'transform.scale': return this.state.baseScale;
130
+ case 'morph.weights': return this.state.baseWeights;
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Resolves source-independent Animation3D bindings to one loaded glTF model.
137
+ * Base reads remain the authored glTF pose so partial fades do not accumulate
138
+ * the previously applied frame back into the next mix.
139
+ */
140
+ class GltfAnimation3DBindingResolver implements Animation3DBindingResolver {
141
+ private readonly _endpoints: Map<string, GltfAnimation3DResolvedEndpoint>;
142
+ private _revision = 0;
143
+ private _destroyed = false;
144
+
145
+ constructor(endpoints: Map<string, GltfAnimation3DResolvedEndpoint>) {
146
+ this._endpoints = endpoints;
147
+ }
148
+
149
+ get revision(): number { return this._revision; }
150
+ get bindingCount(): number { return this._endpoints.size; }
151
+ get destroyed(): boolean { return this._destroyed; }
152
+
153
+ resolve<TBinding extends Animation3DBinding>(
154
+ binding: TBinding,
155
+ ): Animation3DResolvedBinding<TBinding> | null {
156
+ if (this._destroyed) return null;
157
+ const endpoint = this._endpoints.get(binding.id);
158
+ if (!endpoint
159
+ || endpoint.binding.path !== binding.path
160
+ || endpoint.binding.valueType !== binding.valueType
161
+ || endpoint.binding.valueSize !== binding.valueSize) {
162
+ return null;
163
+ }
164
+ return endpoint as unknown as Animation3DResolvedBinding<TBinding>;
165
+ }
166
+
167
+ destroy(): void {
168
+ if (this._destroyed) return;
169
+ this._destroyed = true;
170
+ this._endpoints.clear();
171
+ this._revision++;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Applies a transient Animation3D pose to glTF Transform3D, skinning and morph
177
+ * resources. Target scratch and active lists are retained and reused.
178
+ */
179
+ class GltfAnimation3DPoseApplier {
180
+ private readonly _targetStates: Map<GltfAnimationTarget, GltfAnimation3DTargetState>;
181
+ private readonly _endpoints: Map<string, GltfAnimation3DResolvedEndpoint>;
182
+ private readonly _skinnedPrimitives: readonly GltfSkinnedPrimitiveRuntime[];
183
+ private readonly _activeTargets: GltfAnimation3DTargetState[] = [];
184
+ private readonly _previousTargets: GltfAnimation3DTargetState[] = [];
185
+ private _generation = 0;
186
+ private _destroyed = false;
187
+
188
+ constructor(context: GltfAnimation3DAdapterContext) {
189
+ this._targetStates = context.targetStates;
190
+ this._endpoints = context.endpoints;
191
+ this._skinnedPrimitives = context.skinnedPrimitives;
192
+ }
193
+
194
+ get targetCount(): number { return this._targetStates.size; }
195
+ get destroyed(): boolean { return this._destroyed; }
196
+
197
+ apply(pose: Animation3DPose): void {
198
+ this.assertActive();
199
+ const generation = ++this._generation;
200
+ this._activeTargets.length = 0;
201
+ for (const channel of pose.channels) {
202
+ const endpoint = this._endpoints.get(channel.binding.id);
203
+ if (!endpoint) continue;
204
+ const state = endpoint.state;
205
+ if (state.seenGeneration !== generation) {
206
+ state.seenGeneration = generation;
207
+ state.touchedTransform = false;
208
+ state.touchedWeights = false;
209
+ endpoint.resetCurrentFromBase();
210
+ this._activeTargets.push(state);
211
+ }
212
+ endpoint.writeCurrent(channel.value);
213
+ }
214
+
215
+ let changed = false;
216
+ for (const state of this._previousTargets) {
217
+ if (state.seenGeneration === generation) continue;
218
+ state.translation.set(state.baseTranslation);
219
+ state.rotation.set(state.baseRotation);
220
+ state.scale.set(state.baseScale);
221
+ state.weights.set(state.baseWeights);
222
+ commitTargetState(state, state.appliedTransform, state.appliedWeights);
223
+ changed ||= state.appliedTransform || state.appliedWeights;
224
+ state.appliedTransform = false;
225
+ state.appliedWeights = false;
226
+ }
227
+
228
+ for (const state of this._activeTargets) {
229
+ const restoreTransform = state.appliedTransform && !state.touchedTransform;
230
+ const restoreWeights = state.appliedWeights && !state.touchedWeights;
231
+ commitTargetState(
232
+ state,
233
+ state.touchedTransform || restoreTransform,
234
+ state.touchedWeights || restoreWeights,
235
+ );
236
+ changed ||= state.touchedTransform || state.touchedWeights || restoreTransform || restoreWeights;
237
+ state.appliedTransform = state.touchedTransform;
238
+ state.appliedWeights = state.touchedWeights;
239
+ }
240
+
241
+ this._previousTargets.length = 0;
242
+ this._previousTargets.push(...this._activeTargets);
243
+ if (changed) updateSkinnedPrimitives(this._skinnedPrimitives);
244
+ }
245
+
246
+ destroy(restoreBasePose = true): void {
247
+ if (this._destroyed) return;
248
+ if (restoreBasePose) {
249
+ let changed = false;
250
+ for (const state of this._previousTargets) {
251
+ state.translation.set(state.baseTranslation);
252
+ state.rotation.set(state.baseRotation);
253
+ state.scale.set(state.baseScale);
254
+ state.weights.set(state.baseWeights);
255
+ commitTargetState(state, state.appliedTransform, state.appliedWeights);
256
+ changed ||= state.appliedTransform || state.appliedWeights;
257
+ }
258
+ if (changed) updateSkinnedPrimitives(this._skinnedPrimitives);
259
+ }
260
+ this._destroyed = true;
261
+ this._activeTargets.length = 0;
262
+ this._previousTargets.length = 0;
263
+ this._targetStates.clear();
264
+ this._endpoints.clear();
265
+ }
266
+
267
+ private assertActive(): void {
268
+ if (this._destroyed) throw new Error('glTF Animation3D pose applier has been destroyed.');
269
+ }
270
+ }
271
+
272
+ class GltfAnimation3DRuntimeOwnerComponent extends Component {
273
+ private _runtime: GltfAnimation3DRuntime | null = null;
274
+
275
+ constructor() {
276
+ super('GltfAnimation3DRuntimeOwner');
277
+ }
278
+
279
+ attach(runtime: GltfAnimation3DRuntime): void {
280
+ this._runtime = runtime;
281
+ }
282
+
283
+ release(runtime: GltfAnimation3DRuntime): void {
284
+ if (this._runtime === runtime) this._runtime = null;
285
+ }
286
+
287
+ override clone(): GltfAnimation3DRuntimeOwnerComponent {
288
+ return new GltfAnimation3DRuntimeOwnerComponent();
289
+ }
290
+
291
+ override destroy(): void {
292
+ if (this.destroyed) return;
293
+ const runtime = this._runtime;
294
+ this._runtime = null;
295
+ runtime?.destroy();
296
+ super.destroy();
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Model-scoped owner combining the existing Animation3D mixer with glTF
302
+ * binding and pose adapters. It does not own or dispose the LoadedGltfModel.
303
+ */
304
+ export class GltfAnimation3DRuntime {
305
+ readonly mixer: Animation3DMixer;
306
+ readonly pose = new Animation3DPoseBuffer();
307
+
308
+ private readonly _clips: Animation3DClip[];
309
+ private readonly _owner: GltfAnimation3DRuntimeOwnerComponent;
310
+ private readonly _resolver: GltfAnimation3DBindingResolver;
311
+ private readonly _poseApplier: GltfAnimation3DPoseApplier;
312
+ private _root: Entity | null;
313
+ private _state: GltfAnimation3DRuntimeState = 'active';
314
+ private readonly _signal: AbortSignal | null;
315
+ private readonly _abortListener: (() => void) | null;
316
+
317
+ constructor(model: LoadedGltfModel, options: GltfAnimation3DRuntimeOptions = {}) {
318
+ if (options.signal?.aborted) throw createAbortError('glTF Animation3D runtime creation aborted.', options.signal.reason);
319
+ const context = createAdapterContext(model);
320
+ this._clips = createClips(model.animationClips, context, options.clipIdPrefix);
321
+ this._resolver = new GltfAnimation3DBindingResolver(context.endpoints);
322
+ this._poseApplier = new GltfAnimation3DPoseApplier(context);
323
+ this.mixer = new Animation3DMixer(this._resolver);
324
+ this._root = model.root;
325
+ this._owner = new GltfAnimation3DRuntimeOwnerComponent();
326
+ this._owner.attach(this);
327
+ model.root.addComponent(this._owner);
328
+ this._signal = options.signal ?? null;
329
+ this._abortListener = this._signal
330
+ ? () => this.destroy()
331
+ : null;
332
+ if (this._signal && this._abortListener) {
333
+ this._signal.addEventListener('abort', this._abortListener, { once: true });
334
+ }
335
+ }
336
+
337
+ get state(): GltfAnimation3DRuntimeState { return this._state; }
338
+ get root(): Entity | null { return this._root; }
339
+ get clips(): readonly Animation3DClip[] { return this._clips; }
340
+ /** Diagnostic count without exposing the model-specific resolver handle. */
341
+ get bindingCount(): number { return this._resolver.bindingCount; }
342
+ /** Diagnostic count without exposing the model-specific pose-applier handle. */
343
+ get targetCount(): number { return this._poseApplier.targetCount; }
344
+
345
+ update(deltaSeconds: number): Animation3DPose {
346
+ this.assertActive();
347
+ const pose = this.mixer.update(deltaSeconds, this.pose);
348
+ this._poseApplier.apply(pose);
349
+ return pose;
350
+ }
351
+
352
+ evaluate(): Animation3DPose {
353
+ this.assertActive();
354
+ const pose = this.mixer.evaluate(this.pose);
355
+ this._poseApplier.apply(pose);
356
+ return pose;
357
+ }
358
+
359
+ /** @internal Applies a pose produced by a shared multi-mixer state-machine transaction. */
360
+ applySynchronizedPose(pose: Animation3DPose): void {
361
+ this.assertActive();
362
+ this._poseApplier.apply(pose);
363
+ }
364
+
365
+ setTime(timeSeconds: number): Animation3DPose {
366
+ this.assertActive();
367
+ const pose = this.mixer.setTime(timeSeconds, this.pose);
368
+ this._poseApplier.apply(pose);
369
+ return pose;
370
+ }
371
+
372
+ destroy(): void {
373
+ if (this._state === 'destroyed') return;
374
+ this._state = 'destroyed';
375
+ if (this._signal && this._abortListener) {
376
+ this._signal.removeEventListener('abort', this._abortListener);
377
+ }
378
+ const root = this._root;
379
+ this._root = null;
380
+ this._owner.release(this);
381
+ this.mixer.destroy();
382
+ this._poseApplier.destroy(root ? !root.destroyed : false);
383
+ this._resolver.destroy();
384
+ this._clips.length = 0;
385
+ }
386
+
387
+ private assertActive(): void {
388
+ if (this._state !== 'active' || this._root?.destroyed) {
389
+ this.destroy();
390
+ throw new Error('glTF Animation3D runtime has been destroyed.');
391
+ }
392
+ }
393
+ }
394
+
395
+ export function createGltfAnimation3DRuntime(
396
+ model: LoadedGltfModel,
397
+ options: GltfAnimation3DRuntimeOptions = {},
398
+ ): GltfAnimation3DRuntime {
399
+ return new GltfAnimation3DRuntime(model, options);
400
+ }
401
+
402
+ /** Converts loaded legacy glTF clips without exposing glTF sampler structures. */
403
+ export function createGltfAnimation3DClips(
404
+ model: LoadedGltfModel,
405
+ clipIdPrefix?: string,
406
+ ): readonly Animation3DClip[] {
407
+ const context = createAdapterContext(model);
408
+ return createClips(model.animationClips, context, clipIdPrefix);
409
+ }
410
+
411
+ function createAdapterContext(model: LoadedGltfModel): GltfAnimation3DAdapterContext {
412
+ const targetSizes = new Map<GltfAnimationTarget, number>();
413
+ const skinnedPrimitives = new Set<GltfSkinnedPrimitiveRuntime>();
414
+ for (const clip of model.animationClips) {
415
+ for (const channel of clip.channels) {
416
+ const previousSize = targetSizes.get(channel.target) ?? channel.target.weights.length;
417
+ targetSizes.set(channel.target, Math.max(previousSize, channel.path === 'weights' ? channel.valueSize : 0));
418
+ }
419
+ for (const primitive of clip.skinnedPrimitives) skinnedPrimitives.add(primitive);
420
+ }
421
+
422
+ const targetStates = new Map<GltfAnimationTarget, GltfAnimation3DTargetState>();
423
+ for (const [target, weightSize] of targetSizes) {
424
+ const nodePath = createStableNodePath(model.root, target.entity);
425
+ const baseWeights = new Float32Array(Math.max(weightSize, target.weights.length));
426
+ copyValues(target.weights, baseWeights, baseWeights.length);
427
+ const baseRotation = new Float32Array(target.rotation);
428
+ normalizeQuaternion(baseRotation);
429
+ targetStates.set(target, {
430
+ target,
431
+ nodePath,
432
+ nodeKey: nodePath.join('/'),
433
+ baseTranslation: new Float32Array(target.translation),
434
+ baseRotation,
435
+ baseScale: new Float32Array(target.scale),
436
+ baseWeights,
437
+ translation: new Float32Array(target.translation),
438
+ rotation: new Float32Array(baseRotation),
439
+ scale: new Float32Array(target.scale),
440
+ weights: new Float32Array(baseWeights),
441
+ matrix: new Float32Array(16),
442
+ seenGeneration: 0,
443
+ touchedTransform: false,
444
+ touchedWeights: false,
445
+ appliedTransform: false,
446
+ appliedWeights: false,
447
+ });
448
+ }
449
+
450
+ const endpoints = new Map<string, GltfAnimation3DResolvedEndpoint>();
451
+ const context: GltfAnimation3DAdapterContext = {
452
+ targetStates,
453
+ endpoints,
454
+ skinnedPrimitives: [...skinnedPrimitives],
455
+ };
456
+ const updateSkinning = () => updateSkinnedPrimitives(context.skinnedPrimitives);
457
+ for (const clip of model.animationClips) {
458
+ for (const channel of clip.channels) {
459
+ const state = requiredTargetState(context, channel.target);
460
+ const binding = createBinding(state, channel.path, channel.valueSize);
461
+ if (!endpoints.has(binding.id)) {
462
+ endpoints.set(
463
+ binding.id,
464
+ new GltfAnimation3DResolvedEndpoint(binding, state, bindingPath(channel.path), updateSkinning),
465
+ );
466
+ }
467
+ }
468
+ }
469
+ return context;
470
+ }
471
+
472
+ function createClips(
473
+ clips: readonly GltfAnimationClip[],
474
+ context: GltfAnimation3DAdapterContext,
475
+ clipIdPrefix = 'gltf-animation',
476
+ ): Animation3DClip[] {
477
+ return clips.map((clip, clipIndex) => {
478
+ const id = `${clipIdPrefix}:${clipIndex}`;
479
+ const tracks = clip.channels.map((channel, channelIndex) => {
480
+ const state = requiredTargetState(context, channel.target);
481
+ const binding = context.endpoints.get(
482
+ bindingId(state, bindingPath(channel.path)),
483
+ )?.binding;
484
+ if (!binding) throw new Error(`Missing glTF Animation3D binding for ${channel.path}.`);
485
+ const times = copyFiniteValues(channel.input, `${id}.tracks[${channelIndex}].times`);
486
+ validateTimes(times, clip.duration, `${id}.tracks[${channelIndex}].times`);
487
+ const interpolation = mapInterpolation(channel.interpolation);
488
+ const values = copyFiniteValues(channel.output, `${id}.tracks[${channelIndex}].values`);
489
+ validateTrackValues(times, values, binding.valueSize, interpolation, `${id}.tracks[${channelIndex}]`);
490
+ return {
491
+ id: `${id}:track:${channelIndex}`,
492
+ binding,
493
+ interpolation,
494
+ times,
495
+ values,
496
+ } satisfies Animation3DTrack;
497
+ });
498
+ return {
499
+ format: 'haiyue-animation3d-clip@1',
500
+ id,
501
+ name: clip.name,
502
+ duration: clip.duration,
503
+ tracks,
504
+ events: [],
505
+ };
506
+ });
507
+ }
508
+
509
+ function createBinding(
510
+ state: GltfAnimation3DTargetState,
511
+ path: GltfAnimationPath,
512
+ valueSize: number,
513
+ ): Animation3DBinding {
514
+ const target = Object.freeze({
515
+ kind: 'node-path' as const,
516
+ segments: state.nodePath,
517
+ });
518
+ switch (path) {
519
+ case 'translation':
520
+ return {
521
+ id: bindingId(state, 'transform.translation'),
522
+ target,
523
+ path: 'transform.translation',
524
+ valueType: 'vec3',
525
+ valueSize: 3,
526
+ };
527
+ case 'rotation':
528
+ return {
529
+ id: bindingId(state, 'transform.rotation'),
530
+ target,
531
+ path: 'transform.rotation',
532
+ valueType: 'quaternion',
533
+ valueSize: 4,
534
+ };
535
+ case 'scale':
536
+ return {
537
+ id: bindingId(state, 'transform.scale'),
538
+ target,
539
+ path: 'transform.scale',
540
+ valueType: 'vec3',
541
+ valueSize: 3,
542
+ };
543
+ case 'weights':
544
+ if (!Number.isInteger(valueSize) || valueSize <= 0) {
545
+ throw new RangeError(`glTF morph binding requires a positive valueSize; received ${valueSize}.`);
546
+ }
547
+ return {
548
+ id: bindingId(state, 'morph.weights'),
549
+ target,
550
+ path: 'morph.weights',
551
+ valueType: 'weights',
552
+ valueSize,
553
+ };
554
+ }
555
+ }
556
+
557
+ function bindingPath(path: GltfAnimationPath): GltfAnimation3DBindingPath {
558
+ switch (path) {
559
+ case 'translation': return 'transform.translation';
560
+ case 'rotation': return 'transform.rotation';
561
+ case 'scale': return 'transform.scale';
562
+ case 'weights': return 'morph.weights';
563
+ }
564
+ }
565
+
566
+ function bindingId(state: GltfAnimation3DTargetState, path: GltfAnimation3DBindingPath): string {
567
+ return `gltf:${state.nodeKey}:${path}`;
568
+ }
569
+
570
+ function mapInterpolation(
571
+ interpolation: GltfAnimationChannelRuntime['interpolation'],
572
+ ): Animation3DTrack['interpolation'] {
573
+ switch (interpolation) {
574
+ case 'STEP': return 'step';
575
+ case 'CUBICSPLINE': return 'cubic-spline';
576
+ case 'LINEAR': return 'linear';
577
+ }
578
+ }
579
+
580
+ function requiredTargetState(
581
+ context: GltfAnimation3DAdapterContext,
582
+ target: GltfAnimationTarget,
583
+ ): GltfAnimation3DTargetState {
584
+ const state = context.targetStates.get(target);
585
+ if (!state) throw new Error(`glTF animation target "${target.entity.name}" is not registered.`);
586
+ return state;
587
+ }
588
+
589
+ function createStableNodePath(root: Entity, target: Entity): readonly string[] {
590
+ const reversed: string[] = [];
591
+ let current: Entity | null = target;
592
+ while (current && current !== root) {
593
+ const parent: Entity | null = current.parent;
594
+ if (!parent) {
595
+ throw new Error(`glTF animation target "${target.name}" is outside the loaded model root.`);
596
+ }
597
+ const siblingIndex = parent.children.indexOf(current);
598
+ reversed.push(`${encodeURIComponent(current.name)}[${siblingIndex}]`);
599
+ current = parent;
600
+ }
601
+ if (current !== root) {
602
+ throw new Error(`glTF animation target "${target.name}" is outside the loaded model root.`);
603
+ }
604
+ reversed.reverse();
605
+ return Object.freeze(reversed);
606
+ }
607
+
608
+ function copyFiniteValues(source: ArrayLike<number>, path: string): Float32Array {
609
+ const out = new Float32Array(source.length);
610
+ for (let index = 0; index < source.length; index++) {
611
+ const value = source[index];
612
+ if (!Number.isFinite(value)) throw new RangeError(`${path}[${index}] must be finite.`);
613
+ out[index] = value as number;
614
+ }
615
+ return out;
616
+ }
617
+
618
+ function validateTimes(times: Float32Array, duration: number, path: string): void {
619
+ if (times.length === 0) throw new RangeError(`${path} must contain at least one key.`);
620
+ for (let index = 0; index < times.length; index++) {
621
+ const value = times[index] as number;
622
+ if ((index > 0 && value <= (times[index - 1] as number)) || value < 0 || value > duration) {
623
+ throw new RangeError(`${path} must be strictly increasing and within clip duration.`);
624
+ }
625
+ }
626
+ }
627
+
628
+ function validateTrackValues(
629
+ times: Float32Array,
630
+ values: Float32Array,
631
+ valueSize: number,
632
+ interpolation: Animation3DTrack['interpolation'],
633
+ path: string,
634
+ ): void {
635
+ const stride = interpolation === 'cubic-spline' ? valueSize * 3 : valueSize;
636
+ const expected = times.length * stride;
637
+ if (values.length !== expected) {
638
+ throw new RangeError(`${path}.values requires ${expected} values; received ${values.length}.`);
639
+ }
640
+ }
641
+
642
+ function commitTargetState(
643
+ state: GltfAnimation3DTargetState,
644
+ transformChanged: boolean,
645
+ weightsChanged: boolean,
646
+ ): void {
647
+ if (transformChanged) {
648
+ state.target.transform.localMatrix = composeTrsMatrix(
649
+ state.translation,
650
+ state.rotation,
651
+ state.scale,
652
+ state.matrix,
653
+ );
654
+ }
655
+ if (weightsChanged) applyMorphWeights(state.target, state.weights);
656
+ }
657
+
658
+ function updateSkinnedPrimitives(primitives: readonly GltfSkinnedPrimitiveRuntime[]): void {
659
+ for (const primitive of primitives) updateSkinnedPrimitive(primitive);
660
+ }
661
+
662
+ function copyValues(source: ArrayLike<number>, target: Float32Array, count: number): void {
663
+ for (let index = 0; index < count; index++) target[index] = source[index] ?? 0;
664
+ }
665
+
666
+ function normalizeQuaternion(value: Float32Array): void {
667
+ const x = value[0] ?? 0;
668
+ const y = value[1] ?? 0;
669
+ const z = value[2] ?? 0;
670
+ const w = value[3] ?? 1;
671
+ const length = Math.hypot(x, y, z, w);
672
+ if (length <= Number.EPSILON) {
673
+ value.set([0, 0, 0, 1]);
674
+ return;
675
+ }
676
+ value[0] = x / length;
677
+ value[1] = y / length;
678
+ value[2] = z / length;
679
+ value[3] = w / length;
680
+ }