reframe-video 0.6.23 → 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/.claude-plugin/plugin.json +1 -1
- package/dist/bin.js +91 -66
- package/dist/browserEntry.js +67 -66
- package/dist/cli.js +83 -59
- package/dist/compile-api.js +83 -59
- package/dist/compile.js +83 -59
- package/dist/diff.js +83 -59
- package/dist/frame.js +83 -59
- package/dist/index.js +202 -178
- package/dist/labels.js +83 -59
- package/dist/trace-cli.js +32 -31
- package/package.json +1 -1
- package/skills/reframe/SKILL.md +6 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reframe",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Create and iterate motion-graphics videos as addressable data: deterministic mp4 renders, human edits that survive AI regeneration, label-anchored audio, data-driven batch rendering.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kiyeon Jeon",
|
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({
|
package/dist/browserEntry.js
CHANGED
|
@@ -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
|
|