reframe-video 0.6.5 → 0.6.7
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 +331 -94
- package/dist/browserEntry.js +82 -35
- package/dist/cli.js +305 -75
- package/dist/index.js +79 -8
- package/dist/labels.js +1 -0
- package/dist/renderer-canvas.js +31 -25
- package/dist/trace-cli.js +1 -0
- package/dist/types/assets.d.ts +3 -1
- package/dist/types/audio.d.ts +15 -0
- package/dist/types/dsl.d.ts +4 -1
- package/dist/types/evaluate.d.ts +12 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/ir.d.ts +26 -0
- package/guides/edsl-guide.md +25 -0
- package/package.json +1 -1
- package/preview/src/main.ts +2 -1
package/dist/browserEntry.js
CHANGED
|
@@ -342,6 +342,7 @@
|
|
|
342
342
|
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
|
|
343
343
|
text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
|
|
344
344
|
image: [...COMMON_PROPS, "src", "width", "height", "fit"],
|
|
345
|
+
video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart", "volume"],
|
|
345
346
|
path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
|
|
346
347
|
group: COMMON_PROPS
|
|
347
348
|
};
|
|
@@ -786,6 +787,33 @@
|
|
|
786
787
|
});
|
|
787
788
|
return;
|
|
788
789
|
}
|
|
790
|
+
case "video": {
|
|
791
|
+
const width = num(id, "width", node.props.width);
|
|
792
|
+
const height = num(id, "height", node.props.height);
|
|
793
|
+
const [ax, ay] = ANCHOR_FACTORS[node.props.anchor ?? "top-left"];
|
|
794
|
+
const fps = compiled2.ir.fps ?? 30;
|
|
795
|
+
const start = node.props.start ?? 0;
|
|
796
|
+
const rate = node.props.rate ?? 1;
|
|
797
|
+
const clipStart = node.props.clipStart ?? 0;
|
|
798
|
+
const srcT = clipStart + Math.max(0, t - start) * rate;
|
|
799
|
+
const frame = Math.max(0, Math.round(srcT * fps));
|
|
800
|
+
ops.push({
|
|
801
|
+
type: "video",
|
|
802
|
+
id,
|
|
803
|
+
transform: matrix,
|
|
804
|
+
opacity,
|
|
805
|
+
src: str(id, "src", node.props.src),
|
|
806
|
+
width,
|
|
807
|
+
height,
|
|
808
|
+
offsetX: -width * ax,
|
|
809
|
+
offsetY: -height * ay,
|
|
810
|
+
frame,
|
|
811
|
+
...node.props.fit && node.props.fit !== "fill" ? { fit: node.props.fit } : {},
|
|
812
|
+
...fx,
|
|
813
|
+
...clipSpread
|
|
814
|
+
});
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
789
817
|
case "path": {
|
|
790
818
|
const ox = num(id, "originX", node.props.originX ?? 0);
|
|
791
819
|
const oy = num(id, "originY", node.props.originY ?? 0);
|
|
@@ -879,7 +907,7 @@
|
|
|
879
907
|
for (const s of paint.stops) g.addColorStop(Math.max(0, Math.min(1, s.offset)), s.color);
|
|
880
908
|
return g;
|
|
881
909
|
}
|
|
882
|
-
function renderFrame(ctx2, compiled2, t, images2) {
|
|
910
|
+
function renderFrame(ctx2, compiled2, t, images2, videos2) {
|
|
883
911
|
const { size, background } = compiled2.ir;
|
|
884
912
|
ctx2.setTransform(1, 0, 0, 1, 0, 0);
|
|
885
913
|
ctx2.clearRect(0, 0, size.width, size.height);
|
|
@@ -887,9 +915,9 @@
|
|
|
887
915
|
ctx2.fillStyle = background;
|
|
888
916
|
ctx2.fillRect(0, 0, size.width, size.height);
|
|
889
917
|
}
|
|
890
|
-
drawDisplayList(ctx2, evaluate(compiled2, t), images2);
|
|
918
|
+
drawDisplayList(ctx2, evaluate(compiled2, t), images2, videos2);
|
|
891
919
|
}
|
|
892
|
-
function drawDisplayList(ctx2, ops, images2) {
|
|
920
|
+
function drawDisplayList(ctx2, ops, images2, videos2) {
|
|
893
921
|
for (const op of ops) {
|
|
894
922
|
ctx2.save();
|
|
895
923
|
if (op.clips) {
|
|
@@ -971,28 +999,11 @@
|
|
|
971
999
|
break;
|
|
972
1000
|
}
|
|
973
1001
|
case "image": {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
ctx2.drawImage(img, sx, sy, sw, sh, op.offsetX, op.offsetY, op.width, op.height);
|
|
980
|
-
} else {
|
|
981
|
-
ctx2.drawImage(img, op.offsetX, op.offsetY, op.width, op.height);
|
|
982
|
-
}
|
|
983
|
-
} else {
|
|
984
|
-
ctx2.fillStyle = "#2A2A30";
|
|
985
|
-
ctx2.fillRect(op.offsetX, op.offsetY, op.width, op.height);
|
|
986
|
-
ctx2.strokeStyle = "#FF00FF";
|
|
987
|
-
ctx2.lineWidth = 2;
|
|
988
|
-
ctx2.strokeRect(op.offsetX, op.offsetY, op.width, op.height);
|
|
989
|
-
ctx2.beginPath();
|
|
990
|
-
ctx2.moveTo(op.offsetX, op.offsetY);
|
|
991
|
-
ctx2.lineTo(op.offsetX + op.width, op.offsetY + op.height);
|
|
992
|
-
ctx2.moveTo(op.offsetX + op.width, op.offsetY);
|
|
993
|
-
ctx2.lineTo(op.offsetX, op.offsetY + op.height);
|
|
994
|
-
ctx2.stroke();
|
|
995
|
-
}
|
|
1002
|
+
drawRaster(ctx2, images2?.get(op.src), op);
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
case "video": {
|
|
1006
|
+
drawRaster(ctx2, videos2?.frame(op.src, op.frame), op);
|
|
996
1007
|
break;
|
|
997
1008
|
}
|
|
998
1009
|
case "path": {
|
|
@@ -1047,6 +1058,29 @@
|
|
|
1047
1058
|
const a = img;
|
|
1048
1059
|
return [a.naturalWidth || a.width || 0, a.naturalHeight || a.height || 0];
|
|
1049
1060
|
}
|
|
1061
|
+
function drawRaster(ctx2, img, op) {
|
|
1062
|
+
if (img) {
|
|
1063
|
+
if (op.fit === "cover") {
|
|
1064
|
+
const [iw, ih] = intrinsicSize(img);
|
|
1065
|
+
const { sx, sy, sw, sh } = coverRect(iw, ih, op.width, op.height);
|
|
1066
|
+
ctx2.drawImage(img, sx, sy, sw, sh, op.offsetX, op.offsetY, op.width, op.height);
|
|
1067
|
+
} else {
|
|
1068
|
+
ctx2.drawImage(img, op.offsetX, op.offsetY, op.width, op.height);
|
|
1069
|
+
}
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
ctx2.fillStyle = "#2A2A30";
|
|
1073
|
+
ctx2.fillRect(op.offsetX, op.offsetY, op.width, op.height);
|
|
1074
|
+
ctx2.strokeStyle = "#FF00FF";
|
|
1075
|
+
ctx2.lineWidth = 2;
|
|
1076
|
+
ctx2.strokeRect(op.offsetX, op.offsetY, op.width, op.height);
|
|
1077
|
+
ctx2.beginPath();
|
|
1078
|
+
ctx2.moveTo(op.offsetX, op.offsetY);
|
|
1079
|
+
ctx2.lineTo(op.offsetX + op.width, op.offsetY + op.height);
|
|
1080
|
+
ctx2.moveTo(op.offsetX + op.width, op.offsetY);
|
|
1081
|
+
ctx2.lineTo(op.offsetX, op.offsetY + op.height);
|
|
1082
|
+
ctx2.stroke();
|
|
1083
|
+
}
|
|
1050
1084
|
function quoteFamily(family) {
|
|
1051
1085
|
return family.includes(" ") && !family.includes('"') ? `"${family}"` : family;
|
|
1052
1086
|
}
|
|
@@ -1069,9 +1103,22 @@
|
|
|
1069
1103
|
var ctx = null;
|
|
1070
1104
|
var canvas = null;
|
|
1071
1105
|
var images = /* @__PURE__ */ new Map();
|
|
1106
|
+
var videoFrames = /* @__PURE__ */ new Map();
|
|
1107
|
+
var decode = (dataUrl) => {
|
|
1108
|
+
const img = new Image();
|
|
1109
|
+
img.src = dataUrl;
|
|
1110
|
+
return img.decode().then(() => img);
|
|
1111
|
+
};
|
|
1112
|
+
var videos = {
|
|
1113
|
+
frame(src, index) {
|
|
1114
|
+
const frames = videoFrames.get(src);
|
|
1115
|
+
if (!frames || frames.length === 0) return void 0;
|
|
1116
|
+
return frames[Math.max(0, Math.min(index, frames.length - 1))];
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1072
1119
|
window.__reframe = {
|
|
1073
|
-
// fully decode every image before the first frame — renderFrame is sync
|
|
1074
|
-
async init(ir, assets = {}) {
|
|
1120
|
+
// fully decode every image/video frame before the first frame — renderFrame is sync
|
|
1121
|
+
async init(ir, assets = {}, videoAssets = {}) {
|
|
1075
1122
|
compiled = compileScene(ir);
|
|
1076
1123
|
canvas = document.createElement("canvas");
|
|
1077
1124
|
canvas.width = ir.size.width;
|
|
@@ -1079,19 +1126,19 @@
|
|
|
1079
1126
|
document.body.appendChild(canvas);
|
|
1080
1127
|
ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
1081
1128
|
if (!ctx) throw new Error("could not create 2d context");
|
|
1082
|
-
await Promise.all(
|
|
1083
|
-
Object.entries(assets).map(async ([src, dataUrl]) => {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1129
|
+
await Promise.all([
|
|
1130
|
+
...Object.entries(assets).map(async ([src, dataUrl]) => {
|
|
1131
|
+
images.set(src, await decode(dataUrl));
|
|
1132
|
+
}),
|
|
1133
|
+
...Object.entries(videoAssets).map(async ([src, frames]) => {
|
|
1134
|
+
videoFrames.set(src, await Promise.all(frames.map(decode)));
|
|
1088
1135
|
})
|
|
1089
|
-
);
|
|
1136
|
+
]);
|
|
1090
1137
|
return { duration: compiled.duration, fps: ir.fps ?? 30 };
|
|
1091
1138
|
},
|
|
1092
1139
|
renderFrame(t) {
|
|
1093
1140
|
if (!compiled || !ctx || !canvas) throw new Error("init() not called");
|
|
1094
|
-
renderFrame(ctx, compiled, t, images);
|
|
1141
|
+
renderFrame(ctx, compiled, t, images, videos);
|
|
1095
1142
|
return canvas.toDataURL("image/png");
|
|
1096
1143
|
}
|
|
1097
1144
|
};
|