reframe-video 0.6.1 → 0.6.2
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 +14 -3
- package/dist/browserEntry.js +27 -2
- package/dist/cli.js +5 -2
- package/dist/index.js +34 -4
- package/dist/labels.js +5 -2
- package/dist/renderer-canvas.js +7 -0
- package/dist/trace-cli.js +3 -2
- package/dist/types/effects.d.ts +12 -0
- package/dist/types/evaluate.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/ir.d.ts +17 -0
- package/guides/edsl-guide.md +22 -0
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -377,6 +377,8 @@ function validateScene(ir) {
|
|
|
377
377
|
const props = node.props;
|
|
378
378
|
checkPaint(`node "${node.id}" fill`, props.fill);
|
|
379
379
|
checkPaint(`node "${node.id}" stroke`, props.stroke);
|
|
380
|
+
if (typeof props.blur === "number" && props.blur < 0) problems.push(`node "${node.id}": blur must be >= 0`);
|
|
381
|
+
if (typeof props.shadowBlur === "number" && props.shadowBlur < 0) problems.push(`node "${node.id}": shadowBlur must be >= 0`);
|
|
380
382
|
if (node.type === "group") {
|
|
381
383
|
const clip = node.props.clip;
|
|
382
384
|
if (clip) {
|
|
@@ -591,16 +593,17 @@ function validateComposition(comp) {
|
|
|
591
593
|
}
|
|
592
594
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
593
595
|
}
|
|
594
|
-
var COMMON_PROPS, CAMERA_PROPS, PROPS_BY_TYPE, SceneValidationError, TRANSITIONS;
|
|
596
|
+
var FX_PROPS, COMMON_PROPS, CAMERA_PROPS, PROPS_BY_TYPE, SceneValidationError, TRANSITIONS;
|
|
595
597
|
var init_validate = __esm({
|
|
596
598
|
"../core/src/validate.ts"() {
|
|
597
599
|
"use strict";
|
|
598
|
-
|
|
600
|
+
FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
601
|
+
COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
599
602
|
CAMERA_PROPS = ["x", "y", "zoom", "rotation"];
|
|
600
603
|
PROPS_BY_TYPE = {
|
|
601
604
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
602
605
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
603
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
606
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
604
607
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
605
608
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
606
609
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -928,6 +931,13 @@ var init_gradient = __esm({
|
|
|
928
931
|
}
|
|
929
932
|
});
|
|
930
933
|
|
|
934
|
+
// ../core/src/effects.ts
|
|
935
|
+
var init_effects = __esm({
|
|
936
|
+
"../core/src/effects.ts"() {
|
|
937
|
+
"use strict";
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
|
|
931
941
|
// ../core/src/presets.ts
|
|
932
942
|
function makeRng(seed) {
|
|
933
943
|
let a = seed >>> 0 || 2654435769;
|
|
@@ -1385,6 +1395,7 @@ var init_src = __esm({
|
|
|
1385
1395
|
init_path();
|
|
1386
1396
|
init_camera();
|
|
1387
1397
|
init_gradient();
|
|
1398
|
+
init_effects();
|
|
1388
1399
|
init_presets();
|
|
1389
1400
|
init_devicePreset();
|
|
1390
1401
|
init_cursor();
|
package/dist/browserEntry.js
CHANGED
|
@@ -334,11 +334,12 @@
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// ../core/src/validate.ts
|
|
337
|
-
var
|
|
337
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
338
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
338
339
|
var PROPS_BY_TYPE = {
|
|
339
340
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
340
341
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
341
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
342
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
342
343
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
343
344
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
344
345
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -679,9 +680,21 @@
|
|
|
679
680
|
const v = valueAt(target, prop, base ?? "");
|
|
680
681
|
return v === "" && base === void 0 ? void 0 : String(v);
|
|
681
682
|
};
|
|
683
|
+
const effectFx = (id, p) => {
|
|
684
|
+
const fx = {};
|
|
685
|
+
if (p.blur !== void 0) fx.blur = num(id, "blur", p.blur);
|
|
686
|
+
if (p.shadowColor !== void 0) {
|
|
687
|
+
fx.shadowColor = str(id, "shadowColor", p.shadowColor);
|
|
688
|
+
fx.shadowBlur = num(id, "shadowBlur", p.shadowBlur ?? 0);
|
|
689
|
+
fx.shadowX = num(id, "shadowX", p.shadowX ?? 0);
|
|
690
|
+
fx.shadowY = num(id, "shadowY", p.shadowY ?? 0);
|
|
691
|
+
}
|
|
692
|
+
return fx;
|
|
693
|
+
};
|
|
682
694
|
const walk = (node, parent, parentOpacity, clips) => {
|
|
683
695
|
const id = node.id;
|
|
684
696
|
const clipSpread = clips.length > 0 ? { clips } : void 0;
|
|
697
|
+
const fx = effectFx(id, node.props);
|
|
685
698
|
if (node.type === "line") {
|
|
686
699
|
const opacity2 = parentOpacity * num(id, "opacity", node.props.opacity ?? 1);
|
|
687
700
|
if (opacity2 <= 0) return;
|
|
@@ -699,6 +712,7 @@
|
|
|
699
712
|
y2: y1 + (num(id, "y2", node.props.y2) - y1) * progress,
|
|
700
713
|
stroke: str(id, "stroke", node.props.stroke),
|
|
701
714
|
strokeWidth: num(id, "strokeWidth", node.props.strokeWidth ?? 1),
|
|
715
|
+
...fx,
|
|
702
716
|
...clipSpread
|
|
703
717
|
});
|
|
704
718
|
return;
|
|
@@ -746,6 +760,7 @@
|
|
|
746
760
|
...fill !== void 0 && { fill },
|
|
747
761
|
...stroke !== void 0 && { stroke, strokeWidth },
|
|
748
762
|
...node.type === "rect" && { radius: num(id, "radius", node.props.radius ?? 0) },
|
|
763
|
+
...fx,
|
|
749
764
|
...clipSpread
|
|
750
765
|
});
|
|
751
766
|
return;
|
|
@@ -764,6 +779,7 @@
|
|
|
764
779
|
height,
|
|
765
780
|
offsetX: -width * ax,
|
|
766
781
|
offsetY: -height * ay,
|
|
782
|
+
...fx,
|
|
767
783
|
...clipSpread
|
|
768
784
|
});
|
|
769
785
|
return;
|
|
@@ -787,6 +803,7 @@
|
|
|
787
803
|
...fill !== void 0 && { fill },
|
|
788
804
|
...stroke !== void 0 && { stroke, strokeWidth: num(id, "strokeWidth", node.props.strokeWidth ?? 1) },
|
|
789
805
|
...needsBox && { bbox: pathBBox(dStr) },
|
|
806
|
+
...fx,
|
|
790
807
|
...clipSpread
|
|
791
808
|
});
|
|
792
809
|
return;
|
|
@@ -811,6 +828,7 @@
|
|
|
811
828
|
letterSpacing: num(id, "letterSpacing", node.props.letterSpacing ?? 0),
|
|
812
829
|
align: TEXT_ALIGN[ax] ?? "left",
|
|
813
830
|
baseline: TEXT_BASELINE[ay] ?? "top",
|
|
831
|
+
...fx,
|
|
814
832
|
...clipSpread
|
|
815
833
|
});
|
|
816
834
|
return;
|
|
@@ -889,6 +907,13 @@
|
|
|
889
907
|
}
|
|
890
908
|
ctx2.setTransform(...op.transform);
|
|
891
909
|
ctx2.globalAlpha = Math.max(0, Math.min(1, op.opacity));
|
|
910
|
+
if (op.blur) ctx2.filter = `blur(${op.blur}px)`;
|
|
911
|
+
if (op.shadowColor) {
|
|
912
|
+
ctx2.shadowColor = op.shadowColor;
|
|
913
|
+
ctx2.shadowBlur = op.shadowBlur ?? 0;
|
|
914
|
+
ctx2.shadowOffsetX = op.shadowX ?? 0;
|
|
915
|
+
ctx2.shadowOffsetY = op.shadowY ?? 0;
|
|
916
|
+
}
|
|
892
917
|
switch (op.type) {
|
|
893
918
|
case "rect": {
|
|
894
919
|
const box = { x: op.offsetX, y: op.offsetY, w: op.width, h: op.height };
|
package/dist/cli.js
CHANGED
|
@@ -324,12 +324,13 @@ function compileScene(ir) {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
// ../core/src/validate.ts
|
|
327
|
-
var
|
|
327
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
328
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
328
329
|
var CAMERA_PROPS = ["x", "y", "zoom", "rotation"];
|
|
329
330
|
var PROPS_BY_TYPE = {
|
|
330
331
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
331
332
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
332
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
333
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
333
334
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
334
335
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
335
336
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -375,6 +376,8 @@ function validateScene(ir) {
|
|
|
375
376
|
const props = node.props;
|
|
376
377
|
checkPaint(`node "${node.id}" fill`, props.fill);
|
|
377
378
|
checkPaint(`node "${node.id}" stroke`, props.stroke);
|
|
379
|
+
if (typeof props.blur === "number" && props.blur < 0) problems.push(`node "${node.id}": blur must be >= 0`);
|
|
380
|
+
if (typeof props.shadowBlur === "number" && props.shadowBlur < 0) problems.push(`node "${node.id}": shadowBlur must be >= 0`);
|
|
378
381
|
if (node.type === "group") {
|
|
379
382
|
const clip = node.props.clip;
|
|
380
383
|
if (clip) {
|
package/dist/index.js
CHANGED
|
@@ -334,12 +334,13 @@ function compileScene(ir) {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// ../core/src/validate.ts
|
|
337
|
-
var
|
|
337
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
338
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
338
339
|
var CAMERA_PROPS = ["x", "y", "zoom", "rotation"];
|
|
339
340
|
var PROPS_BY_TYPE = {
|
|
340
341
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
341
342
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
342
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
343
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
343
344
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
344
345
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
345
346
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -385,6 +386,8 @@ function validateScene(ir) {
|
|
|
385
386
|
const props = node.props;
|
|
386
387
|
checkPaint(`node "${node.id}" fill`, props.fill);
|
|
387
388
|
checkPaint(`node "${node.id}" stroke`, props.stroke);
|
|
389
|
+
if (typeof props.blur === "number" && props.blur < 0) problems.push(`node "${node.id}": blur must be >= 0`);
|
|
390
|
+
if (typeof props.shadowBlur === "number" && props.shadowBlur < 0) problems.push(`node "${node.id}": shadowBlur must be >= 0`);
|
|
388
391
|
if (node.type === "group") {
|
|
389
392
|
const clip = node.props.clip;
|
|
390
393
|
if (clip) {
|
|
@@ -987,6 +990,14 @@ function conicGradient(stops, opts = {}) {
|
|
|
987
990
|
};
|
|
988
991
|
}
|
|
989
992
|
|
|
993
|
+
// ../core/src/effects.ts
|
|
994
|
+
function glow(color, blur = 24) {
|
|
995
|
+
return { shadowColor: color, shadowBlur: blur, shadowX: 0, shadowY: 0 };
|
|
996
|
+
}
|
|
997
|
+
function dropShadow(color, blur = 24, x = 0, y = 12) {
|
|
998
|
+
return { shadowColor: color, shadowBlur: blur, shadowX: x, shadowY: y };
|
|
999
|
+
}
|
|
1000
|
+
|
|
990
1001
|
// ../core/src/presets.ts
|
|
991
1002
|
var PRESET_NAMES = [
|
|
992
1003
|
"draw-bloom",
|
|
@@ -1526,11 +1537,11 @@ function ikReach(upper, lower, dx, dy, flip = false) {
|
|
|
1526
1537
|
function humanoid(opts = {}) {
|
|
1527
1538
|
const line2 = opts.color ?? DEFAULT_LINE;
|
|
1528
1539
|
const fill = opts.fill ?? DEFAULT_FILL;
|
|
1529
|
-
const
|
|
1540
|
+
const glow2 = opts.glow;
|
|
1530
1541
|
const blob = (jid, a, b, cy) => {
|
|
1531
1542
|
const d = ovalPath(a, b, 0, cy);
|
|
1532
1543
|
const nodes = [];
|
|
1533
|
-
if (
|
|
1544
|
+
if (glow2) nodes.push(path({ id: `${jid}-glow`, d, x: 0, y: 0, fill: "none", stroke: glow2, strokeWidth: GLOW_W, opacity: 0.18 }));
|
|
1534
1545
|
nodes.push(path({ id: `${jid}-shape`, d, x: 0, y: 0, fill, stroke: line2, strokeWidth: LINE_W }));
|
|
1535
1546
|
return nodes;
|
|
1536
1547
|
};
|
|
@@ -2938,9 +2949,21 @@ function evaluate(compiled, t) {
|
|
|
2938
2949
|
const v = valueAt(target, prop, base ?? "");
|
|
2939
2950
|
return v === "" && base === void 0 ? void 0 : String(v);
|
|
2940
2951
|
};
|
|
2952
|
+
const effectFx = (id, p) => {
|
|
2953
|
+
const fx = {};
|
|
2954
|
+
if (p.blur !== void 0) fx.blur = num(id, "blur", p.blur);
|
|
2955
|
+
if (p.shadowColor !== void 0) {
|
|
2956
|
+
fx.shadowColor = str(id, "shadowColor", p.shadowColor);
|
|
2957
|
+
fx.shadowBlur = num(id, "shadowBlur", p.shadowBlur ?? 0);
|
|
2958
|
+
fx.shadowX = num(id, "shadowX", p.shadowX ?? 0);
|
|
2959
|
+
fx.shadowY = num(id, "shadowY", p.shadowY ?? 0);
|
|
2960
|
+
}
|
|
2961
|
+
return fx;
|
|
2962
|
+
};
|
|
2941
2963
|
const walk = (node, parent, parentOpacity, clips) => {
|
|
2942
2964
|
const id = node.id;
|
|
2943
2965
|
const clipSpread = clips.length > 0 ? { clips } : void 0;
|
|
2966
|
+
const fx = effectFx(id, node.props);
|
|
2944
2967
|
if (node.type === "line") {
|
|
2945
2968
|
const opacity2 = parentOpacity * num(id, "opacity", node.props.opacity ?? 1);
|
|
2946
2969
|
if (opacity2 <= 0) return;
|
|
@@ -2958,6 +2981,7 @@ function evaluate(compiled, t) {
|
|
|
2958
2981
|
y2: y1 + (num(id, "y2", node.props.y2) - y1) * progress,
|
|
2959
2982
|
stroke: str(id, "stroke", node.props.stroke),
|
|
2960
2983
|
strokeWidth: num(id, "strokeWidth", node.props.strokeWidth ?? 1),
|
|
2984
|
+
...fx,
|
|
2961
2985
|
...clipSpread
|
|
2962
2986
|
});
|
|
2963
2987
|
return;
|
|
@@ -3005,6 +3029,7 @@ function evaluate(compiled, t) {
|
|
|
3005
3029
|
...fill !== void 0 && { fill },
|
|
3006
3030
|
...stroke !== void 0 && { stroke, strokeWidth },
|
|
3007
3031
|
...node.type === "rect" && { radius: num(id, "radius", node.props.radius ?? 0) },
|
|
3032
|
+
...fx,
|
|
3008
3033
|
...clipSpread
|
|
3009
3034
|
});
|
|
3010
3035
|
return;
|
|
@@ -3023,6 +3048,7 @@ function evaluate(compiled, t) {
|
|
|
3023
3048
|
height,
|
|
3024
3049
|
offsetX: -width * ax,
|
|
3025
3050
|
offsetY: -height * ay,
|
|
3051
|
+
...fx,
|
|
3026
3052
|
...clipSpread
|
|
3027
3053
|
});
|
|
3028
3054
|
return;
|
|
@@ -3046,6 +3072,7 @@ function evaluate(compiled, t) {
|
|
|
3046
3072
|
...fill !== void 0 && { fill },
|
|
3047
3073
|
...stroke !== void 0 && { stroke, strokeWidth: num(id, "strokeWidth", node.props.strokeWidth ?? 1) },
|
|
3048
3074
|
...needsBox && { bbox: pathBBox(dStr) },
|
|
3075
|
+
...fx,
|
|
3049
3076
|
...clipSpread
|
|
3050
3077
|
});
|
|
3051
3078
|
return;
|
|
@@ -3070,6 +3097,7 @@ function evaluate(compiled, t) {
|
|
|
3070
3097
|
letterSpacing: num(id, "letterSpacing", node.props.letterSpacing ?? 0),
|
|
3071
3098
|
align: TEXT_ALIGN[ax] ?? "left",
|
|
3072
3099
|
baseline: TEXT_BASELINE[ay] ?? "top",
|
|
3100
|
+
...fx,
|
|
3073
3101
|
...clipSpread
|
|
3074
3102
|
});
|
|
3075
3103
|
return;
|
|
@@ -3204,10 +3232,12 @@ export {
|
|
|
3204
3232
|
deviceScreen,
|
|
3205
3233
|
deviceScreenCenter,
|
|
3206
3234
|
deviceScreenPoint,
|
|
3235
|
+
dropShadow,
|
|
3207
3236
|
ellipse,
|
|
3208
3237
|
evaluate,
|
|
3209
3238
|
figure,
|
|
3210
3239
|
formatComposeReport,
|
|
3240
|
+
glow,
|
|
3211
3241
|
group,
|
|
3212
3242
|
humanoid,
|
|
3213
3243
|
ikReach,
|
package/dist/labels.js
CHANGED
|
@@ -318,12 +318,13 @@ function compileScene(ir) {
|
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
// ../core/src/validate.ts
|
|
321
|
-
var
|
|
321
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
322
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
322
323
|
var CAMERA_PROPS = ["x", "y", "zoom", "rotation"];
|
|
323
324
|
var PROPS_BY_TYPE = {
|
|
324
325
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
325
326
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
326
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
327
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
327
328
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
328
329
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
329
330
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -369,6 +370,8 @@ function validateScene(ir) {
|
|
|
369
370
|
const props = node.props;
|
|
370
371
|
checkPaint(`node "${node.id}" fill`, props.fill);
|
|
371
372
|
checkPaint(`node "${node.id}" stroke`, props.stroke);
|
|
373
|
+
if (typeof props.blur === "number" && props.blur < 0) problems.push(`node "${node.id}": blur must be >= 0`);
|
|
374
|
+
if (typeof props.shadowBlur === "number" && props.shadowBlur < 0) problems.push(`node "${node.id}": shadowBlur must be >= 0`);
|
|
372
375
|
if (node.type === "group") {
|
|
373
376
|
const clip = node.props.clip;
|
|
374
377
|
if (clip) {
|
package/dist/renderer-canvas.js
CHANGED
|
@@ -55,6 +55,13 @@ function drawDisplayList(ctx, ops, images) {
|
|
|
55
55
|
}
|
|
56
56
|
ctx.setTransform(...op.transform);
|
|
57
57
|
ctx.globalAlpha = Math.max(0, Math.min(1, op.opacity));
|
|
58
|
+
if (op.blur) ctx.filter = `blur(${op.blur}px)`;
|
|
59
|
+
if (op.shadowColor) {
|
|
60
|
+
ctx.shadowColor = op.shadowColor;
|
|
61
|
+
ctx.shadowBlur = op.shadowBlur ?? 0;
|
|
62
|
+
ctx.shadowOffsetX = op.shadowX ?? 0;
|
|
63
|
+
ctx.shadowOffsetY = op.shadowY ?? 0;
|
|
64
|
+
}
|
|
58
65
|
switch (op.type) {
|
|
59
66
|
case "rect": {
|
|
60
67
|
const box = { x: op.offsetX, y: op.offsetY, w: op.width, h: op.height };
|
package/dist/trace-cli.js
CHANGED
|
@@ -6,11 +6,12 @@ import { resolve as resolve2 } from "node:path";
|
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
8
8
|
// ../core/src/validate.ts
|
|
9
|
-
var
|
|
9
|
+
var FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY"];
|
|
10
|
+
var COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor", "fixed", ...FX_PROPS];
|
|
10
11
|
var PROPS_BY_TYPE = {
|
|
11
12
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
12
13
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
13
|
-
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress"],
|
|
14
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
14
15
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
15
16
|
image: [...COMMON_PROPS, "src", "width", "height"],
|
|
16
17
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop-shadow / outer-glow sugar. These return a partial-props object you spread
|
|
3
|
+
* into a shape node; the underlying `shadow*` props stay animatable (e.g. pulse a
|
|
4
|
+
* glow with `oscillate(id, "shadowBlur", …)`). Units are screen pixels.
|
|
5
|
+
*/
|
|
6
|
+
import type { BaseProps } from "./ir.js";
|
|
7
|
+
type ShadowProps = Pick<BaseProps, "shadowColor" | "shadowBlur" | "shadowX" | "shadowY">;
|
|
8
|
+
/** An outer glow — a shadow with no offset. `rect({ …, ...glow("#FFD24B", 28) })`. */
|
|
9
|
+
export declare function glow(color: string, blur?: number): ShadowProps;
|
|
10
|
+
/** A drop shadow (offset downward by default). `rect({ …, ...dropShadow("#0008", 40, 0, 16) })`. */
|
|
11
|
+
export declare function dropShadow(color: string, blur?: number, x?: number, y?: number): ShadowProps;
|
|
12
|
+
export {};
|
package/dist/types/evaluate.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ interface OpBase {
|
|
|
24
24
|
opacity: number;
|
|
25
25
|
/** Clip regions from ancestor groups (intersected by the renderer). */
|
|
26
26
|
clips?: ClipRegion[];
|
|
27
|
+
/** Paint effects (screen-pixel space). Present only when authored. */
|
|
28
|
+
blur?: number;
|
|
29
|
+
shadowColor?: string;
|
|
30
|
+
shadowBlur?: number;
|
|
31
|
+
shadowX?: number;
|
|
32
|
+
shadowY?: number;
|
|
27
33
|
}
|
|
28
34
|
export type DisplayOp = (OpBase & {
|
|
29
35
|
type: "rect";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { compileScene, type CompiledScene, type PropertySegment, type LabelSpan,
|
|
|
7
7
|
export { pathPoint, pathTangentAngle, type Pt } from "./path.js";
|
|
8
8
|
export { cameraTo, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
|
|
9
9
|
export { linearGradient, radialGradient, conicGradient, isGradient } from "./gradient.js";
|
|
10
|
+
export { glow, dropShadow } from "./effects.js";
|
|
10
11
|
export { motionPreset, PRESET_NAMES, type PresetName, type PresetRig, type PresetOpts } from "./presets.js";
|
|
11
12
|
export { devicePreset, deviceScreen, deviceScreenCenter, deviceBounds, deviceScreenPoint, DEVICE_PRESET_NAMES, type DevicePresetName, type DevicePresetOpts } from "./devicePreset.js";
|
|
12
13
|
export { cursor, cursorTo, cursorPath, cursorClick, cursorDouble, type CursorStyle, type CursorOpts, type CursorToOpts, type CursorPathOpts, type CursorClickOpts } from "./cursor.js";
|
package/dist/types/ir.d.ts
CHANGED
|
@@ -36,6 +36,17 @@ export interface BaseProps {
|
|
|
36
36
|
* for HUD / titles / watermark layers. No-op when the scene has no camera.
|
|
37
37
|
*/
|
|
38
38
|
fixed?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Paint effects (animatable scalars, in screen pixels — not transformed by the
|
|
41
|
+
* node's rotation/scale or the camera, so a shadow keeps a consistent light
|
|
42
|
+
* direction). `shadowColor` enables a drop shadow / outer glow (`glow`/`dropShadow`
|
|
43
|
+
* helpers). No-op on a `group` (use a child; group/composite blur is a later add).
|
|
44
|
+
*/
|
|
45
|
+
blur?: number;
|
|
46
|
+
shadowColor?: string;
|
|
47
|
+
shadowBlur?: number;
|
|
48
|
+
shadowX?: number;
|
|
49
|
+
shadowY?: number;
|
|
39
50
|
}
|
|
40
51
|
/**
|
|
41
52
|
* A paint is a solid color string OR a gradient. Coordinates are normalized to the
|
|
@@ -93,6 +104,12 @@ export interface LineProps {
|
|
|
93
104
|
progress?: number;
|
|
94
105
|
/** Pin to the screen so the scene `camera` does not move it (top-level only). */
|
|
95
106
|
fixed?: boolean;
|
|
107
|
+
/** Paint effects (px, screen-space) — see BaseProps. */
|
|
108
|
+
blur?: number;
|
|
109
|
+
shadowColor?: string;
|
|
110
|
+
shadowBlur?: number;
|
|
111
|
+
shadowX?: number;
|
|
112
|
+
shadowY?: number;
|
|
96
113
|
}
|
|
97
114
|
export interface TextProps extends BaseProps {
|
|
98
115
|
/** Numbers interpolate (count-up) and render via toFixed(contentDecimals). */
|
package/guides/edsl-guide.md
CHANGED
|
@@ -172,6 +172,28 @@ ellipse({ id: "ring", /* … */ fill: "none", stroke: linearGradient(["#3AA0FF",
|
|
|
172
172
|
gradient sweeps/stretches with it. Color-string fills still tween as today.
|
|
173
173
|
- text fill and line stroke are color-only for now. See `examples/scenes/gradient-demo.ts`.
|
|
174
174
|
|
|
175
|
+
## Shadow, glow & blur
|
|
176
|
+
|
|
177
|
+
Drawable nodes (rect / ellipse / path / text / image / line) take animatable paint
|
|
178
|
+
effects, in **screen pixels** (not transformed by the node or camera, so a shadow
|
|
179
|
+
keeps a consistent light direction):
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
rect({ id: "card", /* … */, ...dropShadow("#000000", 64, 0, 34) }) // drop shadow
|
|
183
|
+
ellipse({ id: "orb", /* … */, fill: radialGradient([...]), shadowColor: "#FFC24B", shadowBlur: 22 })
|
|
184
|
+
oscillate("orb", "shadowBlur", { amplitude: 16, frequency: 0.9 }) // PULSING glow
|
|
185
|
+
rect({ id: "card", /* … */, blur: 18 }); tween("card", { blur: 0 }, { duration: 1 }) // focus pull
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- Props: `blur` (gaussian blur of the shape), `shadowColor` (turns the shadow/glow
|
|
189
|
+
on), `shadowBlur`, `shadowX`, `shadowY`. All **animatable** — `tween`/`oscillate`
|
|
190
|
+
them for pulsing glows, focus pulls, etc. (set a base value first so there's
|
|
191
|
+
something to animate from).
|
|
192
|
+
- Sugar: `glow(color, blur)` (offset 0) and `dropShadow(color, blur, x, y)` return
|
|
193
|
+
a partial you spread into props (`...glow("#FFD24B", 28)`); still animatable.
|
|
194
|
+
- No-op on a `group` (apply to a child; group/composite blur is a later add). See
|
|
195
|
+
`examples/scenes/shadow-demo.ts`.
|
|
196
|
+
|
|
175
197
|
## Character rig (skeleton, poses, IK)
|
|
176
198
|
|
|
177
199
|
A first-class, declarative character rig that **compiles to plain IR** (nested
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reframe-video",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
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",
|