@haiyue/extensions 0.1.0 → 0.2.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 (269) hide show
  1. package/README.md +25 -0
  2. package/dist/animation/Animation2DComponent.d.ts +18 -0
  3. package/dist/animation/Animation2DExtensionRegistry.d.ts +7 -0
  4. package/dist/animation/Animation2DRenderSystem.d.ts +6 -0
  5. package/dist/animation/Animation2DRuntime.d.ts +6 -2
  6. package/dist/animation/AnimationTextRasterizer.d.ts +4 -0
  7. package/dist/animation/AnimationVisual2D.d.ts +58 -2
  8. package/dist/animation/interaction/InteractionRuntime.d.ts +83 -0
  9. package/dist/animation/interaction/runtime-types.d.ts +257 -0
  10. package/dist/animation.d.ts +3 -1
  11. package/dist/animation.js +551 -59
  12. package/dist/animation3d.js +1 -1
  13. package/dist/canvas-text.js +1 -1
  14. package/dist/chunks/2d-ui-animation-2d.generated-FpziAeGJ.js +4 -0
  15. package/dist/chunks/2d-ui-indexed-sprite.generated-DmKR0CC3.js +4 -0
  16. package/dist/chunks/Animation2DStateMachine-BHcA6Cu3.js +18212 -0
  17. package/dist/chunks/{AnimationStateMachineController-BIcAh-sT.js → AnimationStateMachineController-4sKaqh9E.js} +2 -2
  18. package/dist/chunks/AnimationVisual2D-8y3qp0_U.js +230 -0
  19. package/dist/chunks/{RenderSystem2DBase-DDT61dAu.js → RenderSystem2DBase-CF2s00vg.js} +2 -2
  20. package/dist/controls/VirtualJoystickControls.d.ts +46 -0
  21. package/dist/controls/contracts.d.ts +91 -0
  22. package/dist/controls.d.ts +2 -0
  23. package/dist/controls.js +358 -0
  24. package/dist/deformable-animation/runtime/DeformableMesh2DRuntimeExtension.d.ts +11 -0
  25. package/dist/deformable-animation/runtime/DeformableMesh2DSampler.d.ts +11 -0
  26. package/dist/deformable-animation.d.ts +5 -0
  27. package/dist/deformable-animation.js +316 -0
  28. package/dist/experimental-indexed-sprite.d.ts +5 -0
  29. package/dist/experimental-indexed-sprite.js +482 -0
  30. package/dist/gltf-worker-runtime.js +9 -9
  31. package/dist/hya-state-machine.js +3 -2
  32. package/dist/index.js +1 -1
  33. package/dist/indexed-sprite/AtlasLayout.d.ts +2 -0
  34. package/dist/indexed-sprite/IndexedSpriteRenderer.d.ts +23 -0
  35. package/dist/indexed-sprite/contracts.d.ts +89 -0
  36. package/dist/internal/2d-ui-shader-artifact.js +232 -23
  37. package/dist/ray-tracing/acceleration/bvh.d.ts +37 -0
  38. package/dist/ray-tracing/acceleration/index.d.ts +6 -0
  39. package/dist/ray-tracing/acceleration/pack.d.ts +152 -0
  40. package/dist/ray-tracing/acceleration/query.d.ts +4 -0
  41. package/dist/ray-tracing/acceleration/runtime.d.ts +30 -0
  42. package/dist/ray-tracing/acceleration/tlas.d.ts +4 -0
  43. package/dist/ray-tracing/acceleration/types.d.ts +165 -0
  44. package/dist/ray-tracing/denoise/index.d.ts +3 -0
  45. package/dist/ray-tracing/denoise/layout.d.ts +9 -0
  46. package/dist/ray-tracing/denoise/runtime.d.ts +23 -0
  47. package/dist/ray-tracing/denoise/types.d.ts +28 -0
  48. package/dist/ray-tracing/hybrid/contract.d.ts +2 -0
  49. package/dist/ray-tracing/hybrid/index.d.ts +5 -0
  50. package/dist/ray-tracing/hybrid/layout.d.ts +17 -0
  51. package/dist/ray-tracing/hybrid/plan.d.ts +2 -0
  52. package/dist/ray-tracing/hybrid/runtime.d.ts +31 -0
  53. package/dist/ray-tracing/hybrid/shaders/hybrid-artifact.generated.d.ts +625 -0
  54. package/dist/ray-tracing/hybrid/types.d.ts +144 -0
  55. package/dist/ray-tracing/lifecycle/device-recovery.d.ts +31 -0
  56. package/dist/ray-tracing/lifecycle/index.d.ts +2 -0
  57. package/dist/ray-tracing/lifecycle/types.d.ts +37 -0
  58. package/dist/ray-tracing/material/index.d.ts +2 -0
  59. package/dist/ray-tracing/material/pack.d.ts +5 -0
  60. package/dist/ray-tracing/material/types.d.ts +63 -0
  61. package/dist/ray-tracing/reference/index.d.ts +122 -0
  62. package/dist/ray-tracing/renderer/index.d.ts +7 -0
  63. package/dist/ray-tracing/renderer/layout.d.ts +20 -0
  64. package/dist/ray-tracing/renderer/plan.d.ts +2 -0
  65. package/dist/ray-tracing/renderer/reference.d.ts +17 -0
  66. package/dist/ray-tracing/renderer/runtime.d.ts +39 -0
  67. package/dist/ray-tracing/renderer/scene.d.ts +4 -0
  68. package/dist/ray-tracing/renderer/types.d.ts +115 -0
  69. package/dist/ray-tracing/sampling/index.d.ts +8 -0
  70. package/dist/ray-tracing/sampling/layout.d.ts +12 -0
  71. package/dist/ray-tracing/sampling/plan.d.ts +5 -0
  72. package/dist/ray-tracing/sampling/revision.d.ts +15 -0
  73. package/dist/ray-tracing/sampling/runtime.d.ts +44 -0
  74. package/dist/ray-tracing/sampling/sequence.d.ts +2 -0
  75. package/dist/ray-tracing/sampling/types.d.ts +96 -0
  76. package/dist/ray-tracing/scene/index.d.ts +41 -0
  77. package/dist/ray-tracing/traversal/index.d.ts +4 -0
  78. package/dist/ray-tracing/traversal/layout.d.ts +16 -0
  79. package/dist/ray-tracing/traversal/plan.d.ts +2 -0
  80. package/dist/ray-tracing/traversal/runtime.d.ts +25 -0
  81. package/dist/ray-tracing/traversal/types.d.ts +79 -0
  82. package/dist/ray-tracing/worker/client.d.ts +25 -0
  83. package/dist/ray-tracing/worker/index.d.ts +5 -0
  84. package/dist/ray-tracing/worker/runtime.d.ts +11 -0
  85. package/dist/ray-tracing/worker/serialization.d.ts +16 -0
  86. package/dist/ray-tracing/worker/source.d.ts +1 -0
  87. package/dist/ray-tracing/worker/types.d.ts +91 -0
  88. package/dist/ray-tracing.d.ts +17 -0
  89. package/dist/ray-tracing.js +7666 -0
  90. package/dist/spine.js +1 -1
  91. package/dist/tilemap.js +1 -1
  92. package/package.json +26 -23
  93. package/dist/animation/Animation2DStateMachineVisualRuntime.d.ts +0 -27
  94. package/dist/animation/Particle2DDescriptorAdapter.d.ts +0 -5
  95. package/dist/animation3d/Animation3DResource.d.ts +0 -28
  96. package/dist/animation3d/hya/HyaAnimation3DStateMachineRuntime.d.ts +0 -65
  97. package/dist/animation3d/hya/index.d.ts +0 -4
  98. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.d.ts +0 -81
  99. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.d.ts +0 -39
  100. package/dist/animation3d/runtime/integration/index.d.ts +0 -2
  101. package/dist/animation3d/runtime/mixer/Action.d.ts +0 -150
  102. package/dist/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.d.ts +0 -6
  103. package/dist/animation3d/runtime/mixer/Mixer.d.ts +0 -59
  104. package/dist/animation3d/runtime/mixer/PoseBuffer.d.ts +0 -1
  105. package/dist/animation3d/runtime/mixer/TrackSampler.d.ts +0 -24
  106. package/dist/animation3d/runtime/mixer/index.d.ts +0 -4
  107. package/dist/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.d.ts +0 -1
  108. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.d.ts +0 -1
  109. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineController.d.ts +0 -1
  110. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.d.ts +0 -1
  111. package/dist/animation3d/runtime/state-machine/index.d.ts +0 -6
  112. package/dist/benchmark.d.ts +0 -30
  113. package/dist/chunks/2d-ui-animation-2d.generated-D4aHzFU2.js +0 -4
  114. package/dist/chunks/Animation2DStateMachine-9IonguNa.js +0 -3245
  115. package/dist/gltf/GltfAccessorReader.d.ts +0 -7
  116. package/dist/gltf/GltfDracoDecoder.d.ts +0 -4
  117. package/dist/gltf/GltfLoaderErrors.d.ts +0 -4
  118. package/dist/gltf/GltfMaterialDescriptor.d.ts +0 -23
  119. package/dist/gltf/GltfMaterialLoader.d.ts +0 -6
  120. package/dist/gltf-worker-runtime.d.ts +0 -7
  121. package/dist/plugins/pluginUtils.d.ts +0 -20
  122. package/dist/plugins.d.ts +0 -6
  123. package/dist/shaders/generated/2d-ui-artifact.generated.d.ts +0 -658
  124. package/dist/spine/Spine2DGpuRenderer.d.ts +0 -65
  125. package/dist/spine/Spine2DRuntime.d.ts +0 -103
  126. package/dist/spine/SpineAnimationBoneTimelines.d.ts +0 -8
  127. package/dist/spine/SpineFloatBuilder.d.ts +0 -15
  128. package/dist/spine/SpinePathConstraintSolver.d.ts +0 -32
  129. package/dist/spine/SpineSkeletonRuntime.d.ts +0 -185
  130. package/dist/spine/SpineSlotAnimation.d.ts +0 -17
  131. package/dist/spine/SpineTimelineRuntime.d.ts +0 -25
  132. package/dist/spine/SpineVertexBuilder.d.ts +0 -61
  133. package/dist/tilemap/Tilemap2DRenderer.d.ts +0 -24
  134. package/dist/utils/arrayAccess.d.ts +0 -4
  135. package/dist/utils/camera2d.d.ts +0 -12
  136. package/src/animation/Animation2DComponent.ts +0 -135
  137. package/src/animation/Animation2DExtensionRegistry.ts +0 -52
  138. package/src/animation/Animation2DRenderSystem.ts +0 -1026
  139. package/src/animation/Animation2DRuntime.ts +0 -1326
  140. package/src/animation/Animation2DStateMachine.ts +0 -39
  141. package/src/animation/Animation2DStateMachineComponent.ts +0 -228
  142. package/src/animation/Animation2DStateMachineRuntime.ts +0 -141
  143. package/src/animation/Animation2DStateMachineSystem.ts +0 -60
  144. package/src/animation/Animation2DStateMachineVisualRuntime.ts +0 -282
  145. package/src/animation/Animation2DSystem.ts +0 -72
  146. package/src/animation/AnimationAssetLoader.ts +0 -84
  147. package/src/animation/AnimationAudioClip.ts +0 -140
  148. package/src/animation/AnimationPathTessellator.ts +0 -691
  149. package/src/animation/AnimationTextRasterizer.ts +0 -340
  150. package/src/animation/AnimationVisual2D.ts +0 -153
  151. package/src/animation/HyaAnimation2DClipAdapter.ts +0 -845
  152. package/src/animation/Particle2DDescriptorAdapter.ts +0 -35
  153. package/src/animation/runtime/mixer/Action.ts +0 -876
  154. package/src/animation/runtime/mixer/Mixer.ts +0 -505
  155. package/src/animation/runtime/mixer/PoseBuffer.ts +0 -105
  156. package/src/animation/runtime/mixer/Sampler.ts +0 -252
  157. package/src/animation/runtime/mixer/Types.ts +0 -138
  158. package/src/animation/runtime/mixer/index.ts +0 -31
  159. package/src/animation-state-machine/AnimationStateMachine.ts +0 -146
  160. package/src/animation-state-machine/AnimationStateMachineChannels.ts +0 -116
  161. package/src/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.ts +0 -197
  162. package/src/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.ts +0 -503
  163. package/src/animation-state-machine/runtime/AnimationStateMachineCompiler.ts +0 -763
  164. package/src/animation-state-machine/runtime/AnimationStateMachineController.ts +0 -987
  165. package/src/animation-state-machine/runtime/AnimationStateMachineMixerPort.ts +0 -54
  166. package/src/animation-state-machine/runtime/index.ts +0 -47
  167. package/src/animation.ts +0 -33
  168. package/src/animation3d/Animation3DAction.ts +0 -73
  169. package/src/animation3d/Animation3DBinding.ts +0 -116
  170. package/src/animation3d/Animation3DClip.ts +0 -22
  171. package/src/animation3d/Animation3DError.ts +0 -34
  172. package/src/animation3d/Animation3DMixer.ts +0 -82
  173. package/src/animation3d/Animation3DPose.ts +0 -100
  174. package/src/animation3d/Animation3DPoseBuffer.ts +0 -85
  175. package/src/animation3d/Animation3DResource.ts +0 -49
  176. package/src/animation3d/Animation3DStateMachine.ts +0 -126
  177. package/src/animation3d/Animation3DStateMachineRuntime.ts +0 -191
  178. package/src/animation3d/Animation3DTrack.ts +0 -29
  179. package/src/animation3d/hya/HyaAnimation3DRuntime.ts +0 -756
  180. package/src/animation3d/hya/HyaAnimation3DStateMachineRuntime.ts +0 -618
  181. package/src/animation3d/hya/HyaAnimation3DTypes.ts +0 -168
  182. package/src/animation3d/hya/index.ts +0 -10
  183. package/src/animation3d/index.ts +0 -76
  184. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.ts +0 -325
  185. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.ts +0 -158
  186. package/src/animation3d/runtime/integration/index.ts +0 -9
  187. package/src/animation3d/runtime/mixer/Action.ts +0 -833
  188. package/src/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.ts +0 -26
  189. package/src/animation3d/runtime/mixer/Mixer.ts +0 -562
  190. package/src/animation3d/runtime/mixer/PoseBuffer.ts +0 -1
  191. package/src/animation3d/runtime/mixer/TrackSampler.ts +0 -399
  192. package/src/animation3d/runtime/mixer/index.ts +0 -8
  193. package/src/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.ts +0 -4
  194. package/src/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.ts +0 -1
  195. package/src/animation3d/runtime/state-machine/Animation3DStateMachineController.ts +0 -1
  196. package/src/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.ts +0 -1
  197. package/src/animation3d/runtime/state-machine/index.ts +0 -45
  198. package/src/animation3d.ts +0 -5
  199. package/src/benchmark.ts +0 -168
  200. package/src/canvas-text/CanvasText2DRenderSystem.ts +0 -292
  201. package/src/canvas-text/CanvasTextComponent.ts +0 -47
  202. package/src/canvas-text.ts +0 -4
  203. package/src/experimental-gltf-worker.ts +0 -18
  204. package/src/experimental-spine-worker.ts +0 -9
  205. package/src/gltf/GltfAccessorReader.ts +0 -271
  206. package/src/gltf/GltfAnimation3DAdapter.ts +0 -680
  207. package/src/gltf/GltfAnimationRuntime.ts +0 -392
  208. package/src/gltf/GltfAssetWorkerClient.ts +0 -136
  209. package/src/gltf/GltfCompatibilityReport.ts +0 -214
  210. package/src/gltf/GltfConservativeBounds.ts +0 -219
  211. package/src/gltf/GltfDracoDecoder.ts +0 -251
  212. package/src/gltf/GltfExtensionAdapter.ts +0 -340
  213. package/src/gltf/GltfLoaderContract.ts +0 -333
  214. package/src/gltf/GltfLoaderErrors.ts +0 -59
  215. package/src/gltf/GltfMaterialDescriptor.ts +0 -134
  216. package/src/gltf/GltfMaterialEncoder.ts +0 -173
  217. package/src/gltf/GltfMaterialLoader.ts +0 -293
  218. package/src/gltf/GltfModelComponent.ts +0 -115
  219. package/src/gltf/GltfModelSystem.ts +0 -208
  220. package/src/gltf/GltfPlugin.ts +0 -84
  221. package/src/gltf/GltfSchema.ts +0 -229
  222. package/src/gltf/GltfUvSemanticPlanner.ts +0 -166
  223. package/src/gltf/gltfLoader.ts +0 -910
  224. package/src/gltf-animation3d.ts +0 -10
  225. package/src/gltf-worker-runtime.ts +0 -10
  226. package/src/gltf.ts +0 -56
  227. package/src/grid/Grid2DComponent.ts +0 -69
  228. package/src/grid.ts +0 -2
  229. package/src/hya-state-machine.ts +0 -19
  230. package/src/index.ts +0 -2
  231. package/src/plugins/pluginUtils.ts +0 -50
  232. package/src/plugins.ts +0 -6
  233. package/src/shaders/generated/2d-ui-animation-2d.generated.wgsl +0 -242
  234. package/src/shaders/generated/2d-ui-artifact.generated.ts +0 -867
  235. package/src/shaders/generated/2d-ui-canvas-text-2d.generated.wgsl +0 -38
  236. package/src/shaders/generated/2d-ui-spine2d.generated.wgsl +0 -41
  237. package/src/shaders/generated/2d-ui-tilemap2d.generated.wgsl +0 -36
  238. package/src/spine/Spine2DComponent.ts +0 -168
  239. package/src/spine/Spine2DGpuRenderer.ts +0 -449
  240. package/src/spine/Spine2DRenderSystem.ts +0 -199
  241. package/src/spine/Spine2DRuntime.ts +0 -1529
  242. package/src/spine/SpineAnimationBoneTimelines.ts +0 -30
  243. package/src/spine/SpineAssetParser.ts +0 -20
  244. package/src/spine/SpineAssetWorkerClient.ts +0 -112
  245. package/src/spine/SpineAssetWorkerContract.ts +0 -4
  246. package/src/spine/SpineAtlasParser.ts +0 -127
  247. package/src/spine/SpineFloatBuilder.ts +0 -66
  248. package/src/spine/SpinePathConstraintSolver.ts +0 -582
  249. package/src/spine/SpinePlugin.ts +0 -76
  250. package/src/spine/SpineSkeletonRuntime.ts +0 -521
  251. package/src/spine/SpineSlotAnimation.ts +0 -195
  252. package/src/spine/SpineTimelineRuntime.ts +0 -453
  253. package/src/spine/SpineVertexBuilder.ts +0 -686
  254. package/src/spine.ts +0 -7
  255. package/src/tilemap/Tilemap2DComponent.ts +0 -232
  256. package/src/tilemap/Tilemap2DRenderSystem.ts +0 -58
  257. package/src/tilemap/Tilemap2DRenderer.ts +0 -289
  258. package/src/tilemap/TilemapPlugin.ts +0 -75
  259. package/src/tilemap.ts +0 -6
  260. package/src/tween/Tween2DComponent.ts +0 -83
  261. package/src/tween/Tween2DSystem.ts +0 -78
  262. package/src/tween.ts +0 -4
  263. package/src/types/earcut.d.ts +0 -7
  264. package/src/types/wgsl.d.ts +0 -4
  265. package/src/utils/RenderSystem2DBase.ts +0 -164
  266. package/src/utils/arrayAccess.ts +0 -17
  267. package/src/utils/camera2d.ts +0 -68
  268. package/src/utils/render2dGpu.ts +0 -132
  269. package/test/fixtures/gltf/animation-characterization.gltf +0 -344
@@ -1,876 +0,0 @@
1
- import type {
2
- Animation2DActionOptions,
3
- Animation2DActionStatus,
4
- Animation2DBinding,
5
- Animation2DBindingMask,
6
- Animation2DBlendMode,
7
- Animation2DClip,
8
- Animation2DEffectCue,
9
- Animation2DEffectEvent,
10
- Animation2DEffectLifecycle,
11
- Animation2DLoopMode,
12
- Animation2DMutablePose,
13
- Animation2DTrack,
14
- } from './Types.js';
15
- import { Animation2DSampler, isNumericBinding } from './Sampler.js';
16
-
17
- export interface Animation2DActionOwner {
18
- readonly time: number;
19
- assertActive(): void;
20
- }
21
-
22
- export interface Animation2DActionTrackRuntime {
23
- readonly track: Animation2DTrack;
24
- readonly sampler: Animation2DSampler;
25
- readonly reference: Float32Array;
26
- }
27
-
28
- interface RuntimeEffect {
29
- readonly cue: Animation2DEffectCue;
30
- readonly start: number;
31
- readonly end: number;
32
- readonly fullSpan: boolean;
33
- readonly loopBehavior: 'continue' | 'restart';
34
- readonly enterEvent: Animation2DEffectEvent;
35
- readonly exitEvent: Animation2DEffectEvent;
36
- readonly restartEvent: Animation2DEffectEvent;
37
- readonly loopEvent: Animation2DEffectEvent;
38
- readonly seekEvent: Animation2DEffectEvent;
39
- }
40
-
41
- interface EffectOutput {
42
- emit(effect: Animation2DEffectEvent): void;
43
- }
44
-
45
- /** @internal Reusable exact state used by controller-owned transactions. */
46
- export interface Animation2DActionSynchronizedState {
47
- status: Animation2DActionStatus;
48
- paused: boolean;
49
- time: number;
50
- rawTime: number;
51
- timeScale: number;
52
- weight: number;
53
- loop: Animation2DLoopMode;
54
- repetitions: number;
55
- clampWhenFinished: boolean;
56
- blendMode: Animation2DBlendMode;
57
- mask: Animation2DBindingMask | null;
58
- layer: number;
59
- effectsStarted: boolean;
60
- fadeActive: boolean;
61
- fadeStart: number;
62
- fadeEnd: number;
63
- fadeFrom: number;
64
- fadeTo: number;
65
- fadeValue: number;
66
- readonly effectActive: Uint8Array;
67
- readonly pendingEffects: Animation2DEffectEvent[];
68
- }
69
-
70
- /**
71
- * Mutable mixer-owned playback state. Effect lifecycle records and sampler
72
- * outputs are allocated at construction and reused on every frame.
73
- */
74
- export class Animation2DActionRuntime {
75
- readonly id: string;
76
- readonly clip: Animation2DClip;
77
- readonly order: number;
78
- readonly runtimeTracks: readonly Animation2DActionTrackRuntime[];
79
- readonly runtimeEffects: readonly RuntimeEffect[];
80
-
81
- private readonly _owner: Animation2DActionOwner;
82
- private readonly _effectActive: Uint8Array;
83
- private readonly _pendingEffects: Animation2DEffectEvent[] = [];
84
- private readonly _pendingEffectOutput: EffectOutput = {
85
- emit: effect => { this._pendingEffects.push(effect); },
86
- };
87
- private _valid = true;
88
- private _status: Animation2DActionStatus = 'idle';
89
- private _paused = false;
90
- private _time = 0;
91
- private _rawTime = 0;
92
- private _timeScale: number;
93
- private _weight: number;
94
- private _loop: Animation2DLoopMode;
95
- private _repetitions: number;
96
- private _clampWhenFinished: boolean;
97
- private _blendMode: Animation2DBlendMode;
98
- private _mask: Animation2DBindingMask | null;
99
- private _layer: number;
100
- private _effectsStarted = false;
101
-
102
- private _fadeActive = false;
103
- private _fadeStart = 0;
104
- private _fadeEnd = 0;
105
- private _fadeFrom = 1;
106
- private _fadeTo = 1;
107
- private _fadeValue = 1;
108
-
109
- constructor(
110
- owner: Animation2DActionOwner,
111
- clip: Animation2DClip,
112
- id: string,
113
- order: number,
114
- options: Animation2DActionOptions = {},
115
- ) {
116
- validateClip(clip);
117
- this._owner = owner;
118
- this.clip = clip;
119
- this.id = id;
120
- this.order = order;
121
- this._loop = options.loop ?? 'once';
122
- this._repetitions = validateRepetitions(
123
- options.repetitions ?? (this._loop === 'once' ? 1 : Infinity),
124
- );
125
- this._clampWhenFinished = options.clampWhenFinished ?? false;
126
- this._timeScale = finiteNumber(options.timeScale ?? 1, 'Animation2DAction.timeScale');
127
- this._weight = nonNegativeNumber(options.weight ?? 1, 'Animation2DAction.weight');
128
- this._fadeValue = this._weight;
129
- this._layer = integerNumber(options.layer ?? 0, 'Animation2DAction.layer');
130
- this._blendMode = options.blendMode ?? 'override';
131
- this._mask = options.mask ?? null;
132
-
133
- const tracks: Animation2DActionTrackRuntime[] = [];
134
- for (let index = 0; index < clip.tracks.length; index++) {
135
- const track = clip.tracks[index]!;
136
- const sampler = new Animation2DSampler(track);
137
- const reference = isNumericBinding(track.binding)
138
- ? new Float32Array(track.binding.valueSize!)
139
- : new Float32Array(0);
140
- if (reference.length > 0) sampler.sample(0, reference);
141
- tracks.push({ track, sampler, reference });
142
- }
143
- this.runtimeTracks = tracks;
144
-
145
- const effects: RuntimeEffect[] = [];
146
- const sourceEffects = clip.effects ?? [];
147
- for (let index = 0; index < sourceEffects.length; index++) {
148
- const cue = sourceEffects[index]!;
149
- const start = cue.start;
150
- const end = cue.end ?? clip.duration;
151
- validateEffect(cue, start, end, clip.duration);
152
- effects.push({
153
- cue,
154
- start,
155
- end,
156
- fullSpan: start === 0 && end === clip.duration,
157
- loopBehavior: cue.loopBehavior ?? (cue.kind === 'particle' ? 'restart' : 'continue'),
158
- enterEvent: effectEvent(id, clip.id, cue, 'enter'),
159
- exitEvent: effectEvent(id, clip.id, cue, 'exit'),
160
- restartEvent: effectEvent(id, clip.id, cue, 'restart'),
161
- loopEvent: effectEvent(id, clip.id, cue, 'loop'),
162
- seekEvent: effectEvent(id, clip.id, cue, 'seek'),
163
- });
164
- }
165
- this.runtimeEffects = effects;
166
- this._effectActive = new Uint8Array(effects.length);
167
- }
168
-
169
- get duration(): number { return this.clip.duration; }
170
- get status(): Animation2DActionStatus { return this._status; }
171
- get paused(): boolean { return this._paused; }
172
- set paused(value: boolean) {
173
- this._assertValid();
174
- this._paused = Boolean(value);
175
- if (this._paused && this._status === 'running') this._status = 'paused';
176
- else if (!this._paused && this._status === 'paused') this._status = 'running';
177
- }
178
- get time(): number { return this._time; }
179
- set time(value: number) { this.seek(value); }
180
- get timeScale(): number { return this._timeScale; }
181
- set timeScale(value: number) {
182
- this._assertValid();
183
- this._timeScale = finiteNumber(value, 'Animation2DAction.timeScale');
184
- }
185
- get weight(): number { return this._weight; }
186
- set weight(value: number) {
187
- this._assertValid();
188
- this._weight = nonNegativeNumber(value, 'Animation2DAction.weight');
189
- this._fadeActive = false;
190
- this._fadeValue = this._weight;
191
- }
192
- get layer(): number { return this._layer; }
193
- set layer(value: number) {
194
- this._assertValid();
195
- this._layer = integerNumber(value, 'Animation2DAction.layer');
196
- }
197
- get loop(): Animation2DLoopMode { return this._loop; }
198
- set loop(value: Animation2DLoopMode) {
199
- this._assertValid();
200
- if (value !== 'once' && value !== 'repeat' && value !== 'ping-pong') {
201
- throw new RangeError(`Unsupported Animation2D loop mode "${String(value)}".`);
202
- }
203
- this._loop = value;
204
- this._setSampleTime(0);
205
- }
206
- get repetitions(): number { return this._repetitions; }
207
- set repetitions(value: number) {
208
- this._assertValid();
209
- this._repetitions = validateRepetitions(value);
210
- }
211
- get clampWhenFinished(): boolean { return this._clampWhenFinished; }
212
- set clampWhenFinished(value: boolean) {
213
- this._assertValid();
214
- this._clampWhenFinished = Boolean(value);
215
- }
216
- get blendMode(): Animation2DBlendMode { return this._blendMode; }
217
- set blendMode(value: Animation2DBlendMode) {
218
- this._assertValid();
219
- if (value !== 'override' && value !== 'additive') {
220
- throw new RangeError(`Unsupported Animation2D blend mode "${String(value)}".`);
221
- }
222
- this._blendMode = value;
223
- }
224
- get mask(): Animation2DBindingMask | null { return this._mask; }
225
- set mask(value: Animation2DBindingMask | null) {
226
- this._assertValid();
227
- this._mask = value;
228
- }
229
- get effectiveWeight(): number {
230
- if (!this._valid || this._paused || (this._status !== 'running'
231
- && !(this._status === 'finished' && this._clampWhenFinished))) return 0;
232
- return this._fadeFactor(this._owner.time);
233
- }
234
-
235
- play(): this {
236
- this._assertValid();
237
- if (this._status === 'finished' && !this._clampWhenFinished) {
238
- this._rawTime = this._timeScale < 0 ? this.clip.duration : 0;
239
- this._setSampleTime(0);
240
- this._effectsStarted = false;
241
- }
242
- this._paused = false;
243
- this._status = 'running';
244
- return this;
245
- }
246
-
247
- pause(): this {
248
- this.paused = true;
249
- return this;
250
- }
251
-
252
- stop(): this {
253
- this._assertValid();
254
- this._queueActiveExits();
255
- this._paused = false;
256
- this._status = 'stopped';
257
- this._effectsStarted = false;
258
- return this;
259
- }
260
-
261
- reset(): this {
262
- this._assertValid();
263
- this._queueActiveExits();
264
- this._paused = false;
265
- this._status = 'idle';
266
- this._rawTime = 0;
267
- this._time = 0;
268
- this._effectsStarted = false;
269
- this._fadeActive = false;
270
- this._fadeValue = this._weight;
271
- this._resetSamplerCursors();
272
- return this;
273
- }
274
-
275
- seek(timeSeconds: number): this {
276
- this._assertValid();
277
- const next = Math.min(
278
- this.clip.duration,
279
- Math.max(0, finiteNumber(timeSeconds, 'Animation2DAction.time')),
280
- );
281
- for (let index = 0; index < this.runtimeEffects.length; index++) {
282
- const wasActive = this._effectActive[index] !== 0;
283
- const active = effectActiveAt(this.runtimeEffects[index]!, next, this.clip.duration);
284
- const effect = this.runtimeEffects[index]!;
285
- if (wasActive && !active) this._pendingEffects.push(effect.exitEvent);
286
- this._pendingEffects.push(effect.seekEvent);
287
- if (!wasActive && active) this._pendingEffects.push(effect.enterEvent);
288
- this._effectActive[index] = active ? 1 : 0;
289
- }
290
- this._rawTime = next;
291
- this._time = next;
292
- this._effectsStarted = true;
293
- this._resetSamplerCursors();
294
- return this;
295
- }
296
-
297
- /**
298
- * Advances a controller-owned absolute playhead without classifying the
299
- * move as a seek. Crossed side-effect boundaries are queued exactly once.
300
- */
301
- synchronizeTime(timeSeconds: number): this {
302
- this._assertValid();
303
- const after = this._clampSynchronizedTime(timeSeconds);
304
- const terminalDirection = this._terminalDirection(after);
305
- if (!this._effectsStarted) {
306
- this._emitInitialEffects(this._pendingEffectOutput);
307
- this._effectsStarted = true;
308
- }
309
- this._emitEffectCrossings(
310
- this._rawTime,
311
- after,
312
- this._pendingEffectOutput,
313
- terminalDirection,
314
- );
315
- this._rawTime = after;
316
- this._setSampleTime(terminalDirection);
317
- this._syncEffectActivity(terminalDirection);
318
- this._resetSamplerCursors();
319
- return this;
320
- }
321
-
322
- reverse(): this {
323
- this._assertValid();
324
- this._timeScale = -Math.max(Number.EPSILON, Math.abs(this._timeScale));
325
- return this;
326
- }
327
-
328
- fadeTo(targetWeight: number, durationSeconds: number): this {
329
- this._assertValid();
330
- const target = nonNegativeNumber(targetWeight, 'Animation2DAction.fade target');
331
- const duration = nonNegativeNumber(durationSeconds, 'Animation2DAction.fade duration');
332
- this._scheduleFade(this._fadeFactor(this._owner.time), target, duration);
333
- return this;
334
- }
335
-
336
- fadeIn(durationSeconds: number): this {
337
- this._assertValid();
338
- const duration = nonNegativeNumber(durationSeconds, 'Animation2DAction.fade duration');
339
- this._scheduleFade(0, this._weight > 0 ? this._weight : 1, duration);
340
- return this;
341
- }
342
-
343
- fadeOut(durationSeconds: number): this {
344
- return this.fadeTo(0, durationSeconds);
345
- }
346
-
347
- crossFadeFrom(source: Animation2DActionRuntime, durationSeconds: number): this {
348
- this._assertSibling(source);
349
- source.play().fadeOut(durationSeconds);
350
- this.play().fadeIn(durationSeconds);
351
- return this;
352
- }
353
-
354
- crossFadeTo(destination: Animation2DActionRuntime, durationSeconds: number): this {
355
- this._assertSibling(destination);
356
- destination.crossFadeFrom(this, durationSeconds);
357
- return this;
358
- }
359
-
360
- acceptsBinding(binding: Animation2DBinding): boolean {
361
- const include = this._mask?.include;
362
- if (include && include.length > 0) {
363
- let accepted = false;
364
- for (let index = 0; index < include.length; index++) {
365
- if (include[index] === binding.id) {
366
- accepted = true;
367
- break;
368
- }
369
- }
370
- if (!accepted) return false;
371
- }
372
- const exclude = this._mask?.exclude;
373
- if (exclude) {
374
- for (let index = 0; index < exclude.length; index++) {
375
- if (exclude[index] === binding.id) return false;
376
- }
377
- }
378
- return true;
379
- }
380
-
381
- flushPendingEffects(out: Animation2DMutablePose): void {
382
- for (let index = 0; index < this._pendingEffects.length; index++) {
383
- out.emit(this._pendingEffects[index]!);
384
- }
385
- this._pendingEffects.length = 0;
386
- }
387
-
388
- advance(mixerDelta: number, out: Animation2DMutablePose): void {
389
- if (!this._valid) return;
390
- this._finishFade(this._owner.time);
391
- this.flushPendingEffects(out);
392
- if (this._paused || this._status !== 'running') return;
393
- if (!this._effectsStarted) {
394
- this._emitInitialEffects(out);
395
- this._effectsStarted = true;
396
- }
397
- const actionDelta = mixerDelta * this._timeScale;
398
- if (actionDelta === 0 || this.clip.duration === 0) return;
399
-
400
- const before = this._rawTime;
401
- let after = before + actionDelta;
402
- let terminalDirection = 0;
403
- const totalDuration = this._loop === 'once'
404
- ? this.clip.duration
405
- : this._repetitions === Infinity
406
- ? Infinity
407
- : this.clip.duration * this._repetitions;
408
- if (totalDuration !== Infinity) {
409
- if (actionDelta > 0 && after >= totalDuration) {
410
- after = totalDuration;
411
- terminalDirection = 1;
412
- } else if (actionDelta < 0 && after <= 0) {
413
- after = 0;
414
- terminalDirection = -1;
415
- }
416
- }
417
-
418
- this._emitEffectCrossings(before, after, out, terminalDirection);
419
- this._rawTime = after;
420
- this._setSampleTime(terminalDirection);
421
- this._syncEffectActivity(terminalDirection);
422
- if (terminalDirection !== 0) {
423
- this._status = 'finished';
424
- if (!this._clampWhenFinished) this._queueActiveExits();
425
- }
426
- }
427
-
428
- /** @internal Allocates one checkpoint that can be reused for every update. */
429
- createSynchronizedState(): Animation2DActionSynchronizedState {
430
- return {
431
- status: this._status,
432
- paused: this._paused,
433
- time: this._time,
434
- rawTime: this._rawTime,
435
- timeScale: this._timeScale,
436
- weight: this._weight,
437
- loop: this._loop,
438
- repetitions: this._repetitions,
439
- clampWhenFinished: this._clampWhenFinished,
440
- blendMode: this._blendMode,
441
- mask: this._mask,
442
- layer: this._layer,
443
- effectsStarted: this._effectsStarted,
444
- fadeActive: this._fadeActive,
445
- fadeStart: this._fadeStart,
446
- fadeEnd: this._fadeEnd,
447
- fadeFrom: this._fadeFrom,
448
- fadeTo: this._fadeTo,
449
- fadeValue: this._fadeValue,
450
- effectActive: new Uint8Array(this._effectActive.length),
451
- pendingEffects: [],
452
- };
453
- }
454
-
455
- /** @internal Captures playhead, fade, and effect-cursor state without sampling. */
456
- captureSynchronizedState(state: Animation2DActionSynchronizedState): void {
457
- this._assertValid();
458
- if (state.effectActive.length !== this._effectActive.length) {
459
- throw new RangeError('Animation2D action checkpoint has an incompatible effect count.');
460
- }
461
- state.status = this._status;
462
- state.paused = this._paused;
463
- state.time = this._time;
464
- state.rawTime = this._rawTime;
465
- state.timeScale = this._timeScale;
466
- state.weight = this._weight;
467
- state.loop = this._loop;
468
- state.repetitions = this._repetitions;
469
- state.clampWhenFinished = this._clampWhenFinished;
470
- state.blendMode = this._blendMode;
471
- state.mask = this._mask;
472
- state.layer = this._layer;
473
- state.effectsStarted = this._effectsStarted;
474
- state.fadeActive = this._fadeActive;
475
- state.fadeStart = this._fadeStart;
476
- state.fadeEnd = this._fadeEnd;
477
- state.fadeFrom = this._fadeFrom;
478
- state.fadeTo = this._fadeTo;
479
- state.fadeValue = this._fadeValue;
480
- state.effectActive.set(this._effectActive);
481
- state.pendingEffects.length = 0;
482
- for (const effect of this._pendingEffects) state.pendingEffects.push(effect);
483
- }
484
-
485
- /** @internal Restores an exact controller transaction checkpoint. */
486
- restoreSynchronizedState(state: Animation2DActionSynchronizedState): void {
487
- this._assertValid();
488
- if (state.effectActive.length !== this._effectActive.length) {
489
- throw new RangeError('Animation2D action checkpoint has an incompatible effect count.');
490
- }
491
- this._status = state.status;
492
- this._paused = state.paused;
493
- this._time = state.time;
494
- this._rawTime = state.rawTime;
495
- this._timeScale = state.timeScale;
496
- this._weight = state.weight;
497
- this._loop = state.loop;
498
- this._repetitions = state.repetitions;
499
- this._clampWhenFinished = state.clampWhenFinished;
500
- this._blendMode = state.blendMode;
501
- this._mask = state.mask;
502
- this._layer = state.layer;
503
- this._effectsStarted = state.effectsStarted;
504
- this._fadeActive = state.fadeActive;
505
- this._fadeStart = state.fadeStart;
506
- this._fadeEnd = state.fadeEnd;
507
- this._fadeFrom = state.fadeFrom;
508
- this._fadeTo = state.fadeTo;
509
- this._fadeValue = state.fadeValue;
510
- this._effectActive.set(state.effectActive);
511
- this._pendingEffects.length = 0;
512
- for (const effect of state.pendingEffects) this._pendingEffects.push(effect);
513
- this._resetSamplerCursors();
514
- }
515
-
516
- invalidate(): void {
517
- if (!this._valid) return;
518
- this._valid = false;
519
- this._status = 'stopped';
520
- this._paused = false;
521
- this._fadeActive = false;
522
- this._pendingEffects.length = 0;
523
- this._effectActive.fill(0);
524
- }
525
-
526
- private _setSampleTime(terminalDirection: number): void {
527
- const duration = this.clip.duration;
528
- if (duration === 0) {
529
- this._time = 0;
530
- return;
531
- }
532
- if (this._loop === 'once') {
533
- this._time = Math.min(duration, Math.max(0, this._rawTime));
534
- return;
535
- }
536
- if (terminalDirection > 0 && this._loop === 'repeat') {
537
- this._time = duration;
538
- return;
539
- }
540
- const traversal = Math.floor(this._rawTime / duration);
541
- let phase = this._rawTime - traversal * duration;
542
- if (phase < 0) phase += duration;
543
- if (this._loop === 'repeat') {
544
- this._time = phase;
545
- } else {
546
- this._time = isEven(traversal) ? phase : duration - phase;
547
- }
548
- }
549
-
550
- private _emitInitialEffects(out: EffectOutput): void {
551
- for (let index = 0; index < this.runtimeEffects.length; index++) {
552
- const active = effectActiveAt(this.runtimeEffects[index]!, this._time, this.clip.duration);
553
- this._effectActive[index] = active ? 1 : 0;
554
- if (active) out.emit(this.runtimeEffects[index]!.enterEvent);
555
- }
556
- }
557
-
558
- private _emitEffectCrossings(
559
- before: number,
560
- after: number,
561
- out: EffectOutput,
562
- terminalDirection = 0,
563
- ): void {
564
- if (before === after || this.runtimeEffects.length === 0) return;
565
- if (this._loop === 'repeat') {
566
- this._emitRepeatEffectCrossings(before, after, out, terminalDirection);
567
- return;
568
- }
569
- if (this._loop === 'once') {
570
- this._emitOnceEffectCrossings(before, after, out);
571
- return;
572
- }
573
- this._emitPingPongEffectCrossings(before, after, out, terminalDirection);
574
- }
575
-
576
- private _emitOnceEffectCrossings(
577
- before: number,
578
- after: number,
579
- out: EffectOutput,
580
- ): void {
581
- for (let index = 0; index < this.runtimeEffects.length; index++) {
582
- const effect = this.runtimeEffects[index]!;
583
- if (after > before) {
584
- if (effect.start > before && effect.start <= after) out.emit(effect.enterEvent);
585
- if (effect.end > before && effect.end <= after) out.emit(effect.exitEvent);
586
- } else {
587
- if (effect.end < before && effect.end >= after) out.emit(effect.enterEvent);
588
- if (effect.start < before && effect.start >= after) out.emit(effect.exitEvent);
589
- }
590
- }
591
- }
592
-
593
- private _emitRepeatEffectCrossings(
594
- before: number,
595
- after: number,
596
- out: EffectOutput,
597
- terminalDirection: number,
598
- ): void {
599
- const duration = this.clip.duration;
600
- const minimum = Math.min(before, after);
601
- const maximum = Math.max(before, after);
602
- const firstCycle = Math.floor(minimum / duration) - 1;
603
- const lastCycle = Math.floor(maximum / duration) + 1;
604
- for (let effectIndex = 0; effectIndex < this.runtimeEffects.length; effectIndex++) {
605
- const effect = this.runtimeEffects[effectIndex]!;
606
- if (effect.fullSpan) {
607
- if (after > before) {
608
- for (let cycle = firstCycle; cycle <= lastCycle; cycle++) {
609
- const boundary = cycle * duration;
610
- if (boundary > before && boundary <= after) {
611
- if (terminalDirection > 0 && boundary === after) out.emit(effect.exitEvent);
612
- else this._emitLoopEffect(effect, out);
613
- }
614
- }
615
- } else {
616
- for (let cycle = lastCycle; cycle >= firstCycle; cycle--) {
617
- const boundary = cycle * duration;
618
- if (boundary < before && boundary >= after) {
619
- if (terminalDirection < 0 && boundary === after) out.emit(effect.exitEvent);
620
- else this._emitLoopEffect(effect, out);
621
- }
622
- }
623
- }
624
- continue;
625
- }
626
- if (after > before) {
627
- for (let cycle = firstCycle; cycle <= lastCycle; cycle++) {
628
- const cycleStart = cycle * duration;
629
- const enter = cycleStart + effect.start;
630
- const exit = cycleStart + effect.end;
631
- if (enter > before && enter <= after
632
- && !(terminalDirection > 0 && enter === after)) out.emit(effect.enterEvent);
633
- if (exit > before && exit <= after) out.emit(effect.exitEvent);
634
- }
635
- } else {
636
- for (let cycle = lastCycle; cycle >= firstCycle; cycle--) {
637
- const cycleStart = cycle * duration;
638
- const enter = cycleStart + effect.end;
639
- const exit = cycleStart + effect.start;
640
- if (enter < before && enter >= after
641
- && !(terminalDirection < 0 && enter === after)) out.emit(effect.enterEvent);
642
- if (exit < before && exit >= after) out.emit(effect.exitEvent);
643
- }
644
- }
645
- }
646
- }
647
-
648
- private _emitPingPongEffectCrossings(
649
- before: number,
650
- after: number,
651
- out: EffectOutput,
652
- terminalDirection: number,
653
- ): void {
654
- const duration = this.clip.duration;
655
- const minimum = Math.min(before, after);
656
- const maximum = Math.max(before, after);
657
- const firstTraversal = Math.floor(minimum / duration) - 1;
658
- const lastTraversal = Math.floor(maximum / duration) + 1;
659
- for (let effectIndex = 0; effectIndex < this.runtimeEffects.length; effectIndex++) {
660
- const effect = this.runtimeEffects[effectIndex]!;
661
- if (effect.fullSpan) {
662
- if (after > before) {
663
- for (let traversal = firstTraversal; traversal <= lastTraversal; traversal++) {
664
- const boundary = traversal * duration;
665
- if (boundary <= before || boundary > after) continue;
666
- if (terminalDirection > 0 && boundary === after) out.emit(effect.exitEvent);
667
- else this._emitLoopEffect(effect, out);
668
- }
669
- } else {
670
- for (let traversal = lastTraversal; traversal >= firstTraversal; traversal--) {
671
- const boundary = traversal * duration;
672
- if (boundary >= before || boundary < after) continue;
673
- if (terminalDirection < 0 && boundary === after) out.emit(effect.exitEvent);
674
- else this._emitLoopEffect(effect, out);
675
- }
676
- }
677
- continue;
678
- }
679
-
680
- if (after > before) {
681
- for (let traversal = firstTraversal; traversal <= lastTraversal; traversal++) {
682
- const traversalStart = traversal * duration;
683
- const forward = isEven(traversal);
684
- const enter = traversalStart + (forward ? effect.start : duration - effect.end);
685
- const exit = traversalStart + (forward ? effect.end : duration - effect.start);
686
- if (enter > before && enter <= after
687
- && !(terminalDirection > 0 && enter === after)) out.emit(effect.enterEvent);
688
- if (exit > before && exit <= after) out.emit(effect.exitEvent);
689
- }
690
- } else {
691
- for (let traversal = lastTraversal; traversal >= firstTraversal; traversal--) {
692
- const traversalStart = traversal * duration;
693
- const forward = isEven(traversal);
694
- const forwardEnter = traversalStart
695
- + (forward ? effect.start : duration - effect.end);
696
- const forwardExit = traversalStart
697
- + (forward ? effect.end : duration - effect.start);
698
- if (forwardExit < before && forwardExit >= after
699
- && !(terminalDirection < 0 && forwardExit === after)) out.emit(effect.enterEvent);
700
- if (forwardEnter < before && forwardEnter >= after) out.emit(effect.exitEvent);
701
- }
702
- }
703
- }
704
- }
705
-
706
- private _emitLoopEffect(effect: RuntimeEffect, out: EffectOutput): void {
707
- out.emit(effect.loopBehavior === 'restart' ? effect.restartEvent : effect.loopEvent);
708
- }
709
-
710
- private _syncEffectActivity(terminalDirection = 0): void {
711
- for (let index = 0; index < this.runtimeEffects.length; index++) {
712
- const effect = this.runtimeEffects[index]!;
713
- const active = effect.fullSpan && this._loop === 'ping-pong'
714
- ? terminalDirection === 0
715
- : effectActiveAt(effect, this._time, this.clip.duration);
716
- this._effectActive[index] = active ? 1 : 0;
717
- }
718
- }
719
-
720
- private _queueActiveExits(): void {
721
- for (let index = 0; index < this._effectActive.length; index++) {
722
- if (this._effectActive[index] === 0) continue;
723
- this._pendingEffects.push(this.runtimeEffects[index]!.exitEvent);
724
- this._effectActive[index] = 0;
725
- }
726
- }
727
-
728
- private _scheduleFade(from: number, to: number, duration: number): void {
729
- this._fadeFrom = from;
730
- this._fadeTo = to;
731
- this._fadeStart = this._owner.time;
732
- this._fadeEnd = this._fadeStart + duration;
733
- if (duration === 0) {
734
- this._weight = to;
735
- this._fadeValue = to;
736
- this._fadeActive = false;
737
- } else {
738
- this._fadeValue = from;
739
- this._fadeActive = true;
740
- }
741
- }
742
-
743
- private _fadeFactor(time: number): number {
744
- if (!this._fadeActive) return this._fadeValue;
745
- if (time <= this._fadeStart) return this._fadeFrom;
746
- if (time >= this._fadeEnd) return this._fadeTo;
747
- const alpha = (time - this._fadeStart) / (this._fadeEnd - this._fadeStart);
748
- return this._fadeFrom + (this._fadeTo - this._fadeFrom) * alpha;
749
- }
750
-
751
- private _finishFade(time: number): void {
752
- if (!this._fadeActive || time < this._fadeEnd) return;
753
- this._weight = this._fadeTo;
754
- this._fadeValue = this._fadeTo;
755
- this._fadeActive = false;
756
- }
757
-
758
- private _assertSibling(action: Animation2DActionRuntime): void {
759
- this._assertValid();
760
- if (action._owner !== this._owner || !action._valid) {
761
- throw new RangeError('Animation2D cross-fade actions must belong to the same active mixer.');
762
- }
763
- }
764
-
765
- private _clampSynchronizedTime(timeSeconds: number): number {
766
- const next = finiteNumber(timeSeconds, 'Animation2DAction synchronized time');
767
- if (this._loop === 'once') return Math.min(this.clip.duration, Math.max(0, next));
768
- if (this._repetitions === Infinity) return next;
769
- return Math.min(this.clip.duration * this._repetitions, Math.max(0, next));
770
- }
771
-
772
- private _terminalDirection(time: number): number {
773
- if (this._loop === 'once') {
774
- if (time === this.clip.duration && this._rawTime < time) return 1;
775
- if (time === 0 && this._rawTime > time) return -1;
776
- return 0;
777
- }
778
- if (this._repetitions === Infinity) return 0;
779
- const totalDuration = this.clip.duration * this._repetitions;
780
- if (time === totalDuration && this._rawTime < time) return 1;
781
- if (time === 0 && this._rawTime > time) return -1;
782
- return 0;
783
- }
784
-
785
- private _resetSamplerCursors(): void {
786
- for (let index = 0; index < this.runtimeTracks.length; index++) {
787
- this.runtimeTracks[index]!.sampler.resetCursor();
788
- }
789
- }
790
-
791
- private _assertValid(): void {
792
- this._owner.assertActive();
793
- if (!this._valid) throw new Error(`Animation2D action "${this.id}" is no longer valid.`);
794
- }
795
- }
796
-
797
- function effectEvent(
798
- actionId: string,
799
- clipId: string,
800
- cue: Animation2DEffectCue,
801
- lifecycle: Animation2DEffectLifecycle,
802
- ): Animation2DEffectEvent {
803
- return { actionId, clipId, cue, lifecycle };
804
- }
805
-
806
- function effectActiveAt(effect: RuntimeEffect, time: number, duration: number): boolean {
807
- if (effect.fullSpan) return time >= 0 && time < duration;
808
- return time >= effect.start && time < effect.end;
809
- }
810
-
811
- function samplePingPongTime(rawTime: number, duration: number): number {
812
- if (duration <= 0) return 0;
813
- const traversal = Math.floor(rawTime / duration);
814
- let phase = rawTime - traversal * duration;
815
- if (phase < 0) phase += duration;
816
- return isEven(traversal) ? phase : duration - phase;
817
- }
818
-
819
- function validateClip(clip: Animation2DClip): void {
820
- if (clip.format !== 'haiyue-animation2d-clip@1') {
821
- throw new RangeError(`Unsupported Animation2D clip format "${String(clip.format)}".`);
822
- }
823
- if (!clip.id) throw new RangeError('Animation2D clip id must not be empty.');
824
- if (!Number.isFinite(clip.duration) || clip.duration < 0) {
825
- throw new RangeError(`Animation2D clip duration must be finite and non-negative; received ${clip.duration}.`);
826
- }
827
- for (let index = 0; index < clip.tracks.length; index++) {
828
- const track = clip.tracks[index]!;
829
- const first = track.times[0];
830
- const last = track.times[track.times.length - 1];
831
- if (first !== undefined && (first < 0 || last! > clip.duration)) {
832
- throw new RangeError(`Animation2D track "${track.id}" keys must lie within its clip.`);
833
- }
834
- }
835
- }
836
-
837
- function validateEffect(
838
- cue: Animation2DEffectCue,
839
- start: number,
840
- end: number,
841
- duration: number,
842
- ): void {
843
- if (!cue.id) throw new RangeError('Animation2D effect cue id must not be empty.');
844
- if (!Number.isFinite(start) || !Number.isFinite(end)
845
- || start < 0 || end < start || end > duration) {
846
- throw new RangeError(`Animation2D effect "${cue.id}" interval must lie within its clip.`);
847
- }
848
- }
849
-
850
- function validateRepetitions(value: number): number {
851
- if (value === Infinity) return value;
852
- if (!Number.isInteger(value) || value <= 0) {
853
- throw new RangeError(`Animation2D repetitions must be a positive integer or Infinity; received ${value}.`);
854
- }
855
- return value;
856
- }
857
-
858
- function finiteNumber(value: number, property: string): number {
859
- if (!Number.isFinite(value)) throw new RangeError(`${property} must be finite; received ${value}.`);
860
- return value;
861
- }
862
-
863
- function nonNegativeNumber(value: number, property: string): number {
864
- const result = finiteNumber(value, property);
865
- if (result < 0) throw new RangeError(`${property} must be non-negative; received ${value}.`);
866
- return result;
867
- }
868
-
869
- function integerNumber(value: number, property: string): number {
870
- if (!Number.isInteger(value)) throw new RangeError(`${property} must be an integer; received ${value}.`);
871
- return value;
872
- }
873
-
874
- function isEven(value: number): boolean {
875
- return Math.abs(value % 2) === 0;
876
- }