@remotion/web-renderer 4.0.448 → 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
@@ -4,4 +4,4 @@ export declare const onlyInlineAudio: ({ assets, fps, timestamp, sampleRate, }:
4
4
  fps: number;
5
5
  timestamp: number;
6
6
  sampleRate: number;
7
- }) => AudioData | null;
7
+ }) => AudioData;
@@ -16,7 +16,6 @@ export declare const calculateTransforms: ({ element, rootElement, }: {
16
16
  precompositing: {
17
17
  needs3DTransformViaWebGL: boolean;
18
18
  needsMaskImage: LinearGradientInfo | null;
19
- needsFilter: string | null;
20
19
  needsPrecompositing: boolean;
21
20
  };
22
21
  };
@@ -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 {};
@@ -671,6 +671,9 @@ var handleArtifacts = () => {
671
671
  // src/audio.ts
672
672
  var TARGET_NUMBER_OF_CHANNELS = 2;
673
673
  function mixAudio(waves, length) {
674
+ if (waves.length === 0) {
675
+ return new Int16Array(length);
676
+ }
674
677
  if (waves.length === 1 && waves[0].length === length) {
675
678
  return waves[0];
676
679
  }
@@ -694,9 +697,6 @@ var onlyInlineAudio = ({
694
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
700
  const expectedLength = Math.round(TARGET_NUMBER_OF_CHANNELS * sampleRate / fps);
701
701
  for (const asset of inlineAudio) {
702
702
  if (asset.toneFrequency !== 1) {
@@ -2058,7 +2058,6 @@ var calculateTransforms = ({
2058
2058
  let opacity = 1;
2059
2059
  let elementComputedStyle = null;
2060
2060
  let maskImageInfo = null;
2061
- let filterValue = null;
2062
2061
  while (parent) {
2063
2062
  const computedStyle = getComputedStyle(parent);
2064
2063
  if (parent === element) {
@@ -2066,16 +2065,6 @@ var calculateTransforms = ({
2066
2065
  opacity = parseFloat(computedStyle.opacity);
2067
2066
  const maskImageValue = getMaskImageValue(computedStyle);
2068
2067
  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
- }
2079
2068
  const originalMaskImage = parent.style.maskImage;
2080
2069
  const originalWebkitMaskImage = parent.style.webkitMaskImage;
2081
2070
  parent.style.maskImage = "none";
@@ -2139,7 +2128,6 @@ var calculateTransforms = ({
2139
2128
  }
2140
2129
  const needs3DTransformViaWebGL = !totalMatrix.is2D;
2141
2130
  const needsMaskImage = maskImageInfo !== null;
2142
- const needsFilter = filterValue !== null;
2143
2131
  return {
2144
2132
  dimensions,
2145
2133
  totalMatrix,
@@ -2155,8 +2143,7 @@ var calculateTransforms = ({
2155
2143
  precompositing: {
2156
2144
  needs3DTransformViaWebGL,
2157
2145
  needsMaskImage: maskImageInfo,
2158
- needsFilter: filterValue,
2159
- needsPrecompositing: Boolean(needs3DTransformViaWebGL || needsMaskImage || needsFilter)
2146
+ needsPrecompositing: Boolean(needs3DTransformViaWebGL || needsMaskImage)
2160
2147
  }
2161
2148
  };
2162
2149
  };
@@ -2406,6 +2393,233 @@ function setBorderRadius({
2406
2393
  };
2407
2394
  }
2408
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
+
2409
2623
  // src/drawing/get-background-fill.ts
2410
2624
  var isColorTransparent = (color) => {
2411
2625
  return color === "transparent" || color.startsWith("rgba") && (color.endsWith(", 0)") || color.endsWith(",0"));
@@ -3122,6 +3336,11 @@ var drawElement = async ({
3122
3336
  parentRect,
3123
3337
  scale
3124
3338
  });
3339
+ const finishClipPath = setClipPath({
3340
+ ctx: context,
3341
+ clipPath: computedStyle.clipPath,
3342
+ rect
3343
+ });
3125
3344
  const finishOpacity = setOpacity({
3126
3345
  ctx: context,
3127
3346
  opacity
@@ -3186,6 +3405,7 @@ var drawElement = async ({
3186
3405
  cleanupAfterChildren: () => {
3187
3406
  finishFilter();
3188
3407
  finishOpacity();
3408
+ finishClipPath();
3189
3409
  finishOverflowHidden();
3190
3410
  }
3191
3411
  };
@@ -3523,11 +3743,6 @@ var handle3dTransform = ({
3523
3743
  return transformed;
3524
3744
  };
3525
3745
 
3526
- // src/drawing/handle-filter.ts
3527
- var getPrecomposeRectForFilter = (element) => {
3528
- return getBiggestBoundingClientRect(element);
3529
- };
3530
-
3531
3746
  // src/drawing/handle-mask.ts
3532
3747
  var getPrecomposeRectForMask = (element) => {
3533
3748
  const boundingRect = getBiggestBoundingClientRect(element);
@@ -3615,12 +3830,6 @@ var processNode = async ({
3615
3830
  if (precompositing.needsMaskImage) {
3616
3831
  precomposeRect = roundToExpandRect(getPrecomposeRectForMask(element));
3617
3832
  }
3618
- if (precompositing.needsFilter) {
3619
- precomposeRect = roundToExpandRect(getWiderRectAndExpand({
3620
- firstRect: precomposeRect,
3621
- secondRect: getPrecomposeRectForFilter(element)
3622
- }));
3623
- }
3624
3833
  if (precompositing.needs3DTransformViaWebGL) {
3625
3834
  const tentativePrecomposeRect = getPrecomposeRectFor3DTransform({
3626
3835
  element,
@@ -3683,13 +3892,8 @@ var processNode = async ({
3683
3892
  }
3684
3893
  }
3685
3894
  const previousTransform = context.getTransform();
3686
- const previousFilter = context.filter;
3687
3895
  context.setTransform(new DOMMatrix);
3688
- if (precompositing.needsFilter) {
3689
- context.filter = precompositing.needsFilter;
3690
- }
3691
3896
  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;
3693
3897
  context.setTransform(previousTransform);
3694
3898
  Internals6.Log.trace({
3695
3899
  logLevel,
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.448",
6
+ "version": "4.0.449",
7
7
  "main": "dist/index.js",
8
8
  "type": "module",
9
9
  "scripts": {
@@ -29,9 +29,12 @@
29
29
  "devDependencies": {
30
30
  "@react-three/fiber": "9.2.0",
31
31
  "@remotion/eslint-config-internal": "4.0.448",
32
+ "@remotion/paths": "4.0.448",
32
33
  "@remotion/player": "4.0.448",
33
34
  "@remotion/media": "4.0.448",
35
+ "@remotion/shapes": "4.0.448",
34
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",