@remotion/web-renderer 4.0.403 → 4.0.405
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/background-keepalive.d.ts +9 -0
- package/dist/drawing/elements-and-bounds.d.ts +9 -0
- package/dist/drawing/get-pretransform-rect.d.ts +1 -1
- package/dist/drawing/handle-3d-transform.d.ts +3 -3
- package/dist/drawing/precompose-and-draw.d.ts +33 -0
- package/dist/drawing/precompose-element.d.ts +0 -0
- package/dist/drawing/renoun.d.ts +125 -0
- package/dist/drawing/transform-in-3d.d.ts +4 -7
- package/dist/drawing/transform-origin.d.ts +21 -0
- package/dist/drawing/transform-perspective-origin.d.ts +17 -0
- package/dist/esm/index.mjs +320 -176
- package/dist/internal-state.d.ts +2 -1
- package/dist/throttle-progress.d.ts +5 -1
- package/dist/wait-for-ready.d.ts +3 -1
- package/package.json +6 -6
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type LogLevel } from 'remotion';
|
|
2
|
+
export type BackgroundKeepalive = {
|
|
3
|
+
waitForTick: () => Promise<void>;
|
|
4
|
+
[Symbol.dispose]: () => void;
|
|
5
|
+
};
|
|
6
|
+
export declare function createBackgroundKeepalive({ fps, logLevel }: {
|
|
7
|
+
fps: number;
|
|
8
|
+
logLevel: LogLevel;
|
|
9
|
+
}): BackgroundKeepalive;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Precompositing } from './calculate-transforms';
|
|
2
|
+
export type ElementAndBounds = {
|
|
3
|
+
element: Element;
|
|
4
|
+
bounds: DOMRect;
|
|
5
|
+
transform: DOMMatrix;
|
|
6
|
+
parentRect: DOMRect;
|
|
7
|
+
precompositing: Precompositing;
|
|
8
|
+
establishes3DRenderingContext: DOMMatrix | null;
|
|
9
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function getPreTransformRect(targetRect: DOMRect, matrix: DOMMatrix): DOMRect;
|
|
1
|
+
export declare function getPreTransformRect(targetRect: DOMRect, matrix: DOMMatrix): DOMRect | null;
|
|
@@ -2,10 +2,10 @@ export declare const getPrecomposeRectFor3DTransform: ({ element, parentRect, ma
|
|
|
2
2
|
element: HTMLElement | SVGElement;
|
|
3
3
|
parentRect: DOMRect;
|
|
4
4
|
matrix: DOMMatrix;
|
|
5
|
-
}) => DOMRect;
|
|
6
|
-
export declare const handle3dTransform: ({ matrix,
|
|
5
|
+
}) => DOMRect | null;
|
|
6
|
+
export declare const handle3dTransform: ({ matrix, sourceRect, tempCanvas, rectAfterTransforms, internalState, }: {
|
|
7
7
|
matrix: DOMMatrix;
|
|
8
|
-
|
|
8
|
+
sourceRect: DOMRect;
|
|
9
9
|
tempCanvas: OffscreenCanvas;
|
|
10
10
|
rectAfterTransforms: DOMRect;
|
|
11
11
|
internalState: {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Precompositing } from './calculate-transforms';
|
|
2
|
+
import type { ElementAndBounds } from './elements-and-bounds';
|
|
3
|
+
export declare const precompose: ({ element, logLevel, parentRect, internalState, precompositing, totalMatrix, rect, isIn3dRenderingContext, }: {
|
|
4
|
+
element: HTMLElement | SVGElement;
|
|
5
|
+
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
6
|
+
parentRect: DOMRect;
|
|
7
|
+
internalState: {
|
|
8
|
+
getDrawn3dPixels: () => number;
|
|
9
|
+
getPrecomposedTiles: () => number;
|
|
10
|
+
addPrecompose: ({ canvasWidth, canvasHeight, }: {
|
|
11
|
+
canvasWidth: number;
|
|
12
|
+
canvasHeight: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
helperCanvasState: import("../internal-state").HelperCanvasState;
|
|
15
|
+
[Symbol.dispose]: () => void;
|
|
16
|
+
getWaitForReadyTime: () => number;
|
|
17
|
+
addWaitForReadyTime: (time: number) => void;
|
|
18
|
+
getAddSampleTime: () => number;
|
|
19
|
+
addAddSampleTime: (time: number) => void;
|
|
20
|
+
getCreateFrameTime: () => number;
|
|
21
|
+
addCreateFrameTime: (time: number) => void;
|
|
22
|
+
getAudioMixingTime: () => number;
|
|
23
|
+
addAudioMixingTime: (time: number) => void;
|
|
24
|
+
};
|
|
25
|
+
precompositing: Precompositing;
|
|
26
|
+
totalMatrix: DOMMatrix;
|
|
27
|
+
rect: DOMRect;
|
|
28
|
+
isIn3dRenderingContext: DOMMatrix | null;
|
|
29
|
+
}) => Promise<{
|
|
30
|
+
drawable: OffscreenCanvas;
|
|
31
|
+
rectAfterTransforms: DOMRect;
|
|
32
|
+
elementsToBeRenderedIndependently: ElementAndBounds[];
|
|
33
|
+
} | null>;
|
|
File without changes
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/** Image format for encoded screenshot output. */
|
|
2
|
+
export type ImageFormat = 'png' | 'jpeg' | 'webp';
|
|
3
|
+
/** Options for rendering a screenshot to canvas. */
|
|
4
|
+
export interface RenderOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Canvas background color. Set to `null` (or omit) for a transparent canvas.
|
|
7
|
+
* When provided, the string is passed directly to `fillStyle`.
|
|
8
|
+
*/
|
|
9
|
+
backgroundColor?: string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Optional existing canvas to render into.
|
|
12
|
+
* When omitted, a new canvas element is created.
|
|
13
|
+
*/
|
|
14
|
+
canvas?: HTMLCanvasElement;
|
|
15
|
+
/**
|
|
16
|
+
* Rendering scale factor. Defaults to `window.devicePixelRatio` (or `1`).
|
|
17
|
+
*/
|
|
18
|
+
scale?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Crop origin X (CSS pixels) relative to the element's left edge.
|
|
21
|
+
* Defaults to the element's left edge.
|
|
22
|
+
*/
|
|
23
|
+
x?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Crop origin Y (CSS pixels) relative to the element's top edge.
|
|
26
|
+
* Defaults to the element's top edge.
|
|
27
|
+
*/
|
|
28
|
+
y?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Output width in CSS pixels. Defaults to the element's width.
|
|
31
|
+
*/
|
|
32
|
+
width?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Output height in CSS pixels. Defaults to the element's height.
|
|
35
|
+
*/
|
|
36
|
+
height?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Controls how `position: fixed` elements outside the captured subtree are
|
|
39
|
+
* handled.
|
|
40
|
+
*
|
|
41
|
+
* - `none` – ignore all fixed elements outside `element`.
|
|
42
|
+
* - `intersecting` – include fixed elements whose bounding rect intersects the capture rect.
|
|
43
|
+
* - `all` – include all fixed elements that overlap the viewport.
|
|
44
|
+
*/
|
|
45
|
+
includeFixed?: 'none' | 'intersecting' | 'all';
|
|
46
|
+
/**
|
|
47
|
+
* CSS selector used to skip elements from rendering.
|
|
48
|
+
* Defaults to `[data-screenshot-ignore]`. Set to `null` or an empty string
|
|
49
|
+
* to disable selector-based skipping.
|
|
50
|
+
*/
|
|
51
|
+
ignoreSelector?: string | null;
|
|
52
|
+
}
|
|
53
|
+
/** Options for encoding a canvas to an image format. */
|
|
54
|
+
export interface EncodeOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Image format to encode. Defaults to `'png'`.
|
|
57
|
+
*/
|
|
58
|
+
format?: ImageFormat;
|
|
59
|
+
/**
|
|
60
|
+
* Image quality for lossy formats (`jpeg`, `webp`). A number between `0` and `1`.
|
|
61
|
+
* Ignored for `png`. Defaults to `0.92`.
|
|
62
|
+
*/
|
|
63
|
+
quality?: number;
|
|
64
|
+
}
|
|
65
|
+
/** Combined options for one-shot screenshot methods that render and encode. */
|
|
66
|
+
export type ScreenshotOptions = RenderOptions & EncodeOptions;
|
|
67
|
+
/**
|
|
68
|
+
* A promise-like object representing a screenshot capture. The underlying
|
|
69
|
+
* render happens once; subsequent calls to `.canvas()`, `.blob()`, or `.url()`
|
|
70
|
+
* reuse the same rendered canvas.
|
|
71
|
+
*/
|
|
72
|
+
export interface ScreenshotTask extends Promise<HTMLCanvasElement> {
|
|
73
|
+
/** Returns the rendered canvas. */
|
|
74
|
+
canvas(): Promise<HTMLCanvasElement>;
|
|
75
|
+
/** Encodes the rendered canvas to a Blob. */
|
|
76
|
+
blob(options?: EncodeOptions): Promise<Blob>;
|
|
77
|
+
/**
|
|
78
|
+
* Encodes the rendered canvas to a Blob and creates an object URL.
|
|
79
|
+
* Remember to call `URL.revokeObjectURL(url)` when done to avoid memory leaks.
|
|
80
|
+
*/
|
|
81
|
+
url(options?: EncodeOptions): Promise<string>;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Renders a DOM element into a canvas using modern browser features.
|
|
85
|
+
*
|
|
86
|
+
* Returns a `ScreenshotTask` that is both a Promise and provides methods
|
|
87
|
+
* to encode the rendered canvas. The underlying render happens once;
|
|
88
|
+
* subsequent calls to `.canvas()`, `.blob()`, or `.url()` reuse the same result.
|
|
89
|
+
*
|
|
90
|
+
* This implementation targets evergreen browsers only and assumes a real DOM +
|
|
91
|
+
* Canvas2D environment (not Node.js).
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // Capture handle pattern - render once, encode multiple ways
|
|
95
|
+
* const shot = screenshot(element, { scale: 2 })
|
|
96
|
+
* const canvas = await shot.canvas()
|
|
97
|
+
* const pngBlob = await shot.blob({ format: 'png' })
|
|
98
|
+
* const webpUrl = await shot.url({ format: 'webp', quality: 0.9 })
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Direct await returns the canvas
|
|
102
|
+
* const canvas = await screenshot(element)
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* // One-shot convenience methods
|
|
106
|
+
* const canvas = await screenshot.canvas(element, { scale: 2 })
|
|
107
|
+
* const blob = await screenshot.blob(element, { format: 'jpeg', quality: 0.85 })
|
|
108
|
+
* const url = await screenshot.url(element, { format: 'png' })
|
|
109
|
+
*/
|
|
110
|
+
declare function screenshot(target: Element | string, options?: RenderOptions): ScreenshotTask;
|
|
111
|
+
declare namespace screenshot {
|
|
112
|
+
var canvas: (target: string | Element, options?: RenderOptions | undefined) => Promise<HTMLCanvasElement>;
|
|
113
|
+
}
|
|
114
|
+
declare namespace screenshot {
|
|
115
|
+
var blob: (target: string | Element, options?: ScreenshotOptions | undefined) => Promise<Blob>;
|
|
116
|
+
}
|
|
117
|
+
declare namespace screenshot {
|
|
118
|
+
var url: (target: string | Element, options?: ScreenshotOptions | undefined) => Promise<string>;
|
|
119
|
+
}
|
|
120
|
+
export { screenshot };
|
|
121
|
+
declare global {
|
|
122
|
+
interface CanvasRenderingContext2D {
|
|
123
|
+
_filterPolyfillValue?: string;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { HelperCanvasState } from '../internal-state';
|
|
2
|
-
export declare const transformIn3d: ({ matrix, sourceCanvas,
|
|
3
|
-
|
|
2
|
+
export declare const transformIn3d: ({ matrix, sourceCanvas, sourceRect, destRect, internalState, }: {
|
|
3
|
+
sourceRect: DOMRect;
|
|
4
4
|
matrix: DOMMatrix;
|
|
5
5
|
sourceCanvas: OffscreenCanvas;
|
|
6
|
-
|
|
6
|
+
destRect: DOMRect;
|
|
7
7
|
internalState: {
|
|
8
8
|
getDrawn3dPixels: () => number;
|
|
9
9
|
getPrecomposedTiles: () => number;
|
|
@@ -22,7 +22,4 @@ export declare const transformIn3d: ({ matrix, sourceCanvas, untransformedRect,
|
|
|
22
22
|
getAudioMixingTime: () => number;
|
|
23
23
|
addAudioMixingTime: (time: number) => void;
|
|
24
24
|
};
|
|
25
|
-
}) =>
|
|
26
|
-
canvas: OffscreenCanvas;
|
|
27
|
-
rect: DOMRect;
|
|
28
|
-
};
|
|
25
|
+
}) => OffscreenCanvas;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type Transform = {
|
|
2
|
+
matrices: DOMMatrix[];
|
|
3
|
+
element: Element;
|
|
4
|
+
transformOrigin: string;
|
|
5
|
+
boundingClientRect: DOMRect | null;
|
|
6
|
+
};
|
|
7
|
+
export declare const parseTransformOriginOrPerspectiveOrigin: (transformOrigin: string) => {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare const getInternalOrigin: (origin: string, boundingClientRect: DOMRect) => {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
};
|
|
15
|
+
export declare const getGlobalOrigin: ({ origin, boundingClientRect, }: {
|
|
16
|
+
origin: string;
|
|
17
|
+
boundingClientRect: DOMRect;
|
|
18
|
+
}) => {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type Transform = {
|
|
2
|
+
matrices: DOMMatrix[];
|
|
3
|
+
element: Element;
|
|
4
|
+
transformOrigin: string;
|
|
5
|
+
boundingClientRect: DOMRect | null;
|
|
6
|
+
};
|
|
7
|
+
export declare const parseTransformOriginOrPerspectiveOrigin: (transformOrigin: string) => {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare const getAbsoluteOrigin: ({ origin, boundingClientRect, }: {
|
|
12
|
+
origin: string;
|
|
13
|
+
boundingClientRect: DOMRect;
|
|
14
|
+
}) => {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
};
|
package/dist/esm/index.mjs
CHANGED
|
@@ -359,7 +359,7 @@ var getEncodableAudioCodecs = async (container, options) => {
|
|
|
359
359
|
};
|
|
360
360
|
// src/render-media-on-web.tsx
|
|
361
361
|
import { BufferTarget, StreamTarget } from "mediabunny";
|
|
362
|
-
import { Internals as
|
|
362
|
+
import { Internals as Internals8 } from "remotion";
|
|
363
363
|
|
|
364
364
|
// src/add-sample.ts
|
|
365
365
|
import { AudioSample, VideoSample } from "mediabunny";
|
|
@@ -488,6 +488,92 @@ var onlyInlineAudio = ({
|
|
|
488
488
|
});
|
|
489
489
|
};
|
|
490
490
|
|
|
491
|
+
// src/background-keepalive.ts
|
|
492
|
+
import { Internals } from "remotion";
|
|
493
|
+
var WORKER_CODE = `
|
|
494
|
+
let intervalId = null;
|
|
495
|
+
self.onmessage = (e) => {
|
|
496
|
+
if (e.data.type === 'start') {
|
|
497
|
+
if (intervalId !== null) {
|
|
498
|
+
clearInterval(intervalId);
|
|
499
|
+
}
|
|
500
|
+
intervalId = setInterval(() => self.postMessage('tick'), e.data.intervalMs);
|
|
501
|
+
} else if (e.data.type === 'stop') {
|
|
502
|
+
if (intervalId !== null) {
|
|
503
|
+
clearInterval(intervalId);
|
|
504
|
+
intervalId = null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
`;
|
|
509
|
+
function createBackgroundKeepalive({
|
|
510
|
+
fps,
|
|
511
|
+
logLevel
|
|
512
|
+
}) {
|
|
513
|
+
const intervalMs = Math.round(1000 / fps);
|
|
514
|
+
let pendingResolvers = [];
|
|
515
|
+
let worker = null;
|
|
516
|
+
let disposed = false;
|
|
517
|
+
if (typeof Worker === "undefined") {
|
|
518
|
+
Internals.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, "Web Workers not available. Rendering may pause when tab is backgrounded.");
|
|
519
|
+
return {
|
|
520
|
+
waitForTick: () => {
|
|
521
|
+
return new Promise((resolve) => {
|
|
522
|
+
setTimeout(resolve, intervalMs);
|
|
523
|
+
});
|
|
524
|
+
},
|
|
525
|
+
[Symbol.dispose]: () => {}
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
const blob = new Blob([WORKER_CODE], { type: "application/javascript" });
|
|
529
|
+
const workerUrl = URL.createObjectURL(blob);
|
|
530
|
+
worker = new Worker(workerUrl);
|
|
531
|
+
worker.onmessage = () => {
|
|
532
|
+
const resolvers = pendingResolvers;
|
|
533
|
+
pendingResolvers = [];
|
|
534
|
+
for (const resolve of resolvers) {
|
|
535
|
+
resolve();
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
worker.onerror = (event) => {
|
|
539
|
+
Internals.Log.error({ logLevel, tag: "@remotion/web-renderer" }, "Background keepalive worker encountered an error and will be terminated.", event);
|
|
540
|
+
const resolvers = pendingResolvers;
|
|
541
|
+
pendingResolvers = [];
|
|
542
|
+
for (const resolve of resolvers) {
|
|
543
|
+
resolve();
|
|
544
|
+
}
|
|
545
|
+
if (!disposed) {
|
|
546
|
+
disposed = true;
|
|
547
|
+
worker?.terminate();
|
|
548
|
+
worker = null;
|
|
549
|
+
URL.revokeObjectURL(workerUrl);
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
worker.postMessage({ type: "start", intervalMs });
|
|
553
|
+
return {
|
|
554
|
+
waitForTick: () => {
|
|
555
|
+
return new Promise((resolve) => {
|
|
556
|
+
pendingResolvers.push(resolve);
|
|
557
|
+
});
|
|
558
|
+
},
|
|
559
|
+
[Symbol.dispose]: () => {
|
|
560
|
+
if (disposed) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
disposed = true;
|
|
564
|
+
worker?.postMessage({ type: "stop" });
|
|
565
|
+
worker?.terminate();
|
|
566
|
+
worker = null;
|
|
567
|
+
URL.revokeObjectURL(workerUrl);
|
|
568
|
+
const resolvers = pendingResolvers;
|
|
569
|
+
pendingResolvers = [];
|
|
570
|
+
for (const resolve of resolvers) {
|
|
571
|
+
resolve();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
491
577
|
// src/create-audio-sample-source.ts
|
|
492
578
|
import { AudioSampleSource } from "mediabunny";
|
|
493
579
|
var createAudioSampleSource = ({
|
|
@@ -509,12 +595,12 @@ var createAudioSampleSource = ({
|
|
|
509
595
|
import { createRef } from "react";
|
|
510
596
|
import { flushSync as flushSync2 } from "react-dom";
|
|
511
597
|
import ReactDOM from "react-dom/client";
|
|
512
|
-
import { Internals as
|
|
598
|
+
import { Internals as Internals3 } from "remotion";
|
|
513
599
|
|
|
514
600
|
// src/update-time.tsx
|
|
515
601
|
import { useImperativeHandle, useState } from "react";
|
|
516
602
|
import { flushSync } from "react-dom";
|
|
517
|
-
import { Internals } from "remotion";
|
|
603
|
+
import { Internals as Internals2 } from "remotion";
|
|
518
604
|
import { jsx } from "react/jsx-runtime";
|
|
519
605
|
var UpdateTime = ({
|
|
520
606
|
children,
|
|
@@ -533,7 +619,7 @@ var UpdateTime = ({
|
|
|
533
619
|
});
|
|
534
620
|
}
|
|
535
621
|
}));
|
|
536
|
-
return /* @__PURE__ */ jsx(
|
|
622
|
+
return /* @__PURE__ */ jsx(Internals2.RemotionRootContexts, {
|
|
537
623
|
audioEnabled,
|
|
538
624
|
videoEnabled,
|
|
539
625
|
logLevel,
|
|
@@ -596,7 +682,7 @@ async function createScaffold({
|
|
|
596
682
|
div.style.pointerEvents = "none";
|
|
597
683
|
const scaffoldClassName = `remotion-scaffold-${Math.random().toString(36).substring(2, 15)}`;
|
|
598
684
|
div.className = scaffoldClassName;
|
|
599
|
-
const cleanupCSS =
|
|
685
|
+
const cleanupCSS = Internals3.CSSUtils.injectCSS(Internals3.CSSUtils.makeDefaultPreviewCSS(`.${scaffoldClassName}`, "white"));
|
|
600
686
|
document.body.appendChild(div);
|
|
601
687
|
const { promise, resolve, reject } = withResolvers();
|
|
602
688
|
const root = ReactDOM.createRoot(div, {
|
|
@@ -614,9 +700,9 @@ async function createScaffold({
|
|
|
614
700
|
const timeUpdater = createRef();
|
|
615
701
|
const collectAssets = createRef();
|
|
616
702
|
flushSync2(() => {
|
|
617
|
-
root.render(/* @__PURE__ */ jsx2(
|
|
703
|
+
root.render(/* @__PURE__ */ jsx2(Internals3.MaxMediaCacheSizeContext.Provider, {
|
|
618
704
|
value: mediaCacheSizeInBytes,
|
|
619
|
-
children: /* @__PURE__ */ jsx2(
|
|
705
|
+
children: /* @__PURE__ */ jsx2(Internals3.RemotionEnvironmentContext.Provider, {
|
|
620
706
|
value: {
|
|
621
707
|
isStudio: false,
|
|
622
708
|
isRendering: true,
|
|
@@ -624,9 +710,9 @@ async function createScaffold({
|
|
|
624
710
|
isReadOnlyStudio: false,
|
|
625
711
|
isClientSideRendering: true
|
|
626
712
|
},
|
|
627
|
-
children: /* @__PURE__ */ jsx2(
|
|
713
|
+
children: /* @__PURE__ */ jsx2(Internals3.DelayRenderContextType.Provider, {
|
|
628
714
|
value: delayRenderScope,
|
|
629
|
-
children: /* @__PURE__ */ jsx2(
|
|
715
|
+
children: /* @__PURE__ */ jsx2(Internals3.CompositionManager.Provider, {
|
|
630
716
|
value: {
|
|
631
717
|
compositions: [
|
|
632
718
|
{
|
|
@@ -662,7 +748,7 @@ async function createScaffold({
|
|
|
662
748
|
},
|
|
663
749
|
folders: []
|
|
664
750
|
},
|
|
665
|
-
children: /* @__PURE__ */ jsx2(
|
|
751
|
+
children: /* @__PURE__ */ jsx2(Internals3.RenderAssetManagerProvider, {
|
|
666
752
|
collectAssets,
|
|
667
753
|
children: /* @__PURE__ */ jsx2(UpdateTime, {
|
|
668
754
|
audioEnabled,
|
|
@@ -671,7 +757,7 @@ async function createScaffold({
|
|
|
671
757
|
compId: id,
|
|
672
758
|
initialFrame,
|
|
673
759
|
timeUpdater,
|
|
674
|
-
children: /* @__PURE__ */ jsx2(
|
|
760
|
+
children: /* @__PURE__ */ jsx2(Internals3.CanUseRemotionHooks.Provider, {
|
|
675
761
|
value: true,
|
|
676
762
|
children: /* @__PURE__ */ jsx2(Component, {
|
|
677
763
|
...resolvedProps
|
|
@@ -799,58 +885,77 @@ function isNetworkError(error) {
|
|
|
799
885
|
return false;
|
|
800
886
|
}
|
|
801
887
|
var HOST = "https://www.remotion.pro";
|
|
888
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
889
|
+
var exponentialBackoffMs = (attempt) => {
|
|
890
|
+
return 1000 * 2 ** (attempt - 1);
|
|
891
|
+
};
|
|
892
|
+
var sleep = (ms) => {
|
|
893
|
+
return new Promise((resolve) => {
|
|
894
|
+
setTimeout(resolve, ms);
|
|
895
|
+
});
|
|
896
|
+
};
|
|
802
897
|
var registerUsageEvent = async ({
|
|
803
898
|
host,
|
|
804
899
|
succeeded,
|
|
805
900
|
event,
|
|
806
901
|
...apiOrLicenseKey
|
|
807
902
|
}) => {
|
|
808
|
-
const abortController = new AbortController;
|
|
809
|
-
const timeout = setTimeout(() => {
|
|
810
|
-
abortController.abort();
|
|
811
|
-
}, 1e4);
|
|
812
903
|
const apiKey = "apiKey" in apiOrLicenseKey ? apiOrLicenseKey.apiKey : null;
|
|
813
904
|
const licenseKey = "licenseKey" in apiOrLicenseKey ? apiOrLicenseKey.licenseKey : null;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
throw new Error(
|
|
905
|
+
let lastError;
|
|
906
|
+
const totalAttempts = DEFAULT_MAX_RETRIES + 1;
|
|
907
|
+
for (let attempt = 1;attempt <= totalAttempts; attempt++) {
|
|
908
|
+
const abortController = new AbortController;
|
|
909
|
+
const timeout = setTimeout(() => {
|
|
910
|
+
abortController.abort();
|
|
911
|
+
}, 1e4);
|
|
912
|
+
try {
|
|
913
|
+
const res = await fetch(`${HOST}/api/track/register-usage-point`, {
|
|
914
|
+
method: "POST",
|
|
915
|
+
body: JSON.stringify({
|
|
916
|
+
event,
|
|
917
|
+
apiKey: licenseKey ?? apiKey,
|
|
918
|
+
host,
|
|
919
|
+
succeeded
|
|
920
|
+
}),
|
|
921
|
+
headers: {
|
|
922
|
+
"Content-Type": "application/json"
|
|
923
|
+
},
|
|
924
|
+
signal: abortController.signal
|
|
925
|
+
});
|
|
926
|
+
clearTimeout(timeout);
|
|
927
|
+
const json = await res.json();
|
|
928
|
+
if (json.success) {
|
|
929
|
+
return {
|
|
930
|
+
billable: json.billable,
|
|
931
|
+
classification: json.classification
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
if (!res.ok) {
|
|
935
|
+
throw new Error(json.error);
|
|
936
|
+
}
|
|
937
|
+
throw new Error(`Unexpected response from server: ${JSON.stringify(json)}`);
|
|
938
|
+
} catch (err) {
|
|
939
|
+
clearTimeout(timeout);
|
|
940
|
+
const error = err;
|
|
941
|
+
const isTimeout = error.name === "AbortError";
|
|
942
|
+
const isRetryable = isNetworkError(error) || isTimeout;
|
|
943
|
+
if (!isRetryable) {
|
|
944
|
+
throw err;
|
|
945
|
+
}
|
|
946
|
+
lastError = isTimeout ? new Error("Request timed out after 10 seconds") : error;
|
|
947
|
+
if (attempt < totalAttempts) {
|
|
948
|
+
const backoffMs = exponentialBackoffMs(attempt);
|
|
949
|
+
console.log(`Failed to send usage event (attempt ${attempt}/${totalAttempts}), retrying in ${backoffMs}ms...`, err);
|
|
950
|
+
await sleep(backoffMs);
|
|
951
|
+
}
|
|
847
952
|
}
|
|
848
|
-
throw err;
|
|
849
953
|
}
|
|
954
|
+
throw lastError;
|
|
850
955
|
};
|
|
851
956
|
|
|
852
957
|
// src/send-telemetry-event.ts
|
|
853
|
-
import { Internals as
|
|
958
|
+
import { Internals as Internals4 } from "remotion";
|
|
854
959
|
var sendUsageEvent = async ({
|
|
855
960
|
licenseKey,
|
|
856
961
|
succeeded,
|
|
@@ -861,7 +966,7 @@ var sendUsageEvent = async ({
|
|
|
861
966
|
return;
|
|
862
967
|
}
|
|
863
968
|
if (licenseKey === null) {
|
|
864
|
-
|
|
969
|
+
Internals4.Log.warn({ logLevel: "warn", tag: "web-renderer" }, `Pass "licenseKey" to ${apiName}(). If you qualify for the Free License (https://remotion.dev/license), pass "free-license" instead.`);
|
|
865
970
|
}
|
|
866
971
|
await registerUsageEvent({
|
|
867
972
|
licenseKey: licenseKey === "free-license" ? null : licenseKey,
|
|
@@ -1207,7 +1312,7 @@ var drawDomElement = (node) => {
|
|
|
1207
1312
|
};
|
|
1208
1313
|
|
|
1209
1314
|
// src/drawing/process-node.ts
|
|
1210
|
-
import { Internals as
|
|
1315
|
+
import { Internals as Internals6 } from "remotion";
|
|
1211
1316
|
|
|
1212
1317
|
// src/drawing/has-transform.ts
|
|
1213
1318
|
var hasTransformCssValue = (style) => {
|
|
@@ -2256,7 +2361,7 @@ var drawBorder = ({
|
|
|
2256
2361
|
};
|
|
2257
2362
|
|
|
2258
2363
|
// src/drawing/draw-box-shadow.ts
|
|
2259
|
-
import { Internals as
|
|
2364
|
+
import { Internals as Internals5 } from "remotion";
|
|
2260
2365
|
var parseBoxShadow = (boxShadowValue) => {
|
|
2261
2366
|
if (!boxShadowValue || boxShadowValue === "none") {
|
|
2262
2367
|
return [];
|
|
@@ -2321,7 +2426,7 @@ var drawBorderRadius = ({
|
|
|
2321
2426
|
throw new Error("Failed to get context");
|
|
2322
2427
|
}
|
|
2323
2428
|
if (shadow.inset) {
|
|
2324
|
-
|
|
2429
|
+
Internals5.Log.warn({
|
|
2325
2430
|
logLevel,
|
|
2326
2431
|
tag: "@remotion/web-renderer"
|
|
2327
2432
|
}, 'Detected "box-shadow" with "inset". This is not yet supported in @remotion/web-renderer');
|
|
@@ -2619,55 +2724,81 @@ var getBiggestBoundingClientRect = (element) => {
|
|
|
2619
2724
|
|
|
2620
2725
|
// src/drawing/get-pretransform-rect.ts
|
|
2621
2726
|
var MAX_SCALE_FACTOR = 100;
|
|
2622
|
-
|
|
2727
|
+
var isScaleTooBig = (matrix) => {
|
|
2623
2728
|
const origin = new DOMPoint(0, 0).matrixTransform(matrix);
|
|
2624
2729
|
const unitX = new DOMPoint(1, 0).matrixTransform(matrix);
|
|
2625
2730
|
const unitY = new DOMPoint(0, 1).matrixTransform(matrix);
|
|
2626
2731
|
const basisX = { x: unitX.x - origin.x, y: unitX.y - origin.y };
|
|
2627
2732
|
const basisY = { x: unitY.x - origin.x, y: unitY.y - origin.y };
|
|
2628
|
-
const scaleX = Math.hypot(basisX.x, basisX.y);
|
|
2629
|
-
const scaleY = Math.hypot(basisY.x, basisY.y);
|
|
2630
|
-
const
|
|
2631
|
-
if (
|
|
2632
|
-
return
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
const
|
|
2643
|
-
const
|
|
2644
|
-
if (
|
|
2645
|
-
return
|
|
2733
|
+
const scaleX = 1 / Math.hypot(basisX.x, basisX.y);
|
|
2734
|
+
const scaleY = 1 / Math.hypot(basisY.x, basisY.y);
|
|
2735
|
+
const maxScale = Math.max(scaleX, scaleY);
|
|
2736
|
+
if (maxScale > MAX_SCALE_FACTOR) {
|
|
2737
|
+
return true;
|
|
2738
|
+
}
|
|
2739
|
+
return false;
|
|
2740
|
+
};
|
|
2741
|
+
function invertProjectivePoint(xp, yp, matrix) {
|
|
2742
|
+
const A = matrix.m11 - xp * matrix.m14;
|
|
2743
|
+
const B = matrix.m21 - xp * matrix.m24;
|
|
2744
|
+
const C = xp * matrix.m44 - matrix.m41;
|
|
2745
|
+
const D = matrix.m12 - yp * matrix.m14;
|
|
2746
|
+
const E = matrix.m22 - yp * matrix.m24;
|
|
2747
|
+
const F = yp * matrix.m44 - matrix.m42;
|
|
2748
|
+
const det = A * E - B * D;
|
|
2749
|
+
if (Math.abs(det) < 0.0000000001) {
|
|
2750
|
+
return null;
|
|
2751
|
+
}
|
|
2752
|
+
const x = (C * E - B * F) / det;
|
|
2753
|
+
const y = (A * F - C * D) / det;
|
|
2754
|
+
return { x, y };
|
|
2755
|
+
}
|
|
2756
|
+
function getPreTransformRect(targetRect, matrix) {
|
|
2757
|
+
if (isScaleTooBig(matrix)) {
|
|
2758
|
+
return null;
|
|
2646
2759
|
}
|
|
2647
2760
|
const corners = [
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2761
|
+
{ x: targetRect.x, y: targetRect.y },
|
|
2762
|
+
{ x: targetRect.x + targetRect.width, y: targetRect.y },
|
|
2763
|
+
{ x: targetRect.x + targetRect.width, y: targetRect.y + targetRect.height },
|
|
2764
|
+
{ x: targetRect.x, y: targetRect.y + targetRect.height }
|
|
2652
2765
|
];
|
|
2653
|
-
const
|
|
2654
|
-
const
|
|
2655
|
-
|
|
2656
|
-
|
|
2766
|
+
const invertedCorners = [];
|
|
2767
|
+
for (const corner of corners) {
|
|
2768
|
+
const inverted = invertProjectivePoint(corner.x, corner.y, matrix);
|
|
2769
|
+
if (inverted === null) {
|
|
2770
|
+
return null;
|
|
2771
|
+
}
|
|
2772
|
+
invertedCorners.push(inverted);
|
|
2773
|
+
}
|
|
2774
|
+
const xCoords = invertedCorners.map((p) => p.x);
|
|
2775
|
+
const yCoords = invertedCorners.map((p) => p.y);
|
|
2776
|
+
return new DOMRect(Math.min(...xCoords), Math.min(...yCoords), Math.max(...xCoords) - Math.min(...xCoords), Math.max(...yCoords) - Math.min(...yCoords));
|
|
2657
2777
|
}
|
|
2658
2778
|
|
|
2659
2779
|
// src/drawing/transform-in-3d.ts
|
|
2660
2780
|
var vsSource = `
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2781
|
+
attribute vec2 aPosition;
|
|
2782
|
+
attribute vec2 aTexCoord;
|
|
2783
|
+
uniform mat4 uTransform;
|
|
2784
|
+
uniform vec2 uResolution;
|
|
2785
|
+
uniform vec2 uOffset;
|
|
2786
|
+
varying vec2 vTexCoord;
|
|
2666
2787
|
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2788
|
+
void main() {
|
|
2789
|
+
vec4 pos = uTransform * vec4(aPosition, 0.0, 1.0);
|
|
2790
|
+
pos.xy = pos.xy + uOffset * pos.w;
|
|
2791
|
+
|
|
2792
|
+
// Convert homogeneous coords to clip space
|
|
2793
|
+
gl_Position = vec4(
|
|
2794
|
+
(pos.x / uResolution.x) * 2.0 - pos.w, // x
|
|
2795
|
+
pos.w - (pos.y / uResolution.y) * 2.0, // y (flipped)
|
|
2796
|
+
0.0,
|
|
2797
|
+
pos.w
|
|
2798
|
+
);
|
|
2799
|
+
|
|
2800
|
+
vTexCoord = aTexCoord;
|
|
2801
|
+
}
|
|
2671
2802
|
`;
|
|
2672
2803
|
var fsSource = `
|
|
2673
2804
|
precision mediump float;
|
|
@@ -2730,7 +2861,8 @@ var createHelperCanvas = ({
|
|
|
2730
2861
|
aPosition: gl.getAttribLocation(program, "aPosition"),
|
|
2731
2862
|
aTexCoord: gl.getAttribLocation(program, "aTexCoord"),
|
|
2732
2863
|
uTransform: gl.getUniformLocation(program, "uTransform"),
|
|
2733
|
-
|
|
2864
|
+
uResolution: gl.getUniformLocation(program, "uResolution"),
|
|
2865
|
+
uOffset: gl.getUniformLocation(program, "uOffset"),
|
|
2734
2866
|
uTexture: gl.getUniformLocation(program, "uTexture")
|
|
2735
2867
|
};
|
|
2736
2868
|
gl.deleteShader(vertexShader);
|
|
@@ -2748,55 +2880,60 @@ var createHelperCanvas = ({
|
|
|
2748
2880
|
var transformIn3d = ({
|
|
2749
2881
|
matrix,
|
|
2750
2882
|
sourceCanvas,
|
|
2751
|
-
|
|
2752
|
-
|
|
2883
|
+
sourceRect,
|
|
2884
|
+
destRect,
|
|
2753
2885
|
internalState
|
|
2754
2886
|
}) => {
|
|
2755
2887
|
const { canvas, gl, program, locations } = createHelperCanvas({
|
|
2756
|
-
canvasWidth:
|
|
2757
|
-
canvasHeight:
|
|
2888
|
+
canvasWidth: destRect.width,
|
|
2889
|
+
canvasHeight: destRect.height,
|
|
2758
2890
|
helperCanvasState: internalState.helperCanvasState
|
|
2759
2891
|
});
|
|
2760
2892
|
gl.useProgram(program);
|
|
2761
|
-
gl.viewport(0, 0,
|
|
2893
|
+
gl.viewport(0, 0, destRect.width, destRect.height);
|
|
2762
2894
|
gl.clearColor(0, 0, 0, 0);
|
|
2763
2895
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
2764
2896
|
gl.enable(gl.BLEND);
|
|
2765
2897
|
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
2766
2898
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
2767
|
-
const
|
|
2768
|
-
gl.bindBuffer(gl.ARRAY_BUFFER,
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2771
|
-
|
|
2899
|
+
const positionBuffer = gl.createBuffer();
|
|
2900
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
2901
|
+
const positions = new Float32Array([
|
|
2902
|
+
sourceRect.x,
|
|
2903
|
+
sourceRect.y,
|
|
2904
|
+
sourceRect.x + sourceRect.width,
|
|
2905
|
+
sourceRect.y,
|
|
2906
|
+
sourceRect.x,
|
|
2907
|
+
sourceRect.y + sourceRect.height,
|
|
2908
|
+
sourceRect.x,
|
|
2909
|
+
sourceRect.y + sourceRect.height,
|
|
2910
|
+
sourceRect.x + sourceRect.width,
|
|
2911
|
+
sourceRect.y,
|
|
2912
|
+
sourceRect.x + sourceRect.width,
|
|
2913
|
+
sourceRect.y + sourceRect.height
|
|
2914
|
+
]);
|
|
2915
|
+
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
2916
|
+
gl.enableVertexAttribArray(locations.aPosition);
|
|
2917
|
+
gl.vertexAttribPointer(locations.aPosition, 2, gl.FLOAT, false, 0, 0);
|
|
2918
|
+
const texCoordBuffer = gl.createBuffer();
|
|
2919
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
2920
|
+
const texCoords = new Float32Array([
|
|
2772
2921
|
0,
|
|
2773
2922
|
0,
|
|
2774
|
-
untransformedRect.x + untransformedRect.width,
|
|
2775
|
-
untransformedRect.y,
|
|
2776
2923
|
1,
|
|
2777
2924
|
0,
|
|
2778
|
-
untransformedRect.x,
|
|
2779
|
-
untransformedRect.y + untransformedRect.height,
|
|
2780
2925
|
0,
|
|
2781
2926
|
1,
|
|
2782
|
-
untransformedRect.x,
|
|
2783
|
-
untransformedRect.y + untransformedRect.height,
|
|
2784
2927
|
0,
|
|
2785
2928
|
1,
|
|
2786
|
-
untransformedRect.x + untransformedRect.width,
|
|
2787
|
-
untransformedRect.y,
|
|
2788
2929
|
1,
|
|
2789
2930
|
0,
|
|
2790
|
-
untransformedRect.x + untransformedRect.width,
|
|
2791
|
-
untransformedRect.y + untransformedRect.height,
|
|
2792
2931
|
1,
|
|
2793
2932
|
1
|
|
2794
2933
|
]);
|
|
2795
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
2796
|
-
gl.enableVertexAttribArray(locations.aPosition);
|
|
2797
|
-
gl.vertexAttribPointer(locations.aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
|
|
2934
|
+
gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
|
|
2798
2935
|
gl.enableVertexAttribArray(locations.aTexCoord);
|
|
2799
|
-
gl.vertexAttribPointer(locations.aTexCoord, 2, gl.FLOAT, false,
|
|
2936
|
+
gl.vertexAttribPointer(locations.aTexCoord, 2, gl.FLOAT, false, 0, 0);
|
|
2800
2937
|
const texture = gl.createTexture();
|
|
2801
2938
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
2802
2939
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
@@ -2805,41 +2942,21 @@ var transformIn3d = ({
|
|
|
2805
2942
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
2806
2943
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas);
|
|
2807
2944
|
const transformMatrix = matrix.toFloat32Array();
|
|
2808
|
-
const zScale = 1e9;
|
|
2809
|
-
const projectionMatrix = new Float32Array([
|
|
2810
|
-
2 / rectAfterTransforms.width,
|
|
2811
|
-
0,
|
|
2812
|
-
0,
|
|
2813
|
-
0,
|
|
2814
|
-
0,
|
|
2815
|
-
-2 / rectAfterTransforms.height,
|
|
2816
|
-
0,
|
|
2817
|
-
0,
|
|
2818
|
-
0,
|
|
2819
|
-
0,
|
|
2820
|
-
-2 / zScale,
|
|
2821
|
-
0,
|
|
2822
|
-
-1 + 2 * -rectAfterTransforms.x / rectAfterTransforms.width,
|
|
2823
|
-
1 - 2 * -rectAfterTransforms.y / rectAfterTransforms.height,
|
|
2824
|
-
0,
|
|
2825
|
-
1
|
|
2826
|
-
]);
|
|
2827
2945
|
gl.uniformMatrix4fv(locations.uTransform, false, transformMatrix);
|
|
2828
|
-
gl.
|
|
2946
|
+
gl.uniform2f(locations.uResolution, destRect.width, destRect.height);
|
|
2947
|
+
gl.uniform2f(locations.uOffset, -destRect.x, -destRect.y);
|
|
2829
2948
|
gl.uniform1i(locations.uTexture, 0);
|
|
2830
2949
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
2831
2950
|
gl.disableVertexAttribArray(locations.aPosition);
|
|
2832
2951
|
gl.disableVertexAttribArray(locations.aTexCoord);
|
|
2833
2952
|
gl.deleteTexture(texture);
|
|
2834
|
-
gl.deleteBuffer(
|
|
2953
|
+
gl.deleteBuffer(positionBuffer);
|
|
2954
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
2835
2955
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2836
2956
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
2837
2957
|
gl.disable(gl.BLEND);
|
|
2838
2958
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
2839
|
-
return
|
|
2840
|
-
canvas,
|
|
2841
|
-
rect: rectAfterTransforms
|
|
2842
|
-
};
|
|
2959
|
+
return canvas;
|
|
2843
2960
|
};
|
|
2844
2961
|
|
|
2845
2962
|
// src/drawing/handle-3d-transform.ts
|
|
@@ -2850,6 +2967,9 @@ var getPrecomposeRectFor3DTransform = ({
|
|
|
2850
2967
|
}) => {
|
|
2851
2968
|
const unclampedBiggestBoundingClientRect = getBiggestBoundingClientRect(element);
|
|
2852
2969
|
const biggestPossiblePretransformRect = getPreTransformRect(parentRect, matrix);
|
|
2970
|
+
if (!biggestPossiblePretransformRect) {
|
|
2971
|
+
return null;
|
|
2972
|
+
}
|
|
2853
2973
|
const preTransformRect = getNarrowerRect({
|
|
2854
2974
|
firstRect: unclampedBiggestBoundingClientRect,
|
|
2855
2975
|
secondRect: biggestPossiblePretransformRect
|
|
@@ -2858,21 +2978,21 @@ var getPrecomposeRectFor3DTransform = ({
|
|
|
2858
2978
|
};
|
|
2859
2979
|
var handle3dTransform = ({
|
|
2860
2980
|
matrix,
|
|
2861
|
-
|
|
2981
|
+
sourceRect,
|
|
2862
2982
|
tempCanvas,
|
|
2863
2983
|
rectAfterTransforms,
|
|
2864
2984
|
internalState
|
|
2865
2985
|
}) => {
|
|
2866
|
-
|
|
2867
|
-
|
|
2986
|
+
if (rectAfterTransforms.width <= 0 || rectAfterTransforms.height <= 0) {
|
|
2987
|
+
return null;
|
|
2988
|
+
}
|
|
2989
|
+
const transformed = transformIn3d({
|
|
2990
|
+
sourceRect,
|
|
2868
2991
|
matrix,
|
|
2869
2992
|
sourceCanvas: tempCanvas,
|
|
2870
|
-
rectAfterTransforms,
|
|
2993
|
+
destRect: rectAfterTransforms,
|
|
2871
2994
|
internalState
|
|
2872
2995
|
});
|
|
2873
|
-
if (transformedRect.width <= 0 || transformedRect.height <= 0) {
|
|
2874
|
-
return null;
|
|
2875
|
-
}
|
|
2876
2996
|
return transformed;
|
|
2877
2997
|
};
|
|
2878
2998
|
|
|
@@ -2973,20 +3093,21 @@ var processNode = async ({
|
|
|
2973
3093
|
const start = Date.now();
|
|
2974
3094
|
let precomposeRect = null;
|
|
2975
3095
|
if (precompositing.needsMaskImage) {
|
|
2976
|
-
precomposeRect =
|
|
2977
|
-
firstRect: precomposeRect,
|
|
2978
|
-
secondRect: getPrecomposeRectForMask(element)
|
|
2979
|
-
});
|
|
3096
|
+
precomposeRect = roundToExpandRect(getPrecomposeRectForMask(element));
|
|
2980
3097
|
}
|
|
2981
3098
|
if (precompositing.needs3DTransformViaWebGL) {
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
parentRect,
|
|
2987
|
-
matrix: totalMatrix
|
|
2988
|
-
})
|
|
3099
|
+
const tentativePrecomposeRect = getPrecomposeRectFor3DTransform({
|
|
3100
|
+
element,
|
|
3101
|
+
parentRect,
|
|
3102
|
+
matrix: totalMatrix
|
|
2989
3103
|
});
|
|
3104
|
+
if (!tentativePrecomposeRect) {
|
|
3105
|
+
return { type: "continue", cleanupAfterChildren: null };
|
|
3106
|
+
}
|
|
3107
|
+
precomposeRect = roundToExpandRect(getWiderRectAndExpand({
|
|
3108
|
+
firstRect: precomposeRect,
|
|
3109
|
+
secondRect: tentativePrecomposeRect
|
|
3110
|
+
}));
|
|
2990
3111
|
}
|
|
2991
3112
|
if (!precomposeRect) {
|
|
2992
3113
|
throw new Error("Precompose rect not found");
|
|
@@ -3019,7 +3140,7 @@ var processNode = async ({
|
|
|
3019
3140
|
if (precompositing.needs3DTransformViaWebGL) {
|
|
3020
3141
|
const t = handle3dTransform({
|
|
3021
3142
|
matrix: totalMatrix,
|
|
3022
|
-
precomposeRect,
|
|
3143
|
+
sourceRect: precomposeRect,
|
|
3023
3144
|
tempCanvas: drawable,
|
|
3024
3145
|
rectAfterTransforms,
|
|
3025
3146
|
internalState
|
|
@@ -3033,7 +3154,7 @@ var processNode = async ({
|
|
|
3033
3154
|
context.setTransform(new DOMMatrix);
|
|
3034
3155
|
context.drawImage(drawable, 0, drawable.height - rectAfterTransforms.height, rectAfterTransforms.width, rectAfterTransforms.height, rectAfterTransforms.left - parentRect.x, rectAfterTransforms.top - parentRect.y, rectAfterTransforms.width, rectAfterTransforms.height);
|
|
3035
3156
|
context.setTransform(previousTransform);
|
|
3036
|
-
|
|
3157
|
+
Internals6.Log.trace({
|
|
3037
3158
|
logLevel,
|
|
3038
3159
|
tag: "@remotion/web-renderer"
|
|
3039
3160
|
}, `Transforming element in 3D - canvas size: ${precomposeRect.width}x${precomposeRect.height} - compose: ${Date.now() - start}ms - helper canvas: ${drawable.width}x${drawable.height}`);
|
|
@@ -3065,7 +3186,7 @@ var processNode = async ({
|
|
|
3065
3186
|
};
|
|
3066
3187
|
|
|
3067
3188
|
// src/drawing/text/draw-text.ts
|
|
3068
|
-
import { Internals as
|
|
3189
|
+
import { Internals as Internals7 } from "remotion";
|
|
3069
3190
|
|
|
3070
3191
|
// src/drawing/text/apply-text-transform.ts
|
|
3071
3192
|
var applyTextTransform = (text, transform) => {
|
|
@@ -3238,7 +3359,7 @@ var drawText = ({
|
|
|
3238
3359
|
} = computedStyle;
|
|
3239
3360
|
const isVertical = writingMode !== "horizontal-tb";
|
|
3240
3361
|
if (isVertical) {
|
|
3241
|
-
|
|
3362
|
+
Internals7.Log.warn({
|
|
3242
3363
|
logLevel,
|
|
3243
3364
|
tag: "@remotion/web-renderer"
|
|
3244
3365
|
}, 'Detected "writing-mode" CSS property. Vertical text is not yet supported in @remotion/web-renderer');
|
|
@@ -3508,7 +3629,14 @@ var createThrottledProgressCallback = (callback, throttleMs = DEFAULT_THROTTLE_M
|
|
|
3508
3629
|
}, remainingTime);
|
|
3509
3630
|
}
|
|
3510
3631
|
};
|
|
3511
|
-
|
|
3632
|
+
const cleanup = () => {
|
|
3633
|
+
if (timeoutId !== null) {
|
|
3634
|
+
clearTimeout(timeoutId);
|
|
3635
|
+
timeoutId = null;
|
|
3636
|
+
}
|
|
3637
|
+
pendingUpdate = null;
|
|
3638
|
+
};
|
|
3639
|
+
return { throttled, [Symbol.dispose]: cleanup };
|
|
3512
3640
|
};
|
|
3513
3641
|
|
|
3514
3642
|
// src/validate-video-frame.ts
|
|
@@ -3546,7 +3674,8 @@ var waitForReady = ({
|
|
|
3546
3674
|
scope,
|
|
3547
3675
|
signal,
|
|
3548
3676
|
apiName,
|
|
3549
|
-
internalState
|
|
3677
|
+
internalState,
|
|
3678
|
+
keepalive
|
|
3550
3679
|
}) => {
|
|
3551
3680
|
const start = performance.now();
|
|
3552
3681
|
const { promise, resolve, reject } = withResolvers();
|
|
@@ -3578,9 +3707,16 @@ var waitForReady = ({
|
|
|
3578
3707
|
reject(new Error(Object.values(scope.remotion_delayRenderTimeouts).map((d) => d.label).join(", ")));
|
|
3579
3708
|
return;
|
|
3580
3709
|
}
|
|
3581
|
-
|
|
3710
|
+
scheduleNextCheck();
|
|
3711
|
+
};
|
|
3712
|
+
const scheduleNextCheck = () => {
|
|
3713
|
+
const rafTick = new Promise((res) => {
|
|
3714
|
+
requestAnimationFrame(() => res());
|
|
3715
|
+
});
|
|
3716
|
+
const backgroundSafeTick = keepalive ? Promise.race([rafTick, keepalive.waitForTick()]) : rafTick;
|
|
3717
|
+
backgroundSafeTick.then(check);
|
|
3582
3718
|
};
|
|
3583
|
-
|
|
3719
|
+
scheduleNextCheck();
|
|
3584
3720
|
return promise;
|
|
3585
3721
|
};
|
|
3586
3722
|
|
|
@@ -3671,11 +3807,11 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3671
3807
|
if (issue.severity === "error") {
|
|
3672
3808
|
return Promise.reject(new Error(issue.message));
|
|
3673
3809
|
}
|
|
3674
|
-
|
|
3810
|
+
Internals8.Log.warn({ logLevel, tag: "@remotion/web-renderer" }, issue.message);
|
|
3675
3811
|
}
|
|
3676
3812
|
finalAudioCodec = audioResult.codec;
|
|
3677
3813
|
}
|
|
3678
|
-
const resolved = await
|
|
3814
|
+
const resolved = await Internals8.resolveVideoConfig({
|
|
3679
3815
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
3680
3816
|
signal: signal ?? new AbortController().signal,
|
|
3681
3817
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -3710,6 +3846,10 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3710
3846
|
}), 0);
|
|
3711
3847
|
const { delayRenderScope, div, timeUpdater, collectAssets } = scaffold;
|
|
3712
3848
|
const internalState = __using(__stack2, makeInternalState(), 0);
|
|
3849
|
+
const keepalive = __using(__stack2, createBackgroundKeepalive({
|
|
3850
|
+
fps: resolved.fps,
|
|
3851
|
+
logLevel
|
|
3852
|
+
}), 0);
|
|
3713
3853
|
const artifactsHandler = handleArtifacts();
|
|
3714
3854
|
const webFsTarget = outputTarget === "web-fs" ? await createWebFsTarget() : null;
|
|
3715
3855
|
const target = webFsTarget ? new StreamTarget(webFsTarget.stream) : new BufferTarget;
|
|
@@ -3717,6 +3857,8 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3717
3857
|
format,
|
|
3718
3858
|
target
|
|
3719
3859
|
}), 0);
|
|
3860
|
+
const throttledProgress = __using(__stack2, createThrottledProgressCallback(onProgress), 0);
|
|
3861
|
+
const throttledOnProgress = throttledProgress?.throttled ?? null;
|
|
3720
3862
|
try {
|
|
3721
3863
|
let __stack = [];
|
|
3722
3864
|
try {
|
|
@@ -3728,7 +3870,8 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3728
3870
|
scope: delayRenderScope,
|
|
3729
3871
|
signal,
|
|
3730
3872
|
apiName: "renderMediaOnWeb",
|
|
3731
|
-
internalState
|
|
3873
|
+
internalState,
|
|
3874
|
+
keepalive
|
|
3732
3875
|
});
|
|
3733
3876
|
if (signal?.aborted) {
|
|
3734
3877
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
@@ -3759,7 +3902,6 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3759
3902
|
renderedFrames: 0,
|
|
3760
3903
|
encodedFrames: 0
|
|
3761
3904
|
};
|
|
3762
|
-
const throttledOnProgress = createThrottledProgressCallback(onProgress);
|
|
3763
3905
|
for (let frame = realFrameRange[0];frame <= realFrameRange[1]; frame++) {
|
|
3764
3906
|
if (signal?.aborted) {
|
|
3765
3907
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
@@ -3770,6 +3912,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3770
3912
|
scope: delayRenderScope,
|
|
3771
3913
|
signal,
|
|
3772
3914
|
apiName: "renderMediaOnWeb",
|
|
3915
|
+
keepalive,
|
|
3773
3916
|
internalState
|
|
3774
3917
|
});
|
|
3775
3918
|
if (signal?.aborted) {
|
|
@@ -3838,7 +3981,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3838
3981
|
videoSampleSource.videoSampleSource.close();
|
|
3839
3982
|
audioSampleSource?.audioSampleSource.close();
|
|
3840
3983
|
await outputWithCleanup.output.finalize();
|
|
3841
|
-
|
|
3984
|
+
Internals8.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`);
|
|
3842
3985
|
if (webFsTarget) {
|
|
3843
3986
|
sendUsageEvent({
|
|
3844
3987
|
licenseKey: licenseKey ?? null,
|
|
@@ -3882,7 +4025,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
3882
4025
|
licenseKey: licenseKey ?? null,
|
|
3883
4026
|
apiName: "renderMediaOnWeb"
|
|
3884
4027
|
}).catch((err2) => {
|
|
3885
|
-
|
|
4028
|
+
Internals8.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
3886
4029
|
});
|
|
3887
4030
|
}
|
|
3888
4031
|
throw err;
|
|
@@ -3923,7 +4066,7 @@ var renderMediaOnWeb = (options) => {
|
|
|
3923
4066
|
};
|
|
3924
4067
|
// src/render-still-on-web.tsx
|
|
3925
4068
|
import {
|
|
3926
|
-
Internals as
|
|
4069
|
+
Internals as Internals9
|
|
3927
4070
|
} from "remotion";
|
|
3928
4071
|
async function internalRenderStillOnWeb({
|
|
3929
4072
|
frame,
|
|
@@ -3940,7 +4083,7 @@ async function internalRenderStillOnWeb({
|
|
|
3940
4083
|
}) {
|
|
3941
4084
|
let __stack = [];
|
|
3942
4085
|
try {
|
|
3943
|
-
const resolved = await
|
|
4086
|
+
const resolved = await Internals9.resolveVideoConfig({
|
|
3944
4087
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
3945
4088
|
signal: signal ?? new AbortController().signal,
|
|
3946
4089
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -3984,7 +4127,8 @@ async function internalRenderStillOnWeb({
|
|
|
3984
4127
|
scope: delayRenderScope,
|
|
3985
4128
|
signal,
|
|
3986
4129
|
apiName: "renderStillOnWeb",
|
|
3987
|
-
internalState: null
|
|
4130
|
+
internalState: null,
|
|
4131
|
+
keepalive: null
|
|
3988
4132
|
});
|
|
3989
4133
|
if (signal?.aborted) {
|
|
3990
4134
|
throw new Error("renderStillOnWeb() was cancelled");
|
|
@@ -4014,7 +4158,7 @@ async function internalRenderStillOnWeb({
|
|
|
4014
4158
|
licenseKey: licenseKey ?? null,
|
|
4015
4159
|
apiName: "renderStillOnWeb"
|
|
4016
4160
|
}).catch((err2) => {
|
|
4017
|
-
|
|
4161
|
+
Internals9.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
4018
4162
|
});
|
|
4019
4163
|
}
|
|
4020
4164
|
throw err;
|
package/dist/internal-state.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ type HelperCanvas = {
|
|
|
6
6
|
aPosition: number;
|
|
7
7
|
aTexCoord: number;
|
|
8
8
|
uTransform: WebGLUniformLocation | null;
|
|
9
|
-
|
|
9
|
+
uResolution: WebGLUniformLocation | null;
|
|
10
|
+
uOffset: WebGLUniformLocation | null;
|
|
10
11
|
uTexture: WebGLUniformLocation | null;
|
|
11
12
|
};
|
|
12
13
|
cleanup: () => void;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { RenderMediaOnWebProgressCallback } from './render-media-on-web';
|
|
2
|
+
export type ThrottledProgressResult = {
|
|
3
|
+
throttled: RenderMediaOnWebProgressCallback;
|
|
4
|
+
[Symbol.dispose]: () => void;
|
|
5
|
+
};
|
|
2
6
|
/**
|
|
3
7
|
* Creates a throttled version of a progress callback that ensures it's not called
|
|
4
8
|
* more frequently than the specified interval (default: 250ms)
|
|
5
9
|
*/
|
|
6
|
-
export declare const createThrottledProgressCallback: (callback: RenderMediaOnWebProgressCallback | null, throttleMs?: number) =>
|
|
10
|
+
export declare const createThrottledProgressCallback: (callback: RenderMediaOnWebProgressCallback | null, throttleMs?: number) => ThrottledProgressResult | null;
|
package/dist/wait-for-ready.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DelayRenderScope } from 'remotion';
|
|
2
|
-
|
|
2
|
+
import type { BackgroundKeepalive } from './background-keepalive';
|
|
3
|
+
export declare const waitForReady: ({ timeoutInMilliseconds, scope, signal, apiName, internalState, keepalive, }: {
|
|
3
4
|
timeoutInMilliseconds: number;
|
|
4
5
|
scope: DelayRenderScope;
|
|
5
6
|
signal: AbortSignal | null;
|
|
@@ -22,4 +23,5 @@ export declare const waitForReady: ({ timeoutInMilliseconds, scope, signal, apiN
|
|
|
22
23
|
getAudioMixingTime: () => number;
|
|
23
24
|
addAudioMixingTime: (time: number) => void;
|
|
24
25
|
} | null;
|
|
26
|
+
keepalive: BackgroundKeepalive | null;
|
|
25
27
|
}) => Promise<void>;
|
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.405",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"sideEffects": false,
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"author": "Remotion <jonny@remotion.dev>",
|
|
19
19
|
"license": "UNLICENSED",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@remotion/licensing": "4.0.
|
|
22
|
-
"remotion": "4.0.
|
|
21
|
+
"@remotion/licensing": "4.0.405",
|
|
22
|
+
"remotion": "4.0.405",
|
|
23
23
|
"mediabunny": "1.27.3"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
27
|
-
"@remotion/player": "4.0.
|
|
28
|
-
"@remotion/media": "4.0.
|
|
26
|
+
"@remotion/eslint-config-internal": "4.0.405",
|
|
27
|
+
"@remotion/player": "4.0.405",
|
|
28
|
+
"@remotion/media": "4.0.405",
|
|
29
29
|
"@typescript/native-preview": "7.0.0-dev.20260105.1",
|
|
30
30
|
"@vitejs/plugin-react": "4.1.0",
|
|
31
31
|
"@vitest/browser-playwright": "4.0.9",
|