@remotion/motion-blur 4.0.527 → 4.0.529
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.
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type HtmlInCanvasProps } from 'remotion';
|
|
3
|
+
export type HtmlInCanvasMotionBlurProps = Pick<HtmlInCanvasProps, 'from' | 'durationInFrames' | 'trimBefore' | 'playbackRate'> & {
|
|
4
|
+
readonly children: React.ReactNode;
|
|
5
|
+
readonly width: number;
|
|
6
|
+
readonly height: number;
|
|
7
|
+
readonly shutterAngle?: number;
|
|
8
|
+
readonly samples?: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Experimental motion blur that averages separately captured HTML-in-canvas
|
|
12
|
+
* snapshots of the children at fractional frames. Preview requires Chrome with
|
|
13
|
+
* the experimental HTML-in-canvas flag enabled. Nested HtmlInCanvas components
|
|
14
|
+
* are currently unsupported.
|
|
15
|
+
*/
|
|
16
|
+
export declare const HtmlInCanvasMotionBlur: React.FC<HtmlInCanvasMotionBlurProps>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HtmlInCanvasMotionBlur = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const remotion_1 = require("remotion");
|
|
7
|
+
const MotionBlurSample = ({ children, width, height, index, count, shutterInFrames, firstFrame, lastFrame, }) => {
|
|
8
|
+
const frame = (0, remotion_1.useCurrentFrame)();
|
|
9
|
+
const sampleFrame = Math.max(firstFrame, Math.min(lastFrame, frame + ((index + 0.5) / count - 0.5) * shutterInFrames));
|
|
10
|
+
return (jsx_runtime_1.jsx("div", { "aria-hidden": index !== Math.floor(count / 2), drawable: '', style: {
|
|
11
|
+
position: 'absolute',
|
|
12
|
+
inset: 0,
|
|
13
|
+
width,
|
|
14
|
+
height,
|
|
15
|
+
isolation: 'isolate',
|
|
16
|
+
pointerEvents: index === Math.floor(count / 2) ? 'auto' : 'none',
|
|
17
|
+
}, children: jsx_runtime_1.jsx(remotion_1.Freeze, { frame: sampleFrame, children: children }) }));
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Experimental motion blur that averages separately captured HTML-in-canvas
|
|
21
|
+
* snapshots of the children at fractional frames. Preview requires Chrome with
|
|
22
|
+
* the experimental HTML-in-canvas flag enabled. Nested HtmlInCanvas components
|
|
23
|
+
* are currently unsupported.
|
|
24
|
+
*/
|
|
25
|
+
const HtmlInCanvasMotionBlur = ({ children, width, height, shutterAngle = 180, samples = 8, from, durationInFrames, trimBefore, playbackRate, }) => {
|
|
26
|
+
const { durationInFrames: compositionDurationInFrames } = (0, remotion_1.useVideoConfig)();
|
|
27
|
+
if (!Number.isInteger(samples) || samples < 1 || samples > 64) {
|
|
28
|
+
throw new TypeError(`"samples" must be an integer between 1 and 64, but got ${String(samples)}`);
|
|
29
|
+
}
|
|
30
|
+
if (typeof shutterAngle !== 'number' ||
|
|
31
|
+
!Number.isFinite(shutterAngle) ||
|
|
32
|
+
shutterAngle < 0 ||
|
|
33
|
+
shutterAngle > 360) {
|
|
34
|
+
throw new TypeError(`"shutterAngle" must be between 0 and 360, but got ${String(shutterAngle)}`);
|
|
35
|
+
}
|
|
36
|
+
const actualSamples = shutterAngle === 0 ? 1 : samples;
|
|
37
|
+
const shutterInFrames = (shutterAngle / 360) * (playbackRate !== null && playbackRate !== void 0 ? playbackRate : 1);
|
|
38
|
+
const firstFrame = trimBefore !== null && trimBefore !== void 0 ? trimBefore : 0;
|
|
39
|
+
const visibleDuration = Math.max(0, Math.min(durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, compositionDurationInFrames - (from !== null && from !== void 0 ? from : 0)));
|
|
40
|
+
const lastFrame = firstFrame + Math.max(0, visibleDuration - 1) * (playbackRate !== null && playbackRate !== void 0 ? playbackRate : 1);
|
|
41
|
+
const onPaint = (0, react_1.useCallback)(({ canvas, element, elementImage }) => {
|
|
42
|
+
const context = canvas.getContext('2d');
|
|
43
|
+
if (!context) {
|
|
44
|
+
throw new Error('Failed to acquire 2D context for motion blur');
|
|
45
|
+
}
|
|
46
|
+
const layoutCanvas = element.parentElement;
|
|
47
|
+
if (!(layoutCanvas instanceof HTMLCanvasElement)) {
|
|
48
|
+
throw new Error('Failed to find the HTML-in-canvas layout canvas');
|
|
49
|
+
}
|
|
50
|
+
const captureElements = Array.from(layoutCanvas.children);
|
|
51
|
+
if (captureElements.length !== actualSamples ||
|
|
52
|
+
captureElements[0] !== element) {
|
|
53
|
+
throw new Error('Motion blur samples are not ready to paint');
|
|
54
|
+
}
|
|
55
|
+
context.reset();
|
|
56
|
+
context.globalCompositeOperation = 'lighter';
|
|
57
|
+
context.globalAlpha = 1 / actualSamples;
|
|
58
|
+
for (const [index, sampleElement] of captureElements.entries()) {
|
|
59
|
+
const image = index === 0
|
|
60
|
+
? elementImage
|
|
61
|
+
: layoutCanvas.captureElementImage(sampleElement);
|
|
62
|
+
try {
|
|
63
|
+
const sampleTransform = context.drawElementImage(image, 0, 0);
|
|
64
|
+
if (index === Math.floor(actualSamples / 2)) {
|
|
65
|
+
sampleElement.style.transform =
|
|
66
|
+
sampleTransform.toString();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
if (index !== 0) {
|
|
71
|
+
image.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}, [actualSamples]);
|
|
76
|
+
const sampleElements = Array.from({ length: actualSamples }, (_, index) => {
|
|
77
|
+
return (jsx_runtime_1.jsx(MotionBlurSample, { width: width, height: height, index: index, count: actualSamples, shutterInFrames: shutterInFrames, firstFrame: firstFrame, lastFrame: lastFrame, children: children }, index));
|
|
78
|
+
});
|
|
79
|
+
// The root wrapper holds the first sample. The rest must be canvas children.
|
|
80
|
+
return (jsx_runtime_1.jsx(remotion_1.HtmlInCanvas, { width: width, height: height, from: from, durationInFrames: durationInFrames, trimBefore: trimBefore, playbackRate: playbackRate, name: "<HtmlInCanvasMotionBlur>", onPaint: onPaint, _remotionInternalCanvasSiblings: sampleElements.slice(1), children: sampleElements[0] }));
|
|
81
|
+
};
|
|
82
|
+
exports.HtmlInCanvasMotionBlur = HtmlInCanvasMotionBlur;
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Trail = exports.CameraMotionBlur = void 0;
|
|
3
|
+
exports.Trail = exports.HtmlInCanvasMotionBlur = exports.CameraMotionBlur = void 0;
|
|
4
4
|
const CameraMotionBlur_1 = require("./CameraMotionBlur");
|
|
5
5
|
Object.defineProperty(exports, "CameraMotionBlur", { enumerable: true, get: function () { return CameraMotionBlur_1.CameraMotionBlur; } });
|
|
6
|
+
const HtmlInCanvasMotionBlur_1 = require("./HtmlInCanvasMotionBlur");
|
|
7
|
+
Object.defineProperty(exports, "HtmlInCanvasMotionBlur", { enumerable: true, get: function () { return HtmlInCanvasMotionBlur_1.HtmlInCanvasMotionBlur; } });
|
|
6
8
|
const Trail_1 = require("./Trail");
|
|
7
9
|
Object.defineProperty(exports, "Trail", { enumerable: true, get: function () { return Trail_1.Trail; } });
|
package/dist/esm/index.mjs
CHANGED
|
@@ -56,16 +56,132 @@ var CameraMotionBlur = ({
|
|
|
56
56
|
})
|
|
57
57
|
});
|
|
58
58
|
};
|
|
59
|
+
// src/HtmlInCanvasMotionBlur.tsx
|
|
60
|
+
import { useCallback } from "react";
|
|
61
|
+
import {
|
|
62
|
+
Freeze as Freeze2,
|
|
63
|
+
HtmlInCanvas,
|
|
64
|
+
useCurrentFrame as useCurrentFrame2,
|
|
65
|
+
useVideoConfig
|
|
66
|
+
} from "remotion";
|
|
67
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
68
|
+
var MotionBlurSample = ({
|
|
69
|
+
children,
|
|
70
|
+
width,
|
|
71
|
+
height,
|
|
72
|
+
index,
|
|
73
|
+
count,
|
|
74
|
+
shutterInFrames,
|
|
75
|
+
firstFrame,
|
|
76
|
+
lastFrame
|
|
77
|
+
}) => {
|
|
78
|
+
const frame = useCurrentFrame2();
|
|
79
|
+
const sampleFrame = Math.max(firstFrame, Math.min(lastFrame, frame + ((index + 0.5) / count - 0.5) * shutterInFrames));
|
|
80
|
+
return /* @__PURE__ */ jsx2("div", {
|
|
81
|
+
"aria-hidden": index !== Math.floor(count / 2),
|
|
82
|
+
...{ drawable: "" },
|
|
83
|
+
style: {
|
|
84
|
+
position: "absolute",
|
|
85
|
+
inset: 0,
|
|
86
|
+
width,
|
|
87
|
+
height,
|
|
88
|
+
isolation: "isolate",
|
|
89
|
+
pointerEvents: index === Math.floor(count / 2) ? "auto" : "none"
|
|
90
|
+
},
|
|
91
|
+
children: /* @__PURE__ */ jsx2(Freeze2, {
|
|
92
|
+
frame: sampleFrame,
|
|
93
|
+
children
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
var HtmlInCanvasMotionBlur = ({
|
|
98
|
+
children,
|
|
99
|
+
width,
|
|
100
|
+
height,
|
|
101
|
+
shutterAngle = 180,
|
|
102
|
+
samples = 8,
|
|
103
|
+
from,
|
|
104
|
+
durationInFrames,
|
|
105
|
+
trimBefore,
|
|
106
|
+
playbackRate
|
|
107
|
+
}) => {
|
|
108
|
+
const { durationInFrames: compositionDurationInFrames } = useVideoConfig();
|
|
109
|
+
if (!Number.isInteger(samples) || samples < 1 || samples > 64) {
|
|
110
|
+
throw new TypeError(`"samples" must be an integer between 1 and 64, but got ${String(samples)}`);
|
|
111
|
+
}
|
|
112
|
+
if (typeof shutterAngle !== "number" || !Number.isFinite(shutterAngle) || shutterAngle < 0 || shutterAngle > 360) {
|
|
113
|
+
throw new TypeError(`"shutterAngle" must be between 0 and 360, but got ${String(shutterAngle)}`);
|
|
114
|
+
}
|
|
115
|
+
const actualSamples = shutterAngle === 0 ? 1 : samples;
|
|
116
|
+
const shutterInFrames = shutterAngle / 360 * (playbackRate ?? 1);
|
|
117
|
+
const firstFrame = trimBefore ?? 0;
|
|
118
|
+
const visibleDuration = Math.max(0, Math.min(durationInFrames ?? Infinity, compositionDurationInFrames - (from ?? 0)));
|
|
119
|
+
const lastFrame = firstFrame + Math.max(0, visibleDuration - 1) * (playbackRate ?? 1);
|
|
120
|
+
const onPaint = useCallback(({ canvas, element, elementImage }) => {
|
|
121
|
+
const context = canvas.getContext("2d");
|
|
122
|
+
if (!context) {
|
|
123
|
+
throw new Error("Failed to acquire 2D context for motion blur");
|
|
124
|
+
}
|
|
125
|
+
const layoutCanvas = element.parentElement;
|
|
126
|
+
if (!(layoutCanvas instanceof HTMLCanvasElement)) {
|
|
127
|
+
throw new Error("Failed to find the HTML-in-canvas layout canvas");
|
|
128
|
+
}
|
|
129
|
+
const captureElements = Array.from(layoutCanvas.children);
|
|
130
|
+
if (captureElements.length !== actualSamples || captureElements[0] !== element) {
|
|
131
|
+
throw new Error("Motion blur samples are not ready to paint");
|
|
132
|
+
}
|
|
133
|
+
context.reset();
|
|
134
|
+
context.globalCompositeOperation = "lighter";
|
|
135
|
+
context.globalAlpha = 1 / actualSamples;
|
|
136
|
+
for (const [index, sampleElement] of captureElements.entries()) {
|
|
137
|
+
const image = index === 0 ? elementImage : layoutCanvas.captureElementImage(sampleElement);
|
|
138
|
+
try {
|
|
139
|
+
const sampleTransform = context.drawElementImage(image, 0, 0);
|
|
140
|
+
if (index === Math.floor(actualSamples / 2)) {
|
|
141
|
+
sampleElement.style.transform = sampleTransform.toString();
|
|
142
|
+
}
|
|
143
|
+
} finally {
|
|
144
|
+
if (index !== 0) {
|
|
145
|
+
image.close();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}, [actualSamples]);
|
|
150
|
+
const sampleElements = Array.from({ length: actualSamples }, (_, index) => {
|
|
151
|
+
return /* @__PURE__ */ jsx2(MotionBlurSample, {
|
|
152
|
+
width,
|
|
153
|
+
height,
|
|
154
|
+
index,
|
|
155
|
+
count: actualSamples,
|
|
156
|
+
shutterInFrames,
|
|
157
|
+
firstFrame,
|
|
158
|
+
lastFrame,
|
|
159
|
+
children
|
|
160
|
+
}, index);
|
|
161
|
+
});
|
|
162
|
+
return /* @__PURE__ */ jsx2(HtmlInCanvas, {
|
|
163
|
+
width,
|
|
164
|
+
height,
|
|
165
|
+
from,
|
|
166
|
+
durationInFrames,
|
|
167
|
+
trimBefore,
|
|
168
|
+
playbackRate,
|
|
169
|
+
name: "<HtmlInCanvasMotionBlur>",
|
|
170
|
+
onPaint,
|
|
171
|
+
_remotionInternalCanvasSiblings: sampleElements.slice(1),
|
|
172
|
+
children: sampleElements[0]
|
|
173
|
+
});
|
|
174
|
+
};
|
|
59
175
|
// src/Trail.tsx
|
|
60
|
-
import { AbsoluteFill as AbsoluteFill2, Freeze as
|
|
61
|
-
import { jsx as
|
|
176
|
+
import { AbsoluteFill as AbsoluteFill2, Freeze as Freeze3, useCurrentFrame as useCurrentFrame3 } from "remotion";
|
|
177
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
62
178
|
var Trail = ({
|
|
63
179
|
children,
|
|
64
180
|
layers,
|
|
65
181
|
lagInFrames,
|
|
66
182
|
trailOpacity
|
|
67
183
|
}) => {
|
|
68
|
-
const frame =
|
|
184
|
+
const frame = useCurrentFrame3();
|
|
69
185
|
if (typeof layers !== "number" || Number.isNaN(layers) || !Number.isFinite(layers)) {
|
|
70
186
|
throw new TypeError(`"layers" must be a number, but got ${JSON.stringify(layers)}`);
|
|
71
187
|
}
|
|
@@ -84,11 +200,11 @@ var Trail = ({
|
|
|
84
200
|
return /* @__PURE__ */ jsxs(AbsoluteFill2, {
|
|
85
201
|
children: [
|
|
86
202
|
new Array(layers).fill(true).map((_, i) => {
|
|
87
|
-
return /* @__PURE__ */
|
|
203
|
+
return /* @__PURE__ */ jsx3(AbsoluteFill2, {
|
|
88
204
|
style: {
|
|
89
205
|
opacity: trailOpacity - (layers - i) / layers * trailOpacity
|
|
90
206
|
},
|
|
91
|
-
children: /* @__PURE__ */
|
|
207
|
+
children: /* @__PURE__ */ jsx3(Freeze3, {
|
|
92
208
|
frame: frame - lagInFrames * (layers - i),
|
|
93
209
|
children
|
|
94
210
|
})
|
|
@@ -100,5 +216,6 @@ var Trail = ({
|
|
|
100
216
|
};
|
|
101
217
|
export {
|
|
102
218
|
Trail,
|
|
219
|
+
HtmlInCanvasMotionBlur,
|
|
103
220
|
CameraMotionBlur
|
|
104
221
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/motion-blur"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/motion-blur",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.529",
|
|
7
7
|
"description": "Motion blur effect for Remotion",
|
|
8
8
|
"main": "dist/cjs/index.js",
|
|
9
9
|
"types": "dist/cjs/index.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"remotion": "4.0.
|
|
24
|
+
"remotion": "4.0.529"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": ">=16.8.0",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"react": "19.2.3",
|
|
41
41
|
"react-dom": "19.2.3",
|
|
42
|
-
"remotion": "4.0.
|
|
43
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
42
|
+
"remotion": "4.0.529",
|
|
43
|
+
"@remotion/eslint-config-internal": "4.0.529",
|
|
44
44
|
"eslint": "9.19.0",
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
46
46
|
},
|