reframe-video 0.6.24 → 0.6.26

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.
@@ -4,7 +4,67 @@ import { readFile } from "node:fs/promises";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
 
7
+ // ../core/src/interpolate.ts
8
+ var BACK_C1 = 1.70158;
9
+ var BACK_C2 = BACK_C1 * 1.525;
10
+ var BACK_C3 = BACK_C1 + 1;
11
+ var ELASTIC_C4 = 2 * Math.PI / 3;
12
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
13
+ function springEase(stiffness, damping, velocity) {
14
+ const K = 5;
15
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
16
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
17
+ const coef = (K - velocity) / wd;
18
+ return (u) => {
19
+ if (u <= 0) return 0;
20
+ if (u >= 1) return 1;
21
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
22
+ };
23
+ }
24
+ function easeOutBounce(u) {
25
+ const n1 = 7.5625;
26
+ const d1 = 2.75;
27
+ if (u < 1 / d1) return n1 * u * u;
28
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
29
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
30
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
31
+ }
32
+ var EASE_TABLE = {
33
+ linear: (u) => u,
34
+ easeInQuad: (u) => u * u,
35
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
36
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
37
+ easeInCubic: (u) => u ** 3,
38
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
39
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
40
+ easeInQuart: (u) => u ** 4,
41
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
42
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
43
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
44
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
45
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
46
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
47
+ // back: overshoots past the target then settles (pop / snap)
48
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
49
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
50
+ easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
51
+ // elastic: rings around the target before settling (playful spring)
52
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
53
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
54
+ easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
55
+ // bounce: drops and bounces to rest (lands without overshoot)
56
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
57
+ easeOutBounce,
58
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
59
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
60
+ spring: springEase(100, 10, 0),
61
+ springBouncy: springEase(180, 8, 0),
62
+ springStiff: springEase(210, 26, 0)
63
+ };
64
+ var EASE_NAMES = Object.keys(EASE_TABLE);
65
+
7
66
  // ../core/src/validate.ts
67
+ var EASE_SET = new Set(EASE_NAMES);
8
68
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
9
69
  var BLEND_MODES = /* @__PURE__ */ new Set([
10
70
  "normal",
@@ -136,6 +196,26 @@ function validateScene(ir) {
136
196
  );
137
197
  }
138
198
  const labels = /* @__PURE__ */ new Set();
199
+ const checkEase = (path2, ease) => {
200
+ if (ease === void 0) return;
201
+ if (typeof ease === "string") {
202
+ if (!EASE_SET.has(ease)) {
203
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
204
+ }
205
+ return;
206
+ }
207
+ if (typeof ease === "object" && ease !== null) {
208
+ const o = ease;
209
+ if ("spring" in o) return;
210
+ if ("cubicBezier" in o) {
211
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
212
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
213
+ }
214
+ return;
215
+ }
216
+ }
217
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
218
+ };
139
219
  const checkTimeline = (tl, path2) => {
140
220
  if ("label" in tl && tl.label !== void 0) {
141
221
  if (labels.has(tl.label)) {
@@ -163,6 +243,7 @@ function validateScene(ir) {
163
243
  if (tl.duration !== void 0 && tl.duration <= 0) {
164
244
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
165
245
  }
246
+ checkEase(path2, tl.ease);
166
247
  for (const id of tl.filter ?? []) {
167
248
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
168
249
  }
@@ -172,6 +253,7 @@ function validateScene(ir) {
172
253
  if (tl.duration !== void 0 && tl.duration <= 0) {
173
254
  problems.push(`${path2}: tween duration must be > 0`);
174
255
  }
256
+ checkEase(path2, tl.ease);
175
257
  break;
176
258
  case "motionPath": {
177
259
  const node = nodeById.get(tl.target);
@@ -192,6 +274,7 @@ function validateScene(ir) {
192
274
  if (tl.curviness !== void 0 && tl.curviness < 0) {
193
275
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
194
276
  }
277
+ checkEase(path2, tl.ease);
195
278
  break;
196
279
  }
197
280
  case "wait":
@@ -318,65 +401,6 @@ function validateComposition(comp) {
318
401
  // ../core/src/presets.ts
319
402
  var SET = 1 / 120;
320
403
 
321
- // ../core/src/interpolate.ts
322
- var BACK_C1 = 1.70158;
323
- var BACK_C2 = BACK_C1 * 1.525;
324
- var BACK_C3 = BACK_C1 + 1;
325
- var ELASTIC_C4 = 2 * Math.PI / 3;
326
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
327
- function springEase(stiffness, damping, velocity) {
328
- const K = 5;
329
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
330
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
331
- const coef = (K - velocity) / wd;
332
- return (u) => {
333
- if (u <= 0) return 0;
334
- if (u >= 1) return 1;
335
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
336
- };
337
- }
338
- function easeOutBounce(u) {
339
- const n1 = 7.5625;
340
- const d1 = 2.75;
341
- if (u < 1 / d1) return n1 * u * u;
342
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
343
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
344
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
345
- }
346
- var EASE_TABLE = {
347
- linear: (u) => u,
348
- easeInQuad: (u) => u * u,
349
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
350
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
351
- easeInCubic: (u) => u ** 3,
352
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
353
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
354
- easeInQuart: (u) => u ** 4,
355
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
356
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
357
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
358
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
359
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
360
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
361
- // back: overshoots past the target then settles (pop / snap)
362
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
363
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
364
- easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
365
- // elastic: rings around the target before settling (playful spring)
366
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
367
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
368
- easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
369
- // bounce: drops and bounces to rest (lands without overshoot)
370
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
371
- easeOutBounce,
372
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
373
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
374
- spring: springEase(100, 10, 0),
375
- springBouncy: springEase(180, 8, 0),
376
- springStiff: springEase(210, 26, 0)
377
- };
378
- var EASE_NAMES = Object.keys(EASE_TABLE);
379
-
380
404
  // ../core/src/evaluate.ts
381
405
  var DEG = Math.PI / 180;
382
406
 
package/dist/compile.js CHANGED
@@ -9,7 +9,67 @@ import { readFile } from "node:fs/promises";
9
9
  import { dirname, resolve } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
11
 
12
+ // ../core/src/interpolate.ts
13
+ var BACK_C1 = 1.70158;
14
+ var BACK_C2 = BACK_C1 * 1.525;
15
+ var BACK_C3 = BACK_C1 + 1;
16
+ var ELASTIC_C4 = 2 * Math.PI / 3;
17
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
18
+ function springEase(stiffness, damping, velocity) {
19
+ const K = 5;
20
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
21
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
22
+ const coef = (K - velocity) / wd;
23
+ return (u) => {
24
+ if (u <= 0) return 0;
25
+ if (u >= 1) return 1;
26
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
27
+ };
28
+ }
29
+ function easeOutBounce(u) {
30
+ const n1 = 7.5625;
31
+ const d1 = 2.75;
32
+ if (u < 1 / d1) return n1 * u * u;
33
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
34
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
35
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
36
+ }
37
+ var EASE_TABLE = {
38
+ linear: (u) => u,
39
+ easeInQuad: (u) => u * u,
40
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
41
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
42
+ easeInCubic: (u) => u ** 3,
43
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
44
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
45
+ easeInQuart: (u) => u ** 4,
46
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
47
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
48
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
49
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
50
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
51
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
52
+ // back: overshoots past the target then settles (pop / snap)
53
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
54
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
55
+ easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
56
+ // elastic: rings around the target before settling (playful spring)
57
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
58
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
59
+ easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
60
+ // bounce: drops and bounces to rest (lands without overshoot)
61
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
62
+ easeOutBounce,
63
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
64
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
65
+ spring: springEase(100, 10, 0),
66
+ springBouncy: springEase(180, 8, 0),
67
+ springStiff: springEase(210, 26, 0)
68
+ };
69
+ var EASE_NAMES = Object.keys(EASE_TABLE);
70
+
12
71
  // ../core/src/validate.ts
72
+ var EASE_SET = new Set(EASE_NAMES);
13
73
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
14
74
  var BLEND_MODES = /* @__PURE__ */ new Set([
15
75
  "normal",
@@ -141,6 +201,26 @@ function validateScene(ir) {
141
201
  );
142
202
  }
143
203
  const labels = /* @__PURE__ */ new Set();
204
+ const checkEase = (path2, ease) => {
205
+ if (ease === void 0) return;
206
+ if (typeof ease === "string") {
207
+ if (!EASE_SET.has(ease)) {
208
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
209
+ }
210
+ return;
211
+ }
212
+ if (typeof ease === "object" && ease !== null) {
213
+ const o = ease;
214
+ if ("spring" in o) return;
215
+ if ("cubicBezier" in o) {
216
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
217
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
218
+ }
219
+ return;
220
+ }
221
+ }
222
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
223
+ };
144
224
  const checkTimeline = (tl, path2) => {
145
225
  if ("label" in tl && tl.label !== void 0) {
146
226
  if (labels.has(tl.label)) {
@@ -168,6 +248,7 @@ function validateScene(ir) {
168
248
  if (tl.duration !== void 0 && tl.duration <= 0) {
169
249
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
170
250
  }
251
+ checkEase(path2, tl.ease);
171
252
  for (const id of tl.filter ?? []) {
172
253
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
173
254
  }
@@ -177,6 +258,7 @@ function validateScene(ir) {
177
258
  if (tl.duration !== void 0 && tl.duration <= 0) {
178
259
  problems.push(`${path2}: tween duration must be > 0`);
179
260
  }
261
+ checkEase(path2, tl.ease);
180
262
  break;
181
263
  case "motionPath": {
182
264
  const node = nodeById.get(tl.target);
@@ -197,6 +279,7 @@ function validateScene(ir) {
197
279
  if (tl.curviness !== void 0 && tl.curviness < 0) {
198
280
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
199
281
  }
282
+ checkEase(path2, tl.ease);
200
283
  break;
201
284
  }
202
285
  case "wait":
@@ -293,65 +376,6 @@ function validateScene(ir) {
293
376
  // ../core/src/presets.ts
294
377
  var SET = 1 / 120;
295
378
 
296
- // ../core/src/interpolate.ts
297
- var BACK_C1 = 1.70158;
298
- var BACK_C2 = BACK_C1 * 1.525;
299
- var BACK_C3 = BACK_C1 + 1;
300
- var ELASTIC_C4 = 2 * Math.PI / 3;
301
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
302
- function springEase(stiffness, damping, velocity) {
303
- const K = 5;
304
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
305
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
306
- const coef = (K - velocity) / wd;
307
- return (u) => {
308
- if (u <= 0) return 0;
309
- if (u >= 1) return 1;
310
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
311
- };
312
- }
313
- function easeOutBounce(u) {
314
- const n1 = 7.5625;
315
- const d1 = 2.75;
316
- if (u < 1 / d1) return n1 * u * u;
317
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
318
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
319
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
320
- }
321
- var EASE_TABLE = {
322
- linear: (u) => u,
323
- easeInQuad: (u) => u * u,
324
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
325
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
326
- easeInCubic: (u) => u ** 3,
327
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
328
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
329
- easeInQuart: (u) => u ** 4,
330
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
331
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
332
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
333
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
334
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
335
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
336
- // back: overshoots past the target then settles (pop / snap)
337
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
338
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
339
- easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
340
- // elastic: rings around the target before settling (playful spring)
341
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
342
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
343
- easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
344
- // bounce: drops and bounces to rest (lands without overshoot)
345
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
346
- easeOutBounce,
347
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
348
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
349
- spring: springEase(100, 10, 0),
350
- springBouncy: springEase(180, 8, 0),
351
- springStiff: springEase(210, 26, 0)
352
- };
353
- var EASE_NAMES = Object.keys(EASE_TABLE);
354
-
355
379
  // ../core/src/evaluate.ts
356
380
  var DEG = Math.PI / 180;
357
381
 
package/dist/diff.js CHANGED
@@ -337,7 +337,67 @@ function compileScene(ir) {
337
337
  };
338
338
  }
339
339
 
340
+ // ../core/src/interpolate.ts
341
+ var BACK_C1 = 1.70158;
342
+ var BACK_C2 = BACK_C1 * 1.525;
343
+ var BACK_C3 = BACK_C1 + 1;
344
+ var ELASTIC_C4 = 2 * Math.PI / 3;
345
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
346
+ function springEase(stiffness, damping, velocity) {
347
+ const K = 5;
348
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
349
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
350
+ const coef = (K - velocity) / wd;
351
+ return (u) => {
352
+ if (u <= 0) return 0;
353
+ if (u >= 1) return 1;
354
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
355
+ };
356
+ }
357
+ function easeOutBounce(u) {
358
+ const n1 = 7.5625;
359
+ const d1 = 2.75;
360
+ if (u < 1 / d1) return n1 * u * u;
361
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
362
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
363
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
364
+ }
365
+ var EASE_TABLE = {
366
+ linear: (u) => u,
367
+ easeInQuad: (u) => u * u,
368
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
369
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
370
+ easeInCubic: (u) => u ** 3,
371
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
372
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
373
+ easeInQuart: (u) => u ** 4,
374
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
375
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
376
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
377
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
378
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
379
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
380
+ // back: overshoots past the target then settles (pop / snap)
381
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
382
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
383
+ easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
384
+ // elastic: rings around the target before settling (playful spring)
385
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
386
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
387
+ easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
388
+ // bounce: drops and bounces to rest (lands without overshoot)
389
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
390
+ easeOutBounce,
391
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
392
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
393
+ spring: springEase(100, 10, 0),
394
+ springBouncy: springEase(180, 8, 0),
395
+ springStiff: springEase(210, 26, 0)
396
+ };
397
+ var EASE_NAMES = Object.keys(EASE_TABLE);
398
+
340
399
  // ../core/src/validate.ts
400
+ var EASE_SET = new Set(EASE_NAMES);
341
401
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
342
402
  var BLEND_MODES = /* @__PURE__ */ new Set([
343
403
  "normal",
@@ -469,6 +529,26 @@ function validateScene(ir) {
469
529
  );
470
530
  }
471
531
  const labels = /* @__PURE__ */ new Set();
532
+ const checkEase = (path2, ease) => {
533
+ if (ease === void 0) return;
534
+ if (typeof ease === "string") {
535
+ if (!EASE_SET.has(ease)) {
536
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
537
+ }
538
+ return;
539
+ }
540
+ if (typeof ease === "object" && ease !== null) {
541
+ const o = ease;
542
+ if ("spring" in o) return;
543
+ if ("cubicBezier" in o) {
544
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
545
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
546
+ }
547
+ return;
548
+ }
549
+ }
550
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
551
+ };
472
552
  const checkTimeline = (tl, path2) => {
473
553
  if ("label" in tl && tl.label !== void 0) {
474
554
  if (labels.has(tl.label)) {
@@ -496,6 +576,7 @@ function validateScene(ir) {
496
576
  if (tl.duration !== void 0 && tl.duration <= 0) {
497
577
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
498
578
  }
579
+ checkEase(path2, tl.ease);
499
580
  for (const id of tl.filter ?? []) {
500
581
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
501
582
  }
@@ -505,6 +586,7 @@ function validateScene(ir) {
505
586
  if (tl.duration !== void 0 && tl.duration <= 0) {
506
587
  problems.push(`${path2}: tween duration must be > 0`);
507
588
  }
589
+ checkEase(path2, tl.ease);
508
590
  break;
509
591
  case "motionPath": {
510
592
  const node = nodeById.get(tl.target);
@@ -525,6 +607,7 @@ function validateScene(ir) {
525
607
  if (tl.curviness !== void 0 && tl.curviness < 0) {
526
608
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
527
609
  }
610
+ checkEase(path2, tl.ease);
528
611
  break;
529
612
  }
530
613
  case "wait":
@@ -651,65 +734,6 @@ function validateComposition(comp) {
651
734
  // ../core/src/presets.ts
652
735
  var SET = 1 / 120;
653
736
 
654
- // ../core/src/interpolate.ts
655
- var BACK_C1 = 1.70158;
656
- var BACK_C2 = BACK_C1 * 1.525;
657
- var BACK_C3 = BACK_C1 + 1;
658
- var ELASTIC_C4 = 2 * Math.PI / 3;
659
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
660
- function springEase(stiffness, damping, velocity) {
661
- const K = 5;
662
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
663
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
664
- const coef = (K - velocity) / wd;
665
- return (u) => {
666
- if (u <= 0) return 0;
667
- if (u >= 1) return 1;
668
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
669
- };
670
- }
671
- function easeOutBounce(u) {
672
- const n1 = 7.5625;
673
- const d1 = 2.75;
674
- if (u < 1 / d1) return n1 * u * u;
675
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
676
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
677
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
678
- }
679
- var EASE_TABLE = {
680
- linear: (u) => u,
681
- easeInQuad: (u) => u * u,
682
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
683
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
684
- easeInCubic: (u) => u ** 3,
685
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
686
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
687
- easeInQuart: (u) => u ** 4,
688
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
689
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
690
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
691
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
692
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
693
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
694
- // back: overshoots past the target then settles (pop / snap)
695
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
696
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
697
- easeInOutBack: (u) => u < 0.5 ? (2 * u) ** 2 * ((BACK_C2 + 1) * 2 * u - BACK_C2) / 2 : ((2 * u - 2) ** 2 * ((BACK_C2 + 1) * (2 * u - 2) + BACK_C2) + 2) / 2,
698
- // elastic: rings around the target before settling (playful spring)
699
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
700
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
701
- easeInOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? -(2 ** (20 * u - 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5)) / 2 : 2 ** (-20 * u + 10) * Math.sin((20 * u - 11.125) * ELASTIC_C5) / 2 + 1,
702
- // bounce: drops and bounces to rest (lands without overshoot)
703
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
704
- easeOutBounce,
705
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
706
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
707
- spring: springEase(100, 10, 0),
708
- springBouncy: springEase(180, 8, 0),
709
- springStiff: springEase(210, 26, 0)
710
- };
711
- var EASE_NAMES = Object.keys(EASE_TABLE);
712
-
713
737
  // ../core/src/evaluate.ts
714
738
  var DEG = Math.PI / 180;
715
739