@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,987 +0,0 @@
1
- import {
2
- evaluateAnimation3DBlend1DWeights,
3
- evaluateAnimation3DBlend2DWeights,
4
- } from './AnimationStateMachineBlendTreeWeights.js';
5
- import type {
6
- CompiledAnimation3DCondition,
7
- CompiledAnimation3DLayer,
8
- CompiledAnimation3DMotion,
9
- CompiledAnimation3DParameter,
10
- CompiledAnimation3DState,
11
- CompiledAnimation3DStateMachine,
12
- CompiledAnimation3DTransition,
13
- } from './AnimationStateMachineCompiler.js';
14
- import type {
15
- Animation3DStateMachineActionHandle,
16
- Animation3DStateMachineMixerPort,
17
- } from './AnimationStateMachineMixerPort.js';
18
-
19
- const TIME_EPSILON = 1e-9;
20
- const DEFAULT_MAX_TRANSITIONS_PER_UPDATE = 128;
21
- const CONTROLLER_UPDATE_TRANSACTION = Symbol('AnimationStateMachineController.updateTransaction');
22
-
23
- export type Animation3DStateMachineControllerStatus =
24
- | 'active'
25
- | 'destroyed';
26
-
27
- export interface Animation3DStateMachineControllerOptions {
28
- /**
29
- * Bounds zero-duration transition cycles and pathological large-delta
30
- * updates per layer. Remaining time is still advanced after the limit is
31
- * reached.
32
- */
33
- readonly maxTransitionsPerUpdate?: number;
34
- }
35
-
36
- export interface Animation3DStateMachineLayerSnapshot {
37
- readonly layerId: string;
38
- readonly currentStateId: string;
39
- readonly currentTime: number;
40
- readonly transitionId: string | null;
41
- readonly sourceStateId: string | null;
42
- readonly destinationStateId: string | null;
43
- readonly transitionProgress: number;
44
- }
45
-
46
- interface RuntimeClip<
47
- TAction extends Animation3DStateMachineActionHandle,
48
- > {
49
- readonly kind: 'clip';
50
- readonly action: TAction;
51
- }
52
-
53
- interface RuntimeBlend1D<
54
- TAction extends Animation3DStateMachineActionHandle,
55
- > {
56
- readonly kind: 'blend-1d';
57
- readonly motion: Extract<CompiledAnimation3DMotion, { readonly kind: 'blend-1d' }>;
58
- readonly children: readonly RuntimeMotion<TAction>[];
59
- readonly weights: Float64Array;
60
- }
61
-
62
- interface RuntimeBlend2D<
63
- TAction extends Animation3DStateMachineActionHandle,
64
- > {
65
- readonly kind: 'blend-2d';
66
- readonly motion: Extract<CompiledAnimation3DMotion, { readonly kind: 'blend-2d' }>;
67
- readonly children: readonly RuntimeMotion<TAction>[];
68
- readonly weights: Float64Array;
69
- }
70
-
71
- type RuntimeMotion<
72
- TAction extends Animation3DStateMachineActionHandle,
73
- > =
74
- | RuntimeClip<TAction>
75
- | RuntimeBlend1D<TAction>
76
- | RuntimeBlend2D<TAction>;
77
-
78
- interface StatePlayback<
79
- TAction extends Animation3DStateMachineActionHandle,
80
- > {
81
- readonly state: CompiledAnimation3DState;
82
- readonly motion: RuntimeMotion<TAction>;
83
- time: number;
84
- }
85
-
86
- interface ActiveTransition<
87
- TAction extends Animation3DStateMachineActionHandle,
88
- > {
89
- readonly definition: CompiledAnimation3DTransition;
90
- readonly source: StatePlayback<TAction>;
91
- readonly destination: StatePlayback<TAction>;
92
- elapsed: number;
93
- }
94
-
95
- interface LayerRuntime<
96
- TAction extends Animation3DStateMachineActionHandle,
97
- > {
98
- readonly definition: CompiledAnimation3DLayer;
99
- current: StatePlayback<TAction>;
100
- transition: ActiveTransition<TAction> | null;
101
- }
102
-
103
- interface LayerTransactionCheckpoint<
104
- TAction extends Animation3DStateMachineActionHandle,
105
- > {
106
- current: StatePlayback<TAction>;
107
- transition: ActiveTransition<TAction> | null;
108
- currentTime: number;
109
- sourceTime: number;
110
- destinationTime: number;
111
- transitionElapsed: number;
112
- }
113
-
114
- interface TransactionalAnimationStateMachineMixerPort {
115
- beginControllerTransaction(): void;
116
- commitControllerTransaction(): void;
117
- rollbackControllerTransaction(): void;
118
- }
119
-
120
- interface InterruptionCandidate<
121
- TAction extends Animation3DStateMachineActionHandle,
122
- > {
123
- readonly transition: CompiledAnimation3DTransition;
124
- readonly anchor: StatePlayback<TAction>;
125
- }
126
-
127
- /**
128
- * Deterministic, mixer-agnostic runtime controller for a compiled definition.
129
- * All string resolution happens in the compiler or at setter/query boundaries.
130
- */
131
- export class Animation3DStateMachineController<
132
- TAction extends Animation3DStateMachineActionHandle =
133
- Animation3DStateMachineActionHandle,
134
- > {
135
- readonly compiled: CompiledAnimation3DStateMachine;
136
- readonly port: Animation3DStateMachineMixerPort<TAction>;
137
- readonly maxTransitionsPerUpdate: number;
138
-
139
- lastUpdateTransitionCount = 0;
140
- transitionLimitReached = false;
141
-
142
- private readonly _parameterValues: Float64Array;
143
- private readonly _transactionParameterValues: Float64Array;
144
- private readonly _layers: LayerRuntime<TAction>[] = [];
145
- private readonly _layerTransactionCheckpoints: LayerTransactionCheckpoint<TAction>[] = [];
146
- private _transactionLastUpdateTransitionCount = 0;
147
- private _transactionLimitReached = false;
148
- private _transactionActive = false;
149
- private _status: Animation3DStateMachineControllerStatus = 'active';
150
-
151
- constructor(
152
- compiled: CompiledAnimation3DStateMachine,
153
- port: Animation3DStateMachineMixerPort<TAction>,
154
- options: Animation3DStateMachineControllerOptions = {},
155
- ) {
156
- const maxTransitions =
157
- options.maxTransitionsPerUpdate ?? DEFAULT_MAX_TRANSITIONS_PER_UPDATE;
158
- if (!Number.isSafeInteger(maxTransitions) || maxTransitions <= 0) {
159
- throw new RangeError('maxTransitionsPerUpdate must be a positive safe integer.');
160
- }
161
- this.compiled = compiled;
162
- this.port = port;
163
- this.maxTransitionsPerUpdate = maxTransitions;
164
- this._parameterValues = new Float64Array(compiled.parameters.length);
165
- this._transactionParameterValues = new Float64Array(compiled.parameters.length);
166
- this._restoreParameterDefaults();
167
- try {
168
- for (const layer of compiled.layers) {
169
- const current = this._createPlayback(
170
- layer,
171
- layer.states[layer.initialStateIndex]!,
172
- 0,
173
- );
174
- this._layers.push({ definition: layer, current, transition: null });
175
- }
176
- this._synchronizeAllLayers();
177
- } catch (error) {
178
- this._destroyAllLayers();
179
- this._status = 'destroyed';
180
- throw error;
181
- }
182
- }
183
-
184
- get status(): Animation3DStateMachineControllerStatus {
185
- return this._status;
186
- }
187
-
188
- get layerSnapshots(): readonly Animation3DStateMachineLayerSnapshot[] {
189
- return Object.freeze(this._layers.map(layer => this._snapshotLayer(layer)));
190
- }
191
-
192
- getLayerSnapshot(layerId: string): Animation3DStateMachineLayerSnapshot {
193
- const layerIndex = this.compiled.layerIndexById.get(layerId);
194
- if (layerIndex === undefined) throw new ReferenceError(`Unknown layer "${layerId}".`);
195
- const runtime = this._layers[layerIndex];
196
- if (!runtime) throw new Error('State-machine controller is destroyed.');
197
- return this._snapshotLayer(runtime);
198
- }
199
-
200
- setFloat(name: string, value: number): this {
201
- if (!Number.isFinite(value)) throw new RangeError('Float parameters must be finite.');
202
- this._setTypedParameter(name, 'float', value);
203
- return this;
204
- }
205
-
206
- setInteger(name: string, value: number): this {
207
- if (!Number.isSafeInteger(value)) {
208
- throw new RangeError('Integer parameters must be safe integers.');
209
- }
210
- this._setTypedParameter(name, 'integer', value);
211
- return this;
212
- }
213
-
214
- setBoolean(name: string, value: boolean): this {
215
- if (typeof value !== 'boolean') throw new TypeError('Boolean parameters require a boolean.');
216
- this._setTypedParameter(name, 'boolean', value ? 1 : 0);
217
- return this;
218
- }
219
-
220
- setTrigger(name: string): this {
221
- this._setTypedParameter(name, 'trigger', 1);
222
- return this;
223
- }
224
-
225
- resetTrigger(name: string): this {
226
- this._setTypedParameter(name, 'trigger', 0);
227
- return this;
228
- }
229
-
230
- getParameter(name: string): number | boolean {
231
- const parameter = this._resolveParameter(name);
232
- const value = this._parameterValues[parameter.index]!;
233
- return parameter.type === 'boolean' || parameter.type === 'trigger'
234
- ? value !== 0
235
- : value;
236
- }
237
-
238
- update(deltaSeconds: number): this {
239
- this[CONTROLLER_UPDATE_TRANSACTION](deltaSeconds);
240
- return this;
241
- }
242
-
243
- /** @internal Keeps controller and transactional mixer ports atomic through final pose evaluation. */
244
- [CONTROLLER_UPDATE_TRANSACTION](
245
- deltaSeconds: number,
246
- beforeUpdate?: () => void,
247
- complete?: () => unknown,
248
- ): unknown {
249
- this._requireActive();
250
- if (!Number.isFinite(deltaSeconds) || deltaSeconds < 0) {
251
- throw new RangeError('State-machine deltaSeconds must be finite and non-negative.');
252
- }
253
- if (this._transactionActive) {
254
- throw new Error('State-machine controller update transaction is already active.');
255
- }
256
-
257
- const transactionalPort = resolveTransactionalPort(this.port);
258
- this._captureUpdateTransaction();
259
- this._transactionActive = true;
260
- let portTransactionActive = false;
261
- try {
262
- if (transactionalPort) {
263
- transactionalPort.beginControllerTransaction();
264
- portTransactionActive = true;
265
- }
266
- beforeUpdate?.();
267
- this.lastUpdateTransitionCount = 0;
268
- this.transitionLimitReached = false;
269
- for (const layer of this._layers) this._updateLayer(layer, deltaSeconds);
270
- const result = complete?.();
271
- transactionalPort?.commitControllerTransaction();
272
- portTransactionActive = false;
273
- this._transactionActive = false;
274
- return result;
275
- } catch (error) {
276
- this._restoreUpdateTransaction();
277
- this._transactionActive = false;
278
- if (portTransactionActive) {
279
- try {
280
- transactionalPort!.rollbackControllerTransaction();
281
- } catch (rollbackError) {
282
- throw new AggregateError(
283
- [error, rollbackError],
284
- 'State-machine update and rollback both failed.',
285
- );
286
- }
287
- }
288
- throw error;
289
- }
290
- }
291
-
292
- /**
293
- * Restores defaults and initial states. Repeated reset calls are safe and
294
- * leave the same observable controller state.
295
- */
296
- reset(): this {
297
- if (this._status === 'destroyed') return this;
298
- this._destroyAllLayers();
299
- this._restoreParameterDefaults();
300
- this.lastUpdateTransitionCount = 0;
301
- this.transitionLimitReached = false;
302
- for (const layer of this.compiled.layers) {
303
- const current = this._createPlayback(
304
- layer,
305
- layer.states[layer.initialStateIndex]!,
306
- 0,
307
- );
308
- this._layers.push({ definition: layer, current, transition: null });
309
- }
310
- this._synchronizeAllLayers();
311
- return this;
312
- }
313
-
314
- /** Stops and releases all port actions. Idempotent. */
315
- destroy(): void {
316
- if (this._status === 'destroyed') return;
317
- this._destroyAllLayers();
318
- this._status = 'destroyed';
319
- }
320
-
321
- private _updateLayer(layer: LayerRuntime<TAction>, deltaSeconds: number): void {
322
- let remaining = deltaSeconds;
323
- let layerTransitionCount = 0;
324
- let inspectImmediateTransitions = true;
325
- while (remaining > TIME_EPSILON || inspectImmediateTransitions) {
326
- inspectImmediateTransitions = false;
327
- if (layerTransitionCount >= this.maxTransitionsPerUpdate) {
328
- this.transitionLimitReached = true;
329
- this._advanceWithoutTransitions(layer, remaining);
330
- remaining = 0;
331
- break;
332
- }
333
-
334
- if (layer.transition) {
335
- const interruption = this._findInterruption(layer);
336
- if (interruption) {
337
- this._interruptTransition(layer, interruption);
338
- layerTransitionCount++;
339
- this.lastUpdateTransitionCount++;
340
- inspectImmediateTransitions = true;
341
- continue;
342
- }
343
- const active = layer.transition;
344
- const timeToCompletion = Math.max(
345
- 0,
346
- active.definition.duration - active.elapsed,
347
- );
348
- if (timeToCompletion <= TIME_EPSILON) {
349
- this._completeTransition(layer);
350
- inspectImmediateTransitions = true;
351
- continue;
352
- }
353
- if (remaining <= TIME_EPSILON) break;
354
- const step = Math.min(remaining, timeToCompletion);
355
- this._advancePlayback(active.source, step);
356
- this._advancePlayback(active.destination, step);
357
- active.elapsed = Math.min(
358
- active.definition.duration,
359
- active.elapsed + step,
360
- );
361
- remaining = Math.max(0, remaining - step);
362
- this._synchronizeLayer(layer);
363
- if (
364
- active.elapsed + TIME_EPSILON >= active.definition.duration
365
- && layer.transition === active
366
- ) {
367
- this._completeTransition(layer);
368
- inspectImmediateTransitions = true;
369
- }
370
- continue;
371
- }
372
-
373
- const candidate = this._findEligibleTransition(
374
- layer.definition,
375
- layer.current,
376
- -1,
377
- );
378
- if (candidate) {
379
- this._startTransition(layer, layer.current, candidate);
380
- layerTransitionCount++;
381
- this.lastUpdateTransitionCount++;
382
- inspectImmediateTransitions = true;
383
- continue;
384
- }
385
- if (remaining <= TIME_EPSILON) break;
386
- const wait = this._timeUntilNextExitTransition(layer);
387
- const step = Number.isFinite(wait)
388
- ? Math.min(remaining, Math.max(wait, TIME_EPSILON))
389
- : remaining;
390
- this._advancePlayback(layer.current, step);
391
- remaining = Math.max(0, remaining - step);
392
- this._synchronizeLayer(layer);
393
- if (Number.isFinite(wait) && step + TIME_EPSILON >= wait) {
394
- inspectImmediateTransitions = true;
395
- }
396
- }
397
- this._synchronizeLayer(layer);
398
- }
399
-
400
- private _captureUpdateTransaction(): void {
401
- this._transactionParameterValues.set(this._parameterValues);
402
- this._transactionLastUpdateTransitionCount = this.lastUpdateTransitionCount;
403
- this._transactionLimitReached = this.transitionLimitReached;
404
- for (let index = 0; index < this._layers.length; index++) {
405
- const layer = this._layers[index]!;
406
- const transition = layer.transition;
407
- let checkpoint = this._layerTransactionCheckpoints[index];
408
- if (!checkpoint) {
409
- checkpoint = {
410
- current: layer.current,
411
- transition,
412
- currentTime: 0,
413
- sourceTime: 0,
414
- destinationTime: 0,
415
- transitionElapsed: 0,
416
- };
417
- this._layerTransactionCheckpoints.push(checkpoint);
418
- }
419
- checkpoint.current = layer.current;
420
- checkpoint.transition = transition;
421
- checkpoint.currentTime = layer.current.time;
422
- checkpoint.sourceTime = transition?.source.time ?? 0;
423
- checkpoint.destinationTime = transition?.destination.time ?? 0;
424
- checkpoint.transitionElapsed = transition?.elapsed ?? 0;
425
- }
426
- }
427
-
428
- private _restoreUpdateTransaction(): void {
429
- this._parameterValues.set(this._transactionParameterValues);
430
- this.lastUpdateTransitionCount = this._transactionLastUpdateTransitionCount;
431
- this.transitionLimitReached = this._transactionLimitReached;
432
- for (let index = 0; index < this._layers.length; index++) {
433
- const layer = this._layers[index]!;
434
- const checkpoint = this._layerTransactionCheckpoints[index]!;
435
- layer.current = checkpoint.current;
436
- layer.transition = checkpoint.transition;
437
- checkpoint.current.time = checkpoint.currentTime;
438
- if (checkpoint.transition) {
439
- checkpoint.transition.source.time = checkpoint.sourceTime;
440
- checkpoint.transition.destination.time = checkpoint.destinationTime;
441
- checkpoint.transition.elapsed = checkpoint.transitionElapsed;
442
- }
443
- }
444
- }
445
-
446
- private _findEligibleTransition(
447
- layer: CompiledAnimation3DLayer,
448
- playback: StatePlayback<TAction>,
449
- excludedTransitionIndex: number,
450
- ): CompiledAnimation3DTransition | null {
451
- for (const transition of layer.transitions) {
452
- if (transition.index === excludedTransitionIndex) continue;
453
- if (
454
- transition.fromStateIndex !== -1
455
- && transition.fromStateIndex !== playback.state.index
456
- ) continue;
457
- if (!this._conditionsPass(transition.conditions)) continue;
458
- if (
459
- transition.hasExitTime
460
- && !this._exitTimeReached(playback, transition.exitTime)
461
- ) continue;
462
- return transition;
463
- }
464
- return null;
465
- }
466
-
467
- private _findInterruption(
468
- layer: LayerRuntime<TAction>,
469
- ): InterruptionCandidate<TAction> | null {
470
- const active = layer.transition!;
471
- const strategy = active.definition.interruption;
472
- if (strategy === 'none') return null;
473
- const source = (): InterruptionCandidate<TAction> | null => {
474
- const transition = this._findEligibleTransition(
475
- layer.definition,
476
- active.source,
477
- active.definition.index,
478
- );
479
- return transition ? { transition, anchor: active.source } : null;
480
- };
481
- const destination = (): InterruptionCandidate<TAction> | null => {
482
- const transition = this._findEligibleTransition(
483
- layer.definition,
484
- active.destination,
485
- active.definition.index,
486
- );
487
- return transition ? { transition, anchor: active.destination } : null;
488
- };
489
- if (strategy === 'source') return source();
490
- if (strategy === 'destination') return destination();
491
- if (strategy === 'source-then-destination') return source() ?? destination();
492
- return destination() ?? source();
493
- }
494
-
495
- private _startTransition(
496
- layer: LayerRuntime<TAction>,
497
- source: StatePlayback<TAction>,
498
- transition: CompiledAnimation3DTransition,
499
- ): void {
500
- const destinationState = layer.definition.states[transition.toStateIndex]!;
501
- const destination = this._createPlayback(
502
- layer.definition,
503
- destinationState,
504
- transition.destinationOffset,
505
- );
506
- // Consume only after destination action creation succeeds and the
507
- // transition can actually become active.
508
- this._consumeTriggers(transition);
509
- const active: ActiveTransition<TAction> = {
510
- definition: transition,
511
- source,
512
- destination,
513
- elapsed: 0,
514
- };
515
- layer.transition = active;
516
- this._fadePlayback(source, 0, transition.duration);
517
- this._fadePlayback(
518
- destination,
519
- layer.definition.weight,
520
- transition.duration,
521
- );
522
- this._synchronizeLayer(layer);
523
- if (transition.duration <= TIME_EPSILON) this._completeTransition(layer);
524
- }
525
-
526
- private _interruptTransition(
527
- layer: LayerRuntime<TAction>,
528
- candidate: InterruptionCandidate<TAction>,
529
- ): void {
530
- const active = layer.transition!;
531
- const discarded = candidate.anchor === active.source
532
- ? active.destination
533
- : active.source;
534
- this._destroyPlayback(discarded);
535
- layer.current = candidate.anchor;
536
- layer.transition = null;
537
- this._startTransition(layer, candidate.anchor, candidate.transition);
538
- }
539
-
540
- private _completeTransition(layer: LayerRuntime<TAction>): void {
541
- const active = layer.transition;
542
- if (!active) return;
543
- this._destroyPlayback(active.source);
544
- layer.current = active.destination;
545
- layer.transition = null;
546
- this._synchronizeLayer(layer);
547
- }
548
-
549
- private _timeUntilNextExitTransition(layer: LayerRuntime<TAction>): number {
550
- let earliest = Infinity;
551
- for (const transition of layer.definition.transitions) {
552
- if (
553
- transition.fromStateIndex !== -1
554
- && transition.fromStateIndex !== layer.current.state.index
555
- ) continue;
556
- if (!transition.hasExitTime || !this._conditionsPass(transition.conditions)) continue;
557
- earliest = Math.min(
558
- earliest,
559
- this._timeUntilExit(layer.current, transition.exitTime),
560
- );
561
- }
562
- return earliest;
563
- }
564
-
565
- private _exitTimeReached(
566
- playback: StatePlayback<TAction>,
567
- exitTime: number,
568
- ): boolean {
569
- const duration = this._playbackDuration(playback);
570
- if (duration <= TIME_EPSILON) return true;
571
- const normalizedTime = playback.time / duration;
572
- if (playback.state.loop === 'once' || exitTime >= 1) {
573
- return normalizedTime + TIME_EPSILON >= exitTime;
574
- }
575
- const cycleTime = normalizedTime - Math.floor(normalizedTime);
576
- return cycleTime + TIME_EPSILON >= exitTime;
577
- }
578
-
579
- private _timeUntilExit(
580
- playback: StatePlayback<TAction>,
581
- exitTime: number,
582
- ): number {
583
- if (this._exitTimeReached(playback, exitTime)) return 0;
584
- const duration = this._playbackDuration(playback);
585
- if (duration <= TIME_EPSILON) return 0;
586
- const speed = this._playbackSpeed(playback);
587
- if (speed <= TIME_EPSILON) return Infinity;
588
- const normalizedTime = playback.time / duration;
589
- let targetNormalized: number;
590
- if (playback.state.loop === 'once' || exitTime >= 1) {
591
- targetNormalized = exitTime;
592
- } else {
593
- targetNormalized = Math.floor(normalizedTime) + exitTime;
594
- if (targetNormalized <= normalizedTime + TIME_EPSILON) targetNormalized += 1;
595
- }
596
- return Math.max(0, (targetNormalized * duration - playback.time) / speed);
597
- }
598
-
599
- private _conditionsPass(
600
- conditions: readonly CompiledAnimation3DCondition[],
601
- ): boolean {
602
- for (const condition of conditions) {
603
- const actual = this._parameterValues[condition.parameterIndex]!;
604
- const expected = condition.value;
605
- if (condition.operator === 'greater' && !(actual > expected)) return false;
606
- if (
607
- condition.operator === 'greater-or-equal'
608
- && !(actual >= expected)
609
- ) return false;
610
- if (condition.operator === 'less' && !(actual < expected)) return false;
611
- if (
612
- condition.operator === 'less-or-equal'
613
- && !(actual <= expected)
614
- ) return false;
615
- if (condition.operator === 'equal' && actual !== expected) return false;
616
- if (condition.operator === 'not-equal' && actual === expected) return false;
617
- if (condition.operator === 'is-true' && actual === 0) return false;
618
- if (condition.operator === 'is-false' && actual !== 0) return false;
619
- if (condition.operator === 'triggered' && actual === 0) return false;
620
- }
621
- return true;
622
- }
623
-
624
- private _consumeTriggers(transition: CompiledAnimation3DTransition): void {
625
- for (const parameterIndex of transition.triggerParameterIndices) {
626
- this._parameterValues[parameterIndex] = 0;
627
- }
628
- }
629
-
630
- private _createPlayback(
631
- layer: CompiledAnimation3DLayer,
632
- state: CompiledAnimation3DState,
633
- normalizedOffset: number,
634
- ): StatePlayback<TAction> {
635
- const createdActions: TAction[] = [];
636
- try {
637
- const motion = this._createRuntimeMotion(layer, state, state.motion, createdActions);
638
- const playback: StatePlayback<TAction> = { state, motion, time: 0 };
639
- playback.time = normalizedOffset * this._playbackDuration(playback);
640
- this._forEachAction(motion, action => {
641
- this.port.setWeight(action, 0);
642
- this.port.setTime(action, playback.time);
643
- this.port.setTimeScale(action, this._playbackSpeed(playback));
644
- this.port.play(action);
645
- });
646
- return playback;
647
- } catch (error) {
648
- for (let index = createdActions.length - 1; index >= 0; index--) {
649
- const action = createdActions[index]!;
650
- this.port.stop(action);
651
- this.port.destroyAction(action);
652
- }
653
- throw error;
654
- }
655
- }
656
-
657
- private _createRuntimeMotion(
658
- layer: CompiledAnimation3DLayer,
659
- state: CompiledAnimation3DState,
660
- motion: CompiledAnimation3DMotion,
661
- createdActions: TAction[],
662
- ): RuntimeMotion<TAction> {
663
- if (motion.kind === 'clip') {
664
- const action = this.port.createAction(motion.clipId, {
665
- layerId: layer.id,
666
- stateId: state.id,
667
- loop: state.loop,
668
- blendMode: layer.blendMode,
669
- mask: layer.mask,
670
- });
671
- if (!Number.isFinite(action.duration) || action.duration < 0) {
672
- throw new RangeError(
673
- `Mixer port returned an invalid duration for clip "${motion.clipId}".`,
674
- );
675
- }
676
- createdActions.push(action);
677
- return { kind: 'clip', action };
678
- }
679
- const children = motion.children.map(child =>
680
- this._createRuntimeMotion(layer, state, child.motion, createdActions));
681
- return motion.kind === 'blend-1d'
682
- ? {
683
- kind: 'blend-1d',
684
- motion,
685
- children,
686
- weights: new Float64Array(children.length),
687
- }
688
- : {
689
- kind: 'blend-2d',
690
- motion,
691
- children,
692
- weights: new Float64Array(children.length),
693
- };
694
- }
695
-
696
- private _advancePlayback(
697
- playback: StatePlayback<TAction>,
698
- deltaSeconds: number,
699
- ): void {
700
- playback.time += deltaSeconds * this._playbackSpeed(playback);
701
- }
702
-
703
- private _advanceWithoutTransitions(
704
- layer: LayerRuntime<TAction>,
705
- deltaSeconds: number,
706
- ): void {
707
- if (deltaSeconds <= TIME_EPSILON) return;
708
- const active = layer.transition;
709
- if (!active) {
710
- this._advancePlayback(layer.current, deltaSeconds);
711
- this._synchronizeLayer(layer);
712
- return;
713
- }
714
- const timeToCompletion = Math.max(0, active.definition.duration - active.elapsed);
715
- const transitionStep = Math.min(deltaSeconds, timeToCompletion);
716
- this._advancePlayback(active.source, transitionStep);
717
- this._advancePlayback(active.destination, transitionStep);
718
- active.elapsed += transitionStep;
719
- const afterCompletion = deltaSeconds - transitionStep;
720
- if (active.elapsed + TIME_EPSILON >= active.definition.duration) {
721
- this._completeTransition(layer);
722
- if (afterCompletion > TIME_EPSILON) {
723
- this._advancePlayback(layer.current, afterCompletion);
724
- }
725
- }
726
- this._synchronizeLayer(layer);
727
- }
728
-
729
- private _synchronizeAllLayers(): void {
730
- for (const layer of this._layers) this._synchronizeLayer(layer);
731
- }
732
-
733
- private _synchronizeLayer(layer: LayerRuntime<TAction>): void {
734
- const active = layer.transition;
735
- if (!active) {
736
- this._applyPlayback(layer.current, layer.definition.weight);
737
- return;
738
- }
739
- const progress = active.definition.duration <= TIME_EPSILON
740
- ? 1
741
- : Math.max(0, Math.min(1, active.elapsed / active.definition.duration));
742
- this._applyPlayback(
743
- active.source,
744
- layer.definition.weight * (1 - progress),
745
- );
746
- this._applyPlayback(
747
- active.destination,
748
- layer.definition.weight * progress,
749
- );
750
- }
751
-
752
- private _applyPlayback(
753
- playback: StatePlayback<TAction>,
754
- parentWeight: number,
755
- ): void {
756
- const speed = this._playbackSpeed(playback);
757
- this._applyMotion(
758
- playback.motion,
759
- parentWeight,
760
- playback.time,
761
- speed,
762
- );
763
- }
764
-
765
- private _applyMotion(
766
- motion: RuntimeMotion<TAction>,
767
- parentWeight: number,
768
- time: number,
769
- timeScale: number,
770
- ): void {
771
- if (motion.kind === 'clip') {
772
- this.port.setWeight(motion.action, parentWeight);
773
- this.port.setTime(motion.action, time);
774
- this.port.setTimeScale(motion.action, timeScale);
775
- return;
776
- }
777
- this._evaluateDirectWeights(motion);
778
- for (let index = 0; index < motion.children.length; index++) {
779
- this._applyMotion(
780
- motion.children[index]!,
781
- parentWeight * motion.weights[index]!,
782
- time,
783
- timeScale,
784
- );
785
- }
786
- }
787
-
788
- private _playbackDuration(playback: StatePlayback<TAction>): number {
789
- return this._motionDuration(playback.motion);
790
- }
791
-
792
- private _motionDuration(motion: RuntimeMotion<TAction>): number {
793
- if (motion.kind === 'clip') return motion.action.duration;
794
- this._evaluateDirectWeights(motion);
795
- let duration = 0;
796
- for (let index = 0; index < motion.children.length; index++) {
797
- duration += motion.weights[index]! * this._motionDuration(motion.children[index]!);
798
- }
799
- return duration;
800
- }
801
-
802
- private _playbackSpeed(playback: StatePlayback<TAction>): number {
803
- const parameterScale = playback.state.speedParameterIndex < 0
804
- ? 1
805
- : this._parameterValues[playback.state.speedParameterIndex]!;
806
- return playback.state.speed * parameterScale;
807
- }
808
-
809
- private _evaluateDirectWeights(
810
- motion: RuntimeBlend1D<TAction> | RuntimeBlend2D<TAction>,
811
- ): void {
812
- if (motion.kind === 'blend-1d') {
813
- evaluateAnimation3DBlend1DWeights(
814
- motion.motion,
815
- this._parameterValues[motion.motion.parameterIndex]!,
816
- motion.weights,
817
- );
818
- } else {
819
- evaluateAnimation3DBlend2DWeights(
820
- motion.motion,
821
- this._parameterValues[motion.motion.parameterXIndex]!,
822
- this._parameterValues[motion.motion.parameterYIndex]!,
823
- motion.weights,
824
- );
825
- }
826
- }
827
-
828
- private _fadePlayback(
829
- playback: StatePlayback<TAction>,
830
- targetParentWeight: number,
831
- durationSeconds: number,
832
- ): void {
833
- this._fadeMotion(playback.motion, targetParentWeight, durationSeconds);
834
- }
835
-
836
- private _fadeMotion(
837
- motion: RuntimeMotion<TAction>,
838
- parentWeight: number,
839
- durationSeconds: number,
840
- ): void {
841
- if (motion.kind === 'clip') {
842
- this.port.fade(motion.action, parentWeight, durationSeconds);
843
- return;
844
- }
845
- this._evaluateDirectWeights(motion);
846
- for (let index = 0; index < motion.children.length; index++) {
847
- this._fadeMotion(
848
- motion.children[index]!,
849
- parentWeight * motion.weights[index]!,
850
- durationSeconds,
851
- );
852
- }
853
- }
854
-
855
- private _destroyPlayback(playback: StatePlayback<TAction>): void {
856
- this._forEachAction(playback.motion, action => {
857
- this.port.stop(action);
858
- this.port.destroyAction(action);
859
- });
860
- }
861
-
862
- private _destroyAllLayers(): void {
863
- for (const layer of this._layers) {
864
- if (layer.transition) {
865
- this._destroyPlayback(layer.transition.source);
866
- this._destroyPlayback(layer.transition.destination);
867
- } else {
868
- this._destroyPlayback(layer.current);
869
- }
870
- }
871
- this._layers.length = 0;
872
- }
873
-
874
- private _forEachAction(
875
- motion: RuntimeMotion<TAction>,
876
- visitor: (action: TAction) => void,
877
- ): void {
878
- if (motion.kind === 'clip') {
879
- visitor(motion.action);
880
- return;
881
- }
882
- for (const child of motion.children) this._forEachAction(child, visitor);
883
- }
884
-
885
- private _snapshotLayer(
886
- layer: LayerRuntime<TAction>,
887
- ): Animation3DStateMachineLayerSnapshot {
888
- const active = layer.transition;
889
- return Object.freeze({
890
- layerId: layer.definition.id,
891
- currentStateId: active?.source.state.id ?? layer.current.state.id,
892
- currentTime: active?.source.time ?? layer.current.time,
893
- transitionId: active?.definition.id ?? null,
894
- sourceStateId: active?.source.state.id ?? null,
895
- destinationStateId: active?.destination.state.id ?? null,
896
- transitionProgress: active
897
- ? (
898
- active.definition.duration <= TIME_EPSILON
899
- ? 1
900
- : Math.max(0, Math.min(1, active.elapsed / active.definition.duration))
901
- )
902
- : 0,
903
- });
904
- }
905
-
906
- private _setTypedParameter(
907
- name: string,
908
- expectedType: CompiledAnimation3DParameter['type'],
909
- value: number,
910
- ): void {
911
- this._requireActive();
912
- const parameter = this._resolveParameter(name);
913
- if (parameter.type !== expectedType) {
914
- throw new TypeError(
915
- `Parameter "${name}" is ${parameter.type}, not ${expectedType}.`,
916
- );
917
- }
918
- this._parameterValues[parameter.index] = value;
919
- }
920
-
921
- private _resolveParameter(name: string): CompiledAnimation3DParameter {
922
- const parameterIndex = this.compiled.parameterIndexByName.get(name);
923
- if (parameterIndex === undefined) throw new ReferenceError(`Unknown parameter "${name}".`);
924
- return this.compiled.parameters[parameterIndex]!;
925
- }
926
-
927
- private _restoreParameterDefaults(): void {
928
- for (const parameter of this.compiled.parameters) {
929
- this._parameterValues[parameter.index] = parameter.defaultValue;
930
- }
931
- }
932
-
933
- private _requireActive(): void {
934
- if (this._status === 'destroyed') {
935
- throw new Error('Animation3D state-machine controller is destroyed.');
936
- }
937
- }
938
- }
939
-
940
- /**
941
- * @internal Extends one controller update transaction through caller-owned
942
- * pose evaluation. It is intentionally not re-exported from package entries.
943
- */
944
- export function runAnimationStateMachineControllerUpdateTransaction<
945
- TAction extends Animation3DStateMachineActionHandle,
946
- TResult,
947
- >(
948
- controller: Animation3DStateMachineController<TAction>,
949
- deltaSeconds: number,
950
- beforeUpdate: () => void,
951
- complete: () => TResult,
952
- ): TResult {
953
- return controller[CONTROLLER_UPDATE_TRANSACTION](
954
- deltaSeconds,
955
- beforeUpdate,
956
- complete,
957
- ) as TResult;
958
- }
959
-
960
- function resolveTransactionalPort(
961
- port: Animation3DStateMachineMixerPort<Animation3DStateMachineActionHandle>,
962
- ): TransactionalAnimationStateMachineMixerPort | null {
963
- const candidate = port as Animation3DStateMachineMixerPort<Animation3DStateMachineActionHandle>
964
- & Partial<TransactionalAnimationStateMachineMixerPort>;
965
- const hasBegin = typeof candidate.beginControllerTransaction === 'function';
966
- const hasCommit = typeof candidate.commitControllerTransaction === 'function';
967
- const hasRollback = typeof candidate.rollbackControllerTransaction === 'function';
968
- const implemented = Number(hasBegin) + Number(hasCommit) + Number(hasRollback);
969
- if (implemented === 0) return null;
970
- if (implemented !== 3) {
971
- throw new TypeError(
972
- 'A transactional state-machine mixer port must implement begin, commit, and rollback.',
973
- );
974
- }
975
- return candidate as TransactionalAnimationStateMachineMixerPort;
976
- }
977
-
978
- /** Factory kept internal to the runtime directory. */
979
- export function createAnimation3DStateMachineController<
980
- TAction extends Animation3DStateMachineActionHandle,
981
- >(
982
- compiled: CompiledAnimation3DStateMachine,
983
- port: Animation3DStateMachineMixerPort<TAction>,
984
- options?: Animation3DStateMachineControllerOptions,
985
- ): Animation3DStateMachineController<TAction> {
986
- return new Animation3DStateMachineController(compiled, port, options);
987
- }