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 +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 +211 -178
- package/dist/labels.js +83 -59
- package/dist/trace-cli.js +32 -31
- package/dist/types/camera.d.ts +27 -0
- package/dist/types/index.d.ts +1 -1
- package/guides/edsl-guide.md +16 -0
- package/package.json +1 -1
package/dist/labels.js
CHANGED
|
@@ -325,7 +325,67 @@ function compileScene(ir) {
|
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// ../core/src/interpolate.ts
|
|
329
|
+
var BACK_C1 = 1.70158;
|
|
330
|
+
var BACK_C2 = BACK_C1 * 1.525;
|
|
331
|
+
var BACK_C3 = BACK_C1 + 1;
|
|
332
|
+
var ELASTIC_C4 = 2 * Math.PI / 3;
|
|
333
|
+
var ELASTIC_C5 = 2 * Math.PI / 4.5;
|
|
334
|
+
function springEase(stiffness, damping, velocity) {
|
|
335
|
+
const K = 5;
|
|
336
|
+
const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
|
|
337
|
+
const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
|
|
338
|
+
const coef = (K - velocity) / wd;
|
|
339
|
+
return (u) => {
|
|
340
|
+
if (u <= 0) return 0;
|
|
341
|
+
if (u >= 1) return 1;
|
|
342
|
+
return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function easeOutBounce(u) {
|
|
346
|
+
const n1 = 7.5625;
|
|
347
|
+
const d1 = 2.75;
|
|
348
|
+
if (u < 1 / d1) return n1 * u * u;
|
|
349
|
+
if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
|
|
350
|
+
if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
|
|
351
|
+
return n1 * (u -= 2.625 / d1) * u + 0.984375;
|
|
352
|
+
}
|
|
353
|
+
var EASE_TABLE = {
|
|
354
|
+
linear: (u) => u,
|
|
355
|
+
easeInQuad: (u) => u * u,
|
|
356
|
+
easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
|
|
357
|
+
easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
|
|
358
|
+
easeInCubic: (u) => u ** 3,
|
|
359
|
+
easeOutCubic: (u) => 1 - (1 - u) ** 3,
|
|
360
|
+
easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
|
|
361
|
+
easeInQuart: (u) => u ** 4,
|
|
362
|
+
easeOutQuart: (u) => 1 - (1 - u) ** 4,
|
|
363
|
+
easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
|
|
364
|
+
easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
|
|
365
|
+
easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
|
|
366
|
+
easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
|
|
367
|
+
// --- expressive eases (GSAP's signature feel) — standard Penner equations ---
|
|
368
|
+
// back: overshoots past the target then settles (pop / snap)
|
|
369
|
+
easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
|
|
370
|
+
easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
|
|
371
|
+
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,
|
|
372
|
+
// elastic: rings around the target before settling (playful spring)
|
|
373
|
+
easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
|
|
374
|
+
easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
|
|
375
|
+
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,
|
|
376
|
+
// bounce: drops and bounces to rest (lands without overshoot)
|
|
377
|
+
easeInBounce: (u) => 1 - easeOutBounce(1 - u),
|
|
378
|
+
easeOutBounce,
|
|
379
|
+
easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
|
|
380
|
+
// damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
|
|
381
|
+
spring: springEase(100, 10, 0),
|
|
382
|
+
springBouncy: springEase(180, 8, 0),
|
|
383
|
+
springStiff: springEase(210, 26, 0)
|
|
384
|
+
};
|
|
385
|
+
var EASE_NAMES = Object.keys(EASE_TABLE);
|
|
386
|
+
|
|
328
387
|
// ../core/src/validate.ts
|
|
388
|
+
var EASE_SET = new Set(EASE_NAMES);
|
|
329
389
|
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
|
|
330
390
|
var BLEND_MODES = /* @__PURE__ */ new Set([
|
|
331
391
|
"normal",
|
|
@@ -457,6 +517,26 @@ function validateScene(ir) {
|
|
|
457
517
|
);
|
|
458
518
|
}
|
|
459
519
|
const labels = /* @__PURE__ */ new Set();
|
|
520
|
+
const checkEase = (path3, ease) => {
|
|
521
|
+
if (ease === void 0) return;
|
|
522
|
+
if (typeof ease === "string") {
|
|
523
|
+
if (!EASE_SET.has(ease)) {
|
|
524
|
+
problems.push(`${path3}: unknown ease "${ease}" \u2014 valid: ${EASE_NAMES.join(", ")} (note: there are no *Sine eases)`);
|
|
525
|
+
}
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (typeof ease === "object" && ease !== null) {
|
|
529
|
+
const o = ease;
|
|
530
|
+
if ("spring" in o) return;
|
|
531
|
+
if ("cubicBezier" in o) {
|
|
532
|
+
if (!Array.isArray(o.cubicBezier) || o.cubicBezier.length !== 4) {
|
|
533
|
+
problems.push(`${path3}: ease cubicBezier must be [x1, y1, x2, y2]`);
|
|
534
|
+
}
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
problems.push(`${path3}: invalid ease \u2014 use a name, { spring }, or { cubicBezier: [x1,y1,x2,y2] }`);
|
|
539
|
+
};
|
|
460
540
|
const checkTimeline = (tl, path3) => {
|
|
461
541
|
if ("label" in tl && tl.label !== void 0) {
|
|
462
542
|
if (labels.has(tl.label)) {
|
|
@@ -484,6 +564,7 @@ function validateScene(ir) {
|
|
|
484
564
|
if (tl.duration !== void 0 && tl.duration <= 0) {
|
|
485
565
|
problems.push(`${path3}: to("${tl.state}") duration must be > 0`);
|
|
486
566
|
}
|
|
567
|
+
checkEase(path3, tl.ease);
|
|
487
568
|
for (const id of tl.filter ?? []) {
|
|
488
569
|
if (!nodeById.has(id)) problems.push(`${path3}: filter contains unknown node "${id}"`);
|
|
489
570
|
}
|
|
@@ -493,6 +574,7 @@ function validateScene(ir) {
|
|
|
493
574
|
if (tl.duration !== void 0 && tl.duration <= 0) {
|
|
494
575
|
problems.push(`${path3}: tween duration must be > 0`);
|
|
495
576
|
}
|
|
577
|
+
checkEase(path3, tl.ease);
|
|
496
578
|
break;
|
|
497
579
|
case "motionPath": {
|
|
498
580
|
const node = nodeById.get(tl.target);
|
|
@@ -513,6 +595,7 @@ function validateScene(ir) {
|
|
|
513
595
|
if (tl.curviness !== void 0 && tl.curviness < 0) {
|
|
514
596
|
problems.push(`${path3}: motionPath "${tl.target}" curviness must be >= 0`);
|
|
515
597
|
}
|
|
598
|
+
checkEase(path3, tl.ease);
|
|
516
599
|
break;
|
|
517
600
|
}
|
|
518
601
|
case "wait":
|
|
@@ -609,65 +692,6 @@ function validateScene(ir) {
|
|
|
609
692
|
// ../core/src/presets.ts
|
|
610
693
|
var SET = 1 / 120;
|
|
611
694
|
|
|
612
|
-
// ../core/src/interpolate.ts
|
|
613
|
-
var BACK_C1 = 1.70158;
|
|
614
|
-
var BACK_C2 = BACK_C1 * 1.525;
|
|
615
|
-
var BACK_C3 = BACK_C1 + 1;
|
|
616
|
-
var ELASTIC_C4 = 2 * Math.PI / 3;
|
|
617
|
-
var ELASTIC_C5 = 2 * Math.PI / 4.5;
|
|
618
|
-
function springEase(stiffness, damping, velocity) {
|
|
619
|
-
const K = 5;
|
|
620
|
-
const zeta = Math.min(0.999, Math.max(0.05, damping / (2 * Math.sqrt(Math.max(1e-6, stiffness)))));
|
|
621
|
-
const wd = K / zeta * Math.sqrt(1 - zeta * zeta);
|
|
622
|
-
const coef = (K - velocity) / wd;
|
|
623
|
-
return (u) => {
|
|
624
|
-
if (u <= 0) return 0;
|
|
625
|
-
if (u >= 1) return 1;
|
|
626
|
-
return 1 - Math.exp(-K * u) * (Math.cos(wd * u) + coef * Math.sin(wd * u));
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
function easeOutBounce(u) {
|
|
630
|
-
const n1 = 7.5625;
|
|
631
|
-
const d1 = 2.75;
|
|
632
|
-
if (u < 1 / d1) return n1 * u * u;
|
|
633
|
-
if (u < 2 / d1) return n1 * (u -= 1.5 / d1) * u + 0.75;
|
|
634
|
-
if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
|
|
635
|
-
return n1 * (u -= 2.625 / d1) * u + 0.984375;
|
|
636
|
-
}
|
|
637
|
-
var EASE_TABLE = {
|
|
638
|
-
linear: (u) => u,
|
|
639
|
-
easeInQuad: (u) => u * u,
|
|
640
|
-
easeOutQuad: (u) => 1 - (1 - u) * (1 - u),
|
|
641
|
-
easeInOutQuad: (u) => u < 0.5 ? 2 * u * u : 1 - (-2 * u + 2) ** 2 / 2,
|
|
642
|
-
easeInCubic: (u) => u ** 3,
|
|
643
|
-
easeOutCubic: (u) => 1 - (1 - u) ** 3,
|
|
644
|
-
easeInOutCubic: (u) => u < 0.5 ? 4 * u ** 3 : 1 - (-2 * u + 2) ** 3 / 2,
|
|
645
|
-
easeInQuart: (u) => u ** 4,
|
|
646
|
-
easeOutQuart: (u) => 1 - (1 - u) ** 4,
|
|
647
|
-
easeInOutQuart: (u) => u < 0.5 ? 8 * u ** 4 : 1 - (-2 * u + 2) ** 4 / 2,
|
|
648
|
-
easeInExpo: (u) => u === 0 ? 0 : 2 ** (10 * u - 10),
|
|
649
|
-
easeOutExpo: (u) => u === 1 ? 1 : 1 - 2 ** (-10 * u),
|
|
650
|
-
easeInOutExpo: (u) => u === 0 ? 0 : u === 1 ? 1 : u < 0.5 ? 2 ** (20 * u - 10) / 2 : (2 - 2 ** (-20 * u + 10)) / 2,
|
|
651
|
-
// --- expressive eases (GSAP's signature feel) — standard Penner equations ---
|
|
652
|
-
// back: overshoots past the target then settles (pop / snap)
|
|
653
|
-
easeInBack: (u) => BACK_C3 * u ** 3 - BACK_C1 * u * u,
|
|
654
|
-
easeOutBack: (u) => 1 + BACK_C3 * (u - 1) ** 3 + BACK_C1 * (u - 1) ** 2,
|
|
655
|
-
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,
|
|
656
|
-
// elastic: rings around the target before settling (playful spring)
|
|
657
|
-
easeInElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : -(2 ** (10 * u - 10)) * Math.sin((u * 10 - 10.75) * ELASTIC_C4),
|
|
658
|
-
easeOutElastic: (u) => u === 0 ? 0 : u === 1 ? 1 : 2 ** (-10 * u) * Math.sin((u * 10 - 0.75) * ELASTIC_C4) + 1,
|
|
659
|
-
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,
|
|
660
|
-
// bounce: drops and bounces to rest (lands without overshoot)
|
|
661
|
-
easeInBounce: (u) => 1 - easeOutBounce(1 - u),
|
|
662
|
-
easeOutBounce,
|
|
663
|
-
easeInOutBounce: (u) => u < 0.5 ? (1 - easeOutBounce(1 - 2 * u)) / 2 : (1 + easeOutBounce(2 * u - 1)) / 2,
|
|
664
|
-
// damped-spring presets (ζ from damping/(2√stiffness)): 0.5 / 0.30 / 0.90
|
|
665
|
-
spring: springEase(100, 10, 0),
|
|
666
|
-
springBouncy: springEase(180, 8, 0),
|
|
667
|
-
springStiff: springEase(210, 26, 0)
|
|
668
|
-
};
|
|
669
|
-
var EASE_NAMES = Object.keys(EASE_TABLE);
|
|
670
|
-
|
|
671
695
|
// ../core/src/evaluate.ts
|
|
672
696
|
var DEG = Math.PI / 180;
|
|
673
697
|
|
package/dist/trace-cli.js
CHANGED
|
@@ -5,37 +5,6 @@ import { writeFile as writeFile2 } from "node:fs/promises";
|
|
|
5
5
|
import { resolve as resolve2 } from "node:path";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
8
|
-
// ../core/src/validate.ts
|
|
9
|
-
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
|
|
10
|
-
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "z", "rotateX", "rotateY", "anchor", "fixed", ...FX_PROPS];
|
|
11
|
-
var PROPS_BY_TYPE = {
|
|
12
|
-
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
13
|
-
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
14
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
15
|
-
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "prefix", "suffix", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
16
|
-
image: [...COMMON_PROPS, "src", "width", "height", "fit"],
|
|
17
|
-
video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart", "volume", "fadeIn", "pan"],
|
|
18
|
-
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
19
|
-
group: COMMON_PROPS
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// ../core/src/dsl.ts
|
|
23
|
-
function seq(...children) {
|
|
24
|
-
return { kind: "seq", children };
|
|
25
|
-
}
|
|
26
|
-
function par(...children) {
|
|
27
|
-
return { kind: "par", children };
|
|
28
|
-
}
|
|
29
|
-
function tween(target, props, opts = {}) {
|
|
30
|
-
return { kind: "tween", target, props, ...opts };
|
|
31
|
-
}
|
|
32
|
-
function wait(duration, label) {
|
|
33
|
-
return { kind: "wait", duration, ...label !== void 0 && { label } };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ../core/src/presets.ts
|
|
37
|
-
var SET = 1 / 120;
|
|
38
|
-
|
|
39
8
|
// ../core/src/interpolate.ts
|
|
40
9
|
var BACK_C1 = 1.70158;
|
|
41
10
|
var BACK_C2 = BACK_C1 * 1.525;
|
|
@@ -95,6 +64,38 @@ var EASE_TABLE = {
|
|
|
95
64
|
};
|
|
96
65
|
var EASE_NAMES = Object.keys(EASE_TABLE);
|
|
97
66
|
|
|
67
|
+
// ../core/src/validate.ts
|
|
68
|
+
var EASE_SET = new Set(EASE_NAMES);
|
|
69
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
|
|
70
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "z", "rotateX", "rotateY", "anchor", "fixed", ...FX_PROPS];
|
|
71
|
+
var PROPS_BY_TYPE = {
|
|
72
|
+
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
73
|
+
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
74
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
75
|
+
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "prefix", "suffix", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
76
|
+
image: [...COMMON_PROPS, "src", "width", "height", "fit"],
|
|
77
|
+
video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart", "volume", "fadeIn", "pan"],
|
|
78
|
+
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
79
|
+
group: COMMON_PROPS
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ../core/src/dsl.ts
|
|
83
|
+
function seq(...children) {
|
|
84
|
+
return { kind: "seq", children };
|
|
85
|
+
}
|
|
86
|
+
function par(...children) {
|
|
87
|
+
return { kind: "par", children };
|
|
88
|
+
}
|
|
89
|
+
function tween(target, props, opts = {}) {
|
|
90
|
+
return { kind: "tween", target, props, ...opts };
|
|
91
|
+
}
|
|
92
|
+
function wait(duration, label) {
|
|
93
|
+
return { kind: "wait", duration, ...label !== void 0 && { label } };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ../core/src/presets.ts
|
|
97
|
+
var SET = 1 / 120;
|
|
98
|
+
|
|
98
99
|
// ../core/src/evaluate.ts
|
|
99
100
|
var DEG = Math.PI / 180;
|
|
100
101
|
|
package/dist/types/camera.d.ts
CHANGED
|
@@ -24,6 +24,33 @@ export declare const CAMERA_PROPS: readonly ["x", "y", "zoom", "rotation", "pers
|
|
|
24
24
|
* collapse to the identity.
|
|
25
25
|
*/
|
|
26
26
|
export declare function cameraMatrix(cam: CameraIR, size: Size): Mat2D;
|
|
27
|
+
/**
|
|
28
|
+
* Frame a scene-space bounding box in the viewport — returns `{ x, y, zoom }` to
|
|
29
|
+
* spread into `cameraTo`, GUARANTEED not to clip the box. The visible scene rect
|
|
30
|
+
* is `W/zoom × H/zoom` centred on `(x, y)`; fitting `box` (+ `margin` padding on
|
|
31
|
+
* the tight axis) means `zoom = min(W/(box.w+2m), H/(box.h+2m))`, capped by
|
|
32
|
+
* `maxZoom` so a tiny target doesn't zoom absurdly close.
|
|
33
|
+
*
|
|
34
|
+
* cameraTo(cameraFit({ x: 200, y: 760, width: 740, height: 360 }, { margin: 90 }),
|
|
35
|
+
* { duration: 1, ease: "easeInOutCubic" })
|
|
36
|
+
*
|
|
37
|
+
* `box` is a top-left rect in scene coords (a centre-anchored panel at (px,py) of
|
|
38
|
+
* size (pw,ph) is `{ x: px-pw/2, y: py-ph/2, width: pw, height: ph }`).
|
|
39
|
+
*/
|
|
40
|
+
export declare function cameraFit(box: {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
}, opts?: {
|
|
46
|
+
size?: Size;
|
|
47
|
+
margin?: number;
|
|
48
|
+
maxZoom?: number;
|
|
49
|
+
}): {
|
|
50
|
+
x: number;
|
|
51
|
+
y: number;
|
|
52
|
+
zoom: number;
|
|
53
|
+
};
|
|
27
54
|
/** Keyframe the camera: a `tween` on the reserved "camera" target. */
|
|
28
55
|
export declare function cameraTo(props: CameraIR, opts?: {
|
|
29
56
|
duration?: number;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { compileComposition, type CompiledComposition, type ScenePlacement, } fr
|
|
|
5
5
|
export { composeScene, formatComposeReport, type OverlayDoc, type ComposeReport, } from "./compose.js";
|
|
6
6
|
export { compileScene, type CompiledScene, type PropertySegment, type LabelSpan, type MotionDriver } from "./compile.js";
|
|
7
7
|
export { pathPoint, pathTangentAngle, type Pt } from "./path.js";
|
|
8
|
-
export { cameraTo, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
|
|
8
|
+
export { cameraTo, cameraFit, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
|
|
9
9
|
export { linearGradient, radialGradient, conicGradient, isGradient } from "./gradient.js";
|
|
10
10
|
export { glow, dropShadow } from "./effects.js";
|
|
11
11
|
export { row, column, grid, type RowOpts, type GridOpts } from "./layout.js";
|
package/guides/edsl-guide.md
CHANGED
|
@@ -90,6 +90,14 @@ row(3, { center: 960, gap: 60, itemWidth: 440 }).map((x, i) =>
|
|
|
90
90
|
|
|
91
91
|
`column` is `row` for the y axis.
|
|
92
92
|
|
|
93
|
+
**Charts/widgets in a panel — derive geometry from the box, and `clip` it.** Don't
|
|
94
|
+
hand-pick a pixels-per-unit scale (bars routinely overflow the panel that way).
|
|
95
|
+
Define the panel rect ONCE, then size from it — bar height `(v/max) · innerH`, x via
|
|
96
|
+
`row(...)` across the panel width — so a tall value can't exceed the box. As a safety
|
|
97
|
+
net, wrap the chart in a clipped group so nothing can ever punch out the panel:
|
|
98
|
+
`group({ clip: { kind: "rect", x, y, width, height, radius } }, [ ...bars ])`. See
|
|
99
|
+
`examples/scenes/annual-report.ts` (and `cameraFit` above to frame the panel).
|
|
100
|
+
|
|
93
101
|
## States: declare looks, not motion
|
|
94
102
|
|
|
95
103
|
Base props on nodes describe the **finished design**. A state is a sparse
|
|
@@ -178,6 +186,14 @@ scene({
|
|
|
178
186
|
`tween` on the `"camera"` target, so `motionPath("camera", pts, …)` (pan along
|
|
179
187
|
a curve) and `oscillate/wiggle("camera", "rotation"|"x"|…)` (handheld drift)
|
|
180
188
|
also work.
|
|
189
|
+
- **Frame a region without clipping — use `cameraFit`, not a guessed `zoom`.** The
|
|
190
|
+
visible scene rect is `W/zoom × H/zoom` centred on `(camera.x, camera.y)`, so a
|
|
191
|
+
hand-picked `zoom` that's too big crops the target. `cameraFit(box, { margin })`
|
|
192
|
+
returns `{ x, y, zoom }` that frames a scene-space bbox (top-left `{x,y,width,
|
|
193
|
+
height}`) with padding, guaranteed in-bounds: `cameraTo(cameraFit({ x, y, width,
|
|
194
|
+
height }, { margin: 80 }), { duration: 1, ease: "easeInOutCubic" })`. A centre-
|
|
195
|
+
anchored panel at `(px,py)` size `(pw,ph)` is `{ x: px-pw/2, y: py-ph/2, width:
|
|
196
|
+
pw, height: ph }`. `maxZoom` (default 2.4) caps absurd close-ups.
|
|
181
197
|
- **Pin HUD/titles to the screen** with `fixed: true` on a TOP-LEVEL node — the
|
|
182
198
|
camera won't move it (for overlays, watermarks, captions).
|
|
183
199
|
- Defaults are the identity, so a scene without a camera is unchanged. Don't name
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reframe-video",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"description": "Declarative motion graphics that AI can write and humans can tweak — human edits survive AI regeneration. Deterministic mp4 renders from a plain-data scene format.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"motion-graphics",
|