@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,833 @@
1
+ import type { Animation3DBinding, Animation3DBindingMask } from '../../Animation3DBinding.js';
2
+ import type {
3
+ Animation3DAction,
4
+ Animation3DActionOptions,
5
+ Animation3DActionStatus,
6
+ Animation3DBlendMode,
7
+ Animation3DLoopMode,
8
+ } from '../../Animation3DAction.js';
9
+ import type { Animation3DClip, Animation3DEvent } from '../../Animation3DClip.js';
10
+ import { Animation3DError } from '../../Animation3DError.js';
11
+ import type { Animation3DMutablePose, Animation3DPoseEvent } from '../../Animation3DPose.js';
12
+ import type { Animation3DTrack } from '../../Animation3DTrack.js';
13
+ import {
14
+ Animation3DTrackSampler,
15
+ validateAnimation3DTrack,
16
+ } from './TrackSampler.js';
17
+
18
+ export interface Animation3DActionOwner {
19
+ readonly time: number;
20
+ assertActive(): void;
21
+ }
22
+
23
+ export interface Animation3DActionTrackRuntime {
24
+ readonly track: Animation3DTrack;
25
+ readonly sampler: Animation3DTrackSampler;
26
+ readonly reference: Float32Array;
27
+ }
28
+
29
+ interface RuntimeClipEvent {
30
+ readonly event: Animation3DEvent;
31
+ readonly poseEvent: Animation3DPoseEvent;
32
+ }
33
+
34
+ /** @internal Reusable exact state used by controller-owned frame transactions. */
35
+ export interface Animation3DActionSynchronizedState {
36
+ status: Animation3DActionStatus;
37
+ enabled: boolean;
38
+ paused: boolean;
39
+ time: number;
40
+ rawTime: number;
41
+ timeScale: number;
42
+ weight: number;
43
+ loop: Animation3DLoopMode;
44
+ repetitions: number;
45
+ clampWhenFinished: boolean;
46
+ blendMode: Animation3DBlendMode;
47
+ mask: Animation3DBindingMask | null;
48
+ startTime: number | null;
49
+ eventsStarted: boolean;
50
+ fadeActive: boolean;
51
+ fadeStart: number;
52
+ fadeEnd: number;
53
+ fadeFrom: number;
54
+ fadeTo: number;
55
+ fadeValue: number;
56
+ warpActive: boolean;
57
+ warpStart: number;
58
+ warpEnd: number;
59
+ warpFrom: number;
60
+ warpTo: number;
61
+ warpValue: number;
62
+ }
63
+
64
+ /**
65
+ * Mutable mixer-owned playback state for one immutable clip.
66
+ */
67
+ export class Animation3DActionRuntime implements Animation3DAction {
68
+ readonly id: string;
69
+ readonly clip: Animation3DClip;
70
+ readonly runtimeTracks: readonly Animation3DActionTrackRuntime[];
71
+
72
+ private readonly _owner: Animation3DActionOwner;
73
+ private readonly _runtimeEvents: readonly RuntimeClipEvent[];
74
+ private _valid = true;
75
+ private _status: Animation3DActionStatus = 'idle';
76
+ private _enabled = true;
77
+ private _paused = false;
78
+ private _time = 0;
79
+ private _rawTime = 0;
80
+ private _timeScale: number;
81
+ private _weight: number;
82
+ private _loop: Animation3DLoopMode;
83
+ private _repetitions: number;
84
+ private _clampWhenFinished: boolean;
85
+ private _blendMode: Animation3DBlendMode;
86
+ private _mask: Animation3DBindingMask | null;
87
+ private _startTime: number | null = null;
88
+ private _eventsStarted = false;
89
+
90
+ private _fadeActive = false;
91
+ private _fadeStart = 0;
92
+ private _fadeEnd = 0;
93
+ private _fadeFrom = 1;
94
+ private _fadeTo = 1;
95
+ private _fadeValue = 1;
96
+
97
+ private _warpActive = false;
98
+ private _warpStart = 0;
99
+ private _warpEnd = 0;
100
+ private _warpFrom = 1;
101
+ private _warpTo = 1;
102
+ private _warpValue = 1;
103
+
104
+ constructor(
105
+ owner: Animation3DActionOwner,
106
+ clip: Animation3DClip,
107
+ id: string,
108
+ options: Animation3DActionOptions = {},
109
+ ) {
110
+ validateClip(clip);
111
+ this._owner = owner;
112
+ this.clip = clip;
113
+ this.id = id;
114
+ this._loop = options.loop ?? 'once';
115
+ this._repetitions = validateRepetitions(
116
+ options.repetitions ?? (this._loop === 'once' ? 1 : Infinity),
117
+ );
118
+ this._clampWhenFinished = options.clampWhenFinished ?? false;
119
+ this._timeScale = finiteNumber(options.timeScale ?? 1, 'Animation3DAction.timeScale');
120
+ this._weight = nonNegativeNumber(options.weight ?? 1, 'Animation3DAction.weight');
121
+ this._blendMode = options.blendMode ?? 'override';
122
+ this._mask = options.mask ?? null;
123
+
124
+ const tracks: Animation3DActionTrackRuntime[] = [];
125
+ for (let index = 0; index < clip.tracks.length; index++) {
126
+ const track = clip.tracks[index]!;
127
+ const sampler = new Animation3DTrackSampler(track);
128
+ const reference = new Float32Array(track.binding.valueSize);
129
+ sampler.sample(0, reference);
130
+ tracks.push({ track, sampler, reference });
131
+ }
132
+ this.runtimeTracks = tracks;
133
+
134
+ const sortedEvents = [...clip.events].sort((a, b) => a.time - b.time);
135
+ const runtimeEvents: RuntimeClipEvent[] = [];
136
+ for (let index = 0; index < sortedEvents.length; index++) {
137
+ const event = sortedEvents[index]!;
138
+ runtimeEvents.push({
139
+ event,
140
+ poseEvent: { actionId: id, clipId: clip.id, event },
141
+ });
142
+ }
143
+ this._runtimeEvents = runtimeEvents;
144
+ }
145
+
146
+ get status(): Animation3DActionStatus { return this._status; }
147
+ get enabled(): boolean { return this._enabled; }
148
+ set enabled(value: boolean) {
149
+ this._assertValid();
150
+ this._enabled = Boolean(value);
151
+ }
152
+ get paused(): boolean { return this._paused; }
153
+ set paused(value: boolean) {
154
+ this._assertValid();
155
+ const next = Boolean(value);
156
+ if (this._paused === next) return;
157
+ this._paused = next;
158
+ if (next && (this._status === 'running' || this._status === 'scheduled')) {
159
+ this._status = 'paused';
160
+ } else if (!next && this._status === 'paused') {
161
+ this._status = this._startTime !== null && this._owner.time < this._startTime
162
+ ? 'scheduled'
163
+ : 'running';
164
+ }
165
+ }
166
+ get time(): number { return this._time; }
167
+ set time(value: number) {
168
+ this._assertValid();
169
+ const duration = this.clip.duration;
170
+ const next = Math.min(duration, Math.max(0, finiteNumber(value, 'Animation3DAction.time')));
171
+ this._rawTime = next;
172
+ this._time = next;
173
+ this._eventsStarted = false;
174
+ this._resetSamplerCursors();
175
+ }
176
+ get timeScale(): number { return this._timeScale; }
177
+ set timeScale(value: number) {
178
+ this._assertValid();
179
+ this._timeScale = finiteNumber(value, 'Animation3DAction.timeScale');
180
+ }
181
+ get weight(): number { return this._weight; }
182
+ set weight(value: number) {
183
+ this._assertValid();
184
+ this._weight = nonNegativeNumber(value, 'Animation3DAction.weight');
185
+ }
186
+ get loop(): Animation3DLoopMode { return this._loop; }
187
+ set loop(value: Animation3DLoopMode) {
188
+ this._assertValid();
189
+ if (value !== 'once' && value !== 'repeat' && value !== 'ping-pong') {
190
+ throw new RangeError(`Unsupported Animation3D loop mode "${String(value)}".`);
191
+ }
192
+ this._loop = value;
193
+ this._setSampleTime(0);
194
+ }
195
+ get repetitions(): number { return this._repetitions; }
196
+ set repetitions(value: number) {
197
+ this._assertValid();
198
+ this._repetitions = validateRepetitions(value);
199
+ }
200
+ get clampWhenFinished(): boolean { return this._clampWhenFinished; }
201
+ set clampWhenFinished(value: boolean) {
202
+ this._assertValid();
203
+ this._clampWhenFinished = Boolean(value);
204
+ }
205
+ get blendMode(): Animation3DBlendMode { return this._blendMode; }
206
+ set blendMode(value: Animation3DBlendMode) {
207
+ this._assertValid();
208
+ if (value !== 'override' && value !== 'additive') {
209
+ throw new RangeError(`Unsupported Animation3D blend mode "${String(value)}".`);
210
+ }
211
+ this._blendMode = value;
212
+ }
213
+ get mask(): Animation3DBindingMask | null { return this._mask; }
214
+ set mask(value: Animation3DBindingMask | null) {
215
+ this._assertValid();
216
+ this._mask = value;
217
+ }
218
+
219
+ get effectiveTimeScale(): number {
220
+ if (!this._valid || this._paused || this._status !== 'running') return 0;
221
+ return this._timeScale * this._warpFactor(this._owner.time);
222
+ }
223
+
224
+ get effectiveWeight(): number {
225
+ if (!this._valid || !this._enabled || this._status === 'idle'
226
+ || this._status === 'scheduled' || this._status === 'stopped'
227
+ || (this._status === 'finished' && !this._clampWhenFinished)) return 0;
228
+ return this._weight * this._fadeFactor(this._owner.time);
229
+ }
230
+
231
+ play(): this {
232
+ this._assertValid();
233
+ this._enabled = true;
234
+ this._paused = false;
235
+ this._status = this._startTime !== null && this._owner.time < this._startTime
236
+ ? 'scheduled'
237
+ : 'running';
238
+ return this;
239
+ }
240
+
241
+ stop(): this {
242
+ this._assertValid();
243
+ this._enabled = false;
244
+ this._paused = false;
245
+ this._status = 'stopped';
246
+ this._startTime = null;
247
+ this._fadeActive = false;
248
+ this._warpActive = false;
249
+ return this;
250
+ }
251
+
252
+ reset(): this {
253
+ this._assertValid();
254
+ this._enabled = true;
255
+ this._paused = false;
256
+ this._status = 'idle';
257
+ this._time = 0;
258
+ this._rawTime = 0;
259
+ this._startTime = null;
260
+ this._eventsStarted = false;
261
+ this._fadeActive = false;
262
+ this._fadeValue = 1;
263
+ this._warpActive = false;
264
+ this._warpValue = 1;
265
+ this._resetSamplerCursors();
266
+ return this;
267
+ }
268
+
269
+ startAt(mixerTimeSeconds: number): this {
270
+ this._assertValid();
271
+ this._startTime = finiteNumber(mixerTimeSeconds, 'Animation3DAction.startAt');
272
+ if (this._status === 'running' || this._status === 'scheduled') {
273
+ this._status = this._owner.time < this._startTime ? 'scheduled' : 'running';
274
+ }
275
+ return this;
276
+ }
277
+
278
+ fadeIn(durationSeconds: number): this {
279
+ this._assertValid();
280
+ const duration = nonNegativeNumber(durationSeconds, 'Animation3DAction.fadeIn');
281
+ this._fadeValue = 0;
282
+ this._scheduleFade(0, 1, duration);
283
+ return this;
284
+ }
285
+
286
+ fadeOut(durationSeconds: number): this {
287
+ this._assertValid();
288
+ const duration = nonNegativeNumber(durationSeconds, 'Animation3DAction.fadeOut');
289
+ this._scheduleFade(this._fadeFactor(this._owner.time), 0, duration);
290
+ return this;
291
+ }
292
+
293
+ crossFadeFrom(source: Animation3DAction, durationSeconds: number, warp = false): this {
294
+ this._assertValid();
295
+ const sourceRuntime = this._requireSibling(source);
296
+ const duration = nonNegativeNumber(durationSeconds, 'Animation3DAction.crossFadeFrom');
297
+ sourceRuntime.play().fadeOut(duration);
298
+ this.play().fadeIn(duration);
299
+ if (warp && sourceRuntime.clip.duration > 0 && this.clip.duration > 0) {
300
+ sourceRuntime._scheduleWarp(1, sourceRuntime.clip.duration / this.clip.duration, duration);
301
+ this._scheduleWarp(this.clip.duration / sourceRuntime.clip.duration, 1, duration);
302
+ }
303
+ return this;
304
+ }
305
+
306
+ crossFadeTo(destination: Animation3DAction, durationSeconds: number, warp = false): this {
307
+ this._assertValid();
308
+ const destinationRuntime = this._requireSibling(destination);
309
+ destinationRuntime.crossFadeFrom(this, durationSeconds, warp);
310
+ return this;
311
+ }
312
+
313
+ stopFading(): this {
314
+ this._assertValid();
315
+ if (this._fadeActive) this._fadeValue = this._fadeFactor(this._owner.time);
316
+ this._fadeActive = false;
317
+ return this;
318
+ }
319
+
320
+ acceptsBinding(binding: Animation3DBinding): boolean {
321
+ const include = this._mask?.include;
322
+ if (include && include.length > 0) {
323
+ let found = false;
324
+ for (let index = 0; index < include.length; index++) {
325
+ if (include[index] === binding.id) {
326
+ found = true;
327
+ break;
328
+ }
329
+ }
330
+ if (!found) return false;
331
+ }
332
+ const exclude = this._mask?.exclude;
333
+ if (exclude) {
334
+ for (let index = 0; index < exclude.length; index++) {
335
+ if (exclude[index] === binding.id) return false;
336
+ }
337
+ }
338
+ return true;
339
+ }
340
+
341
+ canContribute(): boolean {
342
+ return this.effectiveWeight > 0;
343
+ }
344
+
345
+ /** @internal Allocated once by an integration handle and reused every frame. */
346
+ createSynchronizedState(): Animation3DActionSynchronizedState {
347
+ const state = {} as Animation3DActionSynchronizedState;
348
+ this.captureSynchronizedState(state);
349
+ return state;
350
+ }
351
+
352
+ /** @internal Captures every field changed by controller synchronization. */
353
+ captureSynchronizedState(out: Animation3DActionSynchronizedState): void {
354
+ this._assertValid();
355
+ out.status = this._status;
356
+ out.enabled = this._enabled;
357
+ out.paused = this._paused;
358
+ out.time = this._time;
359
+ out.rawTime = this._rawTime;
360
+ out.timeScale = this._timeScale;
361
+ out.weight = this._weight;
362
+ out.loop = this._loop;
363
+ out.repetitions = this._repetitions;
364
+ out.clampWhenFinished = this._clampWhenFinished;
365
+ out.blendMode = this._blendMode;
366
+ out.mask = this._mask;
367
+ out.startTime = this._startTime;
368
+ out.eventsStarted = this._eventsStarted;
369
+ out.fadeActive = this._fadeActive;
370
+ out.fadeStart = this._fadeStart;
371
+ out.fadeEnd = this._fadeEnd;
372
+ out.fadeFrom = this._fadeFrom;
373
+ out.fadeTo = this._fadeTo;
374
+ out.fadeValue = this._fadeValue;
375
+ out.warpActive = this._warpActive;
376
+ out.warpStart = this._warpStart;
377
+ out.warpEnd = this._warpEnd;
378
+ out.warpFrom = this._warpFrom;
379
+ out.warpTo = this._warpTo;
380
+ out.warpValue = this._warpValue;
381
+ }
382
+
383
+ /** @internal Restores event cursors as well as the sampled playhead. */
384
+ restoreSynchronizedState(state: Animation3DActionSynchronizedState): void {
385
+ this._assertValid();
386
+ this._status = state.status;
387
+ this._enabled = state.enabled;
388
+ this._paused = state.paused;
389
+ this._time = state.time;
390
+ this._rawTime = state.rawTime;
391
+ this._timeScale = state.timeScale;
392
+ this._weight = state.weight;
393
+ this._loop = state.loop;
394
+ this._repetitions = state.repetitions;
395
+ this._clampWhenFinished = state.clampWhenFinished;
396
+ this._blendMode = state.blendMode;
397
+ this._mask = state.mask;
398
+ this._startTime = state.startTime;
399
+ this._eventsStarted = state.eventsStarted;
400
+ this._fadeActive = state.fadeActive;
401
+ this._fadeStart = state.fadeStart;
402
+ this._fadeEnd = state.fadeEnd;
403
+ this._fadeFrom = state.fadeFrom;
404
+ this._fadeTo = state.fadeTo;
405
+ this._fadeValue = state.fadeValue;
406
+ this._warpActive = state.warpActive;
407
+ this._warpStart = state.warpStart;
408
+ this._warpEnd = state.warpEnd;
409
+ this._warpFrom = state.warpFrom;
410
+ this._warpTo = state.warpTo;
411
+ this._warpValue = state.warpValue;
412
+ this._resetSamplerCursors();
413
+ }
414
+
415
+ /**
416
+ * Sets an unwrapped controller-owned playhead without emitting events.
417
+ * Integration adapters use this for initial destination offsets before play.
418
+ */
419
+ seekSynchronizedTime(timeSeconds: number): void {
420
+ this._assertValid();
421
+ this._rawTime = this._clampSynchronizedTime(timeSeconds);
422
+ this._setSampleTime(0);
423
+ this._eventsStarted = false;
424
+ this._resetSamplerCursors();
425
+ }
426
+
427
+ /**
428
+ * Moves to an absolute controller-owned playhead and emits every crossed
429
+ * clip event exactly once. This does not advance the mixer clock.
430
+ */
431
+ synchronizeTime(timeSeconds: number, out: Animation3DMutablePose): void {
432
+ this._assertValid();
433
+ const after = this._clampSynchronizedTime(timeSeconds);
434
+ const before = this._rawTime;
435
+ const direction = after === before ? this._timeScale : after - before;
436
+ if (!this._eventsStarted) {
437
+ this._emitStartingEvents(direction, out);
438
+ this._eventsStarted = true;
439
+ }
440
+ this._emitCrossedEvents(before, after, out);
441
+ this._rawTime = after;
442
+ this._setSampleTime(0);
443
+ }
444
+
445
+ advance(
446
+ mixerDelta: number,
447
+ previousMixerTime: number,
448
+ currentMixerTime: number,
449
+ out: Animation3DMutablePose,
450
+ ): void {
451
+ if (!this._valid) return;
452
+ this._finishTransitions(currentMixerTime);
453
+ if (!this._enabled || this._paused) return;
454
+
455
+ let activeMixerDelta = mixerDelta;
456
+ if (this._status === 'scheduled') {
457
+ const startTime = this._startTime;
458
+ if (startTime === null) {
459
+ this._status = 'running';
460
+ } else if (mixerDelta >= 0) {
461
+ if (currentMixerTime < startTime) return;
462
+ activeMixerDelta = currentMixerTime - Math.max(previousMixerTime, startTime);
463
+ this._status = 'running';
464
+ this._startTime = null;
465
+ } else {
466
+ if (currentMixerTime > startTime) return;
467
+ activeMixerDelta = currentMixerTime - Math.min(previousMixerTime, startTime);
468
+ this._status = 'running';
469
+ this._startTime = null;
470
+ }
471
+ }
472
+ if (this._status !== 'running') return;
473
+
474
+ const actionDelta = activeMixerDelta * this._timeScale * this._warpFactor(currentMixerTime);
475
+ if (actionDelta === 0 || this.clip.duration === 0) return;
476
+ const before = this._rawTime;
477
+ let after = before + actionDelta;
478
+ let terminalDirection = 0;
479
+ const totalDuration = this._loop === 'once'
480
+ ? this.clip.duration
481
+ : this._repetitions === Infinity
482
+ ? Infinity
483
+ : this.clip.duration * this._repetitions;
484
+
485
+ if (totalDuration !== Infinity) {
486
+ if (after >= totalDuration && actionDelta > 0) {
487
+ after = totalDuration;
488
+ terminalDirection = 1;
489
+ } else if (after <= 0 && actionDelta < 0) {
490
+ after = 0;
491
+ terminalDirection = -1;
492
+ }
493
+ }
494
+
495
+ if (!this._eventsStarted) {
496
+ this._emitStartingEvents(actionDelta, out);
497
+ this._eventsStarted = true;
498
+ }
499
+ this._emitCrossedEvents(before, after, out);
500
+ this._rawTime = after;
501
+ this._setSampleTime(terminalDirection);
502
+ if (terminalDirection !== 0) {
503
+ this._status = 'finished';
504
+ if (!this._clampWhenFinished) this._enabled = false;
505
+ }
506
+ }
507
+
508
+ invalidate(): void {
509
+ if (!this._valid) return;
510
+ this._valid = false;
511
+ this._enabled = false;
512
+ this._paused = false;
513
+ this._status = 'stopped';
514
+ this._startTime = null;
515
+ this._fadeActive = false;
516
+ this._warpActive = false;
517
+ }
518
+
519
+ private _clampSynchronizedTime(timeSeconds: number): number {
520
+ const next = finiteNumber(timeSeconds, 'Animation3DAction synchronized time');
521
+ if (this._loop === 'once') {
522
+ return Math.min(this.clip.duration, Math.max(0, next));
523
+ }
524
+ if (this._repetitions === Infinity) return next;
525
+ return Math.min(this.clip.duration * this._repetitions, Math.max(0, next));
526
+ }
527
+
528
+ private _setSampleTime(terminalDirection: number): void {
529
+ const duration = this.clip.duration;
530
+ if (duration === 0) {
531
+ this._time = 0;
532
+ return;
533
+ }
534
+ if (this._loop === 'once') {
535
+ this._time = Math.min(duration, Math.max(0, this._rawTime));
536
+ return;
537
+ }
538
+ if (terminalDirection > 0 && this._loop === 'repeat') {
539
+ this._time = duration;
540
+ return;
541
+ }
542
+
543
+ const traversal = Math.floor(this._rawTime / duration);
544
+ let phase = this._rawTime - traversal * duration;
545
+ if (phase < 0) phase += duration;
546
+ if (this._loop === 'repeat') {
547
+ this._time = phase;
548
+ return;
549
+ }
550
+ this._time = isEven(traversal) ? phase : duration - phase;
551
+ }
552
+
553
+ private _emitCrossedEvents(
554
+ before: number,
555
+ after: number,
556
+ out: Animation3DMutablePose,
557
+ ): void {
558
+ if (before === after || this._runtimeEvents.length === 0) return;
559
+ if (this._loop === 'once') {
560
+ this._emitOnceEvents(before, after, out);
561
+ } else if (this._loop === 'repeat') {
562
+ this._emitRepeatEvents(before, after, out);
563
+ } else {
564
+ this._emitPingPongEvents(before, after, out);
565
+ }
566
+ }
567
+
568
+ private _emitStartingEvents(direction: number, out: Animation3DMutablePose): void {
569
+ if (direction >= 0) {
570
+ for (let index = 0; index < this._runtimeEvents.length; index++) {
571
+ const runtimeEvent = this._runtimeEvents[index]!;
572
+ if (runtimeEvent.event.time === this._time) out.emit(runtimeEvent.poseEvent);
573
+ }
574
+ } else {
575
+ for (let index = this._runtimeEvents.length - 1; index >= 0; index--) {
576
+ const runtimeEvent = this._runtimeEvents[index]!;
577
+ if (runtimeEvent.event.time === this._time) out.emit(runtimeEvent.poseEvent);
578
+ }
579
+ }
580
+ }
581
+
582
+ private _emitOnceEvents(before: number, after: number, out: Animation3DMutablePose): void {
583
+ if (after > before) {
584
+ for (let index = 0; index < this._runtimeEvents.length; index++) {
585
+ const runtimeEvent = this._runtimeEvents[index]!;
586
+ if (runtimeEvent.event.time > before && runtimeEvent.event.time <= after) {
587
+ out.emit(runtimeEvent.poseEvent);
588
+ }
589
+ }
590
+ } else {
591
+ for (let index = this._runtimeEvents.length - 1; index >= 0; index--) {
592
+ const runtimeEvent = this._runtimeEvents[index]!;
593
+ if (runtimeEvent.event.time < before && runtimeEvent.event.time >= after) {
594
+ out.emit(runtimeEvent.poseEvent);
595
+ }
596
+ }
597
+ }
598
+ }
599
+
600
+ private _emitRepeatEvents(before: number, after: number, out: Animation3DMutablePose): void {
601
+ const duration = this.clip.duration;
602
+ const minimum = Math.min(before, after);
603
+ const maximum = Math.max(before, after);
604
+ const firstCycle = Math.floor(minimum / duration) - 1;
605
+ const lastCycle = Math.floor(maximum / duration) + 1;
606
+ if (after > before) {
607
+ for (let cycle = firstCycle; cycle <= lastCycle; cycle++) {
608
+ const cycleStart = cycle * duration;
609
+ for (let index = 0; index < this._runtimeEvents.length; index++) {
610
+ const runtimeEvent = this._runtimeEvents[index]!;
611
+ const occurrence = cycleStart + runtimeEvent.event.time;
612
+ if (occurrence > before && occurrence <= after) out.emit(runtimeEvent.poseEvent);
613
+ }
614
+ }
615
+ } else {
616
+ for (let cycle = lastCycle; cycle >= firstCycle; cycle--) {
617
+ const cycleStart = cycle * duration;
618
+ for (let index = this._runtimeEvents.length - 1; index >= 0; index--) {
619
+ const runtimeEvent = this._runtimeEvents[index]!;
620
+ const occurrence = cycleStart + runtimeEvent.event.time;
621
+ if (occurrence < before && occurrence >= after) out.emit(runtimeEvent.poseEvent);
622
+ }
623
+ }
624
+ }
625
+ }
626
+
627
+ private _emitPingPongEvents(before: number, after: number, out: Animation3DMutablePose): void {
628
+ const duration = this.clip.duration;
629
+ const minimum = Math.min(before, after);
630
+ const maximum = Math.max(before, after);
631
+ const firstTraversal = Math.floor(minimum / duration) - 1;
632
+ const lastTraversal = Math.floor(maximum / duration) + 1;
633
+ if (after > before) {
634
+ for (let traversal = firstTraversal; traversal <= lastTraversal; traversal++) {
635
+ if (isEven(traversal)) {
636
+ this._emitPingPongTraversal(traversal, before, after, true, true, out);
637
+ } else {
638
+ this._emitPingPongTraversal(traversal, before, after, false, true, out);
639
+ }
640
+ }
641
+ } else {
642
+ for (let traversal = lastTraversal; traversal >= firstTraversal; traversal--) {
643
+ if (isEven(traversal)) {
644
+ this._emitPingPongTraversal(traversal, before, after, false, false, out);
645
+ } else {
646
+ this._emitPingPongTraversal(traversal, before, after, true, false, out);
647
+ }
648
+ }
649
+ }
650
+ }
651
+
652
+ private _emitPingPongTraversal(
653
+ traversal: number,
654
+ before: number,
655
+ after: number,
656
+ ascendingEvents: boolean,
657
+ forwardRaw: boolean,
658
+ out: Animation3DMutablePose,
659
+ ): void {
660
+ const duration = this.clip.duration;
661
+ const even = isEven(traversal);
662
+ let index = ascendingEvents ? 0 : this._runtimeEvents.length - 1;
663
+ const end = ascendingEvents ? this._runtimeEvents.length : -1;
664
+ const step = ascendingEvents ? 1 : -1;
665
+ for (; index !== end; index += step) {
666
+ const runtimeEvent = this._runtimeEvents[index]!;
667
+ const eventTime = runtimeEvent.event.time;
668
+ if ((even && eventTime === 0) || (!even && eventTime === duration)) continue;
669
+ const occurrence = traversal * duration + (even ? eventTime : duration - eventTime);
670
+ const crossed = forwardRaw
671
+ ? occurrence > before && occurrence <= after
672
+ : occurrence < before && occurrence >= after;
673
+ if (crossed) out.emit(runtimeEvent.poseEvent);
674
+ }
675
+ }
676
+
677
+ private _scheduleFade(from: number, to: number, duration: number): void {
678
+ this._fadeFrom = from;
679
+ this._fadeTo = to;
680
+ this._fadeStart = this._owner.time;
681
+ this._fadeEnd = this._fadeStart + duration;
682
+ if (duration === 0) {
683
+ this._fadeValue = to;
684
+ this._fadeActive = false;
685
+ } else {
686
+ this._fadeValue = from;
687
+ this._fadeActive = true;
688
+ }
689
+ }
690
+
691
+ private _scheduleWarp(from: number, to: number, duration: number): void {
692
+ this._warpFrom = from;
693
+ this._warpTo = to;
694
+ this._warpStart = this._owner.time;
695
+ this._warpEnd = this._warpStart + duration;
696
+ if (duration === 0) {
697
+ this._warpValue = to;
698
+ this._warpActive = false;
699
+ } else {
700
+ this._warpValue = from;
701
+ this._warpActive = true;
702
+ }
703
+ }
704
+
705
+ private _fadeFactor(time: number): number {
706
+ if (!this._fadeActive) return this._fadeValue;
707
+ if (time <= this._fadeStart) return this._fadeFrom;
708
+ if (time >= this._fadeEnd) return this._fadeTo;
709
+ const alpha = (time - this._fadeStart) / (this._fadeEnd - this._fadeStart);
710
+ return this._fadeFrom + (this._fadeTo - this._fadeFrom) * alpha;
711
+ }
712
+
713
+ private _warpFactor(time: number): number {
714
+ if (!this._warpActive) return this._warpValue;
715
+ if (time <= this._warpStart) return this._warpFrom;
716
+ if (time >= this._warpEnd) return this._warpTo;
717
+ const alpha = (time - this._warpStart) / (this._warpEnd - this._warpStart);
718
+ return this._warpFrom + (this._warpTo - this._warpFrom) * alpha;
719
+ }
720
+
721
+ private _finishTransitions(time: number): void {
722
+ if (this._fadeActive && time >= this._fadeEnd) {
723
+ this._fadeValue = this._fadeTo;
724
+ this._fadeActive = false;
725
+ }
726
+ if (this._warpActive && time >= this._warpEnd) {
727
+ this._warpValue = this._warpTo;
728
+ this._warpActive = false;
729
+ }
730
+ }
731
+
732
+ private _requireSibling(action: Animation3DAction): Animation3DActionRuntime {
733
+ if (!(action instanceof Animation3DActionRuntime) || action._owner !== this._owner) {
734
+ throw new RangeError('Animation3D cross-fade actions must belong to the same mixer.');
735
+ }
736
+ action._assertValid();
737
+ return action;
738
+ }
739
+
740
+ private _resetSamplerCursors(): void {
741
+ for (let index = 0; index < this.runtimeTracks.length; index++) {
742
+ this.runtimeTracks[index]!.sampler.resetCursor();
743
+ }
744
+ }
745
+
746
+ private _assertValid(): void {
747
+ this._owner.assertActive();
748
+ if (!this._valid) {
749
+ throw new Animation3DError(
750
+ 'invalid-action',
751
+ `Animation3D action "${this.id}" is no longer valid.`,
752
+ { actionId: this.id },
753
+ );
754
+ }
755
+ }
756
+ }
757
+
758
+ function validateClip(clip: Animation3DClip): void {
759
+ const clipId = typeof clip?.id === 'string' ? clip.id : '';
760
+ const fail = (message: string): never => {
761
+ throw new Animation3DError('invalid-clip', message, { clipId });
762
+ };
763
+ if (!clip || typeof clip !== 'object') {
764
+ fail('Animation3D clip must be an object.');
765
+ }
766
+ if (clip.format !== 'haiyue-animation3d-clip@1') {
767
+ fail(`Unsupported Animation3D clip format "${String(clip.format)}".`);
768
+ }
769
+ if (clipId.trim().length === 0) {
770
+ fail('Animation3D clip id must not be empty.');
771
+ }
772
+ if (typeof clip.name !== 'string') {
773
+ fail(`Animation3D clip "${clipId}" name must be a string.`);
774
+ }
775
+ if (!Number.isFinite(clip.duration) || clip.duration < 0) {
776
+ fail(`Animation3D clip duration must be finite and non-negative; received ${clip.duration}.`);
777
+ }
778
+ if (!Array.isArray(clip.tracks)) {
779
+ fail(`Animation3D clip "${clipId}" tracks must be an array.`);
780
+ }
781
+ if (!Array.isArray(clip.events)) {
782
+ fail(`Animation3D clip "${clipId}" events must be an array.`);
783
+ }
784
+ const trackIds = new Set<string>();
785
+ for (let index = 0; index < clip.tracks.length; index++) {
786
+ const track = clip.tracks[index]!;
787
+ validateAnimation3DTrack(track, clip.duration);
788
+ if (trackIds.has(track.id)) {
789
+ fail(`Animation3D clip "${clipId}" contains duplicate track id "${track.id}".`);
790
+ }
791
+ trackIds.add(track.id);
792
+ }
793
+ const eventIds = new Set<string>();
794
+ for (let index = 0; index < clip.events.length; index++) {
795
+ const event = clip.events[index]!;
796
+ if (!event || typeof event.id !== 'string' || event.id.trim().length === 0) {
797
+ fail(`Animation3D clip "${clipId}" event ids must not be empty.`);
798
+ }
799
+ if (eventIds.has(event.id)) {
800
+ fail(`Animation3D clip "${clipId}" contains duplicate event id "${event.id}".`);
801
+ }
802
+ eventIds.add(event.id);
803
+ if (typeof event.name !== 'string') {
804
+ fail(`Animation3D event "${event.id}" name must be a string.`);
805
+ }
806
+ if (!Number.isFinite(event.time) || event.time < 0 || event.time > clip.duration) {
807
+ fail(`Animation3D event "${event.id}" must lie within its clip duration.`);
808
+ }
809
+ }
810
+ }
811
+
812
+ function validateRepetitions(value: number): number {
813
+ if (value === Infinity) return value;
814
+ if (!Number.isInteger(value) || value <= 0) {
815
+ throw new RangeError(`Animation3DAction.repetitions must be a positive integer or Infinity; received ${value}.`);
816
+ }
817
+ return value;
818
+ }
819
+
820
+ function finiteNumber(value: number, property: string): number {
821
+ if (!Number.isFinite(value)) throw new RangeError(`${property} must be finite; received ${value}.`);
822
+ return value;
823
+ }
824
+
825
+ function nonNegativeNumber(value: number, property: string): number {
826
+ const result = finiteNumber(value, property);
827
+ if (result < 0) throw new RangeError(`${property} must be non-negative; received ${value}.`);
828
+ return result;
829
+ }
830
+
831
+ function isEven(value: number): boolean {
832
+ return Math.abs(value % 2) === 0;
833
+ }