@remotion/web-renderer 4.0.446 → 4.0.448
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/audio.d.ts +2 -1
- package/dist/create-scaffold.d.ts +4 -1
- package/dist/drawing/calculate-transforms.d.ts +1 -0
- package/dist/drawing/handle-filter.d.ts +1 -0
- package/dist/esm/index.mjs +296 -33
- package/dist/html-in-canvas.d.ts +43 -0
- package/dist/index.d.ts +2 -1
- package/dist/render-media-on-web.d.ts +2 -0
- package/dist/render-still-on-web.d.ts +4 -24
- package/dist/render-still-screenshot-task.d.ts +45 -0
- package/dist/take-screenshot.d.ts +11 -1
- package/package.json +7 -7
package/dist/audio.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { TRenderAsset } from 'remotion';
|
|
2
|
-
export declare const onlyInlineAudio: ({ assets, fps, timestamp, }: {
|
|
2
|
+
export declare const onlyInlineAudio: ({ assets, fps, timestamp, sampleRate, }: {
|
|
3
3
|
assets: TRenderAsset[];
|
|
4
4
|
fps: number;
|
|
5
5
|
timestamp: number;
|
|
6
|
+
sampleRate: number;
|
|
6
7
|
}) => AudioData | null;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type ComponentType } from 'react';
|
|
2
2
|
import type { Codec, DelayRenderScope, LogLevel, TRenderAsset } from 'remotion';
|
|
3
3
|
import type { $ZodObject } from 'zod/v4/core';
|
|
4
|
+
import type { HtmlInCanvasContext } from './html-in-canvas';
|
|
4
5
|
import type { TimeUpdaterRef } from './update-time';
|
|
5
6
|
export type ErrorHolder = {
|
|
6
7
|
error: Error | null;
|
|
7
8
|
};
|
|
8
9
|
export declare function checkForError(errorHolder: ErrorHolder): void;
|
|
9
|
-
export declare function createScaffold<Props extends Record<string, unknown>>({ width, height, delayRenderTimeoutInMilliseconds, logLevel, resolvedProps, id, mediaCacheSizeInBytes, durationInFrames, fps, initialFrame, schema, Component, audioEnabled, videoEnabled, defaultCodec, defaultOutName }: {
|
|
10
|
+
export declare function createScaffold<Props extends Record<string, unknown>>({ width, height, delayRenderTimeoutInMilliseconds, logLevel, resolvedProps, id, mediaCacheSizeInBytes, durationInFrames, fps, initialFrame, schema, Component, audioEnabled, videoEnabled, defaultCodec, defaultOutName, allowHtmlInCanvas }: {
|
|
10
11
|
width: number;
|
|
11
12
|
height: number;
|
|
12
13
|
delayRenderTimeoutInMilliseconds: number;
|
|
@@ -23,6 +24,7 @@ export declare function createScaffold<Props extends Record<string, unknown>>({
|
|
|
23
24
|
videoEnabled: boolean;
|
|
24
25
|
defaultCodec: Codec | null;
|
|
25
26
|
defaultOutName: string | null;
|
|
27
|
+
allowHtmlInCanvas: boolean;
|
|
26
28
|
}): {
|
|
27
29
|
delayRenderScope: DelayRenderScope;
|
|
28
30
|
div: HTMLDivElement;
|
|
@@ -31,5 +33,6 @@ export declare function createScaffold<Props extends Record<string, unknown>>({
|
|
|
31
33
|
collectAssets: () => TRenderAsset[];
|
|
32
34
|
} | null>;
|
|
33
35
|
errorHolder: ErrorHolder;
|
|
36
|
+
htmlInCanvasContext: HtmlInCanvasContext | null;
|
|
34
37
|
[Symbol.dispose]: () => void;
|
|
35
38
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getPrecomposeRectForFilter: (element: HTMLElement | SVGElement) => DOMRect;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -584,7 +584,7 @@ var getEncodableAudioCodecs = async (container, options) => {
|
|
|
584
584
|
};
|
|
585
585
|
// src/render-media-on-web.tsx
|
|
586
586
|
import { BufferTarget, StreamTarget } from "mediabunny";
|
|
587
|
-
import { Internals as
|
|
587
|
+
import { Internals as Internals9 } from "remotion";
|
|
588
588
|
import { VERSION } from "remotion/version";
|
|
589
589
|
|
|
590
590
|
// src/add-sample.ts
|
|
@@ -670,7 +670,6 @@ var handleArtifacts = () => {
|
|
|
670
670
|
|
|
671
671
|
// src/audio.ts
|
|
672
672
|
var TARGET_NUMBER_OF_CHANNELS = 2;
|
|
673
|
-
var TARGET_SAMPLE_RATE = 48000;
|
|
674
673
|
function mixAudio(waves, length) {
|
|
675
674
|
if (waves.length === 1 && waves[0].length === length) {
|
|
676
675
|
return waves[0];
|
|
@@ -691,13 +690,14 @@ function mixAudio(waves, length) {
|
|
|
691
690
|
var onlyInlineAudio = ({
|
|
692
691
|
assets,
|
|
693
692
|
fps,
|
|
694
|
-
timestamp
|
|
693
|
+
timestamp,
|
|
694
|
+
sampleRate
|
|
695
695
|
}) => {
|
|
696
696
|
const inlineAudio = assets.filter((asset) => asset.type === "inline-audio");
|
|
697
697
|
if (inlineAudio.length === 0) {
|
|
698
698
|
return null;
|
|
699
699
|
}
|
|
700
|
-
const expectedLength = Math.round(TARGET_NUMBER_OF_CHANNELS *
|
|
700
|
+
const expectedLength = Math.round(TARGET_NUMBER_OF_CHANNELS * sampleRate / fps);
|
|
701
701
|
for (const asset of inlineAudio) {
|
|
702
702
|
if (asset.toneFrequency !== 1) {
|
|
703
703
|
throw new Error("Setting the toneFrequency is not supported yet in web rendering.");
|
|
@@ -709,7 +709,7 @@ var onlyInlineAudio = ({
|
|
|
709
709
|
format: "s16",
|
|
710
710
|
numberOfChannels: TARGET_NUMBER_OF_CHANNELS,
|
|
711
711
|
numberOfFrames: expectedLength / TARGET_NUMBER_OF_CHANNELS,
|
|
712
|
-
sampleRate
|
|
712
|
+
sampleRate,
|
|
713
713
|
timestamp
|
|
714
714
|
});
|
|
715
715
|
};
|
|
@@ -823,6 +823,82 @@ import { flushSync as flushSync2 } from "react-dom";
|
|
|
823
823
|
import ReactDOM from "react-dom/client";
|
|
824
824
|
import { Internals as Internals3 } from "remotion";
|
|
825
825
|
|
|
826
|
+
// src/html-in-canvas.ts
|
|
827
|
+
var supportsNativeHtmlInCanvas = () => {
|
|
828
|
+
if (typeof document === "undefined") {
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
const ctx = document.createElement("canvas").getContext("2d");
|
|
832
|
+
return typeof ctx?.drawElementImage === "function";
|
|
833
|
+
};
|
|
834
|
+
var setupHtmlInCanvas = ({
|
|
835
|
+
wrapper,
|
|
836
|
+
div,
|
|
837
|
+
width,
|
|
838
|
+
height
|
|
839
|
+
}) => {
|
|
840
|
+
if (!supportsNativeHtmlInCanvas()) {
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
const layoutCanvas = document.createElement("canvas");
|
|
844
|
+
layoutCanvas.layoutSubtree = true;
|
|
845
|
+
layoutCanvas.width = width;
|
|
846
|
+
layoutCanvas.height = height;
|
|
847
|
+
layoutCanvas.style.position = "absolute";
|
|
848
|
+
layoutCanvas.style.top = "0";
|
|
849
|
+
layoutCanvas.style.left = "0";
|
|
850
|
+
layoutCanvas.style.width = `${width}px`;
|
|
851
|
+
layoutCanvas.style.height = `${height}px`;
|
|
852
|
+
layoutCanvas.style.visibility = "visible";
|
|
853
|
+
const maybeCtx = layoutCanvas.getContext("2d");
|
|
854
|
+
if (!maybeCtx || typeof maybeCtx.drawElementImage !== "function") {
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
if (typeof layoutCanvas.requestPaint !== "function") {
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
wrapper.removeChild(div);
|
|
861
|
+
layoutCanvas.appendChild(div);
|
|
862
|
+
wrapper.appendChild(layoutCanvas);
|
|
863
|
+
return { layoutCanvas, ctx: maybeCtx };
|
|
864
|
+
};
|
|
865
|
+
var waitForPaint = (layoutCanvas) => {
|
|
866
|
+
return new Promise((resolve) => {
|
|
867
|
+
layoutCanvas.addEventListener("paint", () => resolve(), { once: true });
|
|
868
|
+
layoutCanvas.requestPaint();
|
|
869
|
+
});
|
|
870
|
+
};
|
|
871
|
+
var drawWithHtmlInCanvas = async ({
|
|
872
|
+
htmlInCanvasContext,
|
|
873
|
+
element,
|
|
874
|
+
scaledWidth,
|
|
875
|
+
scaledHeight
|
|
876
|
+
}) => {
|
|
877
|
+
const { ctx, layoutCanvas } = htmlInCanvasContext;
|
|
878
|
+
await waitForPaint(layoutCanvas);
|
|
879
|
+
layoutCanvas.width = scaledWidth;
|
|
880
|
+
layoutCanvas.height = scaledHeight;
|
|
881
|
+
ctx.reset();
|
|
882
|
+
ctx.drawElementImage(element, 0, 0, scaledWidth, scaledHeight);
|
|
883
|
+
const offscreen = new OffscreenCanvas(scaledWidth, scaledHeight);
|
|
884
|
+
const offCtx = offscreen.getContext("2d");
|
|
885
|
+
if (!offCtx) {
|
|
886
|
+
throw new Error("Could not get offscreen context");
|
|
887
|
+
}
|
|
888
|
+
offCtx.drawImage(layoutCanvas, 0, 0);
|
|
889
|
+
return offCtx;
|
|
890
|
+
};
|
|
891
|
+
var teardownHtmlInCanvas = ({
|
|
892
|
+
htmlInCanvasContext,
|
|
893
|
+
wrapper,
|
|
894
|
+
div
|
|
895
|
+
}) => {
|
|
896
|
+
const { layoutCanvas } = htmlInCanvasContext;
|
|
897
|
+
layoutCanvas.removeChild(div);
|
|
898
|
+
wrapper.removeChild(layoutCanvas);
|
|
899
|
+
wrapper.appendChild(div);
|
|
900
|
+
};
|
|
901
|
+
|
|
826
902
|
// src/update-time.tsx
|
|
827
903
|
import { useImperativeHandle, useState } from "react";
|
|
828
904
|
import { flushSync } from "react-dom";
|
|
@@ -943,7 +1019,8 @@ function createScaffold({
|
|
|
943
1019
|
audioEnabled,
|
|
944
1020
|
videoEnabled,
|
|
945
1021
|
defaultCodec,
|
|
946
|
-
defaultOutName
|
|
1022
|
+
defaultOutName,
|
|
1023
|
+
allowHtmlInCanvas
|
|
947
1024
|
}) {
|
|
948
1025
|
if (!ReactDOM.createRoot) {
|
|
949
1026
|
throw new Error("@remotion/web-renderer requires React 18 or higher");
|
|
@@ -969,6 +1046,7 @@ function createScaffold({
|
|
|
969
1046
|
const cleanupCSS = Internals3.CSSUtils.injectCSS(Internals3.CSSUtils.makeDefaultPreviewCSS(`.${scaffoldClassName}`, "white"));
|
|
970
1047
|
wrapper.appendChild(div);
|
|
971
1048
|
document.body.appendChild(wrapper);
|
|
1049
|
+
const htmlInCanvasContext = allowHtmlInCanvas ? setupHtmlInCanvas({ wrapper, div, width, height }) : null;
|
|
972
1050
|
const errorHolder = { error: null };
|
|
973
1051
|
const root = ReactDOM.createRoot(div, {
|
|
974
1052
|
onUncaughtError: (err, errorInfo) => {
|
|
@@ -1029,7 +1107,8 @@ function createScaffold({
|
|
|
1029
1107
|
defaultOutName: defaultOutName ?? null,
|
|
1030
1108
|
defaultVideoImageFormat: null,
|
|
1031
1109
|
defaultPixelFormat: null,
|
|
1032
|
-
defaultProResProfile: null
|
|
1110
|
+
defaultProResProfile: null,
|
|
1111
|
+
defaultSampleRate: null
|
|
1033
1112
|
},
|
|
1034
1113
|
folders: []
|
|
1035
1114
|
},
|
|
@@ -1059,8 +1138,12 @@ function createScaffold({
|
|
|
1059
1138
|
delayRenderScope,
|
|
1060
1139
|
div,
|
|
1061
1140
|
errorHolder,
|
|
1141
|
+
htmlInCanvasContext,
|
|
1062
1142
|
[Symbol.dispose]: () => {
|
|
1063
1143
|
root.unmount();
|
|
1144
|
+
if (htmlInCanvasContext) {
|
|
1145
|
+
teardownHtmlInCanvas({ htmlInCanvasContext, wrapper, div });
|
|
1146
|
+
}
|
|
1064
1147
|
div.remove();
|
|
1065
1148
|
wrapper.remove();
|
|
1066
1149
|
cleanupCSS();
|
|
@@ -1274,6 +1357,9 @@ var sendUsageEvent = async ({
|
|
|
1274
1357
|
});
|
|
1275
1358
|
};
|
|
1276
1359
|
|
|
1360
|
+
// src/take-screenshot.ts
|
|
1361
|
+
import { Internals as Internals8 } from "remotion";
|
|
1362
|
+
|
|
1277
1363
|
// src/tree-walker-cleanup-after-children.ts
|
|
1278
1364
|
var createTreeWalkerCleanupAfterChildren = (treeWalker) => {
|
|
1279
1365
|
const cleanupAfterChildren = [];
|
|
@@ -1972,6 +2058,7 @@ var calculateTransforms = ({
|
|
|
1972
2058
|
let opacity = 1;
|
|
1973
2059
|
let elementComputedStyle = null;
|
|
1974
2060
|
let maskImageInfo = null;
|
|
2061
|
+
let filterValue = null;
|
|
1975
2062
|
while (parent) {
|
|
1976
2063
|
const computedStyle = getComputedStyle(parent);
|
|
1977
2064
|
if (parent === element) {
|
|
@@ -1979,6 +2066,16 @@ var calculateTransforms = ({
|
|
|
1979
2066
|
opacity = parseFloat(computedStyle.opacity);
|
|
1980
2067
|
const maskImageValue = getMaskImageValue(computedStyle);
|
|
1981
2068
|
maskImageInfo = maskImageValue ? parseMaskImage(maskImageValue) : null;
|
|
2069
|
+
const computedFilter = computedStyle.filter;
|
|
2070
|
+
if (computedFilter && computedFilter !== "none") {
|
|
2071
|
+
filterValue = computedFilter;
|
|
2072
|
+
const originalFilter = parent.style.filter;
|
|
2073
|
+
parent.style.filter = "none";
|
|
2074
|
+
const parentRefFilter = parent;
|
|
2075
|
+
toReset.push(() => {
|
|
2076
|
+
parentRefFilter.style.filter = originalFilter;
|
|
2077
|
+
});
|
|
2078
|
+
}
|
|
1982
2079
|
const originalMaskImage = parent.style.maskImage;
|
|
1983
2080
|
const originalWebkitMaskImage = parent.style.webkitMaskImage;
|
|
1984
2081
|
parent.style.maskImage = "none";
|
|
@@ -2042,6 +2139,7 @@ var calculateTransforms = ({
|
|
|
2042
2139
|
}
|
|
2043
2140
|
const needs3DTransformViaWebGL = !totalMatrix.is2D;
|
|
2044
2141
|
const needsMaskImage = maskImageInfo !== null;
|
|
2142
|
+
const needsFilter = filterValue !== null;
|
|
2045
2143
|
return {
|
|
2046
2144
|
dimensions,
|
|
2047
2145
|
totalMatrix,
|
|
@@ -2057,7 +2155,8 @@ var calculateTransforms = ({
|
|
|
2057
2155
|
precompositing: {
|
|
2058
2156
|
needs3DTransformViaWebGL,
|
|
2059
2157
|
needsMaskImage: maskImageInfo,
|
|
2060
|
-
|
|
2158
|
+
needsFilter: filterValue,
|
|
2159
|
+
needsPrecompositing: Boolean(needs3DTransformViaWebGL || needsMaskImage || needsFilter)
|
|
2061
2160
|
}
|
|
2062
2161
|
};
|
|
2063
2162
|
};
|
|
@@ -3424,6 +3523,11 @@ var handle3dTransform = ({
|
|
|
3424
3523
|
return transformed;
|
|
3425
3524
|
};
|
|
3426
3525
|
|
|
3526
|
+
// src/drawing/handle-filter.ts
|
|
3527
|
+
var getPrecomposeRectForFilter = (element) => {
|
|
3528
|
+
return getBiggestBoundingClientRect(element);
|
|
3529
|
+
};
|
|
3530
|
+
|
|
3427
3531
|
// src/drawing/handle-mask.ts
|
|
3428
3532
|
var getPrecomposeRectForMask = (element) => {
|
|
3429
3533
|
const boundingRect = getBiggestBoundingClientRect(element);
|
|
@@ -3511,6 +3615,12 @@ var processNode = async ({
|
|
|
3511
3615
|
if (precompositing.needsMaskImage) {
|
|
3512
3616
|
precomposeRect = roundToExpandRect(getPrecomposeRectForMask(element));
|
|
3513
3617
|
}
|
|
3618
|
+
if (precompositing.needsFilter) {
|
|
3619
|
+
precomposeRect = roundToExpandRect(getWiderRectAndExpand({
|
|
3620
|
+
firstRect: precomposeRect,
|
|
3621
|
+
secondRect: getPrecomposeRectForFilter(element)
|
|
3622
|
+
}));
|
|
3623
|
+
}
|
|
3514
3624
|
if (precompositing.needs3DTransformViaWebGL) {
|
|
3515
3625
|
const tentativePrecomposeRect = getPrecomposeRectFor3DTransform({
|
|
3516
3626
|
element,
|
|
@@ -3573,8 +3683,13 @@ var processNode = async ({
|
|
|
3573
3683
|
}
|
|
3574
3684
|
}
|
|
3575
3685
|
const previousTransform = context.getTransform();
|
|
3686
|
+
const previousFilter = context.filter;
|
|
3576
3687
|
context.setTransform(new DOMMatrix);
|
|
3688
|
+
if (precompositing.needsFilter) {
|
|
3689
|
+
context.filter = precompositing.needsFilter;
|
|
3690
|
+
}
|
|
3577
3691
|
context.drawImage(drawable, 0, drawable.height - rectAfterTransforms.height, rectAfterTransforms.width, rectAfterTransforms.height, rectAfterTransforms.left - parentRect.x, rectAfterTransforms.top - parentRect.y, rectAfterTransforms.width, rectAfterTransforms.height);
|
|
3692
|
+
context.filter = previousFilter;
|
|
3578
3693
|
context.setTransform(previousTransform);
|
|
3579
3694
|
Internals6.Log.trace({
|
|
3580
3695
|
logLevel,
|
|
@@ -3918,10 +4033,32 @@ var createLayer = async ({
|
|
|
3918
4033
|
logLevel,
|
|
3919
4034
|
internalState,
|
|
3920
4035
|
onlyBackgroundClipText,
|
|
3921
|
-
cutout
|
|
4036
|
+
cutout,
|
|
4037
|
+
htmlInCanvasContext,
|
|
4038
|
+
onHtmlInCanvasLayerOutcome
|
|
3922
4039
|
}) => {
|
|
3923
4040
|
const scaledWidth = Math.ceil(cutout.width * scale);
|
|
3924
4041
|
const scaledHeight = Math.ceil(cutout.height * scale);
|
|
4042
|
+
if (!onlyBackgroundClipText && element instanceof HTMLElement && htmlInCanvasContext && onHtmlInCanvasLayerOutcome) {
|
|
4043
|
+
try {
|
|
4044
|
+
const offCtx = await drawWithHtmlInCanvas({
|
|
4045
|
+
htmlInCanvasContext,
|
|
4046
|
+
element,
|
|
4047
|
+
scaledWidth,
|
|
4048
|
+
scaledHeight
|
|
4049
|
+
});
|
|
4050
|
+
onHtmlInCanvasLayerOutcome({ native: true });
|
|
4051
|
+
return offCtx;
|
|
4052
|
+
} catch (err) {
|
|
4053
|
+
const detail = err instanceof Error ? err.message : JSON.stringify(err);
|
|
4054
|
+
onHtmlInCanvasLayerOutcome({
|
|
4055
|
+
native: false,
|
|
4056
|
+
reason: `drawElementImage failed (${detail}); falling back to the built-in DOM composer.`,
|
|
4057
|
+
shouldWarn: true
|
|
4058
|
+
});
|
|
4059
|
+
Internals8.Log.verbose({ logLevel, tag: "@remotion/web-renderer" }, "HTML-in-canvas capture failed, falling back to software compose", err);
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
3925
4062
|
const canvas = new OffscreenCanvas(scaledWidth, scaledHeight);
|
|
3926
4063
|
const context = canvas.getContext("2d");
|
|
3927
4064
|
if (!context) {
|
|
@@ -4166,11 +4303,25 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4166
4303
|
licenseKey,
|
|
4167
4304
|
muted,
|
|
4168
4305
|
scale,
|
|
4169
|
-
isProduction
|
|
4306
|
+
isProduction,
|
|
4307
|
+
allowHtmlInCanvas,
|
|
4308
|
+
sampleRate
|
|
4170
4309
|
}) => {
|
|
4171
4310
|
let __stack2 = [];
|
|
4172
4311
|
try {
|
|
4173
4312
|
validateScale(scale);
|
|
4313
|
+
let htmlInCanvasLayerOutcomeReported = false;
|
|
4314
|
+
const onHtmlInCanvasLayerOutcome = (outcome) => {
|
|
4315
|
+
if (htmlInCanvasLayerOutcomeReported) {
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
htmlInCanvasLayerOutcomeReported = true;
|
|
4319
|
+
if (outcome.native) {
|
|
4320
|
+
Internals9.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, "Using Chromium experimental HTML-in-canvas (drawElementImage) for video frames. See https://github.com/WICG/html-in-canvas");
|
|
4321
|
+
} else if (outcome.shouldWarn) {
|
|
4322
|
+
Internals9.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, `Not using HTML-in-canvas: ${outcome.reason}`);
|
|
4323
|
+
}
|
|
4324
|
+
};
|
|
4174
4325
|
const outputTarget = userDesiredOutputTarget === null ? await canUseWebFsWriter() ? "web-fs" : "arraybuffer" : userDesiredOutputTarget;
|
|
4175
4326
|
if (outputTarget === "web-fs") {
|
|
4176
4327
|
await cleanupStaleOpfsFiles();
|
|
@@ -4201,11 +4352,11 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4201
4352
|
if (issue.severity === "error") {
|
|
4202
4353
|
return Promise.reject(new Error(issue.message));
|
|
4203
4354
|
}
|
|
4204
|
-
|
|
4355
|
+
Internals9.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, issue.message);
|
|
4205
4356
|
}
|
|
4206
4357
|
finalAudioCodec = audioResult.codec;
|
|
4207
4358
|
}
|
|
4208
|
-
const resolved = await
|
|
4359
|
+
const resolved = await Internals9.resolveVideoConfig({
|
|
4209
4360
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
4210
4361
|
signal: signal ?? new AbortController().signal,
|
|
4211
4362
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -4236,9 +4387,38 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4236
4387
|
videoEnabled,
|
|
4237
4388
|
initialFrame: 0,
|
|
4238
4389
|
defaultCodec: resolved.defaultCodec,
|
|
4239
|
-
defaultOutName: resolved.defaultOutName
|
|
4390
|
+
defaultOutName: resolved.defaultOutName,
|
|
4391
|
+
allowHtmlInCanvas
|
|
4240
4392
|
}), 0);
|
|
4241
|
-
const {
|
|
4393
|
+
const {
|
|
4394
|
+
delayRenderScope,
|
|
4395
|
+
div,
|
|
4396
|
+
timeUpdater,
|
|
4397
|
+
collectAssets,
|
|
4398
|
+
errorHolder,
|
|
4399
|
+
htmlInCanvasContext
|
|
4400
|
+
} = scaffold;
|
|
4401
|
+
if (allowHtmlInCanvas && !htmlInCanvasContext) {
|
|
4402
|
+
if (!supportsNativeHtmlInCanvas()) {
|
|
4403
|
+
onHtmlInCanvasLayerOutcome({
|
|
4404
|
+
native: false,
|
|
4405
|
+
reason: "This browser does not expose CanvasRenderingContext2D.prototype.drawElementImage. In Chromium, enable chrome://flags/#canvas-draw-element and use a version that ships the API.",
|
|
4406
|
+
shouldWarn: false
|
|
4407
|
+
});
|
|
4408
|
+
} else {
|
|
4409
|
+
onHtmlInCanvasLayerOutcome({
|
|
4410
|
+
native: false,
|
|
4411
|
+
reason: "drawElementImage is available but canvas.requestPaint() is missing. Use a Chromium version that ships requestPaint.",
|
|
4412
|
+
shouldWarn: true
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
} else if (!allowHtmlInCanvas) {
|
|
4416
|
+
onHtmlInCanvasLayerOutcome({
|
|
4417
|
+
native: false,
|
|
4418
|
+
reason: "allowHtmlInCanvas is false; using the built-in DOM composer.",
|
|
4419
|
+
shouldWarn: false
|
|
4420
|
+
});
|
|
4421
|
+
}
|
|
4242
4422
|
const internalState = __using(__stack2, makeInternalState(), 0);
|
|
4243
4423
|
const keepalive = __using(__stack2, createBackgroundKeepalive({
|
|
4244
4424
|
fps: resolved.fps,
|
|
@@ -4351,7 +4531,9 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4351
4531
|
logLevel,
|
|
4352
4532
|
internalState,
|
|
4353
4533
|
onlyBackgroundClipText: false,
|
|
4354
|
-
cutout: new DOMRect(0, 0, resolved.width, resolved.height)
|
|
4534
|
+
cutout: new DOMRect(0, 0, resolved.width, resolved.height),
|
|
4535
|
+
htmlInCanvasContext,
|
|
4536
|
+
onHtmlInCanvasLayerOutcome: htmlInCanvasContext ? onHtmlInCanvasLayerOutcome : undefined
|
|
4355
4537
|
});
|
|
4356
4538
|
internalState.addCreateFrameTime(performance.now() - createFrameStart);
|
|
4357
4539
|
layerCanvas = layer.canvas;
|
|
@@ -4402,7 +4584,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4402
4584
|
if (signal?.aborted) {
|
|
4403
4585
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
4404
4586
|
}
|
|
4405
|
-
const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, timestamp });
|
|
4587
|
+
const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, timestamp, sampleRate });
|
|
4406
4588
|
internalState.addAudioMixingTime(performance.now() - audioCombineStart);
|
|
4407
4589
|
const addSampleStart = performance.now();
|
|
4408
4590
|
const encodingPromises = [];
|
|
@@ -4427,7 +4609,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4427
4609
|
videoSampleSource?.videoSampleSource.close();
|
|
4428
4610
|
audioSampleSource?.audioSampleSource.close();
|
|
4429
4611
|
await outputWithCleanup.output.finalize();
|
|
4430
|
-
|
|
4612
|
+
Internals9.Log.verbose({ logLevel, tag: "web-renderer" }, `Render timings: waitForReady=${internalState.getWaitForReadyTime().toFixed(2)}ms, createFrame=${internalState.getCreateFrameTime().toFixed(2)}ms, addSample=${internalState.getAddSampleTime().toFixed(2)}ms, audioMixing=${internalState.getAudioMixingTime().toFixed(2)}ms`);
|
|
4431
4613
|
if (webFsTarget) {
|
|
4432
4614
|
sendUsageEvent({
|
|
4433
4615
|
licenseKey: licenseKey ?? null,
|
|
@@ -4478,7 +4660,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
4478
4660
|
isStill: false,
|
|
4479
4661
|
isProduction: isProduction ?? true
|
|
4480
4662
|
}).catch((err2) => {
|
|
4481
|
-
|
|
4663
|
+
Internals9.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
4482
4664
|
});
|
|
4483
4665
|
}
|
|
4484
4666
|
throw err;
|
|
@@ -4515,33 +4697,80 @@ var renderMediaOnWeb = (options) => {
|
|
|
4515
4697
|
licenseKey: options.licenseKey ?? null,
|
|
4516
4698
|
muted: options.muted ?? false,
|
|
4517
4699
|
scale: options.scale ?? 1,
|
|
4518
|
-
isProduction: options.isProduction ?? true
|
|
4700
|
+
isProduction: options.isProduction ?? true,
|
|
4701
|
+
allowHtmlInCanvas: options.allowHtmlInCanvas ?? false,
|
|
4702
|
+
sampleRate: options.sampleRate ?? 48000
|
|
4519
4703
|
}));
|
|
4520
4704
|
return onlyOneRenderAtATimeQueue.ref;
|
|
4521
4705
|
};
|
|
4522
4706
|
// src/render-still-on-web.tsx
|
|
4523
4707
|
import {
|
|
4524
|
-
Internals as
|
|
4708
|
+
Internals as Internals10
|
|
4525
4709
|
} from "remotion";
|
|
4710
|
+
|
|
4711
|
+
// src/render-still-screenshot-task.ts
|
|
4712
|
+
var mimeTypeForFormat = (format) => {
|
|
4713
|
+
if (format === "jpeg") {
|
|
4714
|
+
return "image/jpeg";
|
|
4715
|
+
}
|
|
4716
|
+
if (format === "webp") {
|
|
4717
|
+
return "image/webp";
|
|
4718
|
+
}
|
|
4719
|
+
return "image/png";
|
|
4720
|
+
};
|
|
4721
|
+
var encodeCanvasToBlob = async (canvas, options) => {
|
|
4722
|
+
const format = options?.format ?? "png";
|
|
4723
|
+
const type = mimeTypeForFormat(format);
|
|
4724
|
+
if (format === "png") {
|
|
4725
|
+
return canvas.convertToBlob({ type });
|
|
4726
|
+
}
|
|
4727
|
+
return canvas.convertToBlob({
|
|
4728
|
+
type,
|
|
4729
|
+
quality: options?.quality
|
|
4730
|
+
});
|
|
4731
|
+
};
|
|
4732
|
+
var createRenderStillOnWebResult = ({
|
|
4733
|
+
canvas,
|
|
4734
|
+
internalState
|
|
4735
|
+
}) => {
|
|
4736
|
+
return {
|
|
4737
|
+
internalState,
|
|
4738
|
+
canvas: () => Promise.resolve(canvas),
|
|
4739
|
+
blob: (options) => encodeCanvasToBlob(canvas, options),
|
|
4740
|
+
url: async (options) => {
|
|
4741
|
+
const blob = await encodeCanvasToBlob(canvas, options);
|
|
4742
|
+
return URL.createObjectURL(blob);
|
|
4743
|
+
}
|
|
4744
|
+
};
|
|
4745
|
+
};
|
|
4746
|
+
|
|
4747
|
+
// src/render-still-on-web.tsx
|
|
4526
4748
|
async function internalRenderStillOnWeb({
|
|
4527
4749
|
frame,
|
|
4528
4750
|
delayRenderTimeoutInMilliseconds,
|
|
4529
4751
|
logLevel,
|
|
4530
4752
|
inputProps,
|
|
4531
4753
|
schema,
|
|
4532
|
-
imageFormat,
|
|
4533
4754
|
mediaCacheSizeInBytes,
|
|
4534
4755
|
composition,
|
|
4535
4756
|
signal,
|
|
4536
4757
|
onArtifact,
|
|
4537
4758
|
licenseKey,
|
|
4538
4759
|
scale,
|
|
4539
|
-
isProduction
|
|
4760
|
+
isProduction,
|
|
4761
|
+
allowHtmlInCanvas
|
|
4540
4762
|
}) {
|
|
4541
4763
|
let __stack = [];
|
|
4542
4764
|
try {
|
|
4543
4765
|
validateScale(scale);
|
|
4544
|
-
const
|
|
4766
|
+
const onHtmlInCanvasLayerOutcome = (outcome) => {
|
|
4767
|
+
if (outcome.native) {
|
|
4768
|
+
Internals10.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, "Using Chromium experimental HTML-in-canvas (drawElementImage) for this frame. Pixels may differ from the built-in DOM composer. Set allowHtmlInCanvas: false to force software rasterization. See https://github.com/WICG/html-in-canvas");
|
|
4769
|
+
} else if (outcome.shouldWarn) {
|
|
4770
|
+
Internals10.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, `Not using HTML-in-canvas: ${outcome.reason}`);
|
|
4771
|
+
}
|
|
4772
|
+
};
|
|
4773
|
+
const resolved = await Internals10.resolveVideoConfig({
|
|
4545
4774
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
4546
4775
|
signal: signal ?? new AbortController().signal,
|
|
4547
4776
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -4572,9 +4801,37 @@ async function internalRenderStillOnWeb({
|
|
|
4572
4801
|
schema: schema ?? null,
|
|
4573
4802
|
initialFrame: frame,
|
|
4574
4803
|
defaultCodec: resolved.defaultCodec,
|
|
4575
|
-
defaultOutName: resolved.defaultOutName
|
|
4804
|
+
defaultOutName: resolved.defaultOutName,
|
|
4805
|
+
allowHtmlInCanvas
|
|
4576
4806
|
}), 0);
|
|
4577
|
-
const {
|
|
4807
|
+
const {
|
|
4808
|
+
delayRenderScope,
|
|
4809
|
+
div,
|
|
4810
|
+
collectAssets,
|
|
4811
|
+
errorHolder,
|
|
4812
|
+
htmlInCanvasContext
|
|
4813
|
+
} = scaffold;
|
|
4814
|
+
if (allowHtmlInCanvas && !htmlInCanvasContext) {
|
|
4815
|
+
if (!supportsNativeHtmlInCanvas()) {
|
|
4816
|
+
onHtmlInCanvasLayerOutcome({
|
|
4817
|
+
native: false,
|
|
4818
|
+
reason: "This browser does not expose CanvasRenderingContext2D.prototype.drawElementImage. In Chromium, enable chrome://flags/#canvas-draw-element and use a version that ships the API.",
|
|
4819
|
+
shouldWarn: false
|
|
4820
|
+
});
|
|
4821
|
+
} else {
|
|
4822
|
+
onHtmlInCanvasLayerOutcome({
|
|
4823
|
+
native: false,
|
|
4824
|
+
reason: "drawElementImage is available but canvas.requestPaint() is missing. Use a Chromium version that ships requestPaint.",
|
|
4825
|
+
shouldWarn: true
|
|
4826
|
+
});
|
|
4827
|
+
}
|
|
4828
|
+
} else if (!allowHtmlInCanvas) {
|
|
4829
|
+
onHtmlInCanvasLayerOutcome({
|
|
4830
|
+
native: false,
|
|
4831
|
+
reason: "allowHtmlInCanvas is false; using the built-in DOM composer.",
|
|
4832
|
+
shouldWarn: false
|
|
4833
|
+
});
|
|
4834
|
+
}
|
|
4578
4835
|
const artifactsHandler = handleArtifacts();
|
|
4579
4836
|
try {
|
|
4580
4837
|
if (signal?.aborted) {
|
|
@@ -4598,14 +4855,19 @@ async function internalRenderStillOnWeb({
|
|
|
4598
4855
|
logLevel,
|
|
4599
4856
|
internalState,
|
|
4600
4857
|
onlyBackgroundClipText: false,
|
|
4601
|
-
cutout: new DOMRect(0, 0, resolved.width, resolved.height)
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
type: `image/${imageFormat}`
|
|
4858
|
+
cutout: new DOMRect(0, 0, resolved.width, resolved.height),
|
|
4859
|
+
htmlInCanvasContext,
|
|
4860
|
+
onHtmlInCanvasLayerOutcome: htmlInCanvasContext ? onHtmlInCanvasLayerOutcome : undefined
|
|
4605
4861
|
});
|
|
4862
|
+
const { canvas } = capturedFrame;
|
|
4606
4863
|
const assets = collectAssets.current.collectAssets();
|
|
4607
4864
|
if (onArtifact) {
|
|
4608
|
-
await artifactsHandler.handle({
|
|
4865
|
+
await artifactsHandler.handle({
|
|
4866
|
+
imageData: canvas,
|
|
4867
|
+
frame,
|
|
4868
|
+
assets,
|
|
4869
|
+
onArtifact
|
|
4870
|
+
});
|
|
4609
4871
|
}
|
|
4610
4872
|
sendUsageEvent({
|
|
4611
4873
|
licenseKey: licenseKey ?? null,
|
|
@@ -4614,7 +4876,7 @@ async function internalRenderStillOnWeb({
|
|
|
4614
4876
|
isStill: true,
|
|
4615
4877
|
isProduction
|
|
4616
4878
|
});
|
|
4617
|
-
return {
|
|
4879
|
+
return createRenderStillOnWebResult({ canvas, internalState });
|
|
4618
4880
|
} catch (err) {
|
|
4619
4881
|
if (!signal?.aborted) {
|
|
4620
4882
|
sendUsageEvent({
|
|
@@ -4624,7 +4886,7 @@ async function internalRenderStillOnWeb({
|
|
|
4624
4886
|
isStill: true,
|
|
4625
4887
|
isProduction
|
|
4626
4888
|
}).catch((err2) => {
|
|
4627
|
-
|
|
4889
|
+
Internals10.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
4628
4890
|
});
|
|
4629
4891
|
}
|
|
4630
4892
|
throw err;
|
|
@@ -4646,7 +4908,8 @@ var renderStillOnWeb = (options) => {
|
|
|
4646
4908
|
onArtifact: options.onArtifact ?? null,
|
|
4647
4909
|
licenseKey: options.licenseKey ?? null,
|
|
4648
4910
|
scale: options.scale ?? 1,
|
|
4649
|
-
isProduction: options.isProduction ?? true
|
|
4911
|
+
isProduction: options.isProduction ?? true,
|
|
4912
|
+
allowHtmlInCanvas: options.allowHtmlInCanvas ?? false
|
|
4650
4913
|
}));
|
|
4651
4914
|
return onlyOneRenderAtATimeQueue.ref;
|
|
4652
4915
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type Canvas2DWithDrawElement = CanvasRenderingContext2D & {
|
|
2
|
+
drawElementImage: (element: Element, dx: number, dy: number, dwidth: number, dheight: number) => DOMMatrix;
|
|
3
|
+
};
|
|
4
|
+
type HTMLCanvasWithLayoutSubtree = HTMLCanvasElement & {
|
|
5
|
+
layoutSubtree?: boolean;
|
|
6
|
+
requestPaint?: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const supportsNativeHtmlInCanvas: () => boolean;
|
|
9
|
+
export type HtmlInCanvasContext = {
|
|
10
|
+
layoutCanvas: HTMLCanvasWithLayoutSubtree;
|
|
11
|
+
ctx: Canvas2DWithDrawElement;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Sets up a persistent layoutsubtree canvas that wraps the scaffold div.
|
|
15
|
+
* The div becomes a direct child of the canvas, which is required for drawElementImage.
|
|
16
|
+
* Must be called once before rendering begins; the canvas stays in the DOM for the
|
|
17
|
+
* lifetime of the render.
|
|
18
|
+
*/
|
|
19
|
+
export declare const setupHtmlInCanvas: ({ wrapper, div, width, height, }: {
|
|
20
|
+
wrapper: HTMLDivElement;
|
|
21
|
+
div: HTMLDivElement;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
}) => HtmlInCanvasContext | null;
|
|
25
|
+
/**
|
|
26
|
+
* Triggers a fresh paint record via requestPaint(), waits for the paint event,
|
|
27
|
+
* then captures the element into an OffscreenCanvas using drawElementImage.
|
|
28
|
+
*
|
|
29
|
+
* The caller is responsible for ensuring the frame content is ready (via
|
|
30
|
+
* waitForReady) before calling this function.
|
|
31
|
+
*/
|
|
32
|
+
export declare const drawWithHtmlInCanvas: ({ htmlInCanvasContext, element, scaledWidth, scaledHeight, }: {
|
|
33
|
+
htmlInCanvasContext: HtmlInCanvasContext;
|
|
34
|
+
element: HTMLElement;
|
|
35
|
+
scaledWidth: number;
|
|
36
|
+
scaledHeight: number;
|
|
37
|
+
}) => Promise<OffscreenCanvasRenderingContext2D>;
|
|
38
|
+
export declare const teardownHtmlInCanvas: ({ htmlInCanvasContext, wrapper, div, }: {
|
|
39
|
+
htmlInCanvasContext: HtmlInCanvasContext;
|
|
40
|
+
wrapper: HTMLDivElement;
|
|
41
|
+
div: HTMLDivElement;
|
|
42
|
+
}) => void;
|
|
43
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,6 @@ export type { WebRendererOutputTarget } from './output-target';
|
|
|
10
10
|
export { renderMediaOnWeb } from './render-media-on-web';
|
|
11
11
|
export type { RenderMediaOnWebOptions, RenderMediaOnWebProgress, RenderMediaOnWebProgressCallback, RenderMediaOnWebResult, WebRendererHardwareAcceleration, } from './render-media-on-web';
|
|
12
12
|
export { renderStillOnWeb } from './render-still-on-web';
|
|
13
|
-
export type { RenderStillOnWebImageFormat, RenderStillOnWebOptions, } from './render-still-on-web';
|
|
13
|
+
export type { RenderStillOnWebEncodeOptions, RenderStillOnWebImageFormat, RenderStillOnWebOptions, RenderStillOnWebResult, } from './render-still-on-web';
|
|
14
|
+
export type { HtmlInCanvasLayerOutcome } from './take-screenshot';
|
|
14
15
|
export type { OnFrameCallback } from './validate-video-frame';
|
|
@@ -65,6 +65,8 @@ type OptionalRenderMediaOnWebOptions<Schema extends $ZodObject> = {
|
|
|
65
65
|
isProduction: boolean;
|
|
66
66
|
muted: boolean;
|
|
67
67
|
scale: number;
|
|
68
|
+
allowHtmlInCanvas: boolean;
|
|
69
|
+
sampleRate: number;
|
|
68
70
|
};
|
|
69
71
|
export type RenderMediaOnWebOptions<Schema extends $ZodObject, Props extends Record<string, unknown>> = MandatoryRenderMediaOnWebOptions<Schema, Props> & Partial<OptionalRenderMediaOnWebOptions<Schema>> & InputPropsIfHasProps<Schema, Props>;
|
|
70
72
|
export declare const renderMediaOnWeb: <Schema extends $ZodObject<Readonly<Readonly<{
|
|
@@ -3,10 +3,10 @@ import type { $ZodObject } from 'zod/v4/core';
|
|
|
3
3
|
import type { WebRendererOnArtifact } from './artifact';
|
|
4
4
|
import type { CompositionCalculateMetadataOrExplicit } from './props-if-has-props';
|
|
5
5
|
import type { InputPropsIfHasProps } from './render-media-on-web';
|
|
6
|
-
|
|
6
|
+
import { type RenderStillOnWebResult } from './render-still-screenshot-task';
|
|
7
|
+
export type { RenderStillOnWebEncodeOptions, RenderStillOnWebImageFormat, RenderStillOnWebResult, } from './render-still-screenshot-task';
|
|
7
8
|
type MandatoryRenderStillOnWebOptions<Schema extends $ZodObject, Props extends Record<string, unknown>> = {
|
|
8
9
|
frame: number;
|
|
9
|
-
imageFormat: RenderStillOnWebImageFormat;
|
|
10
10
|
} & {
|
|
11
11
|
composition: CompositionCalculateMetadataOrExplicit<Schema, Props>;
|
|
12
12
|
};
|
|
@@ -20,29 +20,9 @@ type OptionalRenderStillOnWebOptions<Schema extends $ZodObject> = {
|
|
|
20
20
|
licenseKey: string | null;
|
|
21
21
|
scale: number;
|
|
22
22
|
isProduction: boolean;
|
|
23
|
+
allowHtmlInCanvas: boolean;
|
|
23
24
|
};
|
|
24
25
|
export type RenderStillOnWebOptions<Schema extends $ZodObject, Props extends Record<string, unknown>> = MandatoryRenderStillOnWebOptions<Schema, Props> & Partial<OptionalRenderStillOnWebOptions<Schema>> & InputPropsIfHasProps<Schema, Props>;
|
|
25
26
|
export declare const renderStillOnWeb: <Schema extends $ZodObject<Readonly<Readonly<{
|
|
26
27
|
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
27
|
-
}>>, import("zod/v4/core").$ZodObjectConfig>, Props extends Record<string, unknown>>(options: RenderStillOnWebOptions<Schema, Props>) => Promise<
|
|
28
|
-
blob: Blob;
|
|
29
|
-
internalState: {
|
|
30
|
-
getDrawn3dPixels: () => number;
|
|
31
|
-
getPrecomposedTiles: () => number;
|
|
32
|
-
addPrecompose: ({ canvasWidth, canvasHeight, }: {
|
|
33
|
-
canvasWidth: number;
|
|
34
|
-
canvasHeight: number;
|
|
35
|
-
}) => void;
|
|
36
|
-
helperCanvasState: import("./internal-state").HelperCanvasState;
|
|
37
|
-
[Symbol.dispose]: () => void;
|
|
38
|
-
getWaitForReadyTime: () => number;
|
|
39
|
-
addWaitForReadyTime: (time: number) => void;
|
|
40
|
-
getAddSampleTime: () => number;
|
|
41
|
-
addAddSampleTime: (time: number) => void;
|
|
42
|
-
getCreateFrameTime: () => number;
|
|
43
|
-
addCreateFrameTime: (time: number) => void;
|
|
44
|
-
getAudioMixingTime: () => number;
|
|
45
|
-
addAudioMixingTime: (time: number) => void;
|
|
46
|
-
};
|
|
47
|
-
}>;
|
|
48
|
-
export {};
|
|
28
|
+
}>>, import("zod/v4/core").$ZodObjectConfig>, Props extends Record<string, unknown>>(options: RenderStillOnWebOptions<Schema, Props>) => Promise<RenderStillOnWebResult>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { InternalState } from './internal-state';
|
|
2
|
+
export type RenderStillOnWebImageFormat = 'png' | 'jpeg' | 'webp';
|
|
3
|
+
export type RenderStillOnWebEncodeOptions = {
|
|
4
|
+
format?: RenderStillOnWebImageFormat;
|
|
5
|
+
/**
|
|
6
|
+
* Encoder quality for `jpeg` and `webp`, between `0` and `1`.
|
|
7
|
+
* Ignored for `png`.
|
|
8
|
+
*/
|
|
9
|
+
quality?: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Outcome of `renderStillOnWeb()`. The frame is already rendered; use
|
|
13
|
+
* `canvas()`, `blob()`, or `url()` to read pixels or encode (same pattern as
|
|
14
|
+
* Renoun’s `screenshot()` task).
|
|
15
|
+
*/
|
|
16
|
+
export type RenderStillOnWebResult = {
|
|
17
|
+
internalState: InternalState;
|
|
18
|
+
canvas(): Promise<OffscreenCanvas>;
|
|
19
|
+
blob(options?: RenderStillOnWebEncodeOptions): Promise<Blob>;
|
|
20
|
+
/**
|
|
21
|
+
* Creates an object URL from an encoded blob. Call `URL.revokeObjectURL()` when done.
|
|
22
|
+
*/
|
|
23
|
+
url(options?: RenderStillOnWebEncodeOptions): Promise<string>;
|
|
24
|
+
};
|
|
25
|
+
export declare const createRenderStillOnWebResult: ({ canvas, internalState, }: {
|
|
26
|
+
canvas: OffscreenCanvas;
|
|
27
|
+
internalState: {
|
|
28
|
+
getDrawn3dPixels: () => number;
|
|
29
|
+
getPrecomposedTiles: () => number;
|
|
30
|
+
addPrecompose: ({ canvasWidth, canvasHeight, }: {
|
|
31
|
+
canvasWidth: number;
|
|
32
|
+
canvasHeight: number;
|
|
33
|
+
}) => void;
|
|
34
|
+
helperCanvasState: import("./internal-state").HelperCanvasState;
|
|
35
|
+
[Symbol.dispose]: () => void;
|
|
36
|
+
getWaitForReadyTime: () => number;
|
|
37
|
+
addWaitForReadyTime: (time: number) => void;
|
|
38
|
+
getAddSampleTime: () => number;
|
|
39
|
+
addAddSampleTime: (time: number) => void;
|
|
40
|
+
getCreateFrameTime: () => number;
|
|
41
|
+
addCreateFrameTime: (time: number) => void;
|
|
42
|
+
getAudioMixingTime: () => number;
|
|
43
|
+
addAudioMixingTime: (time: number) => void;
|
|
44
|
+
};
|
|
45
|
+
}) => RenderStillOnWebResult;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import type { HtmlInCanvasContext } from './html-in-canvas';
|
|
2
|
+
export type HtmlInCanvasLayerOutcome = {
|
|
3
|
+
native: true;
|
|
4
|
+
} | {
|
|
5
|
+
native: false;
|
|
6
|
+
reason: string;
|
|
7
|
+
shouldWarn: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const createLayer: ({ element, scale, logLevel, internalState, onlyBackgroundClipText, cutout, htmlInCanvasContext, onHtmlInCanvasLayerOutcome, }: {
|
|
2
10
|
element: HTMLElement | SVGElement;
|
|
3
11
|
scale: number;
|
|
4
12
|
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
@@ -22,4 +30,6 @@ export declare const createLayer: ({ element, scale, logLevel, internalState, on
|
|
|
22
30
|
};
|
|
23
31
|
onlyBackgroundClipText: boolean;
|
|
24
32
|
cutout: DOMRect;
|
|
33
|
+
htmlInCanvasContext?: HtmlInCanvasContext | null | undefined;
|
|
34
|
+
onHtmlInCanvasLayerOutcome?: ((outcome: HtmlInCanvasLayerOutcome) => void) | undefined;
|
|
25
35
|
}) => Promise<OffscreenCanvasRenderingContext2D>;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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.448",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"@mediabunny/mp3-encoder": "1.39.2",
|
|
23
23
|
"@mediabunny/aac-encoder": "1.39.2",
|
|
24
24
|
"@mediabunny/flac-encoder": "1.39.2",
|
|
25
|
-
"@remotion/licensing": "4.0.
|
|
26
|
-
"remotion": "4.0.
|
|
25
|
+
"@remotion/licensing": "4.0.448",
|
|
26
|
+
"remotion": "4.0.448",
|
|
27
27
|
"mediabunny": "1.39.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@react-three/fiber": "9.2.0",
|
|
31
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
32
|
-
"@remotion/player": "4.0.
|
|
33
|
-
"@remotion/media": "4.0.
|
|
34
|
-
"@remotion/three": "4.0.
|
|
31
|
+
"@remotion/eslint-config-internal": "4.0.448",
|
|
32
|
+
"@remotion/player": "4.0.448",
|
|
33
|
+
"@remotion/media": "4.0.448",
|
|
34
|
+
"@remotion/three": "4.0.448",
|
|
35
35
|
"@types/three": "0.170.0",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20260217.1",
|
|
37
37
|
"@vitejs/plugin-react": "4.3.4",
|