@remotion/web-renderer 4.0.372 → 4.0.374
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/composable.d.ts +7 -0
- package/dist/composable.js +1 -0
- package/dist/compose.d.ts +2 -2
- package/dist/compose.js +43 -6
- package/dist/esm/index.mjs +135 -82
- package/dist/find-canvas-elements.d.ts +2 -1
- package/dist/find-canvas-elements.js +5 -6
- package/dist/find-svg-elements.d.ts +2 -0
- package/dist/find-svg-elements.js +12 -0
- package/dist/index.js +1 -5
- package/dist/render-still-on-web.d.ts +10 -2
- package/dist/render-still-on-web.js +75 -109
- package/dist/wait-for-ready.d.ts +2 -1
- package/dist/wait-for-ready.js +5 -9
- package/package.json +10 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Composable } from './composable';
|
|
2
2
|
export declare const compose: ({ composables, width, height, }: {
|
|
3
3
|
composables: Composable[];
|
|
4
4
|
width: number;
|
|
5
5
|
height: number;
|
|
6
|
-
}) => OffscreenCanvas
|
|
6
|
+
}) => Promise<OffscreenCanvas>;
|
package/dist/compose.js
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const svgToImageBitmap = (svg) => {
|
|
2
|
+
const computedStyle = getComputedStyle(svg);
|
|
3
|
+
const { transform: originalTransform } = computedStyle;
|
|
4
|
+
svg.style.transform = 'none';
|
|
5
|
+
const svgDimensions = svg.getBoundingClientRect();
|
|
6
|
+
svg.style.transform = originalTransform;
|
|
7
|
+
if (svgDimensions.width === 0 || svgDimensions.height === 0) {
|
|
8
|
+
return Promise.resolve(null);
|
|
9
|
+
}
|
|
10
|
+
const svgData = new XMLSerializer().serializeToString(svg);
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const image = new Image(svgDimensions.width, svgDimensions.height);
|
|
13
|
+
const url = 'data:image/svg+xml;base64,' + window.btoa(svgData);
|
|
14
|
+
image.onload = function () {
|
|
15
|
+
resolve({
|
|
16
|
+
image,
|
|
17
|
+
width: svgDimensions.width,
|
|
18
|
+
height: svgDimensions.height,
|
|
19
|
+
left: svgDimensions.left,
|
|
20
|
+
top: svgDimensions.top,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
image.onerror = () => {
|
|
24
|
+
reject(new Error('Failed to convert SVG to image'));
|
|
25
|
+
};
|
|
26
|
+
image.src = url;
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
export const compose = async ({ composables, width, height, }) => {
|
|
5
30
|
const canvas = new OffscreenCanvas(width, height);
|
|
6
31
|
const context = canvas.getContext('2d');
|
|
7
32
|
if (!context) {
|
|
@@ -9,8 +34,20 @@ const compose = ({ composables, width, height, }) => {
|
|
|
9
34
|
}
|
|
10
35
|
// TODO: Consider z-index
|
|
11
36
|
for (const composable of composables) {
|
|
12
|
-
|
|
37
|
+
if (composable.type === 'canvas') {
|
|
38
|
+
const boundingClientRect = composable.element.getBoundingClientRect();
|
|
39
|
+
context.drawImage(composable.element, boundingClientRect.left, boundingClientRect.top);
|
|
40
|
+
}
|
|
41
|
+
else if (composable.type === 'svg') {
|
|
42
|
+
// This already takes care of the "transform" of the SVG
|
|
43
|
+
// but not of the transforms of the parent
|
|
44
|
+
const imageBitmap = await svgToImageBitmap(composable.element);
|
|
45
|
+
if (imageBitmap) {
|
|
46
|
+
// transform origin
|
|
47
|
+
// Don't need to get transform from SVG
|
|
48
|
+
context.drawImage(imageBitmap.image, imageBitmap.left, imageBitmap.top);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
13
51
|
}
|
|
14
52
|
return canvas;
|
|
15
53
|
};
|
|
16
|
-
exports.compose = compose;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -3,7 +3,35 @@ import ReactDOM from "react-dom/client";
|
|
|
3
3
|
import { Internals } from "remotion";
|
|
4
4
|
|
|
5
5
|
// src/compose.ts
|
|
6
|
-
var
|
|
6
|
+
var svgToImageBitmap = (svg) => {
|
|
7
|
+
const computedStyle = getComputedStyle(svg);
|
|
8
|
+
const { transform: originalTransform } = computedStyle;
|
|
9
|
+
svg.style.transform = "none";
|
|
10
|
+
const svgDimensions = svg.getBoundingClientRect();
|
|
11
|
+
svg.style.transform = originalTransform;
|
|
12
|
+
if (svgDimensions.width === 0 || svgDimensions.height === 0) {
|
|
13
|
+
return Promise.resolve(null);
|
|
14
|
+
}
|
|
15
|
+
const svgData = new XMLSerializer().serializeToString(svg);
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const image = new Image(svgDimensions.width, svgDimensions.height);
|
|
18
|
+
const url = "data:image/svg+xml;base64," + window.btoa(svgData);
|
|
19
|
+
image.onload = function() {
|
|
20
|
+
resolve({
|
|
21
|
+
image,
|
|
22
|
+
width: svgDimensions.width,
|
|
23
|
+
height: svgDimensions.height,
|
|
24
|
+
left: svgDimensions.left,
|
|
25
|
+
top: svgDimensions.top
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
image.onerror = () => {
|
|
29
|
+
reject(new Error("Failed to convert SVG to image"));
|
|
30
|
+
};
|
|
31
|
+
image.src = url;
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var compose = async ({
|
|
7
35
|
composables,
|
|
8
36
|
width,
|
|
9
37
|
height
|
|
@@ -14,7 +42,15 @@ var compose = ({
|
|
|
14
42
|
throw new Error("Could not get context");
|
|
15
43
|
}
|
|
16
44
|
for (const composable of composables) {
|
|
17
|
-
|
|
45
|
+
if (composable.type === "canvas") {
|
|
46
|
+
const boundingClientRect = composable.element.getBoundingClientRect();
|
|
47
|
+
context.drawImage(composable.element, boundingClientRect.left, boundingClientRect.top);
|
|
48
|
+
} else if (composable.type === "svg") {
|
|
49
|
+
const imageBitmap = await svgToImageBitmap(composable.element);
|
|
50
|
+
if (imageBitmap) {
|
|
51
|
+
context.drawImage(imageBitmap.image, imageBitmap.left, imageBitmap.top);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
18
54
|
}
|
|
19
55
|
return canvas;
|
|
20
56
|
};
|
|
@@ -25,28 +61,45 @@ var findCanvasElements = (element) => {
|
|
|
25
61
|
const composables = [];
|
|
26
62
|
Array.from(canvasElements).forEach((canvasElement) => {
|
|
27
63
|
const canvas = canvasElement;
|
|
28
|
-
composables.push(
|
|
64
|
+
composables.push({
|
|
65
|
+
type: "canvas",
|
|
66
|
+
element: canvas
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return composables;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/find-svg-elements.ts
|
|
73
|
+
var findSvgElements = (element) => {
|
|
74
|
+
const svgElements = element.querySelectorAll("svg");
|
|
75
|
+
const composables = [];
|
|
76
|
+
Array.from(svgElements).forEach((svgElement) => {
|
|
77
|
+
const svg = svgElement;
|
|
78
|
+
composables.push({
|
|
79
|
+
type: "svg",
|
|
80
|
+
element: svg
|
|
81
|
+
});
|
|
29
82
|
});
|
|
30
83
|
return composables;
|
|
31
84
|
};
|
|
32
85
|
|
|
33
86
|
// src/wait-for-ready.ts
|
|
34
|
-
var waitForReady = (timeoutInMilliseconds) => {
|
|
87
|
+
var waitForReady = (timeoutInMilliseconds, scope) => {
|
|
35
88
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
36
89
|
const start = Date.now();
|
|
37
90
|
const interval = setInterval(() => {
|
|
38
|
-
if (
|
|
91
|
+
if (scope.remotion_renderReady === true) {
|
|
39
92
|
resolve(true);
|
|
40
93
|
clearInterval(interval);
|
|
41
94
|
return;
|
|
42
95
|
}
|
|
43
|
-
if (
|
|
44
|
-
reject(
|
|
96
|
+
if (scope.remotion_cancelledError !== undefined) {
|
|
97
|
+
reject(scope.remotion_cancelledError);
|
|
45
98
|
clearInterval(interval);
|
|
46
99
|
return;
|
|
47
100
|
}
|
|
48
101
|
if (Date.now() - start > timeoutInMilliseconds + 3000) {
|
|
49
|
-
reject(new Error(Object.values(
|
|
102
|
+
reject(new Error(Object.values(scope.remotion_delayRenderTimeouts).map((d) => d.label).join(", ")));
|
|
50
103
|
clearInterval(interval);
|
|
51
104
|
}
|
|
52
105
|
}, 50);
|
|
@@ -55,61 +108,35 @@ var waitForReady = (timeoutInMilliseconds) => {
|
|
|
55
108
|
|
|
56
109
|
// src/render-still-on-web.tsx
|
|
57
110
|
import { jsx } from "react/jsx-runtime";
|
|
58
|
-
var
|
|
111
|
+
var COMP_ID = "markup";
|
|
112
|
+
var internalRenderStillOnWeb = async ({
|
|
59
113
|
Component,
|
|
60
114
|
width,
|
|
61
115
|
height,
|
|
62
116
|
fps,
|
|
63
117
|
durationInFrames,
|
|
64
|
-
frame
|
|
118
|
+
frame,
|
|
119
|
+
delayRenderTimeoutInMilliseconds,
|
|
120
|
+
logLevel
|
|
65
121
|
}) => {
|
|
66
122
|
const div = document.createElement("div");
|
|
67
123
|
div.style.display = "flex";
|
|
68
124
|
div.style.backgroundColor = "transparent";
|
|
69
|
-
div.style.position = "
|
|
125
|
+
div.style.position = "fixed";
|
|
70
126
|
div.style.width = `${width}px`;
|
|
71
127
|
div.style.height = `${height}px`;
|
|
128
|
+
div.style.zIndex = "-9999";
|
|
72
129
|
document.body.appendChild(div);
|
|
73
|
-
const delayRenderTimeoutInMilliseconds = 1e4;
|
|
74
130
|
if (!ReactDOM.createRoot) {
|
|
75
131
|
throw new Error("@remotion/web-renderer requires React 18 or higher");
|
|
76
132
|
}
|
|
77
|
-
const compositionManagerContext = {
|
|
78
|
-
currentCompositionMetadata: {
|
|
79
|
-
durationInFrames,
|
|
80
|
-
fps,
|
|
81
|
-
height,
|
|
82
|
-
width,
|
|
83
|
-
props: {},
|
|
84
|
-
defaultCodec: null,
|
|
85
|
-
defaultOutName: null,
|
|
86
|
-
defaultVideoImageFormat: null,
|
|
87
|
-
defaultPixelFormat: null,
|
|
88
|
-
defaultProResProfile: null
|
|
89
|
-
},
|
|
90
|
-
folders: [],
|
|
91
|
-
compositions: [
|
|
92
|
-
{
|
|
93
|
-
id: "markup",
|
|
94
|
-
component: Component,
|
|
95
|
-
nonce: 0,
|
|
96
|
-
defaultProps: undefined,
|
|
97
|
-
folderName: null,
|
|
98
|
-
parentFolderName: null,
|
|
99
|
-
schema: null,
|
|
100
|
-
calculateMetadata: null,
|
|
101
|
-
durationInFrames,
|
|
102
|
-
fps,
|
|
103
|
-
height,
|
|
104
|
-
width
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
canvasContent: {
|
|
108
|
-
type: "composition",
|
|
109
|
-
compositionId: "markup"
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
133
|
const root = ReactDOM.createRoot(div);
|
|
134
|
+
const delayRenderScope = {
|
|
135
|
+
remotion_renderReady: true,
|
|
136
|
+
remotion_delayRenderTimeouts: {},
|
|
137
|
+
remotion_puppeteerTimeout: delayRenderTimeoutInMilliseconds,
|
|
138
|
+
remotion_attempt: 0
|
|
139
|
+
};
|
|
113
140
|
root.render(/* @__PURE__ */ jsx(Internals.RemotionEnvironmentContext, {
|
|
114
141
|
value: {
|
|
115
142
|
isStudio: false,
|
|
@@ -118,54 +145,80 @@ var renderStillOnWeb = async ({
|
|
|
118
145
|
isReadOnlyStudio: false,
|
|
119
146
|
isClientSideRendering: true
|
|
120
147
|
},
|
|
121
|
-
children: /* @__PURE__ */ jsx(Internals.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
148
|
+
children: /* @__PURE__ */ jsx(Internals.DelayRenderContextType.Provider, {
|
|
149
|
+
value: delayRenderScope,
|
|
150
|
+
children: /* @__PURE__ */ jsx(Internals.CompositionManagerProvider, {
|
|
151
|
+
initialCanvasContent: {
|
|
152
|
+
type: "composition",
|
|
153
|
+
compositionId: COMP_ID
|
|
154
|
+
},
|
|
155
|
+
onlyRenderComposition: null,
|
|
156
|
+
currentCompositionMetadata: {
|
|
157
|
+
props: {},
|
|
158
|
+
durationInFrames,
|
|
159
|
+
fps,
|
|
160
|
+
height,
|
|
161
|
+
width,
|
|
162
|
+
defaultCodec: null,
|
|
163
|
+
defaultOutName: null,
|
|
164
|
+
defaultVideoImageFormat: null,
|
|
165
|
+
defaultPixelFormat: null,
|
|
166
|
+
defaultProResProfile: null
|
|
167
|
+
},
|
|
168
|
+
initialCompositions: [
|
|
169
|
+
{
|
|
170
|
+
id: COMP_ID,
|
|
171
|
+
component: Component,
|
|
172
|
+
nonce: 0,
|
|
173
|
+
defaultProps: undefined,
|
|
174
|
+
folderName: null,
|
|
175
|
+
parentFolderName: null,
|
|
176
|
+
schema: null,
|
|
177
|
+
calculateMetadata: null,
|
|
178
|
+
durationInFrames,
|
|
179
|
+
fps,
|
|
180
|
+
height,
|
|
181
|
+
width
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
children: /* @__PURE__ */ jsx(Internals.RemotionRoot, {
|
|
185
|
+
audioEnabled: false,
|
|
186
|
+
videoEnabled: true,
|
|
187
|
+
logLevel,
|
|
188
|
+
numberOfAudioTags: 0,
|
|
189
|
+
audioLatencyHint: "interactive",
|
|
190
|
+
frameState: {
|
|
191
|
+
[COMP_ID]: frame
|
|
192
|
+
},
|
|
193
|
+
children: /* @__PURE__ */ jsx(Internals.CanUseRemotionHooks, {
|
|
194
|
+
value: true,
|
|
195
|
+
children: /* @__PURE__ */ jsx(Component, {})
|
|
196
|
+
})
|
|
145
197
|
})
|
|
146
198
|
})
|
|
147
199
|
})
|
|
148
200
|
}));
|
|
149
|
-
|
|
150
|
-
await waitForReady(delayRenderTimeoutInMilliseconds);
|
|
201
|
+
await waitForReady(delayRenderTimeoutInMilliseconds, delayRenderScope);
|
|
151
202
|
const canvasElements = findCanvasElements(div);
|
|
152
|
-
const
|
|
153
|
-
|
|
203
|
+
const svgElements = findSvgElements(div);
|
|
204
|
+
const composed = await compose({
|
|
205
|
+
composables: [...canvasElements, ...svgElements],
|
|
154
206
|
width,
|
|
155
207
|
height
|
|
156
208
|
});
|
|
157
209
|
const imageData = await composed.convertToBlob({
|
|
158
210
|
type: "image/png"
|
|
159
211
|
});
|
|
160
|
-
const blob = new Blob([imageData], { type: "image/png" });
|
|
161
|
-
const url = URL.createObjectURL(blob);
|
|
162
|
-
const a = document.createElement("a");
|
|
163
|
-
a.href = url;
|
|
164
|
-
a.download = "composed.png";
|
|
165
|
-
a.click();
|
|
166
|
-
URL.revokeObjectURL(url);
|
|
167
212
|
root.unmount();
|
|
168
213
|
div.remove();
|
|
214
|
+
return imageData;
|
|
215
|
+
};
|
|
216
|
+
var renderStillOnWeb = (options) => {
|
|
217
|
+
return internalRenderStillOnWeb({
|
|
218
|
+
...options,
|
|
219
|
+
delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
|
|
220
|
+
logLevel: options.logLevel ?? "info"
|
|
221
|
+
});
|
|
169
222
|
};
|
|
170
223
|
export {
|
|
171
224
|
renderStillOnWeb
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Composable } from './composable';
|
|
2
|
+
export declare const findCanvasElements: (element: HTMLDivElement) => Composable[];
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findCanvasElements = void 0;
|
|
4
|
-
const findCanvasElements = (element) => {
|
|
1
|
+
export const findCanvasElements = (element) => {
|
|
5
2
|
const canvasElements = element.querySelectorAll('canvas');
|
|
6
3
|
const composables = [];
|
|
7
4
|
Array.from(canvasElements).forEach((canvasElement) => {
|
|
8
5
|
const canvas = canvasElement;
|
|
9
|
-
composables.push(
|
|
6
|
+
composables.push({
|
|
7
|
+
type: 'canvas',
|
|
8
|
+
element: canvas,
|
|
9
|
+
});
|
|
10
10
|
});
|
|
11
11
|
return composables;
|
|
12
12
|
};
|
|
13
|
-
exports.findCanvasElements = findCanvasElements;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const findSvgElements = (element) => {
|
|
2
|
+
const svgElements = element.querySelectorAll('svg');
|
|
3
|
+
const composables = [];
|
|
4
|
+
Array.from(svgElements).forEach((svgElement) => {
|
|
5
|
+
const svg = svgElement;
|
|
6
|
+
composables.push({
|
|
7
|
+
type: 'svg',
|
|
8
|
+
element: svg,
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
return composables;
|
|
12
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.renderStillOnWeb = void 0;
|
|
4
|
-
var render_still_on_web_1 = require("./render-still-on-web");
|
|
5
|
-
Object.defineProperty(exports, "renderStillOnWeb", { enumerable: true, get: function () { return render_still_on_web_1.renderStillOnWeb; } });
|
|
1
|
+
export { renderStillOnWeb } from './render-still-on-web';
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type ComponentType, type LazyExoticComponent } from 'react';
|
|
2
|
-
|
|
2
|
+
import type { LogLevel } from 'remotion';
|
|
3
|
+
type MandatoryRenderStillOnWebOptions = {
|
|
3
4
|
Component: LazyExoticComponent<ComponentType<Record<string, unknown>>> | ComponentType<Record<string, unknown>>;
|
|
4
5
|
width: number;
|
|
5
6
|
height: number;
|
|
6
7
|
fps: number;
|
|
7
8
|
durationInFrames: number;
|
|
8
9
|
frame: number;
|
|
9
|
-
}
|
|
10
|
+
};
|
|
11
|
+
type OptionalRenderStillOnWebOptions = {
|
|
12
|
+
delayRenderTimeoutInMilliseconds: number;
|
|
13
|
+
logLevel: LogLevel;
|
|
14
|
+
};
|
|
15
|
+
type RenderStillOnWebOptions = MandatoryRenderStillOnWebOptions & Partial<OptionalRenderStillOnWebOptions>;
|
|
16
|
+
export declare const renderStillOnWeb: (options: RenderStillOnWebOptions) => Promise<Blob>;
|
|
17
|
+
export {};
|
|
@@ -1,27 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const compose_1 = require("./compose");
|
|
11
|
-
const find_canvas_elements_1 = require("./find-canvas-elements");
|
|
12
|
-
const wait_for_ready_1 = require("./wait-for-ready");
|
|
13
|
-
const renderStillOnWeb = async ({ Component, width, height, fps, durationInFrames, frame, }) => {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { Internals } from 'remotion';
|
|
4
|
+
import { compose } from './compose';
|
|
5
|
+
import { findCanvasElements } from './find-canvas-elements';
|
|
6
|
+
import { findSvgElements } from './find-svg-elements';
|
|
7
|
+
import { waitForReady } from './wait-for-ready';
|
|
8
|
+
const COMP_ID = 'markup';
|
|
9
|
+
const internalRenderStillOnWeb = async ({ Component, width, height, fps, durationInFrames, frame, delayRenderTimeoutInMilliseconds, logLevel, }) => {
|
|
14
10
|
const div = document.createElement('div');
|
|
15
11
|
// Match same behavior as renderEntry.tsx
|
|
16
12
|
div.style.display = 'flex';
|
|
17
13
|
div.style.backgroundColor = 'transparent';
|
|
18
|
-
div.style.position = '
|
|
14
|
+
div.style.position = 'fixed';
|
|
19
15
|
div.style.width = `${width}px`;
|
|
20
16
|
div.style.height = `${height}px`;
|
|
17
|
+
div.style.zIndex = '-9999';
|
|
21
18
|
document.body.appendChild(div);
|
|
22
|
-
|
|
23
|
-
const delayRenderTimeoutInMilliseconds = 10000;
|
|
24
|
-
if (!client_1.default.createRoot) {
|
|
19
|
+
if (!ReactDOM.createRoot) {
|
|
25
20
|
throw new Error('@remotion/web-renderer requires React 18 or higher');
|
|
26
21
|
}
|
|
27
22
|
// TODO: Env variables
|
|
@@ -32,113 +27,84 @@ const renderStillOnWeb = async ({ Component, width, height, fps, durationInFrame
|
|
|
32
27
|
// TODO: delayRender()
|
|
33
28
|
// TODO: Video config
|
|
34
29
|
// TODO: window.remotion_isPlayer
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
width,
|
|
42
|
-
props: {},
|
|
43
|
-
defaultCodec: null,
|
|
44
|
-
defaultOutName: null,
|
|
45
|
-
defaultVideoImageFormat: null,
|
|
46
|
-
defaultPixelFormat: null,
|
|
47
|
-
defaultProResProfile: null,
|
|
48
|
-
},
|
|
49
|
-
folders: [],
|
|
50
|
-
compositions: [
|
|
51
|
-
{
|
|
52
|
-
// TODO: Make dynamic
|
|
53
|
-
id: 'markup',
|
|
54
|
-
component: Component,
|
|
55
|
-
nonce: 0,
|
|
56
|
-
defaultProps: undefined,
|
|
57
|
-
folderName: null,
|
|
58
|
-
parentFolderName: null,
|
|
59
|
-
schema: null,
|
|
60
|
-
calculateMetadata: null,
|
|
61
|
-
durationInFrames,
|
|
62
|
-
fps,
|
|
63
|
-
height,
|
|
64
|
-
width,
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
canvasContent: {
|
|
68
|
-
type: 'composition',
|
|
69
|
-
compositionId: 'markup',
|
|
70
|
-
},
|
|
30
|
+
const root = ReactDOM.createRoot(div);
|
|
31
|
+
const delayRenderScope = {
|
|
32
|
+
remotion_renderReady: true,
|
|
33
|
+
remotion_delayRenderTimeouts: {},
|
|
34
|
+
remotion_puppeteerTimeout: delayRenderTimeoutInMilliseconds,
|
|
35
|
+
remotion_attempt: 0,
|
|
71
36
|
};
|
|
72
|
-
|
|
73
|
-
root.render((0, jsx_runtime_1.jsx)(remotion_1.Internals.RemotionEnvironmentContext, { value: {
|
|
37
|
+
root.render(_jsx(Internals.RemotionEnvironmentContext, { value: {
|
|
74
38
|
isStudio: false,
|
|
75
39
|
isRendering: true,
|
|
76
40
|
isPlayer: false,
|
|
77
41
|
isReadOnlyStudio: false,
|
|
78
42
|
isClientSideRendering: true,
|
|
79
|
-
}, children: (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
audioEnabled: true,
|
|
84
|
-
// TODO: Hardcoded
|
|
85
|
-
videoEnabled: true,
|
|
86
|
-
// TODO: Hardcoded
|
|
87
|
-
logLevel: "info",
|
|
88
|
-
// TODO: Hardcoded
|
|
89
|
-
numberOfAudioTags: 0,
|
|
90
|
-
// TODO: Hardcoded
|
|
91
|
-
onlyRenderComposition: null,
|
|
92
|
-
// TODO: Hardcoded
|
|
93
|
-
currentCompositionMetadata: {
|
|
94
|
-
// TODO: Empty
|
|
95
|
-
props: {},
|
|
96
|
-
// TODO: Hardcoded
|
|
97
|
-
durationInFrames,
|
|
98
|
-
// TODO: Hardcoded
|
|
99
|
-
fps,
|
|
100
|
-
// TODO: Hardcoded
|
|
101
|
-
height,
|
|
102
|
-
// TODO: Hardcoded
|
|
103
|
-
width,
|
|
43
|
+
}, children: _jsx(Internals.DelayRenderContextType.Provider, { value: delayRenderScope, children: _jsx(Internals.CompositionManagerProvider, { initialCanvasContent: {
|
|
44
|
+
type: 'composition',
|
|
45
|
+
compositionId: COMP_ID,
|
|
46
|
+
}, onlyRenderComposition: null,
|
|
104
47
|
// TODO: Hardcoded
|
|
105
|
-
|
|
48
|
+
currentCompositionMetadata: {
|
|
49
|
+
// TODO: Empty
|
|
50
|
+
props: {},
|
|
51
|
+
durationInFrames,
|
|
52
|
+
fps,
|
|
53
|
+
height,
|
|
54
|
+
width,
|
|
55
|
+
defaultCodec: null,
|
|
56
|
+
defaultOutName: null,
|
|
57
|
+
defaultVideoImageFormat: null,
|
|
58
|
+
defaultPixelFormat: null,
|
|
59
|
+
defaultProResProfile: null,
|
|
60
|
+
}, initialCompositions: [
|
|
61
|
+
{
|
|
62
|
+
id: COMP_ID,
|
|
63
|
+
component: Component,
|
|
64
|
+
nonce: 0,
|
|
65
|
+
// TODO: Do we need to allow to set this?
|
|
66
|
+
defaultProps: undefined,
|
|
67
|
+
folderName: null,
|
|
68
|
+
parentFolderName: null,
|
|
69
|
+
schema: null,
|
|
70
|
+
calculateMetadata: null,
|
|
71
|
+
durationInFrames,
|
|
72
|
+
fps,
|
|
73
|
+
height,
|
|
74
|
+
width,
|
|
75
|
+
},
|
|
76
|
+
], children: _jsx(Internals.RemotionRoot
|
|
106
77
|
// TODO: Hardcoded
|
|
107
|
-
defaultOutName: null,
|
|
108
|
-
// TODO: Hardcoded
|
|
109
|
-
defaultVideoImageFormat: null,
|
|
110
|
-
// TODO: Hardcoded
|
|
111
|
-
defaultPixelFormat: null,
|
|
112
|
-
// TODO: Hardcoded
|
|
113
|
-
defaultProResProfile: null,
|
|
114
|
-
},
|
|
115
|
-
// TODO: Hardcoded
|
|
116
|
-
audioLatencyHint: "interactive", children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CanUseRemotionHooks, { value: true, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CompositionManager.Provider
|
|
117
|
-
// TODO: This context is double-wrapped
|
|
118
78
|
, {
|
|
119
|
-
// TODO:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
79
|
+
// TODO: Hardcoded
|
|
80
|
+
audioEnabled: false,
|
|
81
|
+
// TODO: Hardcoded
|
|
82
|
+
videoEnabled: true, logLevel: logLevel, numberOfAudioTags: 0,
|
|
83
|
+
// TODO: Hardcoded
|
|
84
|
+
audioLatencyHint: "interactive", frameState: {
|
|
85
|
+
[COMP_ID]: frame,
|
|
86
|
+
}, children: _jsx(Internals.CanUseRemotionHooks, { value: true, children: _jsx(Component, {}) }) }) }) }) }));
|
|
87
|
+
// TODO: Scope cancelRender()
|
|
88
|
+
await waitForReady(delayRenderTimeoutInMilliseconds, delayRenderScope);
|
|
89
|
+
const canvasElements = findCanvasElements(div);
|
|
90
|
+
const svgElements = findSvgElements(div);
|
|
91
|
+
const composed = await compose({
|
|
92
|
+
composables: [...canvasElements, ...svgElements],
|
|
127
93
|
width,
|
|
128
94
|
height,
|
|
129
95
|
});
|
|
130
96
|
const imageData = await composed.convertToBlob({
|
|
131
97
|
type: 'image/png',
|
|
132
98
|
});
|
|
133
|
-
// download image
|
|
134
|
-
const blob = new Blob([imageData], { type: 'image/png' });
|
|
135
|
-
const url = URL.createObjectURL(blob);
|
|
136
|
-
const a = document.createElement('a');
|
|
137
|
-
a.href = url;
|
|
138
|
-
a.download = 'composed.png';
|
|
139
|
-
a.click();
|
|
140
|
-
URL.revokeObjectURL(url);
|
|
141
99
|
root.unmount();
|
|
142
100
|
div.remove();
|
|
101
|
+
return imageData;
|
|
102
|
+
};
|
|
103
|
+
export const renderStillOnWeb = (options) => {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
return internalRenderStillOnWeb({
|
|
106
|
+
...options,
|
|
107
|
+
delayRenderTimeoutInMilliseconds: (_a = options.delayRenderTimeoutInMilliseconds) !== null && _a !== void 0 ? _a : 30000,
|
|
108
|
+
logLevel: (_b = options.logLevel) !== null && _b !== void 0 ? _b : 'info',
|
|
109
|
+
});
|
|
143
110
|
};
|
|
144
|
-
exports.renderStillOnWeb = renderStillOnWeb;
|
package/dist/wait-for-ready.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { _InternalTypes } from 'remotion';
|
|
2
|
+
export declare const waitForReady: (timeoutInMilliseconds: number, scope: _InternalTypes["DelayRenderScope"]) => Promise<unknown>;
|
package/dist/wait-for-ready.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForReady = void 0;
|
|
4
|
-
const waitForReady = (timeoutInMilliseconds) => {
|
|
1
|
+
export const waitForReady = (timeoutInMilliseconds, scope) => {
|
|
5
2
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6
3
|
const start = Date.now();
|
|
7
4
|
const interval = setInterval(() => {
|
|
8
|
-
if (
|
|
5
|
+
if (scope.remotion_renderReady === true) {
|
|
9
6
|
resolve(true);
|
|
10
7
|
clearInterval(interval);
|
|
11
8
|
return;
|
|
12
9
|
}
|
|
13
|
-
if (
|
|
14
|
-
reject(
|
|
10
|
+
if (scope.remotion_cancelledError !== undefined) {
|
|
11
|
+
reject(scope.remotion_cancelledError);
|
|
15
12
|
clearInterval(interval);
|
|
16
13
|
return;
|
|
17
14
|
}
|
|
18
15
|
if (Date.now() - start > timeoutInMilliseconds + 3000) {
|
|
19
16
|
// TODO: Error message should be just as good
|
|
20
|
-
reject(new Error(Object.values(
|
|
17
|
+
reject(new Error(Object.values(scope.remotion_delayRenderTimeouts)
|
|
21
18
|
.map((d) => d.label)
|
|
22
19
|
.join(', ')));
|
|
23
20
|
clearInterval(interval);
|
|
@@ -25,4 +22,3 @@ const waitForReady = (timeoutInMilliseconds) => {
|
|
|
25
22
|
}, 50);
|
|
26
23
|
return promise;
|
|
27
24
|
};
|
|
28
|
-
exports.waitForReady = waitForReady;
|
package/package.json
CHANGED
|
@@ -3,24 +3,29 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/web-renderer"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/web-renderer",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.374",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"scripts": {
|
|
10
10
|
"formatting": "prettier --experimental-cli src --check",
|
|
11
11
|
"lint": "eslint src",
|
|
12
|
-
"make": "tsc -d && bun --env-file=../.env.bundle bundle.ts"
|
|
12
|
+
"make": "tsc -d && bun --env-file=../.env.bundle bundle.ts",
|
|
13
|
+
"test": "node src/test/execute.mjs"
|
|
13
14
|
},
|
|
14
15
|
"author": "Remotion <jonny@remotion.dev>",
|
|
15
16
|
"license": "UNLICENSED",
|
|
16
17
|
"dependencies": {
|
|
17
|
-
"remotion": "4.0.
|
|
18
|
+
"remotion": "4.0.374"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
21
|
+
"@remotion/eslint-config-internal": "4.0.374",
|
|
22
|
+
"@vitejs/plugin-react": "^5.1.0",
|
|
23
|
+
"@vitest/browser-webdriverio": "4.0.7",
|
|
21
24
|
"eslint": "9.19.0",
|
|
22
25
|
"react": "19.0.0",
|
|
23
|
-
"react-dom": "19.0.0"
|
|
26
|
+
"react-dom": "19.0.0",
|
|
27
|
+
"vitest": "4.0.7",
|
|
28
|
+
"vitest-browser-react": "^2.0.2"
|
|
24
29
|
},
|
|
25
30
|
"peerDependencies": {
|
|
26
31
|
"react": ">=18.0.0",
|