@remotion/web-renderer 4.0.393 → 4.0.395

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.
Files changed (36) hide show
  1. package/dist/calculate-transforms.d.ts +9 -0
  2. package/dist/calculate-transforms.js +74 -0
  3. package/dist/composable.d.ts +10 -0
  4. package/dist/composable.js +1 -0
  5. package/dist/compose-canvas.d.ts +1 -0
  6. package/dist/compose-canvas.js +12 -0
  7. package/dist/compose-svg.d.ts +1 -0
  8. package/dist/compose-svg.js +34 -0
  9. package/dist/compose.d.ts +3 -1
  10. package/dist/compose.js +5 -3
  11. package/dist/drawing/draw-border.js +307 -55
  12. package/dist/drawing/draw-element-to-canvas.d.ts +3 -1
  13. package/dist/drawing/draw-element-to-canvas.js +16 -5
  14. package/dist/drawing/text/draw-text.js +6 -8
  15. package/dist/drawing/text/get-base-height.d.ts +1 -0
  16. package/dist/drawing/text/get-base-height.js +13 -0
  17. package/dist/drawing/text/handle-text-node.d.ts +3 -1
  18. package/dist/drawing/text/handle-text-node.js +2 -1
  19. package/dist/drawing/transform-in-3d.js +7 -1
  20. package/dist/drawing/turn-svg-into-drawable.js +7 -0
  21. package/dist/esm/index.mjs +494 -85
  22. package/dist/find-capturable-elements.d.ts +2 -0
  23. package/dist/find-capturable-elements.js +28 -0
  24. package/dist/get-biggest-bounding-client-rect.d.ts +1 -0
  25. package/dist/get-biggest-bounding-client-rect.js +18 -0
  26. package/dist/parse-transform-origin.d.ts +4 -0
  27. package/dist/parse-transform-origin.js +7 -0
  28. package/dist/render-media-on-web.d.ts +1 -0
  29. package/dist/render-media-on-web.js +33 -15
  30. package/dist/render-still-on-web.d.ts +1 -0
  31. package/dist/render-still-on-web.js +25 -7
  32. package/dist/send-telemetry-event.d.ts +5 -0
  33. package/dist/send-telemetry-event.js +22 -0
  34. package/dist/take-screenshot.d.ts +5 -2
  35. package/dist/take-screenshot.js +4 -4
  36. package/package.json +7 -6
@@ -0,0 +1,2 @@
1
+ import type { Composable } from './composable';
2
+ export declare const findCapturableElements: (element: HTMLDivElement) => Composable[];
@@ -0,0 +1,28 @@
1
+ export const findCapturableElements = (element) => {
2
+ const canvasAndSvgElements = element.querySelectorAll('svg,canvas,img');
3
+ const composables = [];
4
+ Array.from(canvasAndSvgElements).forEach((capturableElement) => {
5
+ if (capturableElement.tagName.toLocaleLowerCase() === 'canvas') {
6
+ const canvas = capturableElement;
7
+ composables.push({
8
+ type: 'canvas',
9
+ element: canvas,
10
+ });
11
+ }
12
+ else if (capturableElement.tagName.toLocaleLowerCase() === 'svg') {
13
+ const svg = capturableElement;
14
+ composables.push({
15
+ type: 'svg',
16
+ element: svg,
17
+ });
18
+ }
19
+ else if (capturableElement.tagName.toLocaleLowerCase() === 'img') {
20
+ const img = capturableElement;
21
+ composables.push({
22
+ type: 'img',
23
+ element: img,
24
+ });
25
+ }
26
+ });
27
+ return composables;
28
+ };
@@ -0,0 +1 @@
1
+ export declare const getBiggestBoundingClientRect: (element: HTMLElement | SVGElement) => DOMRect;
@@ -0,0 +1,18 @@
1
+ export const getBiggestBoundingClientRect = (element) => {
2
+ const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
3
+ let mostLeft = Infinity;
4
+ let mostTop = Infinity;
5
+ let mostRight = -Infinity;
6
+ let mostBottom = -Infinity;
7
+ while (true) {
8
+ const rect = treeWalker.currentNode.getBoundingClientRect();
9
+ mostLeft = Math.min(mostLeft, rect.left);
10
+ mostTop = Math.min(mostTop, rect.top);
11
+ mostRight = Math.max(mostRight, rect.right);
12
+ mostBottom = Math.max(mostBottom, rect.bottom);
13
+ if (!treeWalker.nextNode()) {
14
+ break;
15
+ }
16
+ }
17
+ return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
18
+ };
@@ -0,0 +1,4 @@
1
+ export declare const parseTransformOrigin: (transformOrigin: string) => {
2
+ x: number;
3
+ y: number;
4
+ } | null;
@@ -0,0 +1,7 @@
1
+ export const parseTransformOrigin = (transformOrigin) => {
2
+ if (transformOrigin.trim() === '') {
3
+ return null;
4
+ }
5
+ const [x, y] = transformOrigin.split(' ');
6
+ return { x: parseFloat(x), y: parseFloat(y) };
7
+ };
@@ -44,6 +44,7 @@ type OptionalRenderMediaOnWebOptions<Schema extends AnyZodObject> = {
44
44
  onArtifact: OnArtifact | null;
45
45
  onFrame: OnFrameCallback | null;
46
46
  outputTarget: WebRendererOutputTarget | null;
47
+ licenseKey: string | undefined;
47
48
  };
48
49
  export type RenderMediaOnWebOptions<Schema extends AnyZodObject, Props extends Record<string, unknown>> = MandatoryRenderMediaOnWebOptions<Schema, Props> & Partial<OptionalRenderMediaOnWebOptions<Schema>> & InputPropsIfHasProps<Schema, Props>;
49
50
  export declare const renderMediaOnWeb: <Schema extends AnyZodObject, Props extends Record<string, unknown>>(options: RenderMediaOnWebOptions<Schema, Props>) => Promise<RenderMediaOnWebResult>;
@@ -9,6 +9,7 @@ import { getRealFrameRange } from './frame-range';
9
9
  import { getDefaultAudioEncodingConfig } from './get-audio-encoding-config';
10
10
  import { codecToMediabunnyCodec, containerToMediabunnyContainer, getDefaultVideoCodecForContainer, getMimeType, getQualityForWebRendererQuality, } from './mediabunny-mappings';
11
11
  import { onlyOneRenderAtATimeQueue } from './render-operations-queue';
12
+ import { sendUsageEvent } from './send-telemetry-event';
12
13
  import { createFrame } from './take-screenshot';
13
14
  import { createThrottledProgressCallback } from './throttle-progress';
14
15
  import { validateVideoFrame } from './validate-video-frame';
@@ -19,7 +20,7 @@ import { cleanupStaleOpfsFiles, createWebFsTarget } from './web-fs-target';
19
20
  // TODO: Metadata
20
21
  // TODO: Validating inputs
21
22
  // TODO: Apply defaultCodec
22
- const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTimeoutInMilliseconds, logLevel, mediaCacheSizeInBytes, schema, codec, container, signal, onProgress, hardwareAcceleration, keyframeIntervalInSeconds, videoBitrate, frameRange, transparent, onArtifact, onFrame, outputTarget: userDesiredOutputTarget, }) => {
23
+ const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTimeoutInMilliseconds, logLevel, mediaCacheSizeInBytes, schema, codec, container, signal, onProgress, hardwareAcceleration, keyframeIntervalInSeconds, videoBitrate, frameRange, transparent, onArtifact, onFrame, outputTarget: userDesiredOutputTarget, licenseKey, }) => {
23
24
  var _a, _b, _c, _d, _e, _f, _g;
24
25
  const outputTarget = userDesiredOutputTarget === null
25
26
  ? (await canUseWebFsWriter())
@@ -151,6 +152,7 @@ const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTi
151
152
  div,
152
153
  width: resolved.width,
153
154
  height: resolved.height,
155
+ logLevel,
154
156
  });
155
157
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
156
158
  throw new Error('renderMediaOnWeb() was cancelled');
@@ -216,6 +218,11 @@ const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTi
216
218
  if (!(target instanceof BufferTarget)) {
217
219
  throw new Error('Expected target to be a BufferTarget');
218
220
  }
221
+ sendUsageEvent({
222
+ licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
223
+ succeeded: true,
224
+ apiName: 'renderMediaOnWeb',
225
+ });
219
226
  return {
220
227
  getBlob: () => {
221
228
  if (!target.buffer) {
@@ -225,6 +232,16 @@ const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTi
225
232
  },
226
233
  };
227
234
  }
235
+ catch (err) {
236
+ sendUsageEvent({
237
+ succeeded: false,
238
+ licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
239
+ apiName: 'renderMediaOnWeb',
240
+ }).catch((err2) => {
241
+ Internals.Log.error({ logLevel: 'error', tag: 'web-renderer' }, 'Failed to send usage event', err2);
242
+ });
243
+ throw err;
244
+ }
228
245
  finally {
229
246
  cleanupFns.forEach((fn) => fn());
230
247
  }
@@ -236,25 +253,26 @@ export const renderMediaOnWeb = (options) => {
236
253
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref
237
254
  .catch(() => Promise.resolve())
238
255
  .then(() => {
239
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
256
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
240
257
  return internalRenderMediaOnWeb({
241
258
  ...options,
242
259
  delayRenderTimeoutInMilliseconds: (_a = options.delayRenderTimeoutInMilliseconds) !== null && _a !== void 0 ? _a : 30000,
243
- logLevel: (_b = options.logLevel) !== null && _b !== void 0 ? _b : 'info',
244
- schema: (_c = options.schema) !== null && _c !== void 0 ? _c : undefined,
245
- mediaCacheSizeInBytes: (_d = options.mediaCacheSizeInBytes) !== null && _d !== void 0 ? _d : null,
260
+ logLevel: (_c = (_b = options.logLevel) !== null && _b !== void 0 ? _b : window.remotion_logLevel) !== null && _c !== void 0 ? _c : 'info',
261
+ schema: (_d = options.schema) !== null && _d !== void 0 ? _d : undefined,
262
+ mediaCacheSizeInBytes: (_e = options.mediaCacheSizeInBytes) !== null && _e !== void 0 ? _e : null,
246
263
  codec,
247
264
  container,
248
- signal: (_e = options.signal) !== null && _e !== void 0 ? _e : null,
249
- onProgress: (_f = options.onProgress) !== null && _f !== void 0 ? _f : null,
250
- hardwareAcceleration: (_g = options.hardwareAcceleration) !== null && _g !== void 0 ? _g : 'no-preference',
251
- keyframeIntervalInSeconds: (_h = options.keyframeIntervalInSeconds) !== null && _h !== void 0 ? _h : 5,
252
- videoBitrate: (_j = options.videoBitrate) !== null && _j !== void 0 ? _j : 'medium',
253
- frameRange: (_k = options.frameRange) !== null && _k !== void 0 ? _k : null,
254
- transparent: (_l = options.transparent) !== null && _l !== void 0 ? _l : false,
255
- onArtifact: (_m = options.onArtifact) !== null && _m !== void 0 ? _m : null,
256
- onFrame: (_o = options.onFrame) !== null && _o !== void 0 ? _o : null,
257
- outputTarget: (_p = options.outputTarget) !== null && _p !== void 0 ? _p : null,
265
+ signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null,
266
+ onProgress: (_g = options.onProgress) !== null && _g !== void 0 ? _g : null,
267
+ hardwareAcceleration: (_h = options.hardwareAcceleration) !== null && _h !== void 0 ? _h : 'no-preference',
268
+ keyframeIntervalInSeconds: (_j = options.keyframeIntervalInSeconds) !== null && _j !== void 0 ? _j : 5,
269
+ videoBitrate: (_k = options.videoBitrate) !== null && _k !== void 0 ? _k : 'medium',
270
+ frameRange: (_l = options.frameRange) !== null && _l !== void 0 ? _l : null,
271
+ transparent: (_m = options.transparent) !== null && _m !== void 0 ? _m : false,
272
+ onArtifact: (_o = options.onArtifact) !== null && _o !== void 0 ? _o : null,
273
+ onFrame: (_p = options.onFrame) !== null && _p !== void 0 ? _p : null,
274
+ outputTarget: (_q = options.outputTarget) !== null && _q !== void 0 ? _q : null,
275
+ licenseKey: (_r = options.licenseKey) !== null && _r !== void 0 ? _r : undefined,
258
276
  });
259
277
  });
260
278
  return onlyOneRenderAtATimeQueue.ref;
@@ -17,6 +17,7 @@ type OptionalRenderStillOnWebOptions<Schema extends AnyZodObject> = {
17
17
  mediaCacheSizeInBytes: number | null;
18
18
  signal: AbortSignal | null;
19
19
  onArtifact: OnArtifact | null;
20
+ licenseKey: string | undefined;
20
21
  };
21
22
  export type RenderStillOnWebOptions<Schema extends AnyZodObject, Props extends Record<string, unknown>> = MandatoryRenderStillOnWebOptions<Schema, Props> & Partial<OptionalRenderStillOnWebOptions<Schema>> & InputPropsIfHasProps<Schema, Props>;
22
23
  export declare const renderStillOnWeb: <Schema extends AnyZodObject, Props extends Record<string, unknown>>(options: RenderStillOnWebOptions<Schema, Props>) => Promise<Blob>;
@@ -2,9 +2,10 @@ import { Internals, } from 'remotion';
2
2
  import { handleArtifacts } from './artifact';
3
3
  import { createScaffold } from './create-scaffold';
4
4
  import { onlyOneRenderAtATimeQueue } from './render-operations-queue';
5
+ import { sendUsageEvent } from './send-telemetry-event';
5
6
  import { takeScreenshot } from './take-screenshot';
6
7
  import { waitForReady } from './wait-for-ready';
7
- async function internalRenderStillOnWeb({ frame, delayRenderTimeoutInMilliseconds, logLevel, inputProps, schema, imageFormat, mediaCacheSizeInBytes, composition, signal, onArtifact, }) {
8
+ async function internalRenderStillOnWeb({ frame, delayRenderTimeoutInMilliseconds, logLevel, inputProps, schema, imageFormat, mediaCacheSizeInBytes, composition, signal, onArtifact, licenseKey, }) {
8
9
  var _a, _b, _c, _d, _e, _f;
9
10
  const resolved = await Internals.resolveVideoConfig({
10
11
  calculateMetadata: (_a = composition.calculateMetadata) !== null && _a !== void 0 ? _a : null,
@@ -57,13 +58,29 @@ async function internalRenderStillOnWeb({ frame, delayRenderTimeoutInMillisecond
57
58
  width: resolved.width,
58
59
  height: resolved.height,
59
60
  imageFormat,
61
+ logLevel,
60
62
  });
61
63
  const assets = collectAssets.current.collectAssets();
62
64
  if (onArtifact) {
63
65
  await artifactsHandler.handle({ imageData, frame, assets, onArtifact });
64
66
  }
67
+ sendUsageEvent({
68
+ licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
69
+ succeeded: true,
70
+ apiName: 'renderStillOnWeb',
71
+ });
65
72
  return imageData;
66
73
  }
74
+ catch (err) {
75
+ sendUsageEvent({
76
+ succeeded: false,
77
+ licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
78
+ apiName: 'renderStillOnWeb',
79
+ }).catch((err2) => {
80
+ Internals.Log.error({ logLevel: 'error', tag: 'web-renderer' }, 'Failed to send usage event', err2);
81
+ });
82
+ throw err;
83
+ }
67
84
  finally {
68
85
  cleanupScaffold();
69
86
  }
@@ -72,15 +89,16 @@ export const renderStillOnWeb = (options) => {
72
89
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref
73
90
  .catch(() => Promise.resolve())
74
91
  .then(() => {
75
- var _a, _b, _c, _d, _e, _f;
92
+ var _a, _b, _c, _d, _e, _f, _g, _h;
76
93
  return internalRenderStillOnWeb({
77
94
  ...options,
78
95
  delayRenderTimeoutInMilliseconds: (_a = options.delayRenderTimeoutInMilliseconds) !== null && _a !== void 0 ? _a : 30000,
79
- logLevel: (_b = options.logLevel) !== null && _b !== void 0 ? _b : 'info',
80
- schema: (_c = options.schema) !== null && _c !== void 0 ? _c : undefined,
81
- mediaCacheSizeInBytes: (_d = options.mediaCacheSizeInBytes) !== null && _d !== void 0 ? _d : null,
82
- signal: (_e = options.signal) !== null && _e !== void 0 ? _e : null,
83
- onArtifact: (_f = options.onArtifact) !== null && _f !== void 0 ? _f : null,
96
+ logLevel: (_c = (_b = options.logLevel) !== null && _b !== void 0 ? _b : window.remotion_logLevel) !== null && _c !== void 0 ? _c : 'info',
97
+ schema: (_d = options.schema) !== null && _d !== void 0 ? _d : undefined,
98
+ mediaCacheSizeInBytes: (_e = options.mediaCacheSizeInBytes) !== null && _e !== void 0 ? _e : null,
99
+ signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null,
100
+ onArtifact: (_g = options.onArtifact) !== null && _g !== void 0 ? _g : null,
101
+ licenseKey: (_h = options.licenseKey) !== null && _h !== void 0 ? _h : undefined,
84
102
  });
85
103
  });
86
104
  return onlyOneRenderAtATimeQueue.ref;
@@ -0,0 +1,5 @@
1
+ export declare const sendUsageEvent: ({ licenseKey, succeeded, apiName, }: {
2
+ licenseKey: string | null;
3
+ succeeded: boolean;
4
+ apiName: string;
5
+ }) => Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { registerUsageEvent } from '@remotion/licensing';
2
+ import { Internals } from 'remotion';
3
+ export const sendUsageEvent = async ({ licenseKey, succeeded, apiName, }) => {
4
+ var _a;
5
+ const host = typeof window === 'undefined'
6
+ ? null
7
+ : typeof window.location === 'undefined'
8
+ ? null
9
+ : ((_a = window.location.origin) !== null && _a !== void 0 ? _a : null);
10
+ if (host === null) {
11
+ return;
12
+ }
13
+ if (licenseKey === null) {
14
+ Internals.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.`);
15
+ }
16
+ await registerUsageEvent({
17
+ apiKey: licenseKey === 'free-license' ? null : licenseKey,
18
+ event: 'webcodec-conversion',
19
+ host,
20
+ succeeded,
21
+ });
22
+ };
@@ -1,12 +1,15 @@
1
+ import type { LogLevel } from 'remotion';
1
2
  import type { RenderStillOnWebImageFormat } from './render-still-on-web';
2
- export declare const createFrame: ({ div, width, height, }: {
3
+ export declare const createFrame: ({ div, width, height, logLevel, }: {
3
4
  div: HTMLDivElement;
4
5
  width: number;
5
6
  height: number;
7
+ logLevel: LogLevel;
6
8
  }) => Promise<OffscreenCanvas>;
7
- export declare const takeScreenshot: ({ div, width, height, imageFormat, }: {
9
+ export declare const takeScreenshot: ({ div, width, height, imageFormat, logLevel, }: {
8
10
  div: HTMLDivElement;
9
11
  width: number;
10
12
  height: number;
11
13
  imageFormat: RenderStillOnWebImageFormat;
14
+ logLevel: LogLevel;
12
15
  }) => Promise<Blob>;
@@ -1,15 +1,15 @@
1
1
  import { compose } from './compose';
2
- export const createFrame = async ({ div, width, height, }) => {
2
+ export const createFrame = async ({ div, width, height, logLevel, }) => {
3
3
  const canvas = new OffscreenCanvas(width, height);
4
4
  const context = canvas.getContext('2d');
5
5
  if (!context) {
6
6
  throw new Error('Could not get context');
7
7
  }
8
- await compose({ element: div, context, offsetLeft: 0, offsetTop: 0 });
8
+ await compose({ element: div, context, offsetLeft: 0, offsetTop: 0, logLevel });
9
9
  return canvas;
10
10
  };
11
- export const takeScreenshot = async ({ div, width, height, imageFormat, }) => {
12
- const frame = await createFrame({ div, width, height });
11
+ export const takeScreenshot = async ({ div, width, height, imageFormat, logLevel, }) => {
12
+ const frame = await createFrame({ div, width, height, logLevel });
13
13
  const imageData = await frame.convertToBlob({
14
14
  type: `image/${imageFormat}`,
15
15
  });
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.393",
6
+ "version": "4.0.395",
7
7
  "main": "dist/index.js",
8
8
  "sideEffects": false,
9
9
  "scripts": {
@@ -16,13 +16,14 @@
16
16
  "author": "Remotion <jonny@remotion.dev>",
17
17
  "license": "UNLICENSED",
18
18
  "dependencies": {
19
- "remotion": "4.0.393",
20
- "mediabunny": "1.27.0"
19
+ "@remotion/licensing": "4.0.395",
20
+ "remotion": "4.0.395",
21
+ "mediabunny": "1.27.2"
21
22
  },
22
23
  "devDependencies": {
23
- "@remotion/eslint-config-internal": "4.0.393",
24
- "@remotion/player": "4.0.393",
25
- "@remotion/media": "4.0.393",
24
+ "@remotion/eslint-config-internal": "4.0.395",
25
+ "@remotion/player": "4.0.395",
26
+ "@remotion/media": "4.0.395",
26
27
  "@vitejs/plugin-react": "4.1.0",
27
28
  "@vitest/browser-playwright": "4.0.9",
28
29
  "playwright": "1.55.1",