reframe-video 0.6.24 → 0.6.25

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.
package/dist/frame.js CHANGED
@@ -364,7 +364,67 @@ function compileScene(ir) {
364
364
  };
365
365
  }
366
366
 
367
+ // ../core/src/interpolate.ts
368
+ var BACK_C1 = 1.70158;
369
+ var BACK_C2 = BACK_C1 * 1.525;
370
+ var BACK_C3 = BACK_C1 + 1;
371
+ var ELASTIC_C4 = 2 * Math.PI / 3;
372
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
373
+ function springEase(stiffness, damping, velocity) {
374
+ const K = 5;
375
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
376
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
377
+ const coef = (K - velocity) / wd;
378
+ return (u) => {
379
+ if (u <= 0) return 0;
380
+ if (u >= 1) return 1;
381
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
382
+ };
383
+ }
384
+ function easeOutBounce(u) {
385
+ const n1 = 7.5625;
386
+ const d1 = 2.75;
387
+ if (u < 1 / d1) return n1 * u * u;
388
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
389
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
390
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
391
+ }
392
+ var EASE_TABLE = {
393
+ linear: (u) => u,
394
+ easeInQuad: (u) => u * u,
395
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
396
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
397
+ easeInCubic: (u) => u ** 3,
398
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
399
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
400
+ easeInQuart: (u) => u ** 4,
401
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
402
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
403
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
404
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
405
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
406
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
407
+ // back: overshoots past the target then settles (pop / snap)
408
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
409
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
410
+ 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,
411
+ // elastic: rings around the target before settling (playful spring)
412
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
413
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
414
+ 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,
415
+ // bounce: drops and bounces to rest (lands without overshoot)
416
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
417
+ easeOutBounce,
418
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
419
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
420
+ spring: springEase(100, 10, 0),
421
+ springBouncy: springEase(180, 8, 0),
422
+ springStiff: springEase(210, 26, 0)
423
+ };
424
+ var EASE_NAMES = Object.keys(EASE_TABLE);
425
+
367
426
  // ../core/src/validate.ts
427
+ var EASE_SET = new Set(EASE_NAMES);
368
428
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
369
429
  var BLEND_MODES = /* @__PURE__ */ new Set([
370
430
  "normal",
@@ -496,6 +556,26 @@ function validateScene(ir) {
496
556
  );
497
557
  }
498
558
  const labels = /* @__PURE__ */ new Set();
559
+ const checkEase = (path2, ease) => {
560
+ if (ease === void 0) return;
561
+ if (typeof ease === "string") {
562
+ if (!EASE_SET.has(ease)) {
563
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
564
+ }
565
+ return;
566
+ }
567
+ if (typeof ease === "object" && ease !== null) {
568
+ const o = ease;
569
+ if ("spring" in o) return;
570
+ if ("cubicBezier" in o) {
571
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
572
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
573
+ }
574
+ return;
575
+ }
576
+ }
577
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
578
+ };
499
579
  const checkTimeline = (tl, path2) => {
500
580
  if ("label" in tl && tl.label !== void 0) {
501
581
  if (labels.has(tl.label)) {
@@ -523,6 +603,7 @@ function validateScene(ir) {
523
603
  if (tl.duration !== void 0 && tl.duration <= 0) {
524
604
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
525
605
  }
606
+ checkEase(path2, tl.ease);
526
607
  for (const id of tl.filter ?? []) {
527
608
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
528
609
  }
@@ -532,6 +613,7 @@ function validateScene(ir) {
532
613
  if (tl.duration !== void 0 && tl.duration <= 0) {
533
614
  problems.push(`${path2}: tween duration must be > 0`);
534
615
  }
616
+ checkEase(path2, tl.ease);
535
617
  break;
536
618
  case "motionPath": {
537
619
  const node = nodeById.get(tl.target);
@@ -552,6 +634,7 @@ function validateScene(ir) {
552
634
  if (tl.curviness !== void 0 && tl.curviness < 0) {
553
635
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
554
636
  }
637
+ checkEase(path2, tl.ease);
555
638
  break;
556
639
  }
557
640
  case "wait":
@@ -678,65 +761,6 @@ function validateComposition(comp) {
678
761
  // ../core/src/presets.ts
679
762
  var SET = 1 / 120;
680
763
 
681
- // ../core/src/interpolate.ts
682
- var BACK_C1 = 1.70158;
683
- var BACK_C2 = BACK_C1 * 1.525;
684
- var BACK_C3 = BACK_C1 + 1;
685
- var ELASTIC_C4 = 2 * Math.PI / 3;
686
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
687
- function springEase(stiffness, damping, velocity) {
688
- const K = 5;
689
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
690
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
691
- const coef = (K - velocity) / wd;
692
- return (u) => {
693
- if (u <= 0) return 0;
694
- if (u >= 1) return 1;
695
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
696
- };
697
- }
698
- function easeOutBounce(u) {
699
- const n1 = 7.5625;
700
- const d1 = 2.75;
701
- if (u < 1 / d1) return n1 * u * u;
702
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
703
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
704
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
705
- }
706
- var EASE_TABLE = {
707
- linear: (u) => u,
708
- easeInQuad: (u) => u * u,
709
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
710
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
711
- easeInCubic: (u) => u ** 3,
712
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
713
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
714
- easeInQuart: (u) => u ** 4,
715
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
716
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
717
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
718
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
719
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
720
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
721
- // back: overshoots past the target then settles (pop / snap)
722
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
723
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
724
- 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,
725
- // elastic: rings around the target before settling (playful spring)
726
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
727
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
728
- 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,
729
- // bounce: drops and bounces to rest (lands without overshoot)
730
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
731
- easeOutBounce,
732
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
733
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
734
- spring: springEase(100, 10, 0),
735
- springBouncy: springEase(180, 8, 0),
736
- springStiff: springEase(210, 26, 0)
737
- };
738
- var EASE_NAMES = Object.keys(EASE_TABLE);
739
-
740
764
  // ../core/src/evaluate.ts
741
765
  var DEG = Math.PI / 180;
742
766
 
package/dist/index.js CHANGED
@@ -341,7 +341,186 @@ function compileScene(ir) {
341
341
  };
342
342
  }
343
343
 
344
+ // ../core/src/interpolate.ts
345
+ var BACK_C1 = 1.70158;
346
+ var BACK_C2 = BACK_C1 * 1.525;
347
+ var BACK_C3 = BACK_C1 + 1;
348
+ var ELASTIC_C4 = 2 * Math.PI / 3;
349
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
350
+ function springEase(stiffness, damping, velocity) {
351
+ const K3 = 5;
352
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
353
+ const wd = K3 / zeta * Math.sqrt(1 - zeta * zeta);
354
+ const coef = (K3 - velocity) / wd;
355
+ return (u) => {
356
+ if (u <= 0) return 0;
357
+ if (u >= 1) return 1;
358
+ return 1 - Math.exp(-K3 * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
359
+ };
360
+ }
361
+ function easeOutBounce(u) {
362
+ const n1 = 7.5625;
363
+ const d1 = 2.75;
364
+ if (u < 1 / d1) return n1 * u * u;
365
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
366
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
367
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
368
+ }
369
+ var EASE_TABLE = {
370
+ linear: (u) => u,
371
+ easeInQuad: (u) => u * u,
372
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
373
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
374
+ easeInCubic: (u) => u ** 3,
375
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
376
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
377
+ easeInQuart: (u) => u ** 4,
378
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
379
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
380
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
381
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
382
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
383
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
384
+ // back: overshoots past the target then settles (pop / snap)
385
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
386
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
387
+ 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,
388
+ // elastic: rings around the target before settling (playful spring)
389
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
390
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
391
+ 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,
392
+ // bounce: drops and bounces to rest (lands without overshoot)
393
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
394
+ easeOutBounce,
395
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
396
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
397
+ spring: springEase(100, 10, 0),
398
+ springBouncy: springEase(180, 8, 0),
399
+ springStiff: springEase(210, 26, 0)
400
+ };
401
+ var EASE_NAMES = Object.keys(EASE_TABLE);
402
+ function resolveEase(ease) {
403
+ if (ease === void 0) return EASE_TABLE.linear;
404
+ if (typeof ease === "string") {
405
+ const fn = EASE_TABLE[ease];
406
+ if (!fn) throw new Error(`unknown ease "${ease}" \u2014 valid: ${Object.keys(EASE_TABLE).join(", ")}`);
407
+ return fn;
408
+ }
409
+ if ("spring" in ease) {
410
+ const { stiffness = 100, damping = 10, velocity = 0 } = ease.spring;
411
+ return springEase(stiffness, damping, velocity);
412
+ }
413
+ return cubicBezierEase(...ease.cubicBezier);
414
+ }
415
+ function cubicBezierEase(x1, y1, x2, y2) {
416
+ const bez = (a, b) => (t) => 3 * a * t * (1 - t) ** 2 + 3 * b * t * t * (1 - t) + t ** 3;
417
+ const bx = bez(x1, x2);
418
+ const by = bez(y1, y2);
419
+ const dbx = (t) => 3 * x1 * (1 - t) * (1 - 3 * t) + 3 * x2 * t * (2 - 3 * t) + 3 * t * t;
420
+ return (u) => {
421
+ if (u <= 0) return 0;
422
+ if (u >= 1) return 1;
423
+ let t = u;
424
+ for (let i = 0; i < 8; i++) {
425
+ const err = bx(t) - u;
426
+ if (Math.abs(err) < 1e-6) return by(t);
427
+ const d = dbx(t);
428
+ if (Math.abs(d) < 1e-6) break;
429
+ t -= err / d;
430
+ }
431
+ let lo = 0;
432
+ let hi = 1;
433
+ t = u;
434
+ while (hi - lo > 1e-6) {
435
+ if (bx(t) < u) lo = t;
436
+ else hi = t;
437
+ t = (lo + hi) / 2;
438
+ }
439
+ return by(t);
440
+ };
441
+ }
442
+ var HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
443
+ function isColor(v) {
444
+ return typeof v === "string" && HEX_COLOR.test(v);
445
+ }
446
+ function parseColor(hex) {
447
+ let h = hex.slice(1);
448
+ if (h.length <= 4) h = [...h].map((c) => c + c).join("");
449
+ const n3 = parseInt(h.padEnd(8, "f"), 16);
450
+ return [n3 >>> 24 & 255, n3 >>> 16 & 255, n3 >>> 8 & 255, n3 & 255];
451
+ }
452
+ function formatColor([r, g, b, a]) {
453
+ const hex = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
454
+ return a >= 255 ? `#${hex(r)}${hex(g)}${hex(b)}` : `#${hex(r)}${hex(g)}${hex(b)}${hex(a)}`;
455
+ }
456
+ function lerpValue(from, to2, u) {
457
+ if (typeof from === "number" && typeof to2 === "number") {
458
+ return from + (to2 - from) * u;
459
+ }
460
+ if (isColor(from) && isColor(to2)) {
461
+ const a = parseColor(from);
462
+ const b = parseColor(to2);
463
+ return formatColor([
464
+ a[0] + (b[0] - a[0]) * u,
465
+ a[1] + (b[1] - a[1]) * u,
466
+ a[2] + (b[2] - a[2]) * u,
467
+ a[3] + (b[3] - a[3]) * u
468
+ ]);
469
+ }
470
+ if (looksLikePath(from) && looksLikePath(to2)) {
471
+ const a = tokenizePath(from);
472
+ const b = tokenizePath(to2);
473
+ if (a && b && morphCompatible(a, b)) return morphPath(a, b, u);
474
+ return u < 0.5 ? from : to2;
475
+ }
476
+ return to2;
477
+ }
478
+ var PATH_BODY = /^[\sMmLlHhVvCcSsQqTtAaZz0-9.,eE+-]+$/;
479
+ function looksLikePath(v) {
480
+ return typeof v === "string" && /^\s*[Mm]/.test(v) && PATH_BODY.test(v);
481
+ }
482
+ var PATH_TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|(-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?)/g;
483
+ function tokenizePath(d) {
484
+ const out = [];
485
+ let cur = null;
486
+ let m;
487
+ PATH_TOKEN.lastIndex = 0;
488
+ while (m = PATH_TOKEN.exec(d)) {
489
+ if (m[1]) out.push(cur = { cmd: m[1], nums: [] });
490
+ else if (m[2]) {
491
+ if (!cur) return null;
492
+ cur.nums.push(parseFloat(m[2]));
493
+ }
494
+ }
495
+ return out.length ? out : null;
496
+ }
497
+ function morphCompatible(a, b) {
498
+ if (a.length !== b.length) return false;
499
+ for (let i = 0; i < a.length; i++) {
500
+ const ca = a[i];
501
+ const cb = b[i];
502
+ if (ca.cmd !== cb.cmd || ca.nums.length !== cb.nums.length) return false;
503
+ if (ca.cmd === "A" || ca.cmd === "a") return false;
504
+ }
505
+ return true;
506
+ }
507
+ var fmtNum = (v) => {
508
+ const r = Number(v.toFixed(3));
509
+ return Object.is(r, -0) ? "0" : String(r);
510
+ };
511
+ function morphPath(a, b, u) {
512
+ let s = "";
513
+ for (let i = 0; i < a.length; i++) {
514
+ const an = a[i].nums;
515
+ const bn = b[i].nums;
516
+ s += (i ? " " : "") + a[i].cmd;
517
+ for (let j = 0; j < an.length; j++) s += " " + fmtNum(an[j] + (bn[j] - an[j]) * u);
518
+ }
519
+ return s;
520
+ }
521
+
344
522
  // ../core/src/validate.ts
523
+ var EASE_SET = new Set(EASE_NAMES);
345
524
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
346
525
  var BLEND_MODES = /* @__PURE__ */ new Set([
347
526
  "normal",
@@ -473,6 +652,26 @@ function validateScene(ir) {
473
652
  );
474
653
  }
475
654
  const labels = /* @__PURE__ */ new Set();
655
+ const checkEase = (path2, ease) => {
656
+ if (ease === void 0) return;
657
+ if (typeof ease === "string") {
658
+ if (!EASE_SET.has(ease)) {
659
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
660
+ }
661
+ return;
662
+ }
663
+ if (typeof ease === "object" && ease !== null) {
664
+ const o = ease;
665
+ if ("spring" in o) return;
666
+ if ("cubicBezier" in o) {
667
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
668
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
669
+ }
670
+ return;
671
+ }
672
+ }
673
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
674
+ };
476
675
  const checkTimeline = (tl, path2) => {
477
676
  if ("label" in tl && tl.label !== void 0) {
478
677
  if (labels.has(tl.label)) {
@@ -500,6 +699,7 @@ function validateScene(ir) {
500
699
  if (tl.duration !== void 0 && tl.duration <= 0) {
501
700
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
502
701
  }
702
+ checkEase(path2, tl.ease);
503
703
  for (const id of tl.filter ?? []) {
504
704
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
505
705
  }
@@ -509,6 +709,7 @@ function validateScene(ir) {
509
709
  if (tl.duration !== void 0 && tl.duration <= 0) {
510
710
  problems.push(`${path2}: tween duration must be > 0`);
511
711
  }
712
+ checkEase(path2, tl.ease);
512
713
  break;
513
714
  case "motionPath": {
514
715
  const node = nodeById.get(tl.target);
@@ -529,6 +730,7 @@ function validateScene(ir) {
529
730
  if (tl.curviness !== void 0 && tl.curviness < 0) {
530
731
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
531
732
  }
733
+ checkEase(path2, tl.ease);
532
734
  break;
533
735
  }
534
736
  case "wait":
@@ -2868,184 +3070,6 @@ function hash01(n3, seed) {
2868
3070
  return h / 4294967295;
2869
3071
  }
2870
3072
 
2871
- // ../core/src/interpolate.ts
2872
- var BACK_C1 = 1.70158;
2873
- var BACK_C2 = BACK_C1 * 1.525;
2874
- var BACK_C3 = BACK_C1 + 1;
2875
- var ELASTIC_C4 = 2 * Math.PI / 3;
2876
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
2877
- function springEase(stiffness, damping, velocity) {
2878
- const K3 = 5;
2879
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
2880
- const wd = K3 / zeta * Math.sqrt(1 - zeta * zeta);
2881
- const coef = (K3 - velocity) / wd;
2882
- return (u) => {
2883
- if (u <= 0) return 0;
2884
- if (u >= 1) return 1;
2885
- return 1 - Math.exp(-K3 * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
2886
- };
2887
- }
2888
- function easeOutBounce(u) {
2889
- const n1 = 7.5625;
2890
- const d1 = 2.75;
2891
- if (u < 1 / d1) return n1 * u * u;
2892
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
2893
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
2894
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
2895
- }
2896
- var EASE_TABLE = {
2897
- linear: (u) => u,
2898
- easeInQuad: (u) => u * u,
2899
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
2900
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
2901
- easeInCubic: (u) => u ** 3,
2902
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
2903
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
2904
- easeInQuart: (u) => u ** 4,
2905
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
2906
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
2907
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
2908
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
2909
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
2910
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
2911
- // back: overshoots past the target then settles (pop / snap)
2912
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
2913
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
2914
- 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,
2915
- // elastic: rings around the target before settling (playful spring)
2916
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
2917
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
2918
- 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,
2919
- // bounce: drops and bounces to rest (lands without overshoot)
2920
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
2921
- easeOutBounce,
2922
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
2923
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
2924
- spring: springEase(100, 10, 0),
2925
- springBouncy: springEase(180, 8, 0),
2926
- springStiff: springEase(210, 26, 0)
2927
- };
2928
- var EASE_NAMES = Object.keys(EASE_TABLE);
2929
- function resolveEase(ease) {
2930
- if (ease === void 0) return EASE_TABLE.linear;
2931
- if (typeof ease === "string") {
2932
- const fn = EASE_TABLE[ease];
2933
- if (!fn) throw new Error(`unknown ease "${ease}" \u2014 valid: ${Object.keys(EASE_TABLE).join(", ")}`);
2934
- return fn;
2935
- }
2936
- if ("spring" in ease) {
2937
- const { stiffness = 100, damping = 10, velocity = 0 } = ease.spring;
2938
- return springEase(stiffness, damping, velocity);
2939
- }
2940
- return cubicBezierEase(...ease.cubicBezier);
2941
- }
2942
- function cubicBezierEase(x1, y1, x2, y2) {
2943
- const bez = (a, b) => (t) => 3 * a * t * (1 - t) ** 2 + 3 * b * t * t * (1 - t) + t ** 3;
2944
- const bx = bez(x1, x2);
2945
- const by = bez(y1, y2);
2946
- const dbx = (t) => 3 * x1 * (1 - t) * (1 - 3 * t) + 3 * x2 * t * (2 - 3 * t) + 3 * t * t;
2947
- return (u) => {
2948
- if (u <= 0) return 0;
2949
- if (u >= 1) return 1;
2950
- let t = u;
2951
- for (let i = 0; i < 8; i++) {
2952
- const err = bx(t) - u;
2953
- if (Math.abs(err) < 1e-6) return by(t);
2954
- const d = dbx(t);
2955
- if (Math.abs(d) < 1e-6) break;
2956
- t -= err / d;
2957
- }
2958
- let lo = 0;
2959
- let hi = 1;
2960
- t = u;
2961
- while (hi - lo > 1e-6) {
2962
- if (bx(t) < u) lo = t;
2963
- else hi = t;
2964
- t = (lo + hi) / 2;
2965
- }
2966
- return by(t);
2967
- };
2968
- }
2969
- var HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
2970
- function isColor(v) {
2971
- return typeof v === "string" && HEX_COLOR.test(v);
2972
- }
2973
- function parseColor(hex) {
2974
- let h = hex.slice(1);
2975
- if (h.length <= 4) h = [...h].map((c) => c + c).join("");
2976
- const n3 = parseInt(h.padEnd(8, "f"), 16);
2977
- return [n3 >>> 24 & 255, n3 >>> 16 & 255, n3 >>> 8 & 255, n3 & 255];
2978
- }
2979
- function formatColor([r, g, b, a]) {
2980
- const hex = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
2981
- return a >= 255 ? `#${hex(r)}${hex(g)}${hex(b)}` : `#${hex(r)}${hex(g)}${hex(b)}${hex(a)}`;
2982
- }
2983
- function lerpValue(from, to2, u) {
2984
- if (typeof from === "number" && typeof to2 === "number") {
2985
- return from + (to2 - from) * u;
2986
- }
2987
- if (isColor(from) && isColor(to2)) {
2988
- const a = parseColor(from);
2989
- const b = parseColor(to2);
2990
- return formatColor([
2991
- a[0] + (b[0] - a[0]) * u,
2992
- a[1] + (b[1] - a[1]) * u,
2993
- a[2] + (b[2] - a[2]) * u,
2994
- a[3] + (b[3] - a[3]) * u
2995
- ]);
2996
- }
2997
- if (looksLikePath(from) && looksLikePath(to2)) {
2998
- const a = tokenizePath(from);
2999
- const b = tokenizePath(to2);
3000
- if (a && b && morphCompatible(a, b)) return morphPath(a, b, u);
3001
- return u < 0.5 ? from : to2;
3002
- }
3003
- return to2;
3004
- }
3005
- var PATH_BODY = /^[\sMmLlHhVvCcSsQqTtAaZz0-9.,eE+-]+$/;
3006
- function looksLikePath(v) {
3007
- return typeof v === "string" && /^\s*[Mm]/.test(v) && PATH_BODY.test(v);
3008
- }
3009
- var PATH_TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|(-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?)/g;
3010
- function tokenizePath(d) {
3011
- const out = [];
3012
- let cur = null;
3013
- let m;
3014
- PATH_TOKEN.lastIndex = 0;
3015
- while (m = PATH_TOKEN.exec(d)) {
3016
- if (m[1]) out.push(cur = { cmd: m[1], nums: [] });
3017
- else if (m[2]) {
3018
- if (!cur) return null;
3019
- cur.nums.push(parseFloat(m[2]));
3020
- }
3021
- }
3022
- return out.length ? out : null;
3023
- }
3024
- function morphCompatible(a, b) {
3025
- if (a.length !== b.length) return false;
3026
- for (let i = 0; i < a.length; i++) {
3027
- const ca = a[i];
3028
- const cb = b[i];
3029
- if (ca.cmd !== cb.cmd || ca.nums.length !== cb.nums.length) return false;
3030
- if (ca.cmd === "A" || ca.cmd === "a") return false;
3031
- }
3032
- return true;
3033
- }
3034
- var fmtNum = (v) => {
3035
- const r = Number(v.toFixed(3));
3036
- return Object.is(r, -0) ? "0" : String(r);
3037
- };
3038
- function morphPath(a, b, u) {
3039
- let s = "";
3040
- for (let i = 0; i < a.length; i++) {
3041
- const an = a[i].nums;
3042
- const bn = b[i].nums;
3043
- s += (i ? " " : "") + a[i].cmd;
3044
- for (let j = 0; j < an.length; j++) s += " " + fmtNum(an[j] + (bn[j] - an[j]) * u);
3045
- }
3046
- return s;
3047
- }
3048
-
3049
3073
  // ../core/src/evaluate.ts
3050
3074
  var IDENTITY = [1, 0, 0, 1, 0, 0];
3051
3075
  function multiply(m, n3) {