@pixerate/editor 0.27.0 → 0.29.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 (112) hide show
  1. package/README.md +44 -2
  2. package/dist/HistoryManager-DWSLd6Tf.d.ts +150 -0
  3. package/dist/HistoryManager-DeQQMBCj.d.cts +150 -0
  4. package/dist/agent/index.cjs +20 -427
  5. package/dist/agent/index.cjs.map +1 -1
  6. package/dist/agent/index.d.cts +4 -342
  7. package/dist/agent/index.d.ts +4 -342
  8. package/dist/agent/index.js +14 -421
  9. package/dist/agent/index.js.map +1 -1
  10. package/dist/animation/index.cjs +62 -0
  11. package/dist/animation/index.cjs.map +1 -0
  12. package/dist/animation/index.d.cts +226 -0
  13. package/dist/animation/index.d.ts +226 -0
  14. package/dist/animation/index.js +62 -0
  15. package/dist/animation/index.js.map +1 -0
  16. package/dist/{builtins-nMXh9sT3.d.cts → builtins-DxC3aUR2.d.cts} +2 -2
  17. package/dist/{builtins-haN82vjT.d.ts → builtins-NGxNxQfJ.d.ts} +2 -2
  18. package/dist/canvas/index.cjs +177 -743
  19. package/dist/canvas/index.cjs.map +1 -1
  20. package/dist/canvas/index.d.cts +6 -289
  21. package/dist/canvas/index.d.ts +6 -289
  22. package/dist/canvas/index.js +49 -615
  23. package/dist/canvas/index.js.map +1 -1
  24. package/dist/chunk-36BLROHV.js +438 -0
  25. package/dist/chunk-36BLROHV.js.map +1 -0
  26. package/dist/{chunk-JT7AXQTE.js → chunk-3RPOW4CS.js} +7 -7
  27. package/dist/{chunk-AGR7EVRW.cjs → chunk-6MDQKHRH.cjs} +6 -6
  28. package/dist/{chunk-AGR7EVRW.cjs.map → chunk-6MDQKHRH.cjs.map} +1 -1
  29. package/dist/chunk-A6PHCAGX.cjs +87 -0
  30. package/dist/chunk-A6PHCAGX.cjs.map +1 -0
  31. package/dist/{chunk-HRMEDT2L.js → chunk-D6AVOTSD.js} +6 -85
  32. package/dist/chunk-D6AVOTSD.js.map +1 -0
  33. package/dist/{chunk-ARRTP33I.js → chunk-D6S5M7HV.js} +2 -2
  34. package/dist/{chunk-ARRTP33I.js.map → chunk-D6S5M7HV.js.map} +1 -1
  35. package/dist/{chunk-6IO7WUSU.js → chunk-DDADOHJW.js} +17 -17
  36. package/dist/{chunk-CPOKFNBG.cjs → chunk-I6BZB5ZH.cjs} +2 -2
  37. package/dist/{chunk-CPOKFNBG.cjs.map → chunk-I6BZB5ZH.cjs.map} +1 -1
  38. package/dist/{chunk-4BVP64JJ.cjs → chunk-K2UYKJ6M.cjs} +24 -103
  39. package/dist/chunk-K2UYKJ6M.cjs.map +1 -0
  40. package/dist/chunk-PIIAZV3L.cjs +244 -0
  41. package/dist/chunk-PIIAZV3L.cjs.map +1 -0
  42. package/dist/chunk-PWJARCI4.js +637 -0
  43. package/dist/chunk-PWJARCI4.js.map +1 -0
  44. package/dist/{chunk-G2I4QJOT.cjs → chunk-QKLRAA4T.cjs} +3 -244
  45. package/dist/chunk-QKLRAA4T.cjs.map +1 -0
  46. package/dist/{chunk-2H7ZHPEJ.js → chunk-QVZZGT4X.js} +1 -242
  47. package/dist/chunk-QVZZGT4X.js.map +1 -0
  48. package/dist/chunk-TGD52FEZ.js +87 -0
  49. package/dist/chunk-TGD52FEZ.js.map +1 -0
  50. package/dist/chunk-TTYCN6ZH.cjs +637 -0
  51. package/dist/chunk-TTYCN6ZH.cjs.map +1 -0
  52. package/dist/{chunk-YK5TATOF.cjs → chunk-U7VGDSNY.cjs} +3 -3
  53. package/dist/{chunk-YK5TATOF.cjs.map → chunk-U7VGDSNY.cjs.map} +1 -1
  54. package/dist/chunk-V7CC7RZ6.cjs +438 -0
  55. package/dist/chunk-V7CC7RZ6.cjs.map +1 -0
  56. package/dist/chunk-YK57D7PW.js +244 -0
  57. package/dist/chunk-YK57D7PW.js.map +1 -0
  58. package/dist/commands/index.cjs +2 -2
  59. package/dist/commands/index.cjs.map +1 -1
  60. package/dist/commands/index.d.cts +2 -2
  61. package/dist/commands/index.d.ts +2 -2
  62. package/dist/commands/index.js +1 -1
  63. package/dist/commands/index.js.map +1 -1
  64. package/dist/easing-B6iAnJHk.d.cts +74 -0
  65. package/dist/easing-B6iAnJHk.d.ts +74 -0
  66. package/dist/extensions/index.cjs +5 -5
  67. package/dist/extensions/index.cjs.map +1 -1
  68. package/dist/extensions/index.js +4 -4
  69. package/dist/generation/index.cjs +4 -4
  70. package/dist/generation/index.cjs.map +1 -1
  71. package/dist/generation/index.js +3 -3
  72. package/dist/generation/index.js.map +1 -1
  73. package/dist/history/index.cjs +4 -2
  74. package/dist/history/index.cjs.map +1 -1
  75. package/dist/history/index.d.cts +3 -149
  76. package/dist/history/index.d.ts +3 -149
  77. package/dist/history/index.js +5 -3
  78. package/dist/image-editor/index.cjs.map +1 -1
  79. package/dist/image-editor/index.js.map +1 -1
  80. package/dist/index.cjs +24 -22
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.cts +3 -2
  83. package/dist/index.d.ts +3 -2
  84. package/dist/index.js +112 -110
  85. package/dist/index.js.map +1 -1
  86. package/dist/parameters/index.cjs +1283 -0
  87. package/dist/parameters/index.cjs.map +1 -0
  88. package/dist/parameters/index.d.cts +595 -0
  89. package/dist/parameters/index.d.ts +595 -0
  90. package/dist/parameters/index.js +1283 -0
  91. package/dist/parameters/index.js.map +1 -0
  92. package/dist/spreadsheet/index.cjs +4 -4
  93. package/dist/spreadsheet/index.cjs.map +1 -1
  94. package/dist/spreadsheet/index.js +8 -8
  95. package/dist/tokens/index.cjs +4 -2
  96. package/dist/tokens/index.cjs.map +1 -1
  97. package/dist/tokens/index.js +6 -4
  98. package/dist/tools/index.cjs +31 -0
  99. package/dist/tools/index.cjs.map +1 -0
  100. package/dist/tools/index.d.cts +343 -0
  101. package/dist/tools/index.d.ts +343 -0
  102. package/dist/tools/index.js +31 -0
  103. package/dist/tools/index.js.map +1 -0
  104. package/dist/{types-GT5a5YAX.d.cts → types-DsiXGmjo.d.cts} +1 -1
  105. package/dist/{types-GT5a5YAX.d.ts → types-DsiXGmjo.d.ts} +1 -1
  106. package/package.json +16 -1
  107. package/dist/chunk-2H7ZHPEJ.js.map +0 -1
  108. package/dist/chunk-4BVP64JJ.cjs.map +0 -1
  109. package/dist/chunk-G2I4QJOT.cjs.map +0 -1
  110. package/dist/chunk-HRMEDT2L.js.map +0 -1
  111. /package/dist/{chunk-JT7AXQTE.js.map → chunk-3RPOW4CS.js.map} +0 -0
  112. /package/dist/{chunk-6IO7WUSU.js.map → chunk-DDADOHJW.js.map} +0 -0
@@ -1,13 +1,3 @@
1
- import {
2
- TokenError,
3
- getTokenCollection,
4
- getTokenVariable,
5
- hexToRgba,
6
- isTokenInScope,
7
- normalizeTokenColor,
8
- resolveToken,
9
- rgbaToHex
10
- } from "../chunk-HRMEDT2L.js";
11
1
  import {
12
2
  DEFAULT_NODE_HEIGHT,
13
3
  DEFAULT_NODE_WIDTH,
@@ -27,79 +17,46 @@ import {
27
17
  DEFAULT_ARRANGE_SHORTCUTS,
28
18
  matchArrangeShortcut
29
19
  } from "../chunk-7DWMJCAT.js";
30
-
31
- // src/canvas/clock.ts
32
- var pageHidden = () => typeof document !== "undefined" && document.hidden;
33
- var realClock = {
34
- live: true,
35
- now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
36
- frame: () => new Promise((resolve) => {
37
- if (typeof requestAnimationFrame === "function" && !pageHidden()) {
38
- requestAnimationFrame(() => resolve());
39
- } else {
40
- setTimeout(resolve, 16);
41
- }
42
- }),
43
- sleep: (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)))
44
- };
45
- var settle = () => new Promise((resolve) => setTimeout(resolve, 0));
46
- var ManualClock = class {
47
- live = false;
48
- time;
49
- frames = [];
50
- sleepers = [];
51
- seq = 0;
52
- constructor(start = 0) {
53
- this.time = start;
54
- }
55
- now() {
56
- return this.time;
57
- }
58
- frame() {
59
- return new Promise((resolve) => this.frames.push(resolve));
60
- }
61
- sleep(ms) {
62
- return new Promise(
63
- (resolve) => this.sleepers.push({
64
- at: this.time + Math.max(0, ms),
65
- seq: this.seq++,
66
- resolve
67
- })
68
- );
69
- }
70
- /** Whether any frames or sleep timers are currently pending. */
71
- get pending() {
72
- return this.frames.length > 0 || this.sleepers.length > 0;
73
- }
74
- /** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */
75
- async advance(ms) {
76
- const end = this.time + Math.max(0, ms);
77
- await settle();
78
- while (true) {
79
- let next;
80
- for (const s of this.sleepers) {
81
- if (s.at <= end && (!next || s.at < next.at || s.at === next.at && s.seq < next.seq)) {
82
- next = s;
83
- }
84
- }
85
- if (!next) break;
86
- this.sleepers.splice(this.sleepers.indexOf(next), 1);
87
- this.time = Math.max(this.time, next.at);
88
- next.resolve();
89
- await settle();
90
- }
91
- this.time = end;
92
- const dueFrames = this.frames.splice(0, this.frames.length);
93
- for (const resolveFrame of dueFrames) {
94
- resolveFrame();
95
- }
96
- await settle();
97
- }
98
- /** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */
99
- async tick(fps = 60) {
100
- await this.advance(Math.round(1e3 / fps));
101
- }
102
- };
20
+ import {
21
+ TokenError,
22
+ getTokenCollection,
23
+ getTokenVariable,
24
+ isTokenInScope,
25
+ resolveToken
26
+ } from "../chunk-D6AVOTSD.js";
27
+ import {
28
+ ANIMATION_EASING_LABELS,
29
+ ANIMATION_EASING_PRESETS,
30
+ ANIMATION_TIME_EPSILON,
31
+ AnimationPlayer,
32
+ CUBIC_BEZIER_PRESETS,
33
+ ManualClock,
34
+ createAnimationPlayer,
35
+ cubicBezierAt,
36
+ easingFromInfluence,
37
+ easingLabel,
38
+ easingToCss,
39
+ evaluateEasing,
40
+ evaluateTrack,
41
+ formatOklab,
42
+ interpolateAnimationValue,
43
+ isAnimationEasing,
44
+ isAnimationKeyframe,
45
+ mixColorsOklab,
46
+ normalizeKeyframes,
47
+ oklabToRgb,
48
+ pageHidden,
49
+ parseCssEasing,
50
+ parseOklab,
51
+ realClock,
52
+ resolveEasing,
53
+ rgbToOklab,
54
+ springAt,
55
+ wrapAnimationTime
56
+ } from "../chunk-PWJARCI4.js";
57
+ import {
58
+ normalizeTokenColor
59
+ } from "../chunk-TGD52FEZ.js";
103
60
 
104
61
  // src/canvas/trajectory.ts
105
62
  var defaultEasing = (t) => --t * t * t + 1;
@@ -2277,7 +2234,7 @@ function fitSingleFrom(pts, u, t0, t1) {
2277
2234
  let best = generate(pts, u, t0, t1);
2278
2235
  let [bestErr, bestSplit] = maxError(pts, best, u);
2279
2236
  const params = u.slice();
2280
- for (let round3 = 0; round3 < MAX_REPARAM; round3++) {
2237
+ for (let round2 = 0; round2 < MAX_REPARAM; round2++) {
2281
2238
  for (let i = 0; i < params.length; i++) params[i] = newton(best, pts[i], params[i]);
2282
2239
  const c = generate(pts, params, t0, t1);
2283
2240
  const [e, s] = maxError(pts, c, params);
@@ -7843,244 +7800,8 @@ function pruneCanvasTokenModes(nodes, state) {
7843
7800
  return changed ? out : nodes;
7844
7801
  }
7845
7802
 
7846
- // src/canvas/animation/easing.ts
7847
- var ANIMATION_EASING_PRESETS = [
7848
- "linear",
7849
- "ease",
7850
- "ease-in",
7851
- "ease-out",
7852
- "ease-in-out",
7853
- "ease-in-back",
7854
- "ease-out-back",
7855
- "spring",
7856
- "hold"
7857
- ];
7858
- var ANIMATION_EASING_LABELS = {
7859
- linear: "Linear",
7860
- hold: "Hold",
7861
- ease: "Ease",
7862
- "ease-in": "Ease in",
7863
- "ease-out": "Ease out",
7864
- "ease-in-out": "Ease in-out",
7865
- "ease-in-back": "Back in",
7866
- "ease-out-back": "Back out",
7867
- spring: "Spring"
7868
- };
7869
- var CUBIC_BEZIER_PRESETS = {
7870
- linear: [0, 0, 1, 1],
7871
- ease: [0.25, 0.1, 0.25, 1],
7872
- "ease-in": [0.42, 0, 1, 1],
7873
- "ease-out": [0, 0, 0.58, 1],
7874
- "ease-in-out": [0.42, 0, 0.58, 1],
7875
- "ease-in-back": [0.36, 0, 0.66, -0.56],
7876
- "ease-out-back": [0.34, 1.56, 0.64, 1]
7877
- };
7878
- var DEFAULT_SPRING = { stiffness: 170, damping: 26, mass: 1, velocity: 0 };
7879
- var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
7880
- var finite2 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
7881
- function cubicBezierAt(x1, y1, x2, y2, x) {
7882
- if (x <= 0) return 0;
7883
- if (x >= 1) return 1;
7884
- x1 = clamp(x1, 0, 1);
7885
- x2 = clamp(x2, 0, 1);
7886
- const bx = (s2) => 3 * (1 - s2) * (1 - s2) * s2 * x1 + 3 * (1 - s2) * s2 * s2 * x2 + s2 * s2 * s2;
7887
- const by = (s2) => 3 * (1 - s2) * (1 - s2) * s2 * y1 + 3 * (1 - s2) * s2 * s2 * y2 + s2 * s2 * s2;
7888
- const dbx = (s2) => 3 * (1 - s2) * (1 - s2) * x1 + 6 * (1 - s2) * s2 * (x2 - x1) + 3 * s2 * s2 * (1 - x2);
7889
- let s = x;
7890
- for (let i = 0; i < 8; i++) {
7891
- const d = dbx(s);
7892
- if (Math.abs(d) < 1e-9) break;
7893
- const next = s - (bx(s) - x) / d;
7894
- if (!(next >= 0 && next <= 1)) break;
7895
- s = next;
7896
- }
7897
- if (Math.abs(bx(s) - x) > 1e-7) {
7898
- let lo = 0;
7899
- let hi = 1;
7900
- for (let i = 0; i < 60; i++) {
7901
- s = (lo + hi) / 2;
7902
- if (bx(s) < x) lo = s;
7903
- else hi = s;
7904
- }
7905
- }
7906
- return by(s);
7907
- }
7908
- function springAt(spring, seconds) {
7909
- const stiffness = Math.max(1e-6, finite2(spring.stiffness, DEFAULT_SPRING.stiffness));
7910
- const damping = Math.max(0, finite2(spring.damping, DEFAULT_SPRING.damping));
7911
- const mass = Math.max(1e-6, finite2(spring.mass, DEFAULT_SPRING.mass));
7912
- const v0 = -finite2(spring.velocity, DEFAULT_SPRING.velocity);
7913
- const t = Math.max(0, seconds);
7914
- const w0 = Math.sqrt(stiffness / mass);
7915
- const zeta = damping / (2 * Math.sqrt(stiffness * mass));
7916
- let x;
7917
- if (zeta < 1 - 1e-6) {
7918
- const wd = w0 * Math.sqrt(1 - zeta * zeta);
7919
- x = Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + (zeta * w0 + v0) / wd * Math.sin(wd * t));
7920
- } else if (zeta <= 1 + 1e-6) {
7921
- x = Math.exp(-w0 * t) * (1 + (w0 + v0) * t);
7922
- } else {
7923
- const r = Math.sqrt(zeta * zeta - 1);
7924
- const s1 = -w0 * (zeta - r);
7925
- const s2 = -w0 * (zeta + r);
7926
- const c2 = (v0 - s1) / (s2 - s1);
7927
- const c1 = 1 - c2;
7928
- x = c1 * Math.exp(s1 * t) + c2 * Math.exp(s2 * t);
7929
- }
7930
- return 1 - x;
7931
- }
7932
- function resolveEasing(easing) {
7933
- if (easing === "hold") return "hold";
7934
- if (easing === "spring") return { type: "spring", ...DEFAULT_SPRING };
7935
- if (typeof easing === "string") {
7936
- const preset = CUBIC_BEZIER_PRESETS[easing];
7937
- if (preset) return { type: "cubic-bezier", x1: preset[0], y1: preset[1], x2: preset[2], y2: preset[3] };
7938
- const parsed = parseCssEasing(easing);
7939
- return parsed ? resolveEasing(parsed) : { type: "cubic-bezier", x1: 0, y1: 0, x2: 1, y2: 1 };
7940
- }
7941
- if (easing && typeof easing === "object") {
7942
- if (easing.type === "spring") {
7943
- return {
7944
- type: "spring",
7945
- stiffness: finite2(easing.stiffness, DEFAULT_SPRING.stiffness),
7946
- damping: finite2(easing.damping, DEFAULT_SPRING.damping),
7947
- mass: finite2(easing.mass, DEFAULT_SPRING.mass),
7948
- velocity: finite2(easing.velocity, DEFAULT_SPRING.velocity)
7949
- };
7950
- }
7951
- if (easing.type === "cubic-bezier") {
7952
- return {
7953
- type: "cubic-bezier",
7954
- x1: clamp(finite2(easing.x1, 0), 0, 1),
7955
- y1: finite2(easing.y1, 0),
7956
- x2: clamp(finite2(easing.x2, 1), 0, 1),
7957
- y2: finite2(easing.y2, 1)
7958
- };
7959
- }
7960
- }
7961
- return { type: "cubic-bezier", x1: 0, y1: 0, x2: 1, y2: 1 };
7962
- }
7963
- function evaluateEasing(easing, u, durationMs = 1e3) {
7964
- if (!(u > 0)) return 0;
7965
- if (u >= 1) return 1;
7966
- const resolved = resolveEasing(easing);
7967
- if (resolved === "hold") return 0;
7968
- if (resolved.type === "spring") return springAt(resolved, u * Math.max(0, durationMs) / 1e3);
7969
- const { x1, y1, x2, y2 } = resolved;
7970
- if (x1 === y1 && x2 === y2) return u;
7971
- return cubicBezierAt(x1, y1, x2, y2, u);
7972
- }
7973
- function easingFromInfluence(outInfluence = 1 / 3, inInfluence = 1 / 3) {
7974
- return {
7975
- type: "cubic-bezier",
7976
- x1: clamp(outInfluence, 0.01, 1),
7977
- y1: 0,
7978
- x2: 1 - clamp(inInfluence, 0.01, 1),
7979
- y2: 1
7980
- };
7981
- }
7982
- var NUMBER = String.raw`\s*(-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)\s*`;
7983
- var CUBIC_RE = new RegExp(`^cubic-bezier\\(${NUMBER},${NUMBER},${NUMBER},${NUMBER}\\)$`, "i");
7984
- function parseCssEasing(text) {
7985
- const value = text.trim().toLowerCase();
7986
- if (value.length > 200) return null;
7987
- if (ANIMATION_EASING_PRESETS.includes(value)) return value;
7988
- if (value === "step-end" || /^steps\(\s*1\s*(,\s*(end|jump-end)\s*)?\)$/.test(value)) return "hold";
7989
- const m = CUBIC_RE.exec(value);
7990
- if (!m) return null;
7991
- const [x1, y1, x2, y2] = m.slice(1).map(Number);
7992
- if (![x1, y1, x2, y2].every(Number.isFinite) || x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) return null;
7993
- return { type: "cubic-bezier", x1, y1, x2, y2 };
7994
- }
7995
- function isAnimationEasing(value) {
7996
- if (typeof value === "string") return parseCssEasing(value) !== null;
7997
- if (typeof value !== "object" || value === null) return false;
7998
- const e = value;
7999
- if (e.type === "spring") return true;
8000
- return e.type === "cubic-bezier" && [e.x1, e.y1, e.x2, e.y2].every((v) => typeof v === "number" && Number.isFinite(v));
8001
- }
8002
- var round = (v, digits = 4) => {
8003
- const p = 10 ** digits;
8004
- return Math.round(v * p) / p;
8005
- };
8006
- function easingToCss(easing, durationMs = 1e3, samples = 24) {
8007
- const resolved = resolveEasing(easing);
8008
- if (resolved === "hold") return "steps(1, end)";
8009
- if (resolved.type === "spring") {
8010
- const n = Math.max(2, Math.floor(samples));
8011
- const points = [];
8012
- for (let i = 0; i <= n; i++) points.push(String(round(i === n ? 1 : springAt(resolved, i / n * durationMs / 1e3))));
8013
- return `linear(${points.join(", ")})`;
8014
- }
8015
- const { x1, y1, x2, y2 } = resolved;
8016
- for (const [name, p] of Object.entries(CUBIC_BEZIER_PRESETS)) {
8017
- if (["linear", "ease", "ease-in", "ease-out", "ease-in-out"].includes(name) && p[0] === x1 && p[1] === y1 && p[2] === x2 && p[3] === y2) {
8018
- return name;
8019
- }
8020
- }
8021
- return `cubic-bezier(${round(x1)}, ${round(y1)}, ${round(x2)}, ${round(y2)})`;
8022
- }
8023
- function easingLabel(easing) {
8024
- if (easing === void 0 || easing === null) return ANIMATION_EASING_LABELS.linear;
8025
- if (typeof easing === "string") return ANIMATION_EASING_LABELS[easing] ?? easing;
8026
- return easing.type === "spring" ? "Spring" : "Custom";
8027
- }
8028
-
8029
- // src/canvas/animation/color.ts
8030
- var toLinear = (c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
8031
- var toGamma = (c) => c <= 31308e-7 ? 12.92 * c : 1.055 * Math.sign(c) * Math.abs(c) ** (1 / 2.4) - 0.055;
8032
- function rgbToOklab(r, g, b, alpha = 1) {
8033
- const lr = toLinear(r);
8034
- const lg = toLinear(g);
8035
- const lb = toLinear(b);
8036
- const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
8037
- const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
8038
- const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
8039
- return {
8040
- l: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
8041
- a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
8042
- b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
8043
- alpha
8044
- };
8045
- }
8046
- function oklabToRgb(color) {
8047
- const l_ = color.l + 0.3963377774 * color.a + 0.2158037573 * color.b;
8048
- const m_ = color.l - 0.1055613458 * color.a - 0.0638541728 * color.b;
8049
- const s_ = color.l - 0.0894841775 * color.a - 1.291485548 * color.b;
8050
- const l = l_ ** 3;
8051
- const m = m_ ** 3;
8052
- const s = s_ ** 3;
8053
- const clamp01 = (v) => Math.min(1, Math.max(0, v));
8054
- return {
8055
- r: clamp01(toGamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s)),
8056
- g: clamp01(toGamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s)),
8057
- b: clamp01(toGamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s)),
8058
- a: clamp01(color.alpha)
8059
- };
8060
- }
8061
- function parseOklab(input) {
8062
- const hex = normalizeTokenColor(input);
8063
- if (hex === null) return null;
8064
- const c = hexToRgba(hex);
8065
- return rgbToOklab(c.r, c.g, c.b, c.a);
8066
- }
8067
- function formatOklab(color) {
8068
- const { r, g, b, a } = oklabToRgb(color);
8069
- return rgbaToHex(r, g, b, a);
8070
- }
8071
- function mixColorsOklab(from, to, t) {
8072
- const a = parseOklab(from);
8073
- const b = parseOklab(to);
8074
- if (!a || !b) return null;
8075
- const alpha = a.alpha + (b.alpha - a.alpha) * t;
8076
- const premul = (k) => a[k] * a.alpha + (b[k] * b.alpha - a[k] * a.alpha) * t;
8077
- if (alpha <= 1e-9) return formatOklab({ l: a.l + (b.l - a.l) * t, a: 0, b: 0, alpha: 0 });
8078
- return formatOklab({ l: premul("l") / alpha, a: premul("a") / alpha, b: premul("b") / alpha, alpha });
8079
- }
8080
-
8081
7803
  // src/canvas/animation/model.ts
8082
7804
  var ANIMATION_DATA_KEY = "animation";
8083
- var ANIMATION_TIME_EPSILON = 1e-6;
8084
7805
  var num = (value) => {
8085
7806
  if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
8086
7807
  if (typeof value === "string") {
@@ -8221,37 +7942,6 @@ function clampAnimationValue(property, value) {
8221
7942
  if (property.max !== void 0) v = Math.min(property.max, v);
8222
7943
  return v;
8223
7944
  }
8224
- function isValue(value) {
8225
- return typeof value === "number" && Number.isFinite(value) || typeof value === "string";
8226
- }
8227
- function isAnimationKeyframe(value) {
8228
- if (typeof value !== "object" || value === null) return false;
8229
- const k = value;
8230
- return typeof k.time === "number" && Number.isFinite(k.time) && isValue(k.value) && (k.easing === void 0 || isAnimationEasing(k.easing));
8231
- }
8232
- var sortedCache = /* @__PURE__ */ new WeakMap();
8233
- function normalizeKeyframes(keyframes) {
8234
- if (!Array.isArray(keyframes)) return [];
8235
- const cached = sortedCache.get(keyframes);
8236
- if (cached && cached.items.length === keyframes.length && cached.items.every((k, i) => k === keyframes[i])) return cached.out;
8237
- const indexed = keyframes.map((k, i) => ({ k, i })).filter(({ k }) => isAnimationKeyframe(k)).sort((a, b) => a.k.time - b.k.time || a.i - b.i);
8238
- const out = [];
8239
- let lastIndex = -1;
8240
- for (const { k, i } of indexed) {
8241
- const prev = out[out.length - 1];
8242
- if (prev && Math.abs(k.time - prev.time) <= ANIMATION_TIME_EPSILON) {
8243
- if (i > lastIndex) {
8244
- out[out.length - 1] = k;
8245
- lastIndex = i;
8246
- }
8247
- continue;
8248
- }
8249
- out.push(k);
8250
- lastIndex = i;
8251
- }
8252
- sortedCache.set(keyframes, { items: [...keyframes], out });
8253
- return out;
8254
- }
8255
7945
  function getNodeAnimation(node) {
8256
7946
  const raw = node?.data?.[ANIMATION_DATA_KEY];
8257
7947
  if (typeof raw !== "object" || raw === null || typeof raw.tracks !== "object" || raw.tracks === null) return null;
@@ -8289,45 +7979,6 @@ function withNodeAnimation(node, animation) {
8289
7979
 
8290
7980
  // src/canvas/animation/evaluate.ts
8291
7981
  var nodesOf = (doc) => Array.isArray(doc) ? doc : doc.nodes;
8292
- function interpolateAnimationValue(from, to, t, type = "number") {
8293
- if (typeof from === "number" && typeof to === "number") return from + (to - from) * t;
8294
- if (t <= 0) return from;
8295
- if (t >= 1) return to;
8296
- if (type === "color" || typeof from === "string" && typeof to === "string") {
8297
- const mixed = mixColorsOklab(from, to, t);
8298
- if (mixed !== null) return mixed;
8299
- }
8300
- return from;
8301
- }
8302
- function segmentIndex(keys, time) {
8303
- let lo = 0;
8304
- let hi = keys.length - 1;
8305
- let found = -1;
8306
- while (lo <= hi) {
8307
- const mid = lo + hi >> 1;
8308
- if (keys[mid].time <= time) {
8309
- found = mid;
8310
- lo = mid + 1;
8311
- } else hi = mid - 1;
8312
- }
8313
- return found;
8314
- }
8315
- function evaluateTrack(track, time, type = "number") {
8316
- const keyframes = Array.isArray(track) ? track : track?.keyframes;
8317
- const keys = normalizeKeyframes(keyframes);
8318
- if (keys.length === 0) return void 0;
8319
- if (!(time > keys[0].time)) return keys[0].value;
8320
- const last = keys[keys.length - 1];
8321
- if (time >= last.time) return last.value;
8322
- const i = segmentIndex(keys, time);
8323
- const a = keys[i];
8324
- const b = keys[i + 1];
8325
- if (time === a.time) return a.value;
8326
- const span = b.time - a.time;
8327
- const u = (time - a.time) / span;
8328
- if (a.easing === "hold") return a.value;
8329
- return interpolateAnimationValue(a.value, b.value, evaluateEasing(a.easing, u, span), type);
8330
- }
8331
7982
  function getAnimationDuration(doc) {
8332
7983
  let end = 0;
8333
7984
  for (const node of nodesOf(doc)) {
@@ -8341,17 +7992,6 @@ function getAnimationDuration(doc) {
8341
7992
  }
8342
7993
  return end;
8343
7994
  }
8344
- function wrapAnimationTime(time, duration, loop = "none") {
8345
- if (!Number.isFinite(time)) return 0;
8346
- if (!(duration > 0)) return 0;
8347
- if (loop === "loop") return (time % duration + duration) % duration;
8348
- if (loop === "ping-pong") {
8349
- const period = duration * 2;
8350
- const m = (time % period + period) % period;
8351
- return m <= duration ? m : period - m;
8352
- }
8353
- return Math.min(duration, Math.max(0, time));
8354
- }
8355
7995
  function evaluateAnimation(doc, time, options = {}) {
8356
7996
  const only = options.ids ? new Set(options.ids) : null;
8357
7997
  const out = {};
@@ -8873,212 +8513,6 @@ function animateNode(nodes, nodeId, options) {
8873
8513
  return { nodes: draft.commit(), refs };
8874
8514
  }
8875
8515
 
8876
- // src/canvas/animation/player.ts
8877
- var AnimationPlayer = class {
8878
- clock;
8879
- durationSource;
8880
- onTime;
8881
- onEnd;
8882
- time;
8883
- playing = false;
8884
- scrubbing = false;
8885
- resumeAfterScrub = false;
8886
- loop;
8887
- rate;
8888
- /** Unwrapped time at `anchorAt` (keeps the ping-pong direction across frames). */
8889
- anchorRaw = 0;
8890
- anchorAt = 0;
8891
- generation = 0;
8892
- cached;
8893
- listeners = /* @__PURE__ */ new Set();
8894
- constructor(options = {}) {
8895
- this.clock = options.clock ?? realClock;
8896
- this.durationSource = options.duration ?? 1e3;
8897
- this.loop = options.loop ?? "none";
8898
- this.rate = Number.isFinite(options.playbackRate) && options.playbackRate !== 0 ? options.playbackRate : 1;
8899
- this.onTime = options.onTime;
8900
- this.onEnd = options.onEnd;
8901
- this.time = this.clamp(options.time ?? 0);
8902
- this.cached = this.snapshot();
8903
- }
8904
- /** Current timeline length (ms). */
8905
- get duration() {
8906
- const d = typeof this.durationSource === "function" ? this.durationSource() : this.durationSource;
8907
- return Number.isFinite(d) && d > 0 ? d : 0;
8908
- }
8909
- get currentTime() {
8910
- return this.time;
8911
- }
8912
- get isPlaying() {
8913
- return this.playing;
8914
- }
8915
- getState() {
8916
- return this.cached;
8917
- }
8918
- subscribe(listener) {
8919
- this.listeners.add(listener);
8920
- return () => {
8921
- this.listeners.delete(listener);
8922
- };
8923
- }
8924
- /** Replaces the callbacks (hooks keep them current without recreating the player). */
8925
- setCallbacks(callbacks) {
8926
- this.onTime = callbacks.onTime;
8927
- this.onEnd = callbacks.onEnd;
8928
- }
8929
- setDuration(duration) {
8930
- this.durationSource = duration;
8931
- this.time = this.clamp(this.time);
8932
- this.emit(false);
8933
- }
8934
- setLoop(loop) {
8935
- if (loop === this.loop) return;
8936
- this.reanchor();
8937
- this.loop = loop;
8938
- this.emit(false);
8939
- }
8940
- setPlaybackRate(rate) {
8941
- if (!Number.isFinite(rate) || rate === 0 || rate === this.rate) return;
8942
- this.reanchor();
8943
- this.rate = rate;
8944
- this.emit(false);
8945
- }
8946
- /** Starts playing from the playhead (from the start again when a one-shot play had ended). */
8947
- play() {
8948
- if (this.playing) return;
8949
- const d = this.duration;
8950
- if (this.loop === "none" && d > 0) {
8951
- if (this.rate > 0 && this.time >= d) this.time = 0;
8952
- if (this.rate < 0 && this.time <= 0) this.time = d;
8953
- }
8954
- this.playing = true;
8955
- this.scrubbing = false;
8956
- this.anchorRaw = this.time;
8957
- this.anchorAt = this.clock.now();
8958
- this.emit(false);
8959
- this.schedule();
8960
- }
8961
- pause() {
8962
- if (!this.playing) return;
8963
- this.tick(false);
8964
- this.playing = false;
8965
- this.generation++;
8966
- this.emit(true);
8967
- }
8968
- toggle() {
8969
- if (this.playing) this.pause();
8970
- else this.play();
8971
- }
8972
- /** Pauses and returns to the start. */
8973
- stop() {
8974
- this.playing = false;
8975
- this.generation++;
8976
- this.seek(0);
8977
- }
8978
- /** Moves the playhead (clamped to the timeline); playback continues from there. */
8979
- seek(time) {
8980
- if (!Number.isFinite(time)) return;
8981
- this.time = this.clamp(time);
8982
- this.anchorRaw = this.time;
8983
- this.anchorAt = this.clock.now();
8984
- this.emit(true);
8985
- }
8986
- /** Seeks while dragging the playhead: playback pauses until `endScrub`. */
8987
- scrub(time) {
8988
- if (!this.scrubbing) {
8989
- this.resumeAfterScrub = this.playing;
8990
- if (this.playing) {
8991
- this.playing = false;
8992
- this.generation++;
8993
- }
8994
- this.scrubbing = true;
8995
- }
8996
- this.seek(time);
8997
- }
8998
- /** Ends a scrub, resuming playback if it was playing when the scrub began. */
8999
- endScrub() {
9000
- if (!this.scrubbing) return;
9001
- this.scrubbing = false;
9002
- const resume = this.resumeAfterScrub;
9003
- this.resumeAfterScrub = false;
9004
- if (resume) this.play();
9005
- else this.emit(false);
9006
- }
9007
- /** Stops scheduling frames and drops listeners. */
9008
- destroy() {
9009
- this.playing = false;
9010
- this.generation++;
9011
- this.listeners.clear();
9012
- }
9013
- clamp(time) {
9014
- return Math.min(this.duration, Math.max(0, Number.isFinite(time) ? time : 0));
9015
- }
9016
- reanchor() {
9017
- if (!this.playing) return;
9018
- this.tick(false);
9019
- this.anchorRaw = this.rawNow();
9020
- this.anchorAt = this.clock.now();
9021
- }
9022
- rawNow() {
9023
- return this.anchorRaw + (this.clock.now() - this.anchorAt) * this.rate;
9024
- }
9025
- schedule() {
9026
- const generation = this.generation;
9027
- this.clock.frame().then(() => {
9028
- if (generation !== this.generation || !this.playing) return;
9029
- this.tick(true);
9030
- if (this.playing) this.schedule();
9031
- });
9032
- }
9033
- /** Advances the playhead to the clock's time; `notify` emits the change. */
9034
- tick(notify) {
9035
- if (!this.playing) return;
9036
- const d = this.duration;
9037
- const raw = this.rawNow();
9038
- let ended = false;
9039
- if (this.loop === "none" || d <= 0) {
9040
- if (this.rate > 0 && raw >= d) {
9041
- this.time = d;
9042
- ended = true;
9043
- } else if (this.rate < 0 && raw <= 0) {
9044
- this.time = 0;
9045
- ended = true;
9046
- } else this.time = this.clamp(raw);
9047
- } else {
9048
- this.time = wrapAnimationTime(raw, d, this.loop);
9049
- }
9050
- if (ended) {
9051
- this.playing = false;
9052
- this.generation++;
9053
- }
9054
- if (notify || ended) this.emit(true);
9055
- if (ended) this.onEnd?.();
9056
- }
9057
- snapshot() {
9058
- return {
9059
- time: this.time,
9060
- playing: this.playing,
9061
- scrubbing: this.scrubbing,
9062
- loop: this.loop,
9063
- playbackRate: this.rate,
9064
- duration: this.duration
9065
- };
9066
- }
9067
- emit(timeChanged) {
9068
- const next = this.snapshot();
9069
- const prev = this.cached;
9070
- if (prev.time === next.time && prev.playing === next.playing && prev.scrubbing === next.scrubbing && prev.loop === next.loop && prev.playbackRate === next.playbackRate && prev.duration === next.duration) {
9071
- return;
9072
- }
9073
- this.cached = next;
9074
- if (timeChanged && prev.time !== next.time) this.onTime?.(next.time);
9075
- for (const listener of this.listeners) listener(next);
9076
- }
9077
- };
9078
- function createAnimationPlayer(options) {
9079
- return new AnimationPlayer(options);
9080
- }
9081
-
9082
8516
  // src/canvas/animation/export.ts
9083
8517
  function sampleAnimationFrames(doc, options = {}) {
9084
8518
  const fps = options.fps ?? 30;
@@ -9109,22 +8543,22 @@ var CSS_ANIMATION_PROPERTIES = {
9109
8543
  width: { css: "width", camel: "width" },
9110
8544
  height: { css: "height", camel: "height" }
9111
8545
  };
9112
- var round2 = (v) => Math.round(v * 1e3) / 1e3;
8546
+ var round = (v) => Math.round(v * 1e3) / 1e3;
9113
8547
  function cssValue(source, value, node, partner, partnerSource) {
9114
8548
  if (source === "x" || source === "y") {
9115
8549
  const dx = source === "x" ? value - node.position.x : partner !== void 0 ? partner - node.position.x : 0;
9116
8550
  const dy = source === "y" ? value - node.position.y : partner !== void 0 && partnerSource === "y" ? partner - node.position.y : 0;
9117
- return `${round2(dx)}px ${round2(dy)}px`;
8551
+ return `${round(dx)}px ${round(dy)}px`;
9118
8552
  }
9119
8553
  if (typeof value === "string") return value;
9120
8554
  switch (source) {
9121
8555
  case "rotation":
9122
- return `${round2(value)}deg`;
8556
+ return `${round(value)}deg`;
9123
8557
  case "scale":
9124
8558
  case "opacity":
9125
- return String(round2(value));
8559
+ return String(round(value));
9126
8560
  default:
9127
- return `${round2(value)}px`;
8561
+ return `${round(value)}px`;
9128
8562
  }
9129
8563
  }
9130
8564
  var sameTimes = (a, b) => a.length === b.length && a.every((k, i) => Math.abs(k.time - b[i].time) < 1e-6 && JSON.stringify(k.easing ?? "linear") === JSON.stringify(b[i].easing ?? "linear"));
@@ -9184,7 +8618,7 @@ function getCssPropertyAnimations(nodes, nodeId, options = {}) {
9184
8618
  if (sources.includes("motionPath")) {
9185
8619
  const position = (t) => {
9186
8620
  const moved = ANIMATABLE_PROPERTIES.find((p) => p.key === "motionPath").write(node, evalAt("motionPath", t));
9187
- return `${round2(moved.position.x - node.position.x)}px ${round2(moved.position.y - node.position.y)}px`;
8621
+ return `${round(moved.position.x - node.position.x)}px ${round(moved.position.y - node.position.y)}px`;
9188
8622
  };
9189
8623
  out.push({ property: css, camel: camel2, sources, stops: sampledStops(duration, fps, allTimes, position), exact: false });
9190
8624
  continue;
@@ -9219,7 +8653,7 @@ function timing(options, duration) {
9219
8653
  const rate = options.playbackRate && Number.isFinite(options.playbackRate) && options.playbackRate !== 0 ? options.playbackRate : 1;
9220
8654
  const loop = options.loop ?? "none";
9221
8655
  return {
9222
- duration: round2(duration / Math.abs(rate)),
8656
+ duration: round(duration / Math.abs(rate)),
9223
8657
  iterations: loop === "none" ? 1 : Infinity,
9224
8658
  direction: loop === "ping-pong" ? rate < 0 ? "alternate-reverse" : "alternate" : rate < 0 ? "reverse" : "normal"
9225
8659
  };
@@ -9236,7 +8670,7 @@ function exportCssAnimation(nodes, nodeId, options = {}) {
9236
8670
  for (const prop of props) {
9237
8671
  const name = `${base}-${cssIdent(prop.property)}`;
9238
8672
  const lines = prop.stops.map((s) => {
9239
- const pct = `${round2(s.offset * 100)}%`;
8673
+ const pct = `${round(s.offset * 100)}%`;
9240
8674
  const easing = s.easing ? ` animation-timing-function: ${s.easing};` : "";
9241
8675
  return ` ${pct} { ${prop.property}: ${s.value};${easing} }`;
9242
8676
  });