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.
package/dist/bin.js CHANGED
@@ -353,6 +353,71 @@ var init_compile = __esm({
353
353
  }
354
354
  });
355
355
 
356
+ // ../core/src/interpolate.ts
357
+ function springEase(stiffness, damping, velocity) {
358
+ const K = 5;
359
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
360
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
361
+ const coef = (K - velocity) / wd;
362
+ return (u) => {
363
+ if (u <= 0) return 0;
364
+ if (u >= 1) return 1;
365
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
366
+ };
367
+ }
368
+ function easeOutBounce(u) {
369
+ const n1 = 7.5625;
370
+ const d1 = 2.75;
371
+ if (u < 1 / d1) return n1 * u * u;
372
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
373
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
374
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
375
+ }
376
+ var BACK_C1, BACK_C2, BACK_C3, ELASTIC_C4, ELASTIC_C5, EASE_TABLE, EASE_NAMES;
377
+ var init_interpolate = __esm({
378
+ "../core/src/interpolate.ts"() {
379
+ "use strict";
380
+ BACK_C1 = 1.70158;
381
+ BACK_C2 = BACK_C1 * 1.525;
382
+ BACK_C3 = BACK_C1 + 1;
383
+ ELASTIC_C4 = 2 * Math.PI / 3;
384
+ ELASTIC_C5 = 2 * Math.PI / 4.5;
385
+ EASE_TABLE = {
386
+ linear: (u) => u,
387
+ easeInQuad: (u) => u * u,
388
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
389
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
390
+ easeInCubic: (u) => u ** 3,
391
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
392
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
393
+ easeInQuart: (u) => u ** 4,
394
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
395
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
396
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
397
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
398
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
399
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
400
+ // back: overshoots past the target then settles (pop / snap)
401
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
402
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
403
+ 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,
404
+ // elastic: rings around the target before settling (playful spring)
405
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
406
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
407
+ 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,
408
+ // bounce: drops and bounces to rest (lands without overshoot)
409
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
410
+ easeOutBounce,
411
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
412
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
413
+ spring: springEase(100, 10, 0),
414
+ springBouncy: springEase(180, 8, 0),
415
+ springStiff: springEase(210, 26, 0)
416
+ };
417
+ EASE_NAMES = Object.keys(EASE_TABLE);
418
+ }
419
+ });
420
+
356
421
  // ../core/src/validate.ts
357
422
  function validateScene(ir) {
358
423
  const problems = [];
@@ -449,6 +514,26 @@ function validateScene(ir) {
449
514
  );
450
515
  }
451
516
  const labels = /* @__PURE__ */ new Set();
517
+ const checkEase = (path2, ease) => {
518
+ if (ease === void 0) return;
519
+ if (typeof ease === "string") {
520
+ if (!EASE_SET.has(ease)) {
521
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
522
+ }
523
+ return;
524
+ }
525
+ if (typeof ease === "object" && ease !== null) {
526
+ const o = ease;
527
+ if ("spring" in o) return;
528
+ if ("cubicBezier" in o) {
529
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
530
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
531
+ }
532
+ return;
533
+ }
534
+ }
535
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
536
+ };
452
537
  const checkTimeline = (tl, path2) => {
453
538
  if ("label" in tl && tl.label !== void 0) {
454
539
  if (labels.has(tl.label)) {
@@ -476,6 +561,7 @@ function validateScene(ir) {
476
561
  if (tl.duration !== void 0 && tl.duration <= 0) {
477
562
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
478
563
  }
564
+ checkEase(path2, tl.ease);
479
565
  for (const id of tl.filter ?? []) {
480
566
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
481
567
  }
@@ -485,6 +571,7 @@ function validateScene(ir) {
485
571
  if (tl.duration !== void 0 && tl.duration <= 0) {
486
572
  problems.push(`${path2}: tween duration must be > 0`);
487
573
  }
574
+ checkEase(path2, tl.ease);
488
575
  break;
489
576
  case "motionPath": {
490
577
  const node = nodeById.get(tl.target);
@@ -505,6 +592,7 @@ function validateScene(ir) {
505
592
  if (tl.curviness !== void 0 && tl.curviness < 0) {
506
593
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
507
594
  }
595
+ checkEase(path2, tl.ease);
508
596
  break;
509
597
  }
510
598
  case "wait":
@@ -626,10 +714,12 @@ function validateComposition(comp) {
626
714
  }
627
715
  if (problems.length > 0) throw new SceneValidationError(problems);
628
716
  }
629
- var FX_PROPS, BLEND_MODES, IMAGE_FITS, COMMON_PROPS, CAMERA_PROPS, PROPS_BY_TYPE, SceneValidationError, TRANSITIONS;
717
+ var EASE_SET, FX_PROPS, BLEND_MODES, IMAGE_FITS, COMMON_PROPS, CAMERA_PROPS, PROPS_BY_TYPE, SceneValidationError, TRANSITIONS;
630
718
  var init_validate = __esm({
631
719
  "../core/src/validate.ts"() {
632
720
  "use strict";
721
+ init_interpolate();
722
+ EASE_SET = new Set(EASE_NAMES);
633
723
  FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
634
724
  BLEND_MODES = /* @__PURE__ */ new Set([
635
725
  "normal",
@@ -1366,71 +1456,6 @@ var init_behaviors = __esm({
1366
1456
  }
1367
1457
  });
1368
1458
 
1369
- // ../core/src/interpolate.ts
1370
- function springEase(stiffness, damping, velocity) {
1371
- const K = 5;
1372
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
1373
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
1374
- const coef = (K - velocity) / wd;
1375
- return (u) => {
1376
- if (u <= 0) return 0;
1377
- if (u >= 1) return 1;
1378
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
1379
- };
1380
- }
1381
- function easeOutBounce(u) {
1382
- const n1 = 7.5625;
1383
- const d1 = 2.75;
1384
- if (u < 1 / d1) return n1 * u * u;
1385
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
1386
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
1387
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
1388
- }
1389
- var BACK_C1, BACK_C2, BACK_C3, ELASTIC_C4, ELASTIC_C5, EASE_TABLE, EASE_NAMES;
1390
- var init_interpolate = __esm({
1391
- "../core/src/interpolate.ts"() {
1392
- "use strict";
1393
- BACK_C1 = 1.70158;
1394
- BACK_C2 = BACK_C1 * 1.525;
1395
- BACK_C3 = BACK_C1 + 1;
1396
- ELASTIC_C4 = 2 * Math.PI / 3;
1397
- ELASTIC_C5 = 2 * Math.PI / 4.5;
1398
- EASE_TABLE = {
1399
- linear: (u) => u,
1400
- easeInQuad: (u) => u * u,
1401
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
1402
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
1403
- easeInCubic: (u) => u ** 3,
1404
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
1405
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
1406
- easeInQuart: (u) => u ** 4,
1407
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
1408
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
1409
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
1410
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
1411
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
1412
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
1413
- // back: overshoots past the target then settles (pop / snap)
1414
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
1415
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
1416
- 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,
1417
- // elastic: rings around the target before settling (playful spring)
1418
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
1419
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
1420
- 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,
1421
- // bounce: drops and bounces to rest (lands without overshoot)
1422
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
1423
- easeOutBounce,
1424
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
1425
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
1426
- spring: springEase(100, 10, 0),
1427
- springBouncy: springEase(180, 8, 0),
1428
- springStiff: springEase(210, 26, 0)
1429
- };
1430
- EASE_NAMES = Object.keys(EASE_TABLE);
1431
- }
1432
- });
1433
-
1434
1459
  // ../core/src/evaluate.ts
1435
1460
  var DEG;
1436
1461
  var init_evaluate = __esm({
@@ -341,72 +341,6 @@
341
341
  };
342
342
  }
343
343
 
344
- // ../core/src/validate.ts
345
- var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
346
- var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "z", "rotateX", "rotateY", "anchor", "fixed", ...FX_PROPS];
347
- var PROPS_BY_TYPE = {
348
- rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
349
- ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
350
- line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
351
- text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "prefix", "suffix", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
352
- image: [...COMMON_PROPS, "src", "width", "height", "fit"],
353
- video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart", "volume", "fadeIn", "pan"],
354
- path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
355
- group: COMMON_PROPS
356
- };
357
-
358
- // ../core/src/camera.ts
359
- function cameraMatrix(cam, size) {
360
- const W = size.width;
361
- const H = size.height;
362
- const x = cam.x ?? W / 2;
363
- const y = cam.y ?? H / 2;
364
- const zoom = cam.zoom ?? 1;
365
- const r = (cam.rotation ?? 0) * Math.PI / 180;
366
- const a = Math.cos(r) * zoom;
367
- const b = Math.sin(r) * zoom;
368
- const c = b === 0 ? 0 : -b;
369
- const d = Math.cos(r) * zoom;
370
- return [a, b, c, d, W / 2 - a * x - c * y, H / 2 - b * x - d * y];
371
- }
372
-
373
- // ../core/src/gradient.ts
374
- function isGradient(p) {
375
- return typeof p === "object" && p !== null && (p.kind === "linear" || p.kind === "radial" || p.kind === "conic");
376
- }
377
-
378
- // ../core/src/presets.ts
379
- var SET = 1 / 120;
380
-
381
- // ../core/src/behaviors.ts
382
- function sampleBehavior(b, t) {
383
- switch (b.name) {
384
- case "oscillate": {
385
- const { amplitude, frequency, phase = 0 } = b.params;
386
- return amplitude * Math.sin(2 * Math.PI * frequency * t + phase);
387
- }
388
- case "wiggle": {
389
- const { amplitude, frequency, seed } = b.params;
390
- return amplitude * valueNoise(t * frequency, seed);
391
- }
392
- }
393
- }
394
- function valueNoise(x, seed) {
395
- const i = Math.floor(x);
396
- const f = x - i;
397
- const u = f * f * (3 - 2 * f);
398
- const a = hash01(i, seed) * 2 - 1;
399
- const b = hash01(i + 1, seed) * 2 - 1;
400
- return a + (b - a) * u;
401
- }
402
- function hash01(n, seed) {
403
- let h = n * 374761393 + seed * 668265263 | 0;
404
- h = h ^ h >>> 13 | 0;
405
- h = Math.imul(h, 1274126177);
406
- h = (h ^ h >>> 16) >>> 0;
407
- return h / 4294967295;
408
- }
409
-
410
344
  // ../core/src/interpolate.ts
411
345
  var BACK_C1 = 1.70158;
412
346
  var BACK_C2 = BACK_C1 * 1.525;
@@ -585,6 +519,73 @@
585
519
  return s;
586
520
  }
587
521
 
522
+ // ../core/src/validate.ts
523
+ var EASE_SET = new Set(EASE_NAMES);
524
+ var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
525
+ var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "z", "rotateX", "rotateY", "anchor", "fixed", ...FX_PROPS];
526
+ var PROPS_BY_TYPE = {
527
+ rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
528
+ ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
529
+ line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
530
+ text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "prefix", "suffix", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
531
+ image: [...COMMON_PROPS, "src", "width", "height", "fit"],
532
+ video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart", "volume", "fadeIn", "pan"],
533
+ path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
534
+ group: COMMON_PROPS
535
+ };
536
+
537
+ // ../core/src/camera.ts
538
+ function cameraMatrix(cam, size) {
539
+ const W = size.width;
540
+ const H = size.height;
541
+ const x = cam.x ?? W / 2;
542
+ const y = cam.y ?? H / 2;
543
+ const zoom = cam.zoom ?? 1;
544
+ const r = (cam.rotation ?? 0) * Math.PI / 180;
545
+ const a = Math.cos(r) * zoom;
546
+ const b = Math.sin(r) * zoom;
547
+ const c = b === 0 ? 0 : -b;
548
+ const d = Math.cos(r) * zoom;
549
+ return [a, b, c, d, W / 2 - a * x - c * y, H / 2 - b * x - d * y];
550
+ }
551
+
552
+ // ../core/src/gradient.ts
553
+ function isGradient(p) {
554
+ return typeof p === "object" && p !== null && (p.kind === "linear" || p.kind === "radial" || p.kind === "conic");
555
+ }
556
+
557
+ // ../core/src/presets.ts
558
+ var SET = 1 / 120;
559
+
560
+ // ../core/src/behaviors.ts
561
+ function sampleBehavior(b, t) {
562
+ switch (b.name) {
563
+ case "oscillate": {
564
+ const { amplitude, frequency, phase = 0 } = b.params;
565
+ return amplitude * Math.sin(2 * Math.PI * frequency * t + phase);
566
+ }
567
+ case "wiggle": {
568
+ const { amplitude, frequency, seed } = b.params;
569
+ return amplitude * valueNoise(t * frequency, seed);
570
+ }
571
+ }
572
+ }
573
+ function valueNoise(x, seed) {
574
+ const i = Math.floor(x);
575
+ const f = x - i;
576
+ const u = f * f * (3 - 2 * f);
577
+ const a = hash01(i, seed) * 2 - 1;
578
+ const b = hash01(i + 1, seed) * 2 - 1;
579
+ return a + (b - a) * u;
580
+ }
581
+ function hash01(n, seed) {
582
+ let h = n * 374761393 + seed * 668265263 | 0;
583
+ h = h ^ h >>> 13 | 0;
584
+ h = Math.imul(h, 1274126177);
585
+ h = (h ^ h >>> 16) >>> 0;
586
+ return h / 4294967295;
587
+ }
588
+
588
589
  // ../core/src/evaluate.ts
589
590
  var IDENTITY = [1, 0, 0, 1, 0, 0];
590
591
  function multiply(m, n) {
package/dist/cli.js CHANGED
@@ -331,7 +331,67 @@ function compileScene(ir) {
331
331
  };
332
332
  }
333
333
 
334
+ // ../core/src/interpolate.ts
335
+ var BACK_C1 = 1.70158;
336
+ var BACK_C2 = BACK_C1 * 1.525;
337
+ var BACK_C3 = BACK_C1 + 1;
338
+ var ELASTIC_C4 = 2 * Math.PI / 3;
339
+ var ELASTIC_C5 = 2 * Math.PI / 4.5;
340
+ function springEase(stiffness, damping, velocity) {
341
+ const K = 5;
342
+ const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
343
+ const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
344
+ const coef = (K - velocity) / wd;
345
+ return (u) => {
346
+ if (u <= 0) return 0;
347
+ if (u >= 1) return 1;
348
+ return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
349
+ };
350
+ }
351
+ function easeOutBounce(u) {
352
+ const n1 = 7.5625;
353
+ const d1 = 2.75;
354
+ if (u < 1 / d1) return n1 * u * u;
355
+ if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
356
+ if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
357
+ return n1 * (u -= 2.625 / d1) * u + 0.984375;
358
+ }
359
+ var EASE_TABLE = {
360
+ linear: (u) => u,
361
+ easeInQuad: (u) => u * u,
362
+ easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
363
+ easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
364
+ easeInCubic: (u) => u ** 3,
365
+ easeOutCubic: (u) => 1 - (1 - u) ** 3,
366
+ easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
367
+ easeInQuart: (u) => u ** 4,
368
+ easeOutQuart: (u) => 1 - (1 - u) ** 4,
369
+ easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
370
+ easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
371
+ easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
372
+ easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
373
+ // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
374
+ // back: overshoots past the target then settles (pop / snap)
375
+ easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
376
+ easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
377
+ 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,
378
+ // elastic: rings around the target before settling (playful spring)
379
+ easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
380
+ easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
381
+ 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,
382
+ // bounce: drops and bounces to rest (lands without overshoot)
383
+ easeInBounce: (u) => 1 - easeOutBounce(1 - u),
384
+ easeOutBounce,
385
+ easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
386
+ // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
387
+ spring: springEase(100, 10, 0),
388
+ springBouncy: springEase(180, 8, 0),
389
+ springStiff: springEase(210, 26, 0)
390
+ };
391
+ var EASE_NAMES = Object.keys(EASE_TABLE);
392
+
334
393
  // ../core/src/validate.ts
394
+ var EASE_SET = new Set(EASE_NAMES);
335
395
  var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
336
396
  var BLEND_MODES = /* @__PURE__ */ new Set([
337
397
  "normal",
@@ -463,6 +523,26 @@ function validateScene(ir) {
463
523
  );
464
524
  }
465
525
  const labels = /* @__PURE__ */ new Set();
526
+ const checkEase = (path2, ease) => {
527
+ if (ease === void 0) return;
528
+ if (typeof ease === "string") {
529
+ if (!EASE_SET.has(ease)) {
530
+ problems.push(`${path2}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
531
+ }
532
+ return;
533
+ }
534
+ if (typeof ease === "object" && ease !== null) {
535
+ const o = ease;
536
+ if ("spring" in o) return;
537
+ if ("cubicBezier" in o) {
538
+ if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
539
+ problems.push(`${path2}: ease cubicBezier must be [x1, y1, x2, y2]`);
540
+ }
541
+ return;
542
+ }
543
+ }
544
+ problems.push(`${path2}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
545
+ };
466
546
  const checkTimeline = (tl, path2) => {
467
547
  if ("label" in tl && tl.label !== void 0) {
468
548
  if (labels.has(tl.label)) {
@@ -490,6 +570,7 @@ function validateScene(ir) {
490
570
  if (tl.duration !== void 0 && tl.duration <= 0) {
491
571
  problems.push(`${path2}: to("${tl.state}") duration must be > 0`);
492
572
  }
573
+ checkEase(path2, tl.ease);
493
574
  for (const id of tl.filter ?? []) {
494
575
  if (!nodeById.has(id)) problems.push(`${path2}: filter contains unknown node "${id}"`);
495
576
  }
@@ -499,6 +580,7 @@ function validateScene(ir) {
499
580
  if (tl.duration !== void 0 && tl.duration <= 0) {
500
581
  problems.push(`${path2}: tween duration must be > 0`);
501
582
  }
583
+ checkEase(path2, tl.ease);
502
584
  break;
503
585
  case "motionPath": {
504
586
  const node = nodeById.get(tl.target);
@@ -519,6 +601,7 @@ function validateScene(ir) {
519
601
  if (tl.curviness !== void 0 && tl.curviness < 0) {
520
602
  problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
521
603
  }
604
+ checkEase(path2, tl.ease);
522
605
  break;
523
606
  }
524
607
  case "wait":
@@ -1068,65 +1151,6 @@ function resolveCompositionAudioPlan(comp) {
1068
1151
  };
1069
1152
  }
1070
1153
 
1071
- // ../core/src/interpolate.ts
1072
- var BACK_C1 = 1.70158;
1073
- var BACK_C2 = BACK_C1 * 1.525;
1074
- var BACK_C3 = BACK_C1 + 1;
1075
- var ELASTIC_C4 = 2 * Math.PI / 3;
1076
- var ELASTIC_C5 = 2 * Math.PI / 4.5;
1077
- function springEase(stiffness, damping, velocity) {
1078
- const K = 5;
1079
- const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
1080
- const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
1081
- const coef = (K - velocity) / wd;
1082
- return (u) => {
1083
- if (u <= 0) return 0;
1084
- if (u >= 1) return 1;
1085
- return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
1086
- };
1087
- }
1088
- function easeOutBounce(u) {
1089
- const n1 = 7.5625;
1090
- const d1 = 2.75;
1091
- if (u < 1 / d1) return n1 * u * u;
1092
- if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
1093
- if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
1094
- return n1 * (u -= 2.625 / d1) * u + 0.984375;
1095
- }
1096
- var EASE_TABLE = {
1097
- linear: (u) => u,
1098
- easeInQuad: (u) => u * u,
1099
- easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
1100
- easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
1101
- easeInCubic: (u) => u ** 3,
1102
- easeOutCubic: (u) => 1 - (1 - u) ** 3,
1103
- easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
1104
- easeInQuart: (u) => u ** 4,
1105
- easeOutQuart: (u) => 1 - (1 - u) ** 4,
1106
- easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
1107
- easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
1108
- easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
1109
- easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
1110
- // --- expressive eases (GSAP's signature feel) — standard Penner equations ---
1111
- // back: overshoots past the target then settles (pop / snap)
1112
- easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
1113
- easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
1114
- 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,
1115
- // elastic: rings around the target before settling (playful spring)
1116
- easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
1117
- easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
1118
- 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,
1119
- // bounce: drops and bounces to rest (lands without overshoot)
1120
- easeInBounce: (u) => 1 - easeOutBounce(1 - u),
1121
- easeOutBounce,
1122
- easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
1123
- // damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
1124
- spring: springEase(100, 10, 0),
1125
- springBouncy: springEase(180, 8, 0),
1126
- springStiff: springEase(210, 26, 0)
1127
- };
1128
- var EASE_NAMES = Object.keys(EASE_TABLE);
1129
-
1130
1154
  // ../core/src/evaluate.ts
1131
1155
  var DEG = Math.PI / 180;
1132
1156