@remotion/web-renderer 4.0.447 → 4.0.449

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 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
- }) => AudioData | null;
6
+ sampleRate: number;
7
+ }) => AudioData;
@@ -0,0 +1,43 @@
1
+ type ClipPathNone = {
2
+ type: 'none';
3
+ };
4
+ type ClipPathPolygon = {
5
+ type: 'polygon';
6
+ points: {
7
+ x: number;
8
+ y: number;
9
+ }[];
10
+ };
11
+ type ClipPathPath = {
12
+ type: 'path';
13
+ d: string;
14
+ fillRule: CanvasFillRule;
15
+ };
16
+ type ClipPathCircle = {
17
+ type: 'circle';
18
+ radius: number;
19
+ cx: number;
20
+ cy: number;
21
+ };
22
+ type ClipPathEllipse = {
23
+ type: 'ellipse';
24
+ rx: number;
25
+ ry: number;
26
+ cx: number;
27
+ cy: number;
28
+ };
29
+ type ClipPathInset = {
30
+ type: 'inset';
31
+ top: number;
32
+ right: number;
33
+ bottom: number;
34
+ left: number;
35
+ };
36
+ type ParsedClipPath = ClipPathNone | ClipPathPolygon | ClipPathPath | ClipPathCircle | ClipPathEllipse | ClipPathInset;
37
+ export declare function parseClipPath(clipPath: string, rect: DOMRect): ParsedClipPath;
38
+ export declare function setClipPath({ ctx, clipPath, rect }: {
39
+ ctx: OffscreenCanvasRenderingContext2D;
40
+ clipPath: string;
41
+ rect: DOMRect;
42
+ }): () => void;
43
+ export {};
@@ -0,0 +1 @@
1
+ export declare const getPrecomposeRectForFilter: (element: HTMLElement | SVGElement) => DOMRect;
@@ -670,8 +670,10 @@ 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) {
674
+ if (waves.length === 0) {
675
+ return new Int16Array(length);
676
+ }
675
677
  if (waves.length === 1 && waves[0].length === length) {
676
678
  return waves[0];
677
679
  }
@@ -691,13 +693,11 @@ function mixAudio(waves, length) {
691
693
  var onlyInlineAudio = ({
692
694
  assets,
693
695
  fps,
694
- timestamp
696
+ timestamp,
697
+ sampleRate
695
698
  }) => {
696
699
  const inlineAudio = assets.filter((asset) => asset.type === "inline-audio");
697
- if (inlineAudio.length === 0) {
698
- return null;
699
- }
700
- const expectedLength = Math.round(TARGET_NUMBER_OF_CHANNELS * TARGET_SAMPLE_RATE / fps);
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: TARGET_SAMPLE_RATE,
712
+ sampleRate,
713
713
  timestamp
714
714
  });
715
715
  };
@@ -1107,7 +1107,8 @@ function createScaffold({
1107
1107
  defaultOutName: defaultOutName ?? null,
1108
1108
  defaultVideoImageFormat: null,
1109
1109
  defaultPixelFormat: null,
1110
- defaultProResProfile: null
1110
+ defaultProResProfile: null,
1111
+ defaultSampleRate: null
1111
1112
  },
1112
1113
  folders: []
1113
1114
  },
@@ -2392,6 +2393,233 @@ function setBorderRadius({
2392
2393
  };
2393
2394
  }
2394
2395
 
2396
+ // src/drawing/clip-path.ts
2397
+ function resolveLength(value, reference) {
2398
+ value = value.trim();
2399
+ if (value.endsWith("%")) {
2400
+ return parseFloat(value) / 100 * reference;
2401
+ }
2402
+ if (value.endsWith("px")) {
2403
+ return parseFloat(value);
2404
+ }
2405
+ return parseFloat(value);
2406
+ }
2407
+ function parsePosition(parts, width, height) {
2408
+ if (parts.length === 0) {
2409
+ return { x: width / 2, y: height / 2 };
2410
+ }
2411
+ if (parts.length === 1) {
2412
+ return { x: resolveLength(parts[0], width), y: height / 2 };
2413
+ }
2414
+ return {
2415
+ x: resolveLength(parts[0], width),
2416
+ y: resolveLength(parts[1], height)
2417
+ };
2418
+ }
2419
+ function parsePolygon(args, rect) {
2420
+ const pointStrings = args.split(",");
2421
+ const points = pointStrings.map((pointStr) => {
2422
+ const coords = pointStr.trim().split(/\s+/);
2423
+ return {
2424
+ x: resolveLength(coords[0], rect.width) + rect.left,
2425
+ y: resolveLength(coords[1], rect.height) + rect.top
2426
+ };
2427
+ });
2428
+ return { type: "polygon", points };
2429
+ }
2430
+ function parsePath(args) {
2431
+ const match = args.match(/^(?:(nonzero|evenodd)\s*,\s*)?["'](.+)["']$/);
2432
+ if (!match) {
2433
+ return {
2434
+ type: "path",
2435
+ d: args.replace(/["']/g, ""),
2436
+ fillRule: "nonzero"
2437
+ };
2438
+ }
2439
+ const fillRule = match[1] === "evenodd" ? "evenodd" : "nonzero";
2440
+ return { type: "path", d: match[2], fillRule };
2441
+ }
2442
+ function parseCircle(args, rect) {
2443
+ const atIndex = args.indexOf(" at ");
2444
+ let radiusStr;
2445
+ let positionParts;
2446
+ if (atIndex !== -1) {
2447
+ radiusStr = args.slice(0, atIndex).trim();
2448
+ positionParts = args.slice(atIndex + 4).trim().split(/\s+/);
2449
+ } else {
2450
+ radiusStr = args.trim();
2451
+ positionParts = [];
2452
+ }
2453
+ const closestSide = Math.min(rect.width, rect.height) / 2;
2454
+ const farthestSide = Math.max(rect.width, rect.height) / 2;
2455
+ let radius;
2456
+ if (radiusStr === "closest-side" || radiusStr === "") {
2457
+ radius = closestSide;
2458
+ } else if (radiusStr === "farthest-side") {
2459
+ radius = farthestSide;
2460
+ } else {
2461
+ const refSize = Math.sqrt(rect.width * rect.width + rect.height * rect.height) / Math.SQRT2;
2462
+ radius = resolveLength(radiusStr, refSize);
2463
+ }
2464
+ const position = parsePosition(positionParts, rect.width, rect.height);
2465
+ return {
2466
+ type: "circle",
2467
+ radius,
2468
+ cx: position.x + rect.left,
2469
+ cy: position.y + rect.top
2470
+ };
2471
+ }
2472
+ function parseEllipse(args, rect) {
2473
+ const atIndex = args.indexOf(" at ");
2474
+ let radiiStr;
2475
+ let positionParts;
2476
+ if (atIndex !== -1) {
2477
+ radiiStr = args.slice(0, atIndex).trim();
2478
+ positionParts = args.slice(atIndex + 4).trim().split(/\s+/);
2479
+ } else {
2480
+ radiiStr = args.trim();
2481
+ positionParts = [];
2482
+ }
2483
+ const radiiParts = radiiStr.split(/\s+/);
2484
+ let rx;
2485
+ let ry;
2486
+ if (radiiParts.length >= 2) {
2487
+ rx = resolveLength(radiiParts[0], rect.width);
2488
+ ry = resolveLength(radiiParts[1], rect.height);
2489
+ } else {
2490
+ rx = rect.width / 2;
2491
+ ry = rect.height / 2;
2492
+ }
2493
+ const position = parsePosition(positionParts, rect.width, rect.height);
2494
+ return {
2495
+ type: "ellipse",
2496
+ rx,
2497
+ ry,
2498
+ cx: position.x + rect.left,
2499
+ cy: position.y + rect.top
2500
+ };
2501
+ }
2502
+ function parseInset(args, rect) {
2503
+ const [insetPart] = args.split(/\s+round\s+/);
2504
+ const parts = insetPart.split(/\s+/);
2505
+ let top;
2506
+ let right;
2507
+ let bottom;
2508
+ let left;
2509
+ if (parts.length === 1) {
2510
+ const val = resolveLength(parts[0], rect.height);
2511
+ top = val;
2512
+ right = val;
2513
+ bottom = val;
2514
+ left = val;
2515
+ } else if (parts.length === 2) {
2516
+ top = resolveLength(parts[0], rect.height);
2517
+ bottom = resolveLength(parts[0], rect.height);
2518
+ right = resolveLength(parts[1], rect.width);
2519
+ left = resolveLength(parts[1], rect.width);
2520
+ } else if (parts.length === 3) {
2521
+ top = resolveLength(parts[0], rect.height);
2522
+ right = resolveLength(parts[1], rect.width);
2523
+ left = resolveLength(parts[1], rect.width);
2524
+ bottom = resolveLength(parts[2], rect.height);
2525
+ } else {
2526
+ top = resolveLength(parts[0], rect.height);
2527
+ right = resolveLength(parts[1], rect.width);
2528
+ bottom = resolveLength(parts[2], rect.height);
2529
+ left = resolveLength(parts[3], rect.width);
2530
+ }
2531
+ return { type: "inset", top, right, bottom, left };
2532
+ }
2533
+ function parseClipPath(clipPath, rect) {
2534
+ if (clipPath === "none" || clipPath === "") {
2535
+ return { type: "none" };
2536
+ }
2537
+ const polygonMatch = clipPath.match(/^polygon\((.+)\)$/);
2538
+ if (polygonMatch) {
2539
+ return parsePolygon(polygonMatch[1], rect);
2540
+ }
2541
+ const pathMatch = clipPath.match(/^path\((.+)\)$/);
2542
+ if (pathMatch) {
2543
+ return parsePath(pathMatch[1]);
2544
+ }
2545
+ const circleMatch = clipPath.match(/^circle\((.+)\)$/);
2546
+ if (circleMatch) {
2547
+ return parseCircle(circleMatch[1], rect);
2548
+ }
2549
+ const ellipseMatch = clipPath.match(/^ellipse\((.+)\)$/);
2550
+ if (ellipseMatch) {
2551
+ return parseEllipse(ellipseMatch[1], rect);
2552
+ }
2553
+ const insetMatch = clipPath.match(/^inset\((.+)\)$/);
2554
+ if (insetMatch) {
2555
+ return parseInset(insetMatch[1], rect);
2556
+ }
2557
+ return { type: "none" };
2558
+ }
2559
+ function setClipPath({
2560
+ ctx,
2561
+ clipPath,
2562
+ rect
2563
+ }) {
2564
+ const parsed = parseClipPath(clipPath, rect);
2565
+ if (parsed.type === "none") {
2566
+ return () => {};
2567
+ }
2568
+ ctx.save();
2569
+ switch (parsed.type) {
2570
+ case "polygon": {
2571
+ ctx.beginPath();
2572
+ for (let i = 0;i < parsed.points.length; i++) {
2573
+ const point = parsed.points[i];
2574
+ if (i === 0) {
2575
+ ctx.moveTo(point.x, point.y);
2576
+ } else {
2577
+ ctx.lineTo(point.x, point.y);
2578
+ }
2579
+ }
2580
+ ctx.closePath();
2581
+ ctx.clip();
2582
+ break;
2583
+ }
2584
+ case "path": {
2585
+ const path2d = new Path2D;
2586
+ const offsetMatrix = new DOMMatrix().translate(rect.left, rect.top);
2587
+ path2d.addPath(new Path2D(parsed.d), offsetMatrix);
2588
+ ctx.clip(path2d, parsed.fillRule);
2589
+ break;
2590
+ }
2591
+ case "circle": {
2592
+ ctx.beginPath();
2593
+ ctx.arc(parsed.cx, parsed.cy, parsed.radius, 0, Math.PI * 2);
2594
+ ctx.closePath();
2595
+ ctx.clip();
2596
+ break;
2597
+ }
2598
+ case "ellipse": {
2599
+ ctx.beginPath();
2600
+ ctx.ellipse(parsed.cx, parsed.cy, parsed.rx, parsed.ry, 0, 0, Math.PI * 2);
2601
+ ctx.closePath();
2602
+ ctx.clip();
2603
+ break;
2604
+ }
2605
+ case "inset": {
2606
+ const x = rect.left + parsed.left;
2607
+ const y = rect.top + parsed.top;
2608
+ const w = rect.width - parsed.left - parsed.right;
2609
+ const h = rect.height - parsed.top - parsed.bottom;
2610
+ ctx.beginPath();
2611
+ ctx.rect(x, y, w, h);
2612
+ ctx.clip();
2613
+ break;
2614
+ }
2615
+ default:
2616
+ break;
2617
+ }
2618
+ return () => {
2619
+ ctx.restore();
2620
+ };
2621
+ }
2622
+
2395
2623
  // src/drawing/get-background-fill.ts
2396
2624
  var isColorTransparent = (color) => {
2397
2625
  return color === "transparent" || color.startsWith("rgba") && (color.endsWith(", 0)") || color.endsWith(",0"));
@@ -3108,6 +3336,11 @@ var drawElement = async ({
3108
3336
  parentRect,
3109
3337
  scale
3110
3338
  });
3339
+ const finishClipPath = setClipPath({
3340
+ ctx: context,
3341
+ clipPath: computedStyle.clipPath,
3342
+ rect
3343
+ });
3111
3344
  const finishOpacity = setOpacity({
3112
3345
  ctx: context,
3113
3346
  opacity
@@ -3172,6 +3405,7 @@ var drawElement = async ({
3172
3405
  cleanupAfterChildren: () => {
3173
3406
  finishFilter();
3174
3407
  finishOpacity();
3408
+ finishClipPath();
3175
3409
  finishOverflowHidden();
3176
3410
  }
3177
3411
  };
@@ -4274,7 +4508,8 @@ var internalRenderMediaOnWeb = async ({
4274
4508
  muted,
4275
4509
  scale,
4276
4510
  isProduction,
4277
- allowHtmlInCanvas
4511
+ allowHtmlInCanvas,
4512
+ sampleRate
4278
4513
  }) => {
4279
4514
  let __stack2 = [];
4280
4515
  try {
@@ -4553,7 +4788,7 @@ var internalRenderMediaOnWeb = async ({
4553
4788
  if (signal?.aborted) {
4554
4789
  throw new Error("renderMediaOnWeb() was cancelled");
4555
4790
  }
4556
- const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, timestamp });
4791
+ const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, timestamp, sampleRate });
4557
4792
  internalState.addAudioMixingTime(performance.now() - audioCombineStart);
4558
4793
  const addSampleStart = performance.now();
4559
4794
  const encodingPromises = [];
@@ -4667,7 +4902,8 @@ var renderMediaOnWeb = (options) => {
4667
4902
  muted: options.muted ?? false,
4668
4903
  scale: options.scale ?? 1,
4669
4904
  isProduction: options.isProduction ?? true,
4670
- allowHtmlInCanvas: options.allowHtmlInCanvas ?? false
4905
+ allowHtmlInCanvas: options.allowHtmlInCanvas ?? false,
4906
+ sampleRate: options.sampleRate ?? 48000
4671
4907
  }));
4672
4908
  return onlyOneRenderAtATimeQueue.ref;
4673
4909
  };
@@ -66,6 +66,7 @@ type OptionalRenderMediaOnWebOptions<Schema extends $ZodObject> = {
66
66
  muted: boolean;
67
67
  scale: number;
68
68
  allowHtmlInCanvas: boolean;
69
+ sampleRate: number;
69
70
  };
70
71
  export type RenderMediaOnWebOptions<Schema extends $ZodObject, Props extends Record<string, unknown>> = MandatoryRenderMediaOnWebOptions<Schema, Props> & Partial<OptionalRenderMediaOnWebOptions<Schema>> & InputPropsIfHasProps<Schema, Props>;
71
72
  export declare const renderMediaOnWeb: <Schema extends $ZodObject<Readonly<Readonly<{
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.447",
6
+ "version": "4.0.449",
7
7
  "main": "dist/index.js",
8
8
  "type": "module",
9
9
  "scripts": {
@@ -22,16 +22,19 @@
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.447",
26
- "remotion": "4.0.447",
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.447",
32
- "@remotion/player": "4.0.447",
33
- "@remotion/media": "4.0.447",
34
- "@remotion/three": "4.0.447",
31
+ "@remotion/eslint-config-internal": "4.0.448",
32
+ "@remotion/paths": "4.0.448",
33
+ "@remotion/player": "4.0.448",
34
+ "@remotion/media": "4.0.448",
35
+ "@remotion/shapes": "4.0.448",
36
+ "@remotion/three": "4.0.448",
37
+ "@remotion/transitions": "4.0.448",
35
38
  "@types/three": "0.170.0",
36
39
  "@typescript/native-preview": "7.0.0-dev.20260217.1",
37
40
  "@vitejs/plugin-react": "4.3.4",