@vune-ui/animation 0.1.20

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 (68) hide show
  1. package/ARCHITECTURE.md +470 -0
  2. package/CHANGELOG.md +88 -0
  3. package/LICENSE +21 -0
  4. package/PERFORMANCE.md +151 -0
  5. package/README.md +630 -0
  6. package/dist/index.d.ts +474 -0
  7. package/dist/src/canvas/index.d.ts +15 -0
  8. package/dist/src/canvas/index.js +67 -0
  9. package/dist/src/constraints/index.d.ts +33 -0
  10. package/dist/src/constraints/index.js +346 -0
  11. package/dist/src/core/bezier.js +51 -0
  12. package/dist/src/core/composition.js +17 -0
  13. package/dist/src/core/controls.js +22 -0
  14. package/dist/src/core/default-engine.js +20 -0
  15. package/dist/src/core/easing.js +58 -0
  16. package/dist/src/core/engine.js +1031 -0
  17. package/dist/src/core/frame-budget.js +30 -0
  18. package/dist/src/core/index.d.ts +43 -0
  19. package/dist/src/core/index.js +17 -0
  20. package/dist/src/core/js-spring-batch.js +57 -0
  21. package/dist/src/core/kinetics.js +140 -0
  22. package/dist/src/core/math.js +20 -0
  23. package/dist/src/core/motion-value.js +53 -0
  24. package/dist/src/core/planner.js +72 -0
  25. package/dist/src/core/specs.js +70 -0
  26. package/dist/src/dom/index.d.ts +41 -0
  27. package/dist/src/dom/index.js +364 -0
  28. package/dist/src/gesture/index.d.ts +66 -0
  29. package/dist/src/gesture/index.js +376 -0
  30. package/dist/src/index.js +53 -0
  31. package/dist/src/interpolate/color.js +223 -0
  32. package/dist/src/interpolate/css.d.ts +13 -0
  33. package/dist/src/interpolate/css.js +34 -0
  34. package/dist/src/interpolate/index.d.ts +13 -0
  35. package/dist/src/interpolate/index.js +55 -0
  36. package/dist/src/interpolate/transform.js +247 -0
  37. package/dist/src/layout/index.d.ts +56 -0
  38. package/dist/src/layout/index.js +485 -0
  39. package/dist/src/material/index.d.ts +9 -0
  40. package/dist/src/material/index.js +70 -0
  41. package/dist/src/path/index.d.ts +37 -0
  42. package/dist/src/path/index.js +527 -0
  43. package/dist/src/render/frame-batcher.js +52 -0
  44. package/dist/src/scroll/index.d.ts +55 -0
  45. package/dist/src/scroll/index.js +233 -0
  46. package/dist/src/timeline/index.d.ts +147 -0
  47. package/dist/src/timeline/index.js +849 -0
  48. package/dist/src/transition/index.d.ts +88 -0
  49. package/dist/src/transition/index.js +369 -0
  50. package/dist/src/wasm/index.d.ts +29 -0
  51. package/dist/src/wasm/index.js +8 -0
  52. package/dist/src/wasm/loader.js +55 -0
  53. package/dist/src/wasm/shared-wasm-spring-batch.js +52 -0
  54. package/dist/src/wasm/wasm-spring-batch.js +52 -0
  55. package/dist/src/webgl/index.d.ts +22 -0
  56. package/dist/src/webgl/index.js +94 -0
  57. package/dist/src/webgpu/index.d.ts +35 -0
  58. package/dist/src/webgpu/index.js +73 -0
  59. package/dist/src/webgpu/spring-batch.js +218 -0
  60. package/dist/src/worker/index.d.ts +17 -0
  61. package/dist/src/worker/index.js +1 -0
  62. package/dist/src/worker/shared-spring-worker.js +218 -0
  63. package/dist/src/worker/shared-worker.js +75 -0
  64. package/dist/wasm/kernel-scalar.wasm +0 -0
  65. package/dist/wasm/kernel-shared-scalar.wasm +0 -0
  66. package/dist/wasm/kernel-shared-simd.wasm +0 -0
  67. package/dist/wasm/kernel-simd.wasm +0 -0
  68. package/package.json +113 -0
package/PERFORMANCE.md ADDED
@@ -0,0 +1,151 @@
1
+ # Performance snapshot
2
+
3
+ Measurements below include a fresh 0.7.0 verification run. The existing spring/Worker/timeline paths are unchanged semantically; new scroll, constraint, and renderer-bridge measurements were collected in the same Node environment. They are microbenchmarks unless explicitly stated and do not include browser layout, paint, compositing, framework overhead, or real input latency.
4
+
5
+ ```text
6
+ Node.js v22.16.0
7
+ Clang 17.0.0 wasm32 target
8
+ ```
9
+
10
+ ## Dense spring kernel
11
+
12
+ ```sh
13
+ npm run bench -- 10000 600
14
+ ```
15
+
16
+ ```text
17
+ JS 66.12 ms total | 0.1102 ms/frame | 10000 springs
18
+ WASM-simd 13.65 ms total | 0.0227 ms/frame | 10000 springs
19
+ ```
20
+
21
+ The design property that matters more than the exact ratio is unchanged: the WASM path evaluates a dense Structure-of-Arrays batch instead of crossing the JS/WASM boundary once per value. After promotion, active spring state remains in WASM linear memory.
22
+
23
+ ## Shared Worker path
24
+
25
+ ```sh
26
+ npm run bench:worker -- 10000 300
27
+ ```
28
+
29
+ ```text
30
+ JS 40.02 ms solver wall | 0.1334 ms/frame | 10000 active springs
31
+ WASM-simd 7.43 ms solver wall | 0.0248 ms/frame | 10000 active springs
32
+ Worker-simd 20.08 ms solver wall | 0.0669 ms/frame | 10000 active springs
33
+ Worker submit 0.00086 ms/frame main-thread submission cost
34
+ ```
35
+
36
+ Worker wall time is expected to vary with scheduler noise. Its main benefit is moving a large numeric workload away from the UI thread while keeping the same shared state buffers. `Atomics.waitAsync()` is used when available, so supported runtimes do not need a per-frame Worker completion message.
37
+
38
+ ## Compiled timeline/keyframe tracks
39
+
40
+ ```sh
41
+ npm run bench:timeline -- 1000 600
42
+ npm run bench:timeline -- 10000 600
43
+ ```
44
+
45
+ ```text
46
+ Timeline 36.46 ms total | 0.0608 ms/frame | 1000 numeric tracks | 600 frames
47
+ Timeline 336.66 ms total | 0.5611 ms/frame | 10000 numeric tracks | 600 frames
48
+ ```
49
+
50
+ The timeline benchmark uses three-keyframe numeric tracks with cubic-bezier easing and velocity propagation. Keyframe times and numeric values are compiled into typed arrays. Built-in cubic-bezier curves are compiled once into a shared 256-entry lookup table, avoiding Newton/bisection solving for every track on every frame.
51
+
52
+ The lookup path was verified against the exact cubic-bezier evaluator with a normalized position error below `0.0002` across the built-in non-linear curves. Numeric timeline sampling itself creates no per-frame timeline metadata objects.
53
+
54
+ Timeline drivers receive real elapsed wall time even though spring solvers keep their own defensive `dt` clamp. That lets a finite timeline catch up immediately after a suspended tab. Infinite-repeat callbacks are coalesced into one callback per engine frame with a `crossedIterations` count, so a long suspension cannot create an unbounded callback loop.
55
+
56
+ ## SVG path morph
57
+
58
+ ```sh
59
+ npm run bench:path -- 256 10000
60
+ ```
61
+
62
+ ```text
63
+ Path preprocess 10.41 ms | 256 segments
64
+ Numeric sample 23.43 ms | 0.00234 ms/frame | 10000 frames
65
+ String format 544.45 ms | 0.54445 ms/frame | 1000 frames
66
+ ```
67
+
68
+ After path topology preprocessing, the numeric morph is cheap. For long SVG paths, formatting the `d` string dominates. `PathMorpher.sampleInto()` exists so Canvas/WebGL/custom renderers can consume the reusable numeric buffer without string serialization.
69
+
70
+ ## Gesture / direct-manipulation primitives
71
+
72
+ ```sh
73
+ npm run bench:gestures -- 500000
74
+ ```
75
+
76
+ ```text
77
+ rubber-band 6.99 ms | 14.0 ns/op
78
+ analytic decay 13.15 ms | 26.3 ns/op
79
+ analytic bounce spring 32.55 ms | 65.1 ns/op
80
+ velocity regression 83.89 ms | 335.6 ns/sample
81
+ ```
82
+
83
+ `VelocityTracker` stores history in a fixed typed-array ring buffer. Release physics remains caller-thread analytical math because a drag generally owns one or two axes; dispatching that amount of arithmetic to WASM/Worker would cost more than computing it locally.
84
+
85
+ ## MotionValue / DOM allocation policy
86
+
87
+ `MotionValue.subscribeValue()` is the value-only hot subscription path. Internal DOM, structured interpolation, and layout-progress bindings use it when available, so ordinary render bindings do not allocate `{ previous, velocity, version }` metadata on each frame. The older detailed `subscribe()` API remains compatible for consumers that need velocity/version metadata.
88
+
89
+ The DOM adapter also keeps one global dirty-element queue, so a frame updating many elements schedules one flush rather than one microtask per element.
90
+
91
+ ## Interpretation
92
+
93
+ Exact values are machine- and workload-dependent. Backend thresholds are policy inputs, not universal constants. `FrameBudgetGovernor` exists so an integration can respond to measured main-thread pressure rather than tuning around one benchmark machine.
94
+
95
+ ## State transitions and matched layout (0.6.0)
96
+
97
+ ```sh
98
+ npm run bench:transitions -- 10000 1000
99
+ ```
100
+
101
+ Final median-of-nine verification run:
102
+
103
+ ```text
104
+ state graph numeric 0.2851 ms/frame | 10000 MotionValues
105
+ state graph shared 0.1764 ms/frame | 10000 callback values, 1 progress animation
106
+ shared layout setup 5.3111 ms total | 1000 matched targets
107
+ shared layout write 0.2963 ms/frame | 1000 matched targets, 1 progress animation
108
+ ```
109
+
110
+ The numeric state-graph case uses long-running timing animations so all 10,000 values stay active for the measured frames. Spring-based state changes use the existing dense spring backend and can therefore promote to WASM/Worker under the normal thresholds.
111
+
112
+ The structured case routes 10,000 callback values through one scalar progress animation. Numeric callback interpolation is inlined (`from + delta * progress`) and current structured values are only snapshotted on interruption/completion instead of being written to a `Map` every frame.
113
+
114
+ Shared-layout setup includes keyed snapshot matching, target measurement, projection construction, decomposition, and the initial write for 1,000 synthetic Element-like targets. Steady-state projection reuses one six-number matrix buffer per item and writes `will-change`/`transform-origin` only at setup, not every frame. This cut the synthetic 1,000-target write path from roughly 0.7 ms/frame during development to about 0.32 ms/frame in the final run.
115
+
116
+ This is still not a browser rendering benchmark: style recalculation, real layout, paint, and compositing are excluded. The important invariant is that one matched group consumes one motion solver entry regardless of target count.
117
+
118
+
119
+ ## Scroll tracker and constraint graph (0.7.0)
120
+
121
+ ```sh
122
+ npm run bench:constraints -- 10000 1000
123
+ npm run bench:scroll -- 500000
124
+ ```
125
+
126
+ Verification run:
127
+
128
+ ```text
129
+ Constraints 10000: 124.61 ms total | 0.1246 ms/frame | 10000 chained relations
130
+ ScrollTracker 500000: 201.23 ms total | 402.5 ns/sample
131
+ ```
132
+
133
+ The constraint benchmark is intentionally adversarial: 10,000 affine relations form one dependency chain, so every result depends on the previous one and all 10,000 instructions must execute. The graph is already compiled before timing. Steady-state evaluation uses typed value/velocity arrays and a compact topological instruction stream.
134
+
135
+ The scroll benchmark includes `VelocityTracker` regression plus offset/progress `MotionValue` commits. Real DOM scrolling is normally cheaper in aggregate because delivered events are coalesced and scroll metrics are read once per animation frame rather than once per raw event.
136
+
137
+ ## Renderer bridges (0.7.0)
138
+
139
+ ```sh
140
+ npm run bench:renderers -- 1000 500
141
+ ```
142
+
143
+ Synthetic verification run with 1,000 scalar `MotionValue`s changing on every frame:
144
+
145
+ ```text
146
+ Canvas snapshot 1000: 0.0337 ms/frame | one draw callback
147
+ WebGL uniforms 1000: 0.0561 ms/frame | 1000 uniform writes/frame
148
+ WebGPU buffer 1000: 0.0361 ms/frame | one writeBuffer/frame
149
+ ```
150
+
151
+ These numbers measure JavaScript adapter overhead against fake renderer APIs, not actual GPU driver cost or rasterization. The useful invariant is submission shape: Canvas gets one retained numeric snapshot and one draw callback, while WebGPU packs all 1,000 scalars into one retained staging array and one buffer upload. WebGL still requires one API uniform write per declared scalar uniform; real high-count data should therefore be packed into UBOs/textures/buffers rather than represented as thousands of standalone uniforms.