@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,282 +0,0 @@
1
- import type { Entity } from '@haiyue/engine';
2
- import type { AssetManager } from '@haiyue/engine/assets';
3
- import type { ParsedAnimation } from '@haiyue/animation-spec';
4
- import type { Animation2DExtensionRegistry } from './Animation2DExtensionRegistry.js';
5
- import type { HyaAnimation2DEffectPayload } from './HyaAnimation2DClipAdapter.js';
6
- import {
7
- Animation2DRuntime,
8
- type Animation2DRuntimeNode,
9
- } from './Animation2DRuntime.js';
10
- import type { Animation2DEffectEvent, Animation2DPose } from './runtime/mixer/index.js';
11
- import {
12
- audioAutoplayRejectedDiagnostic,
13
- type AnimationStateMachineChannelDiagnostic,
14
- } from '../animation-state-machine/AnimationStateMachineChannels.js';
15
-
16
- /** State-machine-only pose writer kept out of the ordinary Animation2D bundle. */
17
- export class Animation2DStateMachineVisualRuntime extends Animation2DRuntime {
18
- private readonly _particleOwners = new Map<string, string[]>();
19
- private readonly _audioOwners = new Map<string, string[]>();
20
- private readonly _effectPayloads = new Map<string, HyaAnimation2DEffectPayload>();
21
- private readonly _diagnostics: AnimationStateMachineChannelDiagnostic[] = [];
22
- private readonly _reportedAudioRejections = new Set<string>();
23
-
24
- constructor(
25
- owner: Entity,
26
- animation: ParsedAnimation,
27
- runtimeExtensions?: Animation2DExtensionRegistry,
28
- assetManager?: AssetManager,
29
- ) {
30
- super(owner, animation, runtimeExtensions, assetManager);
31
- for (const node of this._nodes) {
32
- for (const particle of node.particles) {
33
- particle.playing = false;
34
- particle.emitting = false;
35
- particle.clear();
36
- }
37
- for (const audio of node.audio) audio.exitStateMachine();
38
- }
39
- }
40
-
41
- get diagnostics(): readonly AnimationStateMachineChannelDiagnostic[] {
42
- return this._diagnostics;
43
- }
44
-
45
- get sideEffectOwnerCount(): number {
46
- return ownerCount(this._particleOwners) + ownerCount(this._audioOwners);
47
- }
48
-
49
- resetSideEffects(): void {
50
- this._particleOwners.clear();
51
- this._audioOwners.clear();
52
- this._effectPayloads.clear();
53
- for (const node of this._nodes) {
54
- for (const particle of node.particles) {
55
- particle.playing = false;
56
- particle.emitting = false;
57
- particle.clear();
58
- }
59
- for (const audio of node.audio) audio.exitStateMachine();
60
- }
61
- }
62
-
63
- applyPose(pose: Animation2DPose, playing = this._playing, speed = this._speed): void {
64
- this._playing = playing;
65
- this._speed = speed;
66
- this._opacityMemo.clear();
67
- for (const node of this._nodes) {
68
- node.entity.disabled = false;
69
- node.transform.setPosition(node.initialX, node.initialY);
70
- node.transform.rotation = node.initialRotation;
71
- node.transform.setScale(node.initialScaleX, node.initialScaleY);
72
- node.opacity = node.initialOpacity;
73
- }
74
- for (const channel of pose.channels) {
75
- const node = this._nodesById.get(channel.binding.targetId);
76
- if (!node) {
77
- throw new ReferenceError(`Animation2D pose references unknown node "${channel.binding.targetId}".`);
78
- }
79
- switch (channel.binding.path) {
80
- case 'transform.position': {
81
- const value = numericPoseValue(channel.value, channel.binding.id, 2);
82
- node.transform.setPosition(value[0]!, -value[1]!);
83
- break;
84
- }
85
- case 'transform.rotation': {
86
- const value = numericPoseValue(channel.value, channel.binding.id, 1);
87
- node.transform.rotation = -value[0]!;
88
- break;
89
- }
90
- case 'transform.scale': {
91
- const value = numericPoseValue(channel.value, channel.binding.id, 2);
92
- node.transform.setScale(value[0]!, value[1]!);
93
- break;
94
- }
95
- case 'opacity': {
96
- const value = numericPoseValue(channel.value, channel.binding.id, 1);
97
- node.opacity = clamp(value[0]!, 0, 1);
98
- break;
99
- }
100
- case 'visibility':
101
- if (typeof channel.value !== 'boolean') {
102
- throw new TypeError(`Animation2D visibility binding "${channel.binding.id}" requires a boolean.`);
103
- }
104
- node.entity.disabled = !channel.value;
105
- break;
106
- default:
107
- if (!this._applyStateMachineVisualChannel(node, channel.binding.path, channel.value)) {
108
- throw new RangeError(`Animation2D state-machine runtime does not support pose binding path "${channel.binding.path}".`);
109
- }
110
- }
111
- }
112
- for (const node of this._nodes) this._applyVisualOpacity(node);
113
- for (const [key, owners] of this._audioOwners) {
114
- if (owners.length === 0) continue;
115
- const target = parseEffectTargetKey(key);
116
- const node = this._nodesById.get(target.targetId);
117
- this._audioTarget(key)?.updateStateMachineProperties(
118
- speed,
119
- node ? this._resolveOpacity(node) : 1,
120
- );
121
- }
122
- for (const effect of pose.effects) this._applyEffect(effect, playing, speed);
123
- this._lastAppliedTime = Number.NaN;
124
- }
125
-
126
- override setPlaying(playing: boolean): void {
127
- this._playing = playing;
128
- for (const [key, owners] of this._particleOwners) {
129
- if (owners.length === 0) continue;
130
- const target = this._particleTarget(key);
131
- if (target) target.playing = playing;
132
- }
133
- for (const [key, owners] of this._audioOwners) {
134
- if (owners.length === 0) continue;
135
- const target = this._audioTarget(key);
136
- target?.setStateMachinePlaying(playing, this._speed, reason => this._reportAudioRejection(key, reason));
137
- }
138
- }
139
-
140
- override destroy(): void {
141
- this.resetSideEffects();
142
- super.destroy();
143
- }
144
-
145
- private _applyVisualOpacity(node: Animation2DRuntimeNode): void {
146
- const opacity = this._resolveOpacity(node);
147
- if (node.deferredVisuals.length > 0 && this._isNodeActive(node)) {
148
- for (const deferred of node.deferredVisuals.splice(0)) this._materializeCoreVisual(node, deferred);
149
- }
150
- for (const visual of node.visuals) {
151
- const alpha = visual.baseAlpha * opacity;
152
- if (Math.abs(alpha - visual.lastAlpha) < 1e-6) continue;
153
- visual.color[3] = alpha;
154
- visual.component.revision++;
155
- visual.lastAlpha = alpha;
156
- }
157
- for (const extension of node.extensions) extension.setOpacity?.(opacity);
158
- }
159
-
160
- private _applyEffect(effect: Animation2DEffectEvent, playing: boolean, speed: number): void {
161
- const payload = effect.cue.payload as HyaAnimation2DEffectPayload | undefined;
162
- if (!payload || typeof payload.targetId !== 'string' || !Number.isSafeInteger(payload.slot)) {
163
- throw new TypeError(`Animation2D effect cue "${effect.cue.id}" has an invalid HYA target payload.`);
164
- }
165
- const key = effectTargetKey(payload);
166
- this._effectPayloads.set(key, payload);
167
- const owners = effect.cue.kind === 'particle'
168
- ? this._particleOwners
169
- : this._audioOwners;
170
- const stack = owners.get(key) ?? [];
171
- if (!owners.has(key)) owners.set(key, stack);
172
-
173
- if (effect.lifecycle === 'enter') {
174
- const existing = stack.indexOf(effect.actionId);
175
- if (existing >= 0) stack.splice(existing, 1);
176
- stack.push(effect.actionId);
177
- if (effect.cue.kind === 'particle') {
178
- const particle = this._particleTarget(key);
179
- if (particle) {
180
- particle.emitting = true;
181
- particle.restart(true);
182
- particle.playing = playing;
183
- }
184
- } else {
185
- const audio = this._audioTarget(key);
186
- const node = this._nodesById.get(payload.targetId);
187
- const opacity = node ? this._resolveOpacity(node) : 1;
188
- audio?.enterStateMachine(playing, speed, opacity, reason => this._reportAudioRejection(key, reason));
189
- }
190
- return;
191
- }
192
-
193
- if (effect.lifecycle === 'exit') {
194
- const index = stack.indexOf(effect.actionId);
195
- const wasDominant = index === stack.length - 1;
196
- if (index >= 0) stack.splice(index, 1);
197
- if (stack.length === 0) {
198
- owners.delete(key);
199
- if (effect.cue.kind === 'particle') {
200
- const particle = this._particleTarget(key);
201
- if (particle) {
202
- particle.playing = false;
203
- particle.emitting = false;
204
- particle.clear();
205
- }
206
- } else this._audioTarget(key)?.exitStateMachine();
207
- } else if (wasDominant && effect.cue.kind === 'particle') {
208
- const particle = this._particleTarget(key);
209
- if (particle) {
210
- particle.emitting = true;
211
- particle.restart(true);
212
- particle.playing = playing;
213
- }
214
- }
215
- return;
216
- }
217
-
218
- if (stack[stack.length - 1] !== effect.actionId) return;
219
- if (effect.lifecycle === 'loop') return;
220
- if (effect.cue.kind === 'particle') {
221
- const particle = this._particleTarget(key);
222
- if (particle) {
223
- particle.emitting = true;
224
- particle.restart(true);
225
- particle.playing = playing;
226
- }
227
- } else {
228
- const audio = this._audioTarget(key);
229
- const node = this._nodesById.get(payload.targetId);
230
- const opacity = node ? this._resolveOpacity(node) : 1;
231
- audio?.restartStateMachine(playing, speed, opacity, reason => this._reportAudioRejection(key, reason));
232
- }
233
- }
234
-
235
- private _particleTarget(key: string) {
236
- const target = parseEffectTargetKey(key);
237
- return this._nodesById.get(target.targetId)?.particles[target.slot];
238
- }
239
-
240
- private _audioTarget(key: string) {
241
- const target = parseEffectTargetKey(key);
242
- return this._nodesById.get(target.targetId)?.audio[target.slot];
243
- }
244
-
245
- private _reportAudioRejection(key: string, reason: unknown): void {
246
- if (this._reportedAudioRejections.has(key)) return;
247
- this._reportedAudioRejections.add(key);
248
- const target = parseEffectTargetKey(key);
249
- const sourcePath = this._effectPayloads.get(key)?.sourcePath
250
- ?? `$.nodes[id=${JSON.stringify(target.targetId)}].components[audio=${target.slot}]`;
251
- this._diagnostics.push(audioAutoplayRejectedDiagnostic(sourcePath, reason));
252
- }
253
- }
254
-
255
- function effectTargetKey(payload: HyaAnimation2DEffectPayload): string {
256
- return `${payload.targetId}\u0000${payload.slot}`;
257
- }
258
-
259
- function parseEffectTargetKey(key: string): { readonly targetId: string; readonly slot: number } {
260
- const separator = key.lastIndexOf('\u0000');
261
- return {
262
- targetId: key.slice(0, separator),
263
- slot: Number(key.slice(separator + 1)),
264
- };
265
- }
266
-
267
- function ownerCount(owners: ReadonlyMap<string, readonly string[]>): number {
268
- let count = 0;
269
- for (const stack of owners.values()) count += stack.length;
270
- return count;
271
- }
272
-
273
- function numericPoseValue(value: unknown, bindingId: string, size: number): Readonly<Float32Array> {
274
- if (!(value instanceof Float32Array) || value.length < size) {
275
- throw new TypeError(`Animation2D numeric binding "${bindingId}" requires ${size} Float32 values.`);
276
- }
277
- return value;
278
- }
279
-
280
- function clamp(value: number, min: number, max: number): number {
281
- return Math.min(max, Math.max(min, value));
282
- }
@@ -1,72 +0,0 @@
1
- import { System, type Entity, type World } from '@haiyue/engine';
2
- import type { AssetManager } from '@haiyue/engine/assets';
3
- import { Animation2DComponent } from './Animation2DComponent';
4
- import { Animation2DRuntime } from './Animation2DRuntime';
5
-
6
- export interface Animation2DSystemOptions {
7
- priority?: number;
8
- /** Shared engine asset manager used by sprite2d resources. */
9
- assetManager?: AssetManager;
10
- }
11
-
12
- export class Animation2DSystem extends System {
13
- private readonly _assetManager: AssetManager | undefined;
14
-
15
- constructor(options: Animation2DSystemOptions = {}) {
16
- super({ all: [Animation2DComponent] });
17
- this.name = 'Animation2DSystem';
18
- if (options.priority !== undefined) this.priority = options.priority;
19
- this._assetManager = options.assetManager;
20
- }
21
-
22
- override update(world: World, _time: number, delta: number): this {
23
- if (this.disabled) return this;
24
- const entities = this.entitySet.get(world);
25
- if (!entities) return this;
26
- for (const entity of entities) this._updateEntity(entity, delta);
27
- return this;
28
- }
29
-
30
- override destroy(): this {
31
- for (const world of this.usedBy) {
32
- const entities = this.entitySet.get(world);
33
- if (!entities) continue;
34
- for (const entity of entities) entity.getComponent(Animation2DComponent)?._disposeRuntime();
35
- }
36
- return super.destroy();
37
- }
38
-
39
- private _updateEntity(entity: Entity, delta: number): void {
40
- const component = entity.getComponent(Animation2DComponent);
41
- if (!component) return;
42
- if (component.disabled) {
43
- component._disposeRuntime();
44
- return;
45
- }
46
- if (component.completed && component.animation.endBehavior === 'destroy' && !component.playing) return;
47
- component._runtime ??= new Animation2DRuntime(entity, component.animation, component.runtimeExtensions, this._assetManager);
48
- if (component.playing && delta > 0 && component.speed > 0) {
49
- component.currentTime += delta * 0.001 * component.speed;
50
- if (component.currentTime >= component.animation.duration) {
51
- if (component.loop) {
52
- component.currentTime %= component.animation.duration;
53
- component._forceParticleSeek = true;
54
- } else {
55
- component.currentTime = component.animation.duration;
56
- component.playing = false;
57
- component.completed = true;
58
- if (component.animation.endBehavior === 'destroy') {
59
- component._disposeRuntime();
60
- component._needsApply = false;
61
- return;
62
- }
63
- }
64
- }
65
- component._needsApply = true;
66
- }
67
- if (!component._needsApply) return;
68
- component._runtime.apply(component.currentTime, component.playing, component.speed, component._forceParticleSeek);
69
- component._needsApply = false;
70
- component._forceParticleSeek = false;
71
- }
72
- }
@@ -1,84 +0,0 @@
1
- import {
2
- ANIMATION_MIME_TYPE,
3
- parseAnimation,
4
- type AnimationResource,
5
- type AnimationParseOptions,
6
- type ParsedAnimation,
7
- } from '@haiyue/animation-spec';
8
- import type { AssetLoaderRegistration } from '@haiyue/engine/assets';
9
-
10
- export const HAIYUE_ANIMATION_ASSET_TYPE = 'animation/haiyue' as const;
11
-
12
- export interface AnimationAssetLoaderOptions {
13
- parse?: AnimationParseOptions;
14
- fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
15
- }
16
-
17
- let nextAnimationLoaderId = 1;
18
-
19
- /** Creates an AssetManager loader without installing source-format converters in the runtime. */
20
- export function createAnimationAssetLoader(
21
- options: AnimationAssetLoaderOptions = {},
22
- ): AssetLoaderRegistration<ParsedAnimation> {
23
- const fetchResource = options.fetch ?? fetch;
24
- const loaderId = nextAnimationLoaderId++;
25
- return {
26
- type: HAIYUE_ANIMATION_ASSET_TYPE,
27
- extensions: ['.hya'],
28
- mimeTypes: [ANIMATION_MIME_TYPE],
29
- aliases: ['hya'],
30
- async load(url, context) {
31
- context.setPhase('loading');
32
- const networkKey = `network:hya:${url}`;
33
- let buffer = context.cache.network.get(networkKey) as ArrayBuffer | undefined;
34
- let responseUrl = '';
35
- if (!buffer) {
36
- const response = await fetchResource(url, { signal: context.signal });
37
- if (!response.ok) throw new Error(`Failed to load Haiyue animation (${response.status} ${response.statusText}): ${url}`);
38
- responseUrl = response.url;
39
- buffer = await response.arrayBuffer();
40
- if (context.signal.aborted) throw context.signal.reason;
41
- context.cache.network.set(networkKey, buffer, buffer.byteLength);
42
- }
43
- context.reportProgress(buffer.byteLength, buffer.byteLength);
44
- context.setPhase('parsing');
45
- const parsedKey = `parsed:hya:${loaderId}:${url}`;
46
- let animation = context.cache.parsed.get(parsedKey) as ParsedAnimation | undefined;
47
- if (!animation) {
48
- animation = resolveAnimationResourceUris(
49
- parseAnimation(buffer, options.parse),
50
- responseUrl || absoluteAnimationUrl(url),
51
- );
52
- context.cache.parsed.set(parsedKey, animation, buffer.byteLength);
53
- }
54
- return animation;
55
- },
56
- };
57
- }
58
-
59
- /** Package-relative resources resolve from the fetched HYA, including redirects. */
60
- function resolveAnimationResourceUris(animation: ParsedAnimation, sourceUrl: string): ParsedAnimation {
61
- if (!sourceUrl || animation.resources.length === 0) return animation;
62
- const resources = animation.resources.map(resource => {
63
- try {
64
- return Object.freeze({ ...resource, uri: new URL(resource.uri, sourceUrl).href });
65
- } catch {
66
- return resource;
67
- }
68
- }) as readonly AnimationResource[];
69
- return Object.freeze({ ...animation, resources: Object.freeze(resources) });
70
- }
71
-
72
- function absoluteAnimationUrl(url: string): string {
73
- try {
74
- return new URL(url).href;
75
- } catch {
76
- const base = typeof globalThis.location === 'object' ? globalThis.location.href : '';
77
- if (!base) return '';
78
- try {
79
- return new URL(url, base).href;
80
- } catch {
81
- return '';
82
- }
83
- }
84
- }
@@ -1,140 +0,0 @@
1
- import type { AnimationAudioComponent, AnimationNode } from '@haiyue/animation-spec';
2
-
3
- /** HTML media-backed audio clip with composition-time seek and playback-rate synchronization. */
4
- export class AnimationAudioClip {
5
- private readonly element: HTMLAudioElement | null;
6
- private readonly nodeStart: number;
7
- private readonly nodeEnd: number;
8
- private readonly startOffset: number;
9
- private readonly baseVolume: number;
10
- private readonly clipRate: number;
11
- private readonly loop: boolean;
12
- private playPending = false;
13
- private destroyed = false;
14
- private stateMachineActive = false;
15
- private playRequestEpoch = 0;
16
-
17
- constructor(uri: string, component: AnimationAudioComponent, node: Readonly<AnimationNode>, animationDuration: number) {
18
- this.nodeStart = node.start ?? 0;
19
- this.nodeEnd = this.nodeStart + (node.duration ?? animationDuration - this.nodeStart);
20
- this.startOffset = component.startOffset ?? 0;
21
- this.baseVolume = component.volume ?? 1;
22
- this.clipRate = component.playbackRate ?? 1;
23
- this.loop = component.loop ?? false;
24
- this.element = typeof Audio === 'undefined' ? null : new Audio(uri);
25
- if (this.element) {
26
- this.element.preload = 'auto';
27
- this.element.loop = this.loop;
28
- }
29
- }
30
-
31
- sync(compositionTime: number, playing: boolean, speed: number, opacity: number): void {
32
- const element = this.element;
33
- if (!element || this.destroyed) return;
34
- const active = compositionTime >= this.nodeStart && compositionTime <= this.nodeEnd;
35
- element.volume = clamp(this.baseVolume * opacity, 0, 1);
36
- element.playbackRate = clamp(this.clipRate * speed, 0.0625, 16);
37
- if (!active || !playing || speed <= 0) {
38
- this._cancelPendingPlay();
39
- return;
40
- }
41
- let target = this.startOffset + (compositionTime - this.nodeStart) * this.clipRate;
42
- if (this.loop && Number.isFinite(element.duration) && element.duration > 0) target %= element.duration;
43
- if (Number.isFinite(target) && Math.abs(element.currentTime - target) > 0.12) {
44
- try { element.currentTime = Math.max(0, target); } catch { /* Metadata may not be loaded yet. */ }
45
- }
46
- if (element.paused) this._requestPlay();
47
- }
48
-
49
- enterStateMachine(
50
- playing: boolean,
51
- speed: number,
52
- opacity: number,
53
- rejected: (reason: unknown) => void,
54
- ): void {
55
- const element = this.element;
56
- if (!element || this.destroyed) return;
57
- this.stateMachineActive = true;
58
- element.volume = clamp(this.baseVolume * opacity, 0, 1);
59
- element.playbackRate = clamp(this.clipRate * Math.max(speed, 0.0625), 0.0625, 16);
60
- try { element.currentTime = Math.max(0, this.startOffset); } catch { /* Metadata may not be loaded yet. */ }
61
- if (playing && speed > 0) this._requestPlay(rejected);
62
- else this._cancelPendingPlay();
63
- }
64
-
65
- restartStateMachine(
66
- playing: boolean,
67
- speed: number,
68
- opacity: number,
69
- rejected: (reason: unknown) => void,
70
- ): void {
71
- this.enterStateMachine(playing, speed, opacity, rejected);
72
- }
73
-
74
- setStateMachinePlaying(
75
- playing: boolean,
76
- speed: number,
77
- rejected: (reason: unknown) => void,
78
- ): void {
79
- const element = this.element;
80
- if (!element || this.destroyed || !this.stateMachineActive) return;
81
- element.playbackRate = clamp(this.clipRate * Math.max(speed, 0.0625), 0.0625, 16);
82
- if (playing && speed > 0) this._requestPlay(rejected);
83
- else this._cancelPendingPlay();
84
- }
85
-
86
- updateStateMachineProperties(speed: number, opacity: number): void {
87
- const element = this.element;
88
- if (!element || this.destroyed || !this.stateMachineActive) return;
89
- element.volume = clamp(this.baseVolume * opacity, 0, 1);
90
- element.playbackRate = clamp(this.clipRate * Math.max(speed, 0.0625), 0.0625, 16);
91
- }
92
-
93
- exitStateMachine(): void {
94
- this.stateMachineActive = false;
95
- this._cancelPendingPlay();
96
- }
97
-
98
- pause(): void { this._cancelPendingPlay(); }
99
-
100
- destroy(): void {
101
- if (this.destroyed) return;
102
- this.destroyed = true;
103
- this.stateMachineActive = false;
104
- const element = this.element;
105
- if (!element) return;
106
- this._cancelPendingPlay();
107
- element.removeAttribute('src');
108
- element.load();
109
- }
110
-
111
- private _requestPlay(rejected?: (reason: unknown) => void): void {
112
- const element = this.element;
113
- if (!element || this.playPending || this.destroyed) return;
114
- const epoch = ++this.playRequestEpoch;
115
- const stateMachineRequest = rejected !== undefined;
116
- this.playPending = true;
117
- void element.play()
118
- .then(() => {
119
- if (epoch !== this.playRequestEpoch
120
- || this.destroyed
121
- || (stateMachineRequest && !this.stateMachineActive)) element.pause();
122
- })
123
- .catch(reason => {
124
- if (epoch === this.playRequestEpoch) rejected?.(reason);
125
- })
126
- .finally(() => {
127
- if (epoch === this.playRequestEpoch) this.playPending = false;
128
- });
129
- }
130
-
131
- private _cancelPendingPlay(): void {
132
- this.playRequestEpoch++;
133
- this.playPending = false;
134
- this.element?.pause();
135
- }
136
- }
137
-
138
- function clamp(value: number, minimum: number, maximum: number): number {
139
- return Math.min(maximum, Math.max(minimum, value));
140
- }