@haiyue/extensions 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/animation/Animation2DComponent.d.ts +46 -0
  4. package/dist/animation/Animation2DExtensionRegistry.d.ts +27 -0
  5. package/dist/animation/Animation2DRenderSystem.d.ts +89 -0
  6. package/dist/animation/Animation2DRuntime.d.ts +99 -0
  7. package/dist/animation/Animation2DStateMachine.d.ts +13 -0
  8. package/dist/animation/Animation2DStateMachineComponent.d.ts +54 -0
  9. package/dist/animation/Animation2DStateMachineRuntime.d.ts +30 -0
  10. package/dist/animation/Animation2DStateMachineSystem.d.ts +14 -0
  11. package/dist/animation/Animation2DStateMachineVisualRuntime.d.ts +27 -0
  12. package/dist/animation/Animation2DSystem.d.ts +14 -0
  13. package/dist/animation/AnimationAssetLoader.d.ts +9 -0
  14. package/dist/animation/AnimationAudioClip.d.ts +26 -0
  15. package/dist/animation/AnimationPathTessellator.d.ts +52 -0
  16. package/dist/animation/AnimationTextRasterizer.d.ts +21 -0
  17. package/dist/animation/AnimationVisual2D.d.ts +68 -0
  18. package/dist/animation/HyaAnimation2DClipAdapter.d.ts +16 -0
  19. package/dist/animation/Particle2DDescriptorAdapter.d.ts +5 -0
  20. package/dist/animation/runtime/mixer/Action.d.ts +150 -0
  21. package/dist/animation/runtime/mixer/Mixer.d.ts +54 -0
  22. package/dist/animation/runtime/mixer/PoseBuffer.d.ts +23 -0
  23. package/dist/animation/runtime/mixer/Sampler.d.ts +17 -0
  24. package/dist/animation/runtime/mixer/Types.d.ts +101 -0
  25. package/dist/animation/runtime/mixer/index.d.ts +6 -0
  26. package/dist/animation-state-machine/AnimationStateMachine.d.ts +111 -0
  27. package/dist/animation-state-machine/AnimationStateMachineChannels.d.ts +23 -0
  28. package/dist/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.d.ts +51 -0
  29. package/dist/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.d.ts +14 -0
  30. package/dist/animation-state-machine/runtime/AnimationStateMachineCompiler.d.ts +109 -0
  31. package/dist/animation-state-machine/runtime/AnimationStateMachineController.d.ts +103 -0
  32. package/dist/animation-state-machine/runtime/AnimationStateMachineMixerPort.d.ts +35 -0
  33. package/dist/animation-state-machine/runtime/index.d.ts +7 -0
  34. package/dist/animation.d.ts +15 -0
  35. package/dist/animation.js +1171 -0
  36. package/dist/animation3d/Animation3DAction.d.ts +46 -0
  37. package/dist/animation3d/Animation3DBinding.d.ts +85 -0
  38. package/dist/animation3d/Animation3DClip.d.ts +20 -0
  39. package/dist/animation3d/Animation3DError.d.ts +13 -0
  40. package/dist/animation3d/Animation3DMixer.d.ts +27 -0
  41. package/dist/animation3d/Animation3DPose.d.ts +40 -0
  42. package/dist/animation3d/Animation3DPoseBuffer.d.ts +24 -0
  43. package/dist/animation3d/Animation3DResource.d.ts +28 -0
  44. package/dist/animation3d/Animation3DStateMachine.d.ts +95 -0
  45. package/dist/animation3d/Animation3DStateMachineRuntime.d.ts +70 -0
  46. package/dist/animation3d/Animation3DTrack.d.ts +19 -0
  47. package/dist/animation3d/hya/HyaAnimation3DRuntime.d.ts +73 -0
  48. package/dist/animation3d/hya/HyaAnimation3DStateMachineRuntime.d.ts +65 -0
  49. package/dist/animation3d/hya/HyaAnimation3DTypes.d.ts +170 -0
  50. package/dist/animation3d/hya/index.d.ts +4 -0
  51. package/dist/animation3d/index.d.ts +14 -0
  52. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.d.ts +81 -0
  53. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.d.ts +39 -0
  54. package/dist/animation3d/runtime/integration/index.d.ts +2 -0
  55. package/dist/animation3d/runtime/mixer/Action.d.ts +150 -0
  56. package/dist/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.d.ts +6 -0
  57. package/dist/animation3d/runtime/mixer/Mixer.d.ts +59 -0
  58. package/dist/animation3d/runtime/mixer/PoseBuffer.d.ts +1 -0
  59. package/dist/animation3d/runtime/mixer/TrackSampler.d.ts +24 -0
  60. package/dist/animation3d/runtime/mixer/index.d.ts +4 -0
  61. package/dist/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.d.ts +1 -0
  62. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.d.ts +1 -0
  63. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineController.d.ts +1 -0
  64. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.d.ts +1 -0
  65. package/dist/animation3d/runtime/state-machine/index.d.ts +6 -0
  66. package/dist/animation3d.d.ts +5 -0
  67. package/dist/animation3d.js +1708 -0
  68. package/dist/benchmark.d.ts +30 -0
  69. package/dist/benchmark.js +119 -0
  70. package/dist/canvas-text/CanvasText2DRenderSystem.d.ts +24 -0
  71. package/dist/canvas-text/CanvasTextComponent.d.ts +18 -0
  72. package/dist/canvas-text.d.ts +4 -0
  73. package/dist/canvas-text.js +276 -0
  74. package/dist/chunks/2d-ui-animation-2d.generated-D4aHzFU2.js +4 -0
  75. package/dist/chunks/2d-ui-canvas-text-2d.generated-C0Eaej2m.js +4 -0
  76. package/dist/chunks/2d-ui-spine2d.generated-CUUi8xjl.js +4 -0
  77. package/dist/chunks/2d-ui-tilemap2d.generated-gebw4mX7.js +4 -0
  78. package/dist/chunks/Animation2DStateMachine-9IonguNa.js +3245 -0
  79. package/dist/chunks/AnimationStateMachineController-BIcAh-sT.js +1438 -0
  80. package/dist/chunks/GltfAnimation3DAdapter-Cu3rQQsW.js +2240 -0
  81. package/dist/chunks/GltfAnimationRuntime-CRHsLycN.js +631 -0
  82. package/dist/chunks/RenderSystem2DBase-DDT61dAu.js +227 -0
  83. package/dist/chunks/Spine2DRuntime-D9M9LAQR.js +3056 -0
  84. package/dist/chunks/SpineAssetParser-BSDmPge1.js +378 -0
  85. package/dist/chunks/gltfLoader-Dm22jLYB.js +2085 -0
  86. package/dist/chunks/pluginUtils-CvwroRMd.js +33 -0
  87. package/dist/experimental-gltf-worker.d.ts +4 -0
  88. package/dist/experimental-gltf-worker.js +138 -0
  89. package/dist/experimental-spine-worker.d.ts +4 -0
  90. package/dist/experimental-spine-worker.js +110 -0
  91. package/dist/gltf/GltfAccessorReader.d.ts +7 -0
  92. package/dist/gltf/GltfAnimation3DAdapter.d.ts +47 -0
  93. package/dist/gltf/GltfAnimationRuntime.d.ts +10 -0
  94. package/dist/gltf/GltfAssetWorkerClient.d.ts +20 -0
  95. package/dist/gltf/GltfCompatibilityReport.d.ts +70 -0
  96. package/dist/gltf/GltfConservativeBounds.d.ts +18 -0
  97. package/dist/gltf/GltfDracoDecoder.d.ts +4 -0
  98. package/dist/gltf/GltfExtensionAdapter.d.ts +54 -0
  99. package/dist/gltf/GltfLoaderContract.d.ts +249 -0
  100. package/dist/gltf/GltfLoaderErrors.d.ts +4 -0
  101. package/dist/gltf/GltfMaterialDescriptor.d.ts +23 -0
  102. package/dist/gltf/GltfMaterialEncoder.d.ts +20 -0
  103. package/dist/gltf/GltfMaterialLoader.d.ts +6 -0
  104. package/dist/gltf/GltfModelComponent.d.ts +72 -0
  105. package/dist/gltf/GltfModelSystem.d.ts +37 -0
  106. package/dist/gltf/GltfPlugin.d.ts +6 -0
  107. package/dist/gltf/GltfSchema.d.ts +225 -0
  108. package/dist/gltf/GltfUvSemanticPlanner.d.ts +33 -0
  109. package/dist/gltf/gltfLoader.d.ts +9 -0
  110. package/dist/gltf-animation3d.d.ts +3 -0
  111. package/dist/gltf-animation3d.js +8 -0
  112. package/dist/gltf-worker-runtime.d.ts +7 -0
  113. package/dist/gltf-worker-runtime.js +6981 -0
  114. package/dist/gltf.d.ts +12 -0
  115. package/dist/gltf.js +517 -0
  116. package/dist/grid/Grid2DComponent.d.ts +25 -0
  117. package/dist/grid.d.ts +2 -0
  118. package/dist/grid.js +56 -0
  119. package/dist/hya-state-machine.d.ts +7 -0
  120. package/dist/hya-state-machine.js +2934 -0
  121. package/dist/index.d.ts +2 -0
  122. package/dist/index.js +7 -0
  123. package/dist/internal/2d-ui-shader-artifact.js +870 -0
  124. package/dist/plugins/pluginUtils.d.ts +20 -0
  125. package/dist/plugins.d.ts +6 -0
  126. package/dist/shaders/generated/2d-ui-artifact.generated.d.ts +658 -0
  127. package/dist/spine/Spine2DComponent.d.ts +116 -0
  128. package/dist/spine/Spine2DGpuRenderer.d.ts +65 -0
  129. package/dist/spine/Spine2DRenderSystem.d.ts +27 -0
  130. package/dist/spine/Spine2DRuntime.d.ts +103 -0
  131. package/dist/spine/SpineAnimationBoneTimelines.d.ts +8 -0
  132. package/dist/spine/SpineAssetParser.d.ts +18 -0
  133. package/dist/spine/SpineAssetWorkerClient.d.ts +19 -0
  134. package/dist/spine/SpineAssetWorkerContract.d.ts +6 -0
  135. package/dist/spine/SpineAtlasParser.d.ts +21 -0
  136. package/dist/spine/SpineFloatBuilder.d.ts +15 -0
  137. package/dist/spine/SpinePathConstraintSolver.d.ts +32 -0
  138. package/dist/spine/SpinePlugin.d.ts +8 -0
  139. package/dist/spine/SpineSkeletonRuntime.d.ts +185 -0
  140. package/dist/spine/SpineSlotAnimation.d.ts +17 -0
  141. package/dist/spine/SpineTimelineRuntime.d.ts +25 -0
  142. package/dist/spine/SpineVertexBuilder.d.ts +61 -0
  143. package/dist/spine.d.ts +7 -0
  144. package/dist/spine.js +578 -0
  145. package/dist/tilemap/Tilemap2DComponent.d.ts +110 -0
  146. package/dist/tilemap/Tilemap2DRenderSystem.d.ts +11 -0
  147. package/dist/tilemap/Tilemap2DRenderer.d.ts +24 -0
  148. package/dist/tilemap/TilemapPlugin.d.ts +8 -0
  149. package/dist/tilemap.d.ts +6 -0
  150. package/dist/tilemap.js +535 -0
  151. package/dist/tween/Tween2DComponent.d.ts +70 -0
  152. package/dist/tween/Tween2DSystem.d.ts +12 -0
  153. package/dist/tween.d.ts +4 -0
  154. package/dist/tween.js +138 -0
  155. package/dist/utils/RenderSystem2DBase.d.ts +42 -0
  156. package/dist/utils/arrayAccess.d.ts +4 -0
  157. package/dist/utils/camera2d.d.ts +12 -0
  158. package/dist/utils/render2dGpu.d.ts +32 -0
  159. package/package.json +124 -0
  160. package/src/animation/Animation2DComponent.ts +135 -0
  161. package/src/animation/Animation2DExtensionRegistry.ts +52 -0
  162. package/src/animation/Animation2DRenderSystem.ts +1026 -0
  163. package/src/animation/Animation2DRuntime.ts +1326 -0
  164. package/src/animation/Animation2DStateMachine.ts +39 -0
  165. package/src/animation/Animation2DStateMachineComponent.ts +228 -0
  166. package/src/animation/Animation2DStateMachineRuntime.ts +141 -0
  167. package/src/animation/Animation2DStateMachineSystem.ts +60 -0
  168. package/src/animation/Animation2DStateMachineVisualRuntime.ts +282 -0
  169. package/src/animation/Animation2DSystem.ts +72 -0
  170. package/src/animation/AnimationAssetLoader.ts +84 -0
  171. package/src/animation/AnimationAudioClip.ts +140 -0
  172. package/src/animation/AnimationPathTessellator.ts +691 -0
  173. package/src/animation/AnimationTextRasterizer.ts +340 -0
  174. package/src/animation/AnimationVisual2D.ts +153 -0
  175. package/src/animation/HyaAnimation2DClipAdapter.ts +845 -0
  176. package/src/animation/Particle2DDescriptorAdapter.ts +35 -0
  177. package/src/animation/runtime/mixer/Action.ts +876 -0
  178. package/src/animation/runtime/mixer/Mixer.ts +505 -0
  179. package/src/animation/runtime/mixer/PoseBuffer.ts +105 -0
  180. package/src/animation/runtime/mixer/Sampler.ts +252 -0
  181. package/src/animation/runtime/mixer/Types.ts +138 -0
  182. package/src/animation/runtime/mixer/index.ts +31 -0
  183. package/src/animation-state-machine/AnimationStateMachine.ts +146 -0
  184. package/src/animation-state-machine/AnimationStateMachineChannels.ts +116 -0
  185. package/src/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.ts +197 -0
  186. package/src/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.ts +503 -0
  187. package/src/animation-state-machine/runtime/AnimationStateMachineCompiler.ts +763 -0
  188. package/src/animation-state-machine/runtime/AnimationStateMachineController.ts +987 -0
  189. package/src/animation-state-machine/runtime/AnimationStateMachineMixerPort.ts +54 -0
  190. package/src/animation-state-machine/runtime/index.ts +47 -0
  191. package/src/animation.ts +33 -0
  192. package/src/animation3d/Animation3DAction.ts +73 -0
  193. package/src/animation3d/Animation3DBinding.ts +116 -0
  194. package/src/animation3d/Animation3DClip.ts +22 -0
  195. package/src/animation3d/Animation3DError.ts +34 -0
  196. package/src/animation3d/Animation3DMixer.ts +82 -0
  197. package/src/animation3d/Animation3DPose.ts +100 -0
  198. package/src/animation3d/Animation3DPoseBuffer.ts +85 -0
  199. package/src/animation3d/Animation3DResource.ts +49 -0
  200. package/src/animation3d/Animation3DStateMachine.ts +126 -0
  201. package/src/animation3d/Animation3DStateMachineRuntime.ts +191 -0
  202. package/src/animation3d/Animation3DTrack.ts +29 -0
  203. package/src/animation3d/hya/HyaAnimation3DRuntime.ts +756 -0
  204. package/src/animation3d/hya/HyaAnimation3DStateMachineRuntime.ts +618 -0
  205. package/src/animation3d/hya/HyaAnimation3DTypes.ts +168 -0
  206. package/src/animation3d/hya/index.ts +10 -0
  207. package/src/animation3d/index.ts +76 -0
  208. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.ts +325 -0
  209. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.ts +158 -0
  210. package/src/animation3d/runtime/integration/index.ts +9 -0
  211. package/src/animation3d/runtime/mixer/Action.ts +833 -0
  212. package/src/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.ts +26 -0
  213. package/src/animation3d/runtime/mixer/Mixer.ts +562 -0
  214. package/src/animation3d/runtime/mixer/PoseBuffer.ts +1 -0
  215. package/src/animation3d/runtime/mixer/TrackSampler.ts +399 -0
  216. package/src/animation3d/runtime/mixer/index.ts +8 -0
  217. package/src/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.ts +4 -0
  218. package/src/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.ts +1 -0
  219. package/src/animation3d/runtime/state-machine/Animation3DStateMachineController.ts +1 -0
  220. package/src/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.ts +1 -0
  221. package/src/animation3d/runtime/state-machine/index.ts +45 -0
  222. package/src/animation3d.ts +5 -0
  223. package/src/benchmark.ts +168 -0
  224. package/src/canvas-text/CanvasText2DRenderSystem.ts +292 -0
  225. package/src/canvas-text/CanvasTextComponent.ts +47 -0
  226. package/src/canvas-text.ts +4 -0
  227. package/src/experimental-gltf-worker.ts +18 -0
  228. package/src/experimental-spine-worker.ts +9 -0
  229. package/src/gltf/GltfAccessorReader.ts +271 -0
  230. package/src/gltf/GltfAnimation3DAdapter.ts +680 -0
  231. package/src/gltf/GltfAnimationRuntime.ts +392 -0
  232. package/src/gltf/GltfAssetWorkerClient.ts +136 -0
  233. package/src/gltf/GltfCompatibilityReport.ts +214 -0
  234. package/src/gltf/GltfConservativeBounds.ts +219 -0
  235. package/src/gltf/GltfDracoDecoder.ts +251 -0
  236. package/src/gltf/GltfExtensionAdapter.ts +340 -0
  237. package/src/gltf/GltfLoaderContract.ts +333 -0
  238. package/src/gltf/GltfLoaderErrors.ts +59 -0
  239. package/src/gltf/GltfMaterialDescriptor.ts +134 -0
  240. package/src/gltf/GltfMaterialEncoder.ts +173 -0
  241. package/src/gltf/GltfMaterialLoader.ts +293 -0
  242. package/src/gltf/GltfModelComponent.ts +115 -0
  243. package/src/gltf/GltfModelSystem.ts +208 -0
  244. package/src/gltf/GltfPlugin.ts +84 -0
  245. package/src/gltf/GltfSchema.ts +229 -0
  246. package/src/gltf/GltfUvSemanticPlanner.ts +166 -0
  247. package/src/gltf/gltfLoader.ts +910 -0
  248. package/src/gltf-animation3d.ts +10 -0
  249. package/src/gltf-worker-runtime.ts +10 -0
  250. package/src/gltf.ts +56 -0
  251. package/src/grid/Grid2DComponent.ts +69 -0
  252. package/src/grid.ts +2 -0
  253. package/src/hya-state-machine.ts +19 -0
  254. package/src/index.ts +2 -0
  255. package/src/plugins/pluginUtils.ts +50 -0
  256. package/src/plugins.ts +6 -0
  257. package/src/shaders/generated/2d-ui-animation-2d.generated.wgsl +242 -0
  258. package/src/shaders/generated/2d-ui-artifact.generated.ts +867 -0
  259. package/src/shaders/generated/2d-ui-canvas-text-2d.generated.wgsl +38 -0
  260. package/src/shaders/generated/2d-ui-spine2d.generated.wgsl +41 -0
  261. package/src/shaders/generated/2d-ui-tilemap2d.generated.wgsl +36 -0
  262. package/src/spine/Spine2DComponent.ts +168 -0
  263. package/src/spine/Spine2DGpuRenderer.ts +449 -0
  264. package/src/spine/Spine2DRenderSystem.ts +199 -0
  265. package/src/spine/Spine2DRuntime.ts +1529 -0
  266. package/src/spine/SpineAnimationBoneTimelines.ts +30 -0
  267. package/src/spine/SpineAssetParser.ts +20 -0
  268. package/src/spine/SpineAssetWorkerClient.ts +112 -0
  269. package/src/spine/SpineAssetWorkerContract.ts +4 -0
  270. package/src/spine/SpineAtlasParser.ts +127 -0
  271. package/src/spine/SpineFloatBuilder.ts +66 -0
  272. package/src/spine/SpinePathConstraintSolver.ts +582 -0
  273. package/src/spine/SpinePlugin.ts +76 -0
  274. package/src/spine/SpineSkeletonRuntime.ts +521 -0
  275. package/src/spine/SpineSlotAnimation.ts +195 -0
  276. package/src/spine/SpineTimelineRuntime.ts +453 -0
  277. package/src/spine/SpineVertexBuilder.ts +686 -0
  278. package/src/spine.ts +7 -0
  279. package/src/tilemap/Tilemap2DComponent.ts +232 -0
  280. package/src/tilemap/Tilemap2DRenderSystem.ts +58 -0
  281. package/src/tilemap/Tilemap2DRenderer.ts +289 -0
  282. package/src/tilemap/TilemapPlugin.ts +75 -0
  283. package/src/tilemap.ts +6 -0
  284. package/src/tween/Tween2DComponent.ts +83 -0
  285. package/src/tween/Tween2DSystem.ts +78 -0
  286. package/src/tween.ts +4 -0
  287. package/src/types/earcut.d.ts +7 -0
  288. package/src/types/wgsl.d.ts +4 -0
  289. package/src/utils/RenderSystem2DBase.ts +164 -0
  290. package/src/utils/arrayAccess.ts +17 -0
  291. package/src/utils/camera2d.ts +68 -0
  292. package/src/utils/render2dGpu.ts +132 -0
  293. package/test/fixtures/gltf/animation-characterization.gltf +344 -0
@@ -0,0 +1,763 @@
1
+ import type {
2
+ AnimationStateMachineBindingMask as Animation3DBindingMask,
3
+ AnimationStateMachineBlendMode as Animation3DBlendMode,
4
+ AnimationStateMachineDefinition,
5
+ AnimationStateMachineLoopMode as Animation3DLoopMode,
6
+ AnimationStateMachineMotionDefinition as Animation3DMotionDefinition,
7
+ AnimationStateMachineParameterDefinition as Animation3DParameterDefinition,
8
+ AnimationStateMachineTransitionCondition as Animation3DTransitionCondition,
9
+ AnimationStateMachineTransitionInterruption as Animation3DTransitionInterruption,
10
+ } from '../AnimationStateMachine.js';
11
+
12
+ type LegacyAnimation3DStateMachineDefinition =
13
+ Omit<AnimationStateMachineDefinition, 'format'> & Readonly<{
14
+ format: 'haiyue-animation3d-state-machine@1';
15
+ }>;
16
+
17
+ type SupportedAnimationStateMachineDefinition =
18
+ | AnimationStateMachineDefinition
19
+ | LegacyAnimation3DStateMachineDefinition;
20
+
21
+ export type Animation3DStateMachineValidationCode =
22
+ | 'invalid-value'
23
+ | 'duplicate-id'
24
+ | 'missing-reference'
25
+ | 'parameter-type-mismatch'
26
+ | 'invalid-operator'
27
+ | 'empty-blend-tree'
28
+ | 'invalid-thresholds'
29
+ | 'recursive-motion';
30
+
31
+ export interface Animation3DStateMachineValidationIssue {
32
+ readonly code: Animation3DStateMachineValidationCode;
33
+ readonly path: string;
34
+ readonly message: string;
35
+ }
36
+
37
+ export class AnimationStateMachineValidationError extends Error {
38
+ readonly issues: readonly Animation3DStateMachineValidationIssue[];
39
+
40
+ constructor(issues: readonly Animation3DStateMachineValidationIssue[]) {
41
+ super(
42
+ `Invalid animation state-machine definition (${issues.length} ${
43
+ issues.length === 1 ? 'issue' : 'issues'
44
+ }).`,
45
+ );
46
+ this.name = 'AnimationStateMachineValidationError';
47
+ this.issues = Object.freeze([...issues]);
48
+ }
49
+ }
50
+
51
+ export type CompiledAnimation3DParameterType =
52
+ | 'float'
53
+ | 'integer'
54
+ | 'boolean'
55
+ | 'trigger';
56
+
57
+ export interface CompiledAnimation3DParameter {
58
+ readonly index: number;
59
+ readonly name: string;
60
+ readonly type: CompiledAnimation3DParameterType;
61
+ /** Triggers and false booleans use 0; true booleans use 1. */
62
+ readonly defaultValue: number;
63
+ }
64
+
65
+ export type CompiledAnimation3DConditionOperator =
66
+ | 'greater'
67
+ | 'greater-or-equal'
68
+ | 'less'
69
+ | 'less-or-equal'
70
+ | 'equal'
71
+ | 'not-equal'
72
+ | 'is-true'
73
+ | 'is-false'
74
+ | 'triggered';
75
+
76
+ export interface CompiledAnimation3DCondition {
77
+ readonly parameterIndex: number;
78
+ readonly operator: CompiledAnimation3DConditionOperator;
79
+ readonly value: number;
80
+ }
81
+
82
+ export interface CompiledAnimation3DClipMotion {
83
+ readonly kind: 'clip';
84
+ readonly clipId: string;
85
+ }
86
+
87
+ export interface CompiledAnimation3DBlend1DChild {
88
+ readonly threshold: number;
89
+ readonly motion: CompiledAnimation3DMotion;
90
+ }
91
+
92
+ export interface CompiledAnimation3DBlend1DMotion {
93
+ readonly kind: 'blend-1d';
94
+ readonly parameterIndex: number;
95
+ readonly children: readonly CompiledAnimation3DBlend1DChild[];
96
+ }
97
+
98
+ export interface CompiledAnimation3DBlend2DChild {
99
+ readonly position: readonly [number, number];
100
+ readonly motion: CompiledAnimation3DMotion;
101
+ readonly declarationIndex: number;
102
+ }
103
+
104
+ export interface CompiledAnimation3DBlend2DMotion {
105
+ readonly kind: 'blend-2d';
106
+ readonly algorithm: 'cartesian' | 'directional';
107
+ readonly parameterXIndex: number;
108
+ readonly parameterYIndex: number;
109
+ readonly children: readonly CompiledAnimation3DBlend2DChild[];
110
+ }
111
+
112
+ export type CompiledAnimation3DMotion =
113
+ | CompiledAnimation3DClipMotion
114
+ | CompiledAnimation3DBlend1DMotion
115
+ | CompiledAnimation3DBlend2DMotion;
116
+
117
+ export interface CompiledAnimation3DState {
118
+ readonly index: number;
119
+ readonly id: string;
120
+ readonly name: string;
121
+ readonly motion: CompiledAnimation3DMotion;
122
+ readonly speed: number;
123
+ readonly speedParameterIndex: number;
124
+ readonly loop: Animation3DLoopMode;
125
+ }
126
+
127
+ export interface CompiledAnimation3DTransition {
128
+ readonly index: number;
129
+ readonly id: string;
130
+ /** -1 denotes any-state. */
131
+ readonly fromStateIndex: number;
132
+ readonly toStateIndex: number;
133
+ readonly conditions: readonly CompiledAnimation3DCondition[];
134
+ readonly triggerParameterIndices: readonly number[];
135
+ readonly duration: number;
136
+ readonly hasExitTime: boolean;
137
+ readonly exitTime: number;
138
+ readonly destinationOffset: number;
139
+ readonly interruption: Animation3DTransitionInterruption;
140
+ }
141
+
142
+ export interface CompiledAnimation3DLayer {
143
+ readonly index: number;
144
+ readonly id: string;
145
+ readonly name: string;
146
+ readonly initialStateIndex: number;
147
+ readonly states: readonly CompiledAnimation3DState[];
148
+ /** Preserves declaration order, which is transition priority. */
149
+ readonly transitions: readonly CompiledAnimation3DTransition[];
150
+ readonly blendMode: Animation3DBlendMode;
151
+ readonly weight: number;
152
+ readonly mask: Animation3DBindingMask | null;
153
+ /** Compiler-created lookup; the update path uses numeric indices instead. */
154
+ readonly stateIndexById: ReadonlyMap<string, number>;
155
+ }
156
+
157
+ export interface CompiledAnimation3DStateMachine {
158
+ readonly format: 'haiyue-animation-state-machine-compiled@1';
159
+ readonly id: string;
160
+ readonly name: string;
161
+ readonly parameters: readonly CompiledAnimation3DParameter[];
162
+ readonly layers: readonly CompiledAnimation3DLayer[];
163
+ /** Setter/query boundary lookup; the update path uses numeric indices. */
164
+ readonly parameterIndexByName: ReadonlyMap<string, number>;
165
+ readonly layerIndexById: ReadonlyMap<string, number>;
166
+ }
167
+
168
+ interface ValidationContext {
169
+ readonly issues: Animation3DStateMachineValidationIssue[];
170
+ readonly parameterByName: Map<string, Animation3DParameterDefinition>;
171
+ readonly motionStack: Set<object>;
172
+ }
173
+
174
+ const INTERRUPTION_VALUES: readonly Animation3DTransitionInterruption[] = [
175
+ 'none',
176
+ 'source',
177
+ 'destination',
178
+ 'source-then-destination',
179
+ 'destination-then-source',
180
+ ];
181
+
182
+ export function validateAnimationStateMachineDefinition(
183
+ definition: SupportedAnimationStateMachineDefinition,
184
+ ): readonly Animation3DStateMachineValidationIssue[] {
185
+ const issues: Animation3DStateMachineValidationIssue[] = [];
186
+ const parameterByName = new Map<string, Animation3DParameterDefinition>();
187
+ const context: ValidationContext = {
188
+ issues,
189
+ parameterByName,
190
+ motionStack: new Set<object>(),
191
+ };
192
+
193
+ if (
194
+ definition.format !== 'haiyue-animation-state-machine@1'
195
+ && definition.format !== 'haiyue-animation3d-state-machine@1'
196
+ ) {
197
+ issue(context, 'invalid-value', 'format', 'Unsupported state-machine format.');
198
+ }
199
+ validateNonEmptyString(context, definition.id, 'id');
200
+ validateNonEmptyString(context, definition.name, 'name');
201
+
202
+ definition.parameters.forEach((parameter, parameterIndex) => {
203
+ const path = `parameters[${parameterIndex}]`;
204
+ validateNonEmptyString(context, parameter.name, `${path}.name`);
205
+ if (parameterByName.has(parameter.name)) {
206
+ issue(
207
+ context,
208
+ 'duplicate-id',
209
+ `${path}.name`,
210
+ `Duplicate parameter name "${parameter.name}".`,
211
+ );
212
+ } else {
213
+ parameterByName.set(parameter.name, parameter);
214
+ }
215
+ if (parameter.type === 'float') {
216
+ validateFinite(context, parameter.defaultValue, `${path}.defaultValue`);
217
+ } else if (parameter.type === 'integer') {
218
+ if (!Number.isSafeInteger(parameter.defaultValue)) {
219
+ issue(
220
+ context,
221
+ 'invalid-value',
222
+ `${path}.defaultValue`,
223
+ 'Integer parameter defaults must be safe integers.',
224
+ );
225
+ }
226
+ } else if (parameter.type === 'boolean') {
227
+ if (typeof parameter.defaultValue !== 'boolean') {
228
+ issue(
229
+ context,
230
+ 'invalid-value',
231
+ `${path}.defaultValue`,
232
+ 'Boolean parameter defaults must be boolean.',
233
+ );
234
+ }
235
+ } else if (parameter.type === 'trigger') {
236
+ // Triggers always compile with a cleared default.
237
+ } else {
238
+ issue(context, 'invalid-value', `${path}.type`, 'Unknown parameter type.');
239
+ }
240
+ });
241
+
242
+ const layerIds = new Set<string>();
243
+ definition.layers.forEach((layer, layerIndex) => {
244
+ const layerPath = `layers[${layerIndex}]`;
245
+ validateNonEmptyString(context, layer.id, `${layerPath}.id`);
246
+ validateNonEmptyString(context, layer.name, `${layerPath}.name`);
247
+ if (layerIds.has(layer.id)) {
248
+ issue(context, 'duplicate-id', `${layerPath}.id`, `Duplicate layer id "${layer.id}".`);
249
+ }
250
+ layerIds.add(layer.id);
251
+ validateUnitWeight(context, layer.weight ?? 1, `${layerPath}.weight`);
252
+ if (
253
+ layer.blendMode !== undefined
254
+ && layer.blendMode !== 'override'
255
+ && layer.blendMode !== 'additive'
256
+ ) {
257
+ issue(context, 'invalid-value', `${layerPath}.blendMode`, 'Unknown layer blend mode.');
258
+ }
259
+
260
+ const stateIds = new Set<string>();
261
+ layer.states.forEach((state, stateIndex) => {
262
+ const statePath = `${layerPath}.states[${stateIndex}]`;
263
+ validateNonEmptyString(context, state.id, `${statePath}.id`);
264
+ validateNonEmptyString(context, state.name, `${statePath}.name`);
265
+ if (stateIds.has(state.id)) {
266
+ issue(context, 'duplicate-id', `${statePath}.id`, `Duplicate state id "${state.id}".`);
267
+ }
268
+ stateIds.add(state.id);
269
+ validateFinite(context, state.speed ?? 1, `${statePath}.speed`);
270
+ if (
271
+ state.loop !== undefined
272
+ && state.loop !== 'once'
273
+ && state.loop !== 'repeat'
274
+ && state.loop !== 'ping-pong'
275
+ ) {
276
+ issue(context, 'invalid-value', `${statePath}.loop`, 'Unknown state loop mode.');
277
+ }
278
+ if (state.speedParameter !== undefined) {
279
+ validateNumericParameter(context, state.speedParameter, `${statePath}.speedParameter`);
280
+ }
281
+ validateMotion(context, state.motion, `${statePath}.motion`);
282
+ });
283
+
284
+ if (!stateIds.has(layer.initialStateId)) {
285
+ issue(
286
+ context,
287
+ 'missing-reference',
288
+ `${layerPath}.initialStateId`,
289
+ `Initial state "${layer.initialStateId}" does not exist in this layer.`,
290
+ );
291
+ }
292
+
293
+ const transitionIds = new Set<string>();
294
+ layer.transitions.forEach((transition, transitionIndex) => {
295
+ const transitionPath = `${layerPath}.transitions[${transitionIndex}]`;
296
+ validateNonEmptyString(context, transition.id, `${transitionPath}.id`);
297
+ if (transitionIds.has(transition.id)) {
298
+ issue(
299
+ context,
300
+ 'duplicate-id',
301
+ `${transitionPath}.id`,
302
+ `Duplicate transition id "${transition.id}".`,
303
+ );
304
+ }
305
+ transitionIds.add(transition.id);
306
+ if (transition.from !== '*' && !stateIds.has(transition.from)) {
307
+ issue(
308
+ context,
309
+ 'missing-reference',
310
+ `${transitionPath}.from`,
311
+ `Source state "${transition.from}" does not exist in this layer.`,
312
+ );
313
+ }
314
+ if (!stateIds.has(transition.to)) {
315
+ issue(
316
+ context,
317
+ 'missing-reference',
318
+ `${transitionPath}.to`,
319
+ `Destination state "${transition.to}" does not exist in this layer.`,
320
+ );
321
+ }
322
+ validateNonNegativeFinite(context, transition.duration, `${transitionPath}.duration`);
323
+ if (
324
+ transition.hasExitTime !== undefined
325
+ && typeof transition.hasExitTime !== 'boolean'
326
+ ) {
327
+ issue(
328
+ context,
329
+ 'invalid-value',
330
+ `${transitionPath}.hasExitTime`,
331
+ 'hasExitTime must be boolean.',
332
+ );
333
+ }
334
+ if (transition.hasExitTime === true && transition.exitTime === undefined) {
335
+ issue(
336
+ context,
337
+ 'invalid-value',
338
+ `${transitionPath}.exitTime`,
339
+ 'exitTime is required when hasExitTime is true.',
340
+ );
341
+ }
342
+ if (transition.exitTime !== undefined) {
343
+ validateNonNegativeFinite(context, transition.exitTime, `${transitionPath}.exitTime`);
344
+ }
345
+ if (transition.destinationOffset !== undefined) {
346
+ validateNonNegativeFinite(
347
+ context,
348
+ transition.destinationOffset,
349
+ `${transitionPath}.destinationOffset`,
350
+ );
351
+ }
352
+ if (
353
+ transition.interruption !== undefined
354
+ && !INTERRUPTION_VALUES.includes(transition.interruption)
355
+ ) {
356
+ issue(
357
+ context,
358
+ 'invalid-value',
359
+ `${transitionPath}.interruption`,
360
+ 'Unknown transition interruption strategy.',
361
+ );
362
+ }
363
+ transition.conditions.forEach((condition, conditionIndex) => {
364
+ validateCondition(
365
+ context,
366
+ condition,
367
+ `${transitionPath}.conditions[${conditionIndex}]`,
368
+ );
369
+ });
370
+ });
371
+ });
372
+
373
+ return Object.freeze(issues);
374
+ }
375
+
376
+ export function compileAnimationStateMachineDefinition(
377
+ definition: SupportedAnimationStateMachineDefinition,
378
+ ): CompiledAnimation3DStateMachine {
379
+ const issues = validateAnimationStateMachineDefinition(definition);
380
+ if (issues.length > 0) throw new AnimationStateMachineValidationError(issues);
381
+
382
+ const parameterIndexByName = new Map<string, number>();
383
+ const parameters: CompiledAnimation3DParameter[] = definition.parameters.map(
384
+ (parameter, index) => {
385
+ parameterIndexByName.set(parameter.name, index);
386
+ return Object.freeze({
387
+ index,
388
+ name: parameter.name,
389
+ type: parameter.type,
390
+ defaultValue: parameter.type === 'trigger'
391
+ ? 0
392
+ : parameter.type === 'boolean'
393
+ ? (parameter.defaultValue ? 1 : 0)
394
+ : parameter.defaultValue,
395
+ });
396
+ },
397
+ );
398
+
399
+ const layerIndexById = new Map<string, number>();
400
+ const layers: CompiledAnimation3DLayer[] = definition.layers.map((layer, layerIndex) => {
401
+ layerIndexById.set(layer.id, layerIndex);
402
+ const stateIndexById = new Map<string, number>();
403
+ layer.states.forEach((state, stateIndex) => stateIndexById.set(state.id, stateIndex));
404
+ const states: CompiledAnimation3DState[] = layer.states.map((state, stateIndex) =>
405
+ Object.freeze({
406
+ index: stateIndex,
407
+ id: state.id,
408
+ name: state.name,
409
+ motion: compileMotion(state.motion, parameterIndexByName),
410
+ speed: state.speed ?? 1,
411
+ speedParameterIndex: state.speedParameter === undefined
412
+ ? -1
413
+ : parameterIndexByName.get(state.speedParameter)!,
414
+ loop: state.loop ?? 'repeat',
415
+ }),
416
+ );
417
+ const transitions: CompiledAnimation3DTransition[] = layer.transitions.map(
418
+ (transition, transitionIndex) => {
419
+ const conditions = transition.conditions.map(condition =>
420
+ compileCondition(condition, parameterIndexByName));
421
+ const triggerParameterIndices = conditions
422
+ .filter(condition => condition.operator === 'triggered')
423
+ .map(condition => condition.parameterIndex);
424
+ return Object.freeze({
425
+ index: transitionIndex,
426
+ id: transition.id,
427
+ fromStateIndex: transition.from === '*'
428
+ ? -1
429
+ : stateIndexById.get(transition.from)!,
430
+ toStateIndex: stateIndexById.get(transition.to)!,
431
+ conditions: Object.freeze(conditions),
432
+ triggerParameterIndices: Object.freeze(triggerParameterIndices),
433
+ duration: transition.duration,
434
+ hasExitTime: transition.hasExitTime ?? false,
435
+ exitTime: transition.exitTime ?? 0,
436
+ destinationOffset: transition.destinationOffset ?? 0,
437
+ interruption: transition.interruption ?? 'none',
438
+ });
439
+ },
440
+ );
441
+ return Object.freeze({
442
+ index: layerIndex,
443
+ id: layer.id,
444
+ name: layer.name,
445
+ initialStateIndex: stateIndexById.get(layer.initialStateId)!,
446
+ states: Object.freeze(states),
447
+ transitions: Object.freeze(transitions),
448
+ blendMode: layer.blendMode ?? 'override',
449
+ weight: layer.weight ?? 1,
450
+ mask: compileMask(layer.mask),
451
+ stateIndexById,
452
+ });
453
+ });
454
+
455
+ return Object.freeze({
456
+ format: 'haiyue-animation-state-machine-compiled@1',
457
+ id: definition.id,
458
+ name: definition.name,
459
+ parameters: Object.freeze(parameters),
460
+ layers: Object.freeze(layers),
461
+ parameterIndexByName,
462
+ layerIndexById,
463
+ });
464
+ }
465
+
466
+ /** Compatibility aliases for the original 3D-prefixed runtime API. */
467
+ export {
468
+ AnimationStateMachineValidationError as Animation3DStateMachineValidationError,
469
+ };
470
+ export const validateAnimation3DStateMachineDefinition =
471
+ validateAnimationStateMachineDefinition;
472
+ export const compileAnimation3DStateMachineDefinition =
473
+ compileAnimationStateMachineDefinition;
474
+ export const compileAnimation3DStateMachine =
475
+ compileAnimationStateMachineDefinition;
476
+
477
+ function validateMotion(
478
+ context: ValidationContext,
479
+ motion: Animation3DMotionDefinition,
480
+ path: string,
481
+ ): void {
482
+ if (typeof motion !== 'object' || motion === null) {
483
+ issue(context, 'invalid-value', path, 'Motion must be an object.');
484
+ return;
485
+ }
486
+ if (context.motionStack.has(motion)) {
487
+ issue(context, 'recursive-motion', path, 'Recursive motion cycle detected.');
488
+ return;
489
+ }
490
+ context.motionStack.add(motion);
491
+ if (motion.kind === 'clip') {
492
+ validateNonEmptyString(context, motion.clipId, `${path}.clipId`);
493
+ } else if (motion.kind === 'blend-1d') {
494
+ validateNumericParameter(context, motion.parameter, `${path}.parameter`);
495
+ if (motion.children.length === 0) {
496
+ issue(context, 'empty-blend-tree', `${path}.children`, '1D blend tree cannot be empty.');
497
+ }
498
+ let previousThreshold = -Infinity;
499
+ motion.children.forEach((child, childIndex) => {
500
+ const childPath = `${path}.children[${childIndex}]`;
501
+ validateFinite(context, child.threshold, `${childPath}.threshold`);
502
+ if (childIndex > 0 && child.threshold <= previousThreshold) {
503
+ issue(
504
+ context,
505
+ 'invalid-thresholds',
506
+ `${childPath}.threshold`,
507
+ child.threshold === previousThreshold
508
+ ? '1D blend thresholds must be unique.'
509
+ : '1D blend thresholds must be strictly increasing.',
510
+ );
511
+ }
512
+ previousThreshold = child.threshold;
513
+ validateMotion(context, child.motion, `${childPath}.motion`);
514
+ });
515
+ } else if (motion.kind === 'blend-2d') {
516
+ validateNumericParameter(context, motion.parameterX, `${path}.parameterX`);
517
+ validateNumericParameter(context, motion.parameterY, `${path}.parameterY`);
518
+ if (motion.algorithm !== 'cartesian' && motion.algorithm !== 'directional') {
519
+ issue(context, 'invalid-value', `${path}.algorithm`, 'Unknown 2D blend algorithm.');
520
+ }
521
+ if (motion.children.length === 0) {
522
+ issue(context, 'empty-blend-tree', `${path}.children`, '2D blend tree cannot be empty.');
523
+ }
524
+ const positions = new Set<string>();
525
+ motion.children.forEach((child, childIndex) => {
526
+ const childPath = `${path}.children[${childIndex}]`;
527
+ const x = child.position[0];
528
+ const y = child.position[1];
529
+ validateFinite(context, x, `${childPath}.position[0]`);
530
+ validateFinite(context, y, `${childPath}.position[1]`);
531
+ const key = `${x}\u0000${y}`;
532
+ if (positions.has(key)) {
533
+ issue(
534
+ context,
535
+ 'invalid-value',
536
+ `${childPath}.position`,
537
+ '2D blend child positions must be unique.',
538
+ );
539
+ }
540
+ positions.add(key);
541
+ validateMotion(context, child.motion, `${childPath}.motion`);
542
+ });
543
+ } else {
544
+ issue(context, 'invalid-value', `${path}.kind`, 'Unknown motion kind.');
545
+ }
546
+ context.motionStack.delete(motion);
547
+ }
548
+
549
+ function validateCondition(
550
+ context: ValidationContext,
551
+ condition: Animation3DTransitionCondition,
552
+ path: string,
553
+ ): void {
554
+ const parameter = context.parameterByName.get(condition.parameter);
555
+ if (!parameter) {
556
+ issue(
557
+ context,
558
+ 'missing-reference',
559
+ `${path}.parameter`,
560
+ `Parameter "${condition.parameter}" does not exist.`,
561
+ );
562
+ return;
563
+ }
564
+ const operator = condition.operator;
565
+ if (parameter.type === 'float' || parameter.type === 'integer') {
566
+ const valid = operator === 'greater'
567
+ || operator === 'greater-or-equal'
568
+ || operator === 'less'
569
+ || operator === 'less-or-equal'
570
+ || operator === 'equal'
571
+ || operator === 'not-equal';
572
+ if (!valid) {
573
+ issue(
574
+ context,
575
+ 'invalid-operator',
576
+ `${path}.operator`,
577
+ `Operator "${operator}" is invalid for ${parameter.type} parameters.`,
578
+ );
579
+ return;
580
+ }
581
+ const value = 'value' in condition ? condition.value : undefined;
582
+ if (
583
+ typeof value !== 'number'
584
+ || !Number.isFinite(value)
585
+ || (parameter.type === 'integer' && !Number.isSafeInteger(value))
586
+ ) {
587
+ issue(
588
+ context,
589
+ 'parameter-type-mismatch',
590
+ `${path}.value`,
591
+ parameter.type === 'integer'
592
+ ? 'Integer conditions require a safe integer value.'
593
+ : 'Float conditions require a finite numeric value.',
594
+ );
595
+ }
596
+ return;
597
+ }
598
+ if (parameter.type === 'boolean') {
599
+ if (
600
+ operator !== 'equal'
601
+ && operator !== 'not-equal'
602
+ && operator !== 'is-true'
603
+ && operator !== 'is-false'
604
+ ) {
605
+ issue(
606
+ context,
607
+ 'invalid-operator',
608
+ `${path}.operator`,
609
+ `Operator "${operator}" is invalid for boolean parameters.`,
610
+ );
611
+ return;
612
+ }
613
+ if (
614
+ (operator === 'equal' || operator === 'not-equal')
615
+ && (!('value' in condition) || typeof condition.value !== 'boolean')
616
+ ) {
617
+ issue(
618
+ context,
619
+ 'parameter-type-mismatch',
620
+ `${path}.value`,
621
+ 'Boolean equality conditions require a boolean value.',
622
+ );
623
+ }
624
+ return;
625
+ }
626
+ if (operator !== 'triggered') {
627
+ issue(
628
+ context,
629
+ 'invalid-operator',
630
+ `${path}.operator`,
631
+ `Operator "${operator}" is invalid for trigger parameters.`,
632
+ );
633
+ }
634
+ }
635
+
636
+ function validateNumericParameter(
637
+ context: ValidationContext,
638
+ parameterName: string,
639
+ path: string,
640
+ ): void {
641
+ const parameter = context.parameterByName.get(parameterName);
642
+ if (!parameter) {
643
+ issue(
644
+ context,
645
+ 'missing-reference',
646
+ path,
647
+ `Parameter "${parameterName}" does not exist.`,
648
+ );
649
+ } else if (parameter.type !== 'float' && parameter.type !== 'integer') {
650
+ issue(
651
+ context,
652
+ 'parameter-type-mismatch',
653
+ path,
654
+ `Parameter "${parameterName}" must be float or integer.`,
655
+ );
656
+ }
657
+ }
658
+
659
+ function compileMotion(
660
+ motion: Animation3DMotionDefinition,
661
+ parameterIndexByName: ReadonlyMap<string, number>,
662
+ ): CompiledAnimation3DMotion {
663
+ if (motion.kind === 'clip') {
664
+ return Object.freeze({ kind: 'clip', clipId: motion.clipId });
665
+ }
666
+ if (motion.kind === 'blend-1d') {
667
+ return Object.freeze({
668
+ kind: 'blend-1d',
669
+ parameterIndex: parameterIndexByName.get(motion.parameter)!,
670
+ children: Object.freeze(motion.children.map(child => Object.freeze({
671
+ threshold: child.threshold,
672
+ motion: compileMotion(child.motion, parameterIndexByName),
673
+ }))),
674
+ });
675
+ }
676
+ return Object.freeze({
677
+ kind: 'blend-2d',
678
+ algorithm: motion.algorithm,
679
+ parameterXIndex: parameterIndexByName.get(motion.parameterX)!,
680
+ parameterYIndex: parameterIndexByName.get(motion.parameterY)!,
681
+ children: Object.freeze(motion.children.map((child, declarationIndex) =>
682
+ Object.freeze({
683
+ position: Object.freeze([child.position[0], child.position[1]]) as readonly [number, number],
684
+ motion: compileMotion(child.motion, parameterIndexByName),
685
+ declarationIndex,
686
+ }))),
687
+ });
688
+ }
689
+
690
+ function compileCondition(
691
+ condition: Animation3DTransitionCondition,
692
+ parameterIndexByName: ReadonlyMap<string, number>,
693
+ ): CompiledAnimation3DCondition {
694
+ const rawValue = 'value' in condition ? condition.value : 0;
695
+ return Object.freeze({
696
+ parameterIndex: parameterIndexByName.get(condition.parameter)!,
697
+ operator: condition.operator,
698
+ value: typeof rawValue === 'boolean' ? (rawValue ? 1 : 0) : rawValue,
699
+ });
700
+ }
701
+
702
+ function compileMask(
703
+ mask: Animation3DBindingMask | undefined,
704
+ ): Animation3DBindingMask | null {
705
+ if (!mask) return null;
706
+ return Object.freeze({
707
+ ...(mask.include === undefined
708
+ ? {}
709
+ : { include: Object.freeze([...mask.include]) }),
710
+ ...(mask.exclude === undefined
711
+ ? {}
712
+ : { exclude: Object.freeze([...mask.exclude]) }),
713
+ });
714
+ }
715
+
716
+ function validateNonEmptyString(
717
+ context: ValidationContext,
718
+ value: string,
719
+ path: string,
720
+ ): void {
721
+ if (typeof value !== 'string' || value.length === 0) {
722
+ issue(context, 'invalid-value', path, 'Expected a non-empty string.');
723
+ }
724
+ }
725
+
726
+ function validateFinite(
727
+ context: ValidationContext,
728
+ value: number,
729
+ path: string,
730
+ ): void {
731
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
732
+ issue(context, 'invalid-value', path, 'Expected a finite number.');
733
+ }
734
+ }
735
+
736
+ function validateNonNegativeFinite(
737
+ context: ValidationContext,
738
+ value: number,
739
+ path: string,
740
+ ): void {
741
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
742
+ issue(context, 'invalid-value', path, 'Expected a finite number greater than or equal to zero.');
743
+ }
744
+ }
745
+
746
+ function validateUnitWeight(
747
+ context: ValidationContext,
748
+ value: number,
749
+ path: string,
750
+ ): void {
751
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0 || value > 1) {
752
+ issue(context, 'invalid-value', path, 'Layer weight must be a finite number in [0, 1].');
753
+ }
754
+ }
755
+
756
+ function issue(
757
+ context: ValidationContext,
758
+ code: Animation3DStateMachineValidationCode,
759
+ path: string,
760
+ message: string,
761
+ ): void {
762
+ context.issues.push(Object.freeze({ code, path, message }));
763
+ }