@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
@@ -6,7 +6,7 @@ import {
6
6
  StreamTarget,
7
7
  VideoSampleSource
8
8
  } from "mediabunny";
9
- import { Internals as Internals4 } from "remotion";
9
+ import { Internals as Internals6 } from "remotion";
10
10
 
11
11
  // src/add-sample.ts
12
12
  import { AudioSample, VideoSample } from "mediabunny";
@@ -460,20 +460,95 @@ var onlyOneRenderAtATimeQueue = {
460
460
  ref: Promise.resolve()
461
461
  };
462
462
 
463
+ // ../licensing/dist/esm/index.mjs
464
+ var HOST = "https://www.remotion.pro";
465
+ var registerUsageEvent = async ({
466
+ apiKey,
467
+ host,
468
+ succeeded,
469
+ event
470
+ }) => {
471
+ const abortController = new AbortController;
472
+ const timeout = setTimeout(() => {
473
+ abortController.abort();
474
+ }, 1e4);
475
+ try {
476
+ const res = await fetch(`${HOST}/api/track/register-usage-point`, {
477
+ method: "POST",
478
+ body: JSON.stringify({
479
+ event,
480
+ apiKey,
481
+ host,
482
+ succeeded
483
+ }),
484
+ headers: {
485
+ "Content-Type": "application/json"
486
+ },
487
+ signal: abortController.signal
488
+ });
489
+ clearTimeout(timeout);
490
+ const json = await res.json();
491
+ if (json.success) {
492
+ return {
493
+ billable: json.billable,
494
+ classification: json.classification
495
+ };
496
+ }
497
+ if (!res.ok) {
498
+ throw new Error(json.error);
499
+ }
500
+ const read = await res.json();
501
+ return read;
502
+ } catch (err) {
503
+ clearTimeout(timeout);
504
+ if (err instanceof Error && err.name === "AbortError") {
505
+ throw new Error("Request timed out after 10 seconds");
506
+ }
507
+ throw err;
508
+ }
509
+ };
510
+
511
+ // src/send-telemetry-event.ts
512
+ import { Internals as Internals3 } from "remotion";
513
+ var sendUsageEvent = async ({
514
+ licenseKey,
515
+ succeeded,
516
+ apiName
517
+ }) => {
518
+ const host = typeof window === "undefined" ? null : typeof window.location === "undefined" ? null : window.location.origin ?? null;
519
+ if (host === null) {
520
+ return;
521
+ }
522
+ if (licenseKey === null) {
523
+ Internals3.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.`);
524
+ }
525
+ await registerUsageEvent({
526
+ apiKey: licenseKey === "free-license" ? null : licenseKey,
527
+ event: "webcodec-conversion",
528
+ host,
529
+ succeeded
530
+ });
531
+ };
532
+
463
533
  // src/drawing/turn-svg-into-drawable.ts
464
534
  var turnSvgIntoDrawable = (svg) => {
535
+ const { fill, color } = getComputedStyle(svg);
465
536
  const originalTransform = svg.style.transform;
466
537
  const originalTransformOrigin = svg.style.transformOrigin;
467
538
  const originalMarginLeft = svg.style.marginLeft;
468
539
  const originalMarginRight = svg.style.marginRight;
469
540
  const originalMarginTop = svg.style.marginTop;
470
541
  const originalMarginBottom = svg.style.marginBottom;
542
+ const originalFill = svg.style.fill;
543
+ const originalColor = svg.style.color;
471
544
  svg.style.transform = "none";
472
545
  svg.style.transformOrigin = "";
473
546
  svg.style.marginLeft = "0";
474
547
  svg.style.marginRight = "0";
475
548
  svg.style.marginTop = "0";
476
549
  svg.style.marginBottom = "0";
550
+ svg.style.fill = fill;
551
+ svg.style.color = color;
477
552
  const svgData = new XMLSerializer().serializeToString(svg);
478
553
  svg.style.marginLeft = originalMarginLeft;
479
554
  svg.style.marginRight = originalMarginRight;
@@ -481,6 +556,8 @@ var turnSvgIntoDrawable = (svg) => {
481
556
  svg.style.marginBottom = originalMarginBottom;
482
557
  svg.style.transform = originalTransform;
483
558
  svg.style.transformOrigin = originalTransformOrigin;
559
+ svg.style.fill = originalFill;
560
+ svg.style.color = originalColor;
484
561
  return new Promise((resolve, reject) => {
485
562
  const image = new Image;
486
563
  const url = `data:image/svg+xml;base64,${btoa(svgData)}`;
@@ -506,6 +583,29 @@ var drawDomElement = (node) => {
506
583
  return domDrawFn;
507
584
  };
508
585
 
586
+ // src/drawing/draw-element-to-canvas.ts
587
+ import { Internals as Internals4 } from "remotion";
588
+
589
+ // src/get-biggest-bounding-client-rect.ts
590
+ var getBiggestBoundingClientRect = (element) => {
591
+ const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
592
+ let mostLeft = Infinity;
593
+ let mostTop = Infinity;
594
+ let mostRight = -Infinity;
595
+ let mostBottom = -Infinity;
596
+ while (true) {
597
+ const rect = treeWalker.currentNode.getBoundingClientRect();
598
+ mostLeft = Math.min(mostLeft, rect.left);
599
+ mostTop = Math.min(mostTop, rect.top);
600
+ mostRight = Math.max(mostRight, rect.right);
601
+ mostBottom = Math.max(mostBottom, rect.bottom);
602
+ if (!treeWalker.nextNode()) {
603
+ break;
604
+ }
605
+ }
606
+ return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
607
+ };
608
+
509
609
  // src/drawing/parse-transform-origin.ts
510
610
  var parseTransformOrigin = (transformOrigin) => {
511
611
  if (transformOrigin.trim() === "") {
@@ -747,87 +847,340 @@ function setBorderRadius({
747
847
  }
748
848
 
749
849
  // src/drawing/draw-border.ts
750
- var drawBorder = ({
850
+ var parseBorderWidth = (value) => {
851
+ return parseFloat(value) || 0;
852
+ };
853
+ var getBorderSideProperties = (computedStyle) => {
854
+ return {
855
+ top: {
856
+ width: parseBorderWidth(computedStyle.borderTopWidth),
857
+ color: computedStyle.borderTopColor || computedStyle.borderColor || "black",
858
+ style: computedStyle.borderTopStyle || computedStyle.borderStyle || "solid"
859
+ },
860
+ right: {
861
+ width: parseBorderWidth(computedStyle.borderRightWidth),
862
+ color: computedStyle.borderRightColor || computedStyle.borderColor || "black",
863
+ style: computedStyle.borderRightStyle || computedStyle.borderStyle || "solid"
864
+ },
865
+ bottom: {
866
+ width: parseBorderWidth(computedStyle.borderBottomWidth),
867
+ color: computedStyle.borderBottomColor || computedStyle.borderColor || "black",
868
+ style: computedStyle.borderBottomStyle || computedStyle.borderStyle || "solid"
869
+ },
870
+ left: {
871
+ width: parseBorderWidth(computedStyle.borderLeftWidth),
872
+ color: computedStyle.borderLeftColor || computedStyle.borderColor || "black",
873
+ style: computedStyle.borderLeftStyle || computedStyle.borderStyle || "solid"
874
+ }
875
+ };
876
+ };
877
+ var getLineDashPattern = (style, width) => {
878
+ if (style === "dashed") {
879
+ return [width * 2, width];
880
+ }
881
+ if (style === "dotted") {
882
+ return [width, width];
883
+ }
884
+ return [];
885
+ };
886
+ var drawBorderSide = ({
751
887
  ctx,
888
+ side,
752
889
  x,
753
890
  y,
754
891
  width,
755
892
  height,
756
893
  borderRadius,
757
- computedStyle
894
+ borderProperties
758
895
  }) => {
759
- const {
760
- borderStyle,
761
- borderColor,
762
- borderWidth: computedBorderWidth
763
- } = computedStyle;
764
- const borderWidths = computedBorderWidth.split(/\s+/).map((w) => parseFloat(w));
765
- const borderTop = borderWidths[0] || 0;
766
- const borderRight = borderWidths[1] || borderTop;
767
- const borderBottom = borderWidths[2] || borderTop;
768
- const borderLeft = borderWidths[3] || borderRight;
769
- const hasBorder = borderStyle && borderStyle !== "none" && borderStyle !== "hidden" && (borderTop > 0 || borderRight > 0 || borderBottom > 0 || borderLeft > 0);
770
- if (!hasBorder) {
896
+ const { width: borderWidth, color, style } = borderProperties;
897
+ if (borderWidth <= 0 || style === "none" || style === "hidden") {
771
898
  return;
772
899
  }
773
- const originalStrokeStyle = ctx.strokeStyle;
774
- const originalLineWidth = ctx.lineWidth;
775
- const originalLineDash = ctx.getLineDash();
776
- ctx.strokeStyle = borderColor;
777
- if (borderStyle === "dashed") {
778
- const max = Math.max(borderTop, borderRight, borderBottom, borderLeft);
779
- ctx.setLineDash([max * 2, max]);
780
- } else if (borderStyle === "dotted") {
781
- ctx.setLineDash([
782
- Math.max(borderTop, borderRight, borderBottom, borderLeft)
783
- ]);
900
+ ctx.beginPath();
901
+ ctx.strokeStyle = color;
902
+ ctx.lineWidth = borderWidth;
903
+ ctx.setLineDash(getLineDashPattern(style, borderWidth));
904
+ const halfWidth = borderWidth / 2;
905
+ if (side === "top") {
906
+ const startX = x + borderRadius.topLeft.horizontal;
907
+ const startY = y + halfWidth;
908
+ const endX = x + width - borderRadius.topRight.horizontal;
909
+ const endY = y + halfWidth;
910
+ ctx.moveTo(startX, startY);
911
+ ctx.lineTo(endX, endY);
912
+ } else if (side === "right") {
913
+ const startX = x + width - halfWidth;
914
+ const startY = y + borderRadius.topRight.vertical;
915
+ const endX = x + width - halfWidth;
916
+ const endY = y + height - borderRadius.bottomRight.vertical;
917
+ ctx.moveTo(startX, startY);
918
+ ctx.lineTo(endX, endY);
919
+ } else if (side === "bottom") {
920
+ const startX = x + borderRadius.bottomLeft.horizontal;
921
+ const startY = y + height - halfWidth;
922
+ const endX = x + width - borderRadius.bottomRight.horizontal;
923
+ const endY = y + height - halfWidth;
924
+ ctx.moveTo(startX, startY);
925
+ ctx.lineTo(endX, endY);
926
+ } else if (side === "left") {
927
+ const startX = x + halfWidth;
928
+ const startY = y + borderRadius.topLeft.vertical;
929
+ const endX = x + halfWidth;
930
+ const endY = y + height - borderRadius.bottomLeft.vertical;
931
+ ctx.moveTo(startX, startY);
932
+ ctx.lineTo(endX, endY);
933
+ }
934
+ ctx.stroke();
935
+ };
936
+ var drawCorner = ({
937
+ ctx,
938
+ corner,
939
+ x,
940
+ y,
941
+ width,
942
+ height,
943
+ borderRadius,
944
+ topBorder,
945
+ rightBorder,
946
+ bottomBorder,
947
+ leftBorder
948
+ }) => {
949
+ const radius = borderRadius[corner];
950
+ if (radius.horizontal <= 0 && radius.vertical <= 0) {
951
+ return;
952
+ }
953
+ let border1;
954
+ let border2;
955
+ let centerX;
956
+ let centerY;
957
+ let startAngle;
958
+ let endAngle;
959
+ if (corner === "topLeft") {
960
+ border1 = leftBorder;
961
+ border2 = topBorder;
962
+ centerX = x + radius.horizontal;
963
+ centerY = y + radius.vertical;
964
+ startAngle = Math.PI;
965
+ endAngle = Math.PI * 3 / 2;
966
+ } else if (corner === "topRight") {
967
+ border1 = topBorder;
968
+ border2 = rightBorder;
969
+ centerX = x + width - radius.horizontal;
970
+ centerY = y + radius.vertical;
971
+ startAngle = -Math.PI / 2;
972
+ endAngle = 0;
973
+ } else if (corner === "bottomRight") {
974
+ border1 = rightBorder;
975
+ border2 = bottomBorder;
976
+ centerX = x + width - radius.horizontal;
977
+ centerY = y + height - radius.vertical;
978
+ startAngle = 0;
979
+ endAngle = Math.PI / 2;
784
980
  } else {
785
- ctx.setLineDash([]);
981
+ border1 = bottomBorder;
982
+ border2 = leftBorder;
983
+ centerX = x + radius.horizontal;
984
+ centerY = y + height - radius.vertical;
985
+ startAngle = Math.PI / 2;
986
+ endAngle = Math.PI;
987
+ }
988
+ const avgWidth = (border1.width + border2.width) / 2;
989
+ const useColor = border1.width >= border2.width ? border1.color : border2.color;
990
+ const useStyle = border1.width >= border2.width ? border1.style : border2.style;
991
+ if (avgWidth > 0 && useStyle !== "none" && useStyle !== "hidden") {
992
+ ctx.beginPath();
993
+ ctx.strokeStyle = useColor;
994
+ ctx.lineWidth = avgWidth;
995
+ ctx.setLineDash(getLineDashPattern(useStyle, avgWidth));
996
+ const adjustedRadiusH = Math.max(0, radius.horizontal - avgWidth / 2);
997
+ const adjustedRadiusV = Math.max(0, radius.vertical - avgWidth / 2);
998
+ ctx.ellipse(centerX, centerY, adjustedRadiusH, adjustedRadiusV, 0, startAngle, endAngle);
999
+ ctx.stroke();
786
1000
  }
787
- const maxBorderWidth = Math.max(borderTop, borderRight, borderBottom, borderLeft);
1001
+ };
1002
+ var drawUniformBorder = ({
1003
+ ctx,
1004
+ x,
1005
+ y,
1006
+ width,
1007
+ height,
1008
+ borderRadius,
1009
+ borderWidth,
1010
+ borderColor,
1011
+ borderStyle
1012
+ }) => {
788
1013
  ctx.beginPath();
789
- const borderX = x + maxBorderWidth / 2;
790
- const borderY = y + maxBorderWidth / 2;
791
- const borderWidth = width - maxBorderWidth;
792
- const borderHeight = height - maxBorderWidth;
1014
+ ctx.strokeStyle = borderColor;
1015
+ ctx.lineWidth = borderWidth;
1016
+ ctx.setLineDash(getLineDashPattern(borderStyle, borderWidth));
1017
+ const halfWidth = borderWidth / 2;
1018
+ const borderX = x + halfWidth;
1019
+ const borderY = y + halfWidth;
1020
+ const borderW = width - borderWidth;
1021
+ const borderH = height - borderWidth;
793
1022
  const adjustedBorderRadius = {
794
1023
  topLeft: {
795
- horizontal: Math.max(0, borderRadius.topLeft.horizontal - maxBorderWidth / 2),
796
- vertical: Math.max(0, borderRadius.topLeft.vertical - maxBorderWidth / 2)
1024
+ horizontal: Math.max(0, borderRadius.topLeft.horizontal - halfWidth),
1025
+ vertical: Math.max(0, borderRadius.topLeft.vertical - halfWidth)
797
1026
  },
798
1027
  topRight: {
799
- horizontal: Math.max(0, borderRadius.topRight.horizontal - maxBorderWidth / 2),
800
- vertical: Math.max(0, borderRadius.topRight.vertical - maxBorderWidth / 2)
1028
+ horizontal: Math.max(0, borderRadius.topRight.horizontal - halfWidth),
1029
+ vertical: Math.max(0, borderRadius.topRight.vertical - halfWidth)
801
1030
  },
802
1031
  bottomRight: {
803
- horizontal: Math.max(0, borderRadius.bottomRight.horizontal - maxBorderWidth / 2),
804
- vertical: Math.max(0, borderRadius.bottomRight.vertical - maxBorderWidth / 2)
1032
+ horizontal: Math.max(0, borderRadius.bottomRight.horizontal - halfWidth),
1033
+ vertical: Math.max(0, borderRadius.bottomRight.vertical - halfWidth)
805
1034
  },
806
1035
  bottomLeft: {
807
- horizontal: Math.max(0, borderRadius.bottomLeft.horizontal - maxBorderWidth / 2),
808
- vertical: Math.max(0, borderRadius.bottomLeft.vertical - maxBorderWidth / 2)
1036
+ horizontal: Math.max(0, borderRadius.bottomLeft.horizontal - halfWidth),
1037
+ vertical: Math.max(0, borderRadius.bottomLeft.vertical - halfWidth)
809
1038
  }
810
1039
  };
811
1040
  ctx.moveTo(borderX + adjustedBorderRadius.topLeft.horizontal, borderY);
812
- ctx.lineTo(borderX + borderWidth - adjustedBorderRadius.topRight.horizontal, borderY);
1041
+ ctx.lineTo(borderX + borderW - adjustedBorderRadius.topRight.horizontal, borderY);
813
1042
  if (adjustedBorderRadius.topRight.horizontal > 0 || adjustedBorderRadius.topRight.vertical > 0) {
814
- ctx.ellipse(borderX + borderWidth - adjustedBorderRadius.topRight.horizontal, borderY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
1043
+ ctx.ellipse(borderX + borderW - adjustedBorderRadius.topRight.horizontal, borderY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
815
1044
  }
816
- ctx.lineTo(borderX + borderWidth, borderY + borderHeight - adjustedBorderRadius.bottomRight.vertical);
1045
+ ctx.lineTo(borderX + borderW, borderY + borderH - adjustedBorderRadius.bottomRight.vertical);
817
1046
  if (adjustedBorderRadius.bottomRight.horizontal > 0 || adjustedBorderRadius.bottomRight.vertical > 0) {
818
- ctx.ellipse(borderX + borderWidth - adjustedBorderRadius.bottomRight.horizontal, borderY + borderHeight - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
1047
+ ctx.ellipse(borderX + borderW - adjustedBorderRadius.bottomRight.horizontal, borderY + borderH - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
819
1048
  }
820
- ctx.lineTo(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderHeight);
1049
+ ctx.lineTo(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderH);
821
1050
  if (adjustedBorderRadius.bottomLeft.horizontal > 0 || adjustedBorderRadius.bottomLeft.vertical > 0) {
822
- ctx.ellipse(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderHeight - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
1051
+ ctx.ellipse(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderH - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
823
1052
  }
824
1053
  ctx.lineTo(borderX, borderY + adjustedBorderRadius.topLeft.vertical);
825
1054
  if (adjustedBorderRadius.topLeft.horizontal > 0 || adjustedBorderRadius.topLeft.vertical > 0) {
826
1055
  ctx.ellipse(borderX + adjustedBorderRadius.topLeft.horizontal, borderY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
827
1056
  }
828
1057
  ctx.closePath();
829
- ctx.lineWidth = maxBorderWidth;
830
1058
  ctx.stroke();
1059
+ };
1060
+ var drawBorder = ({
1061
+ ctx,
1062
+ x,
1063
+ y,
1064
+ width,
1065
+ height,
1066
+ borderRadius,
1067
+ computedStyle
1068
+ }) => {
1069
+ const borders = getBorderSideProperties(computedStyle);
1070
+ const hasBorder = borders.top.width > 0 || borders.right.width > 0 || borders.bottom.width > 0 || borders.left.width > 0;
1071
+ if (!hasBorder) {
1072
+ return;
1073
+ }
1074
+ const originalStrokeStyle = ctx.strokeStyle;
1075
+ const originalLineWidth = ctx.lineWidth;
1076
+ const originalLineDash = ctx.getLineDash();
1077
+ const allSidesEqual = borders.top.width === borders.right.width && borders.top.width === borders.bottom.width && borders.top.width === borders.left.width && borders.top.color === borders.right.color && borders.top.color === borders.bottom.color && borders.top.color === borders.left.color && borders.top.style === borders.right.style && borders.top.style === borders.bottom.style && borders.top.style === borders.left.style && borders.top.width > 0;
1078
+ if (allSidesEqual) {
1079
+ drawUniformBorder({
1080
+ ctx,
1081
+ x,
1082
+ y,
1083
+ width,
1084
+ height,
1085
+ borderRadius,
1086
+ borderWidth: borders.top.width,
1087
+ borderColor: borders.top.color,
1088
+ borderStyle: borders.top.style
1089
+ });
1090
+ } else {
1091
+ drawCorner({
1092
+ ctx,
1093
+ corner: "topLeft",
1094
+ x,
1095
+ y,
1096
+ width,
1097
+ height,
1098
+ borderRadius,
1099
+ topBorder: borders.top,
1100
+ rightBorder: borders.right,
1101
+ bottomBorder: borders.bottom,
1102
+ leftBorder: borders.left
1103
+ });
1104
+ drawCorner({
1105
+ ctx,
1106
+ corner: "topRight",
1107
+ x,
1108
+ y,
1109
+ width,
1110
+ height,
1111
+ borderRadius,
1112
+ topBorder: borders.top,
1113
+ rightBorder: borders.right,
1114
+ bottomBorder: borders.bottom,
1115
+ leftBorder: borders.left
1116
+ });
1117
+ drawCorner({
1118
+ ctx,
1119
+ corner: "bottomRight",
1120
+ x,
1121
+ y,
1122
+ width,
1123
+ height,
1124
+ borderRadius,
1125
+ topBorder: borders.top,
1126
+ rightBorder: borders.right,
1127
+ bottomBorder: borders.bottom,
1128
+ leftBorder: borders.left
1129
+ });
1130
+ drawCorner({
1131
+ ctx,
1132
+ corner: "bottomLeft",
1133
+ x,
1134
+ y,
1135
+ width,
1136
+ height,
1137
+ borderRadius,
1138
+ topBorder: borders.top,
1139
+ rightBorder: borders.right,
1140
+ bottomBorder: borders.bottom,
1141
+ leftBorder: borders.left
1142
+ });
1143
+ drawBorderSide({
1144
+ ctx,
1145
+ side: "top",
1146
+ x,
1147
+ y,
1148
+ width,
1149
+ height,
1150
+ borderRadius,
1151
+ borderProperties: borders.top
1152
+ });
1153
+ drawBorderSide({
1154
+ ctx,
1155
+ side: "right",
1156
+ x,
1157
+ y,
1158
+ width,
1159
+ height,
1160
+ borderRadius,
1161
+ borderProperties: borders.right
1162
+ });
1163
+ drawBorderSide({
1164
+ ctx,
1165
+ side: "bottom",
1166
+ x,
1167
+ y,
1168
+ width,
1169
+ height,
1170
+ borderRadius,
1171
+ borderProperties: borders.bottom
1172
+ });
1173
+ drawBorderSide({
1174
+ ctx,
1175
+ side: "left",
1176
+ x,
1177
+ y,
1178
+ width,
1179
+ height,
1180
+ borderRadius,
1181
+ borderProperties: borders.left
1182
+ });
1183
+ }
831
1184
  ctx.strokeStyle = originalStrokeStyle;
832
1185
  ctx.lineWidth = originalLineWidth;
833
1186
  ctx.setLineDash(originalLineDash);
@@ -933,6 +1286,12 @@ var createHelperCanvas = ({
933
1286
  helperCanvas.gl.clear(helperCanvas.gl.COLOR_BUFFER_BIT);
934
1287
  return helperCanvas;
935
1288
  }
1289
+ if (helperCanvas) {
1290
+ helperCanvas.gl.deleteProgram(helperCanvas.program);
1291
+ helperCanvas.gl.deleteShader(helperCanvas.vertexShader);
1292
+ helperCanvas.gl.deleteShader(helperCanvas.fragmentShader);
1293
+ helperCanvas = null;
1294
+ }
936
1295
  const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
937
1296
  const gl = canvas.getContext("webgl");
938
1297
  if (!gl) {
@@ -973,7 +1332,7 @@ var createHelperCanvas = ({
973
1332
  gl.clear(gl.COLOR_BUFFER_BIT);
974
1333
  gl.enable(gl.BLEND);
975
1334
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
976
- helperCanvas = { canvas, gl, program };
1335
+ helperCanvas = { canvas, gl, program, vertexShader, fragmentShader };
977
1336
  return helperCanvas;
978
1337
  };
979
1338
  var transformIn3d = ({
@@ -1065,7 +1424,8 @@ var drawElementToCanvas = async ({
1065
1424
  context,
1066
1425
  draw,
1067
1426
  offsetLeft,
1068
- offsetTop
1427
+ offsetTop,
1428
+ logLevel
1069
1429
  }) => {
1070
1430
  const { totalMatrix, reset, dimensions, opacity, computedStyle } = calculateTransforms(element);
1071
1431
  if (opacity === 0) {
@@ -1077,10 +1437,12 @@ var drawElementToCanvas = async ({
1077
1437
  return "continue";
1078
1438
  }
1079
1439
  if (!totalMatrix.is2D) {
1080
- const canvasOffsetLeft = Math.min(dimensions.left, 0);
1081
- const canvasOffsetTop = Math.min(dimensions.top, 0);
1082
- const tempCanvasWidth = Math.max(dimensions.width, dimensions.right);
1083
- const tempCanvasHeight = Math.max(dimensions.height, dimensions.bottom);
1440
+ const biggestBoundingClientRect = getBiggestBoundingClientRect(element);
1441
+ const canvasOffsetLeft = Math.min(biggestBoundingClientRect.left, 0);
1442
+ const canvasOffsetTop = Math.min(biggestBoundingClientRect.top, 0);
1443
+ const tempCanvasWidth = Math.max(biggestBoundingClientRect.width, biggestBoundingClientRect.right);
1444
+ const tempCanvasHeight = Math.max(biggestBoundingClientRect.height, biggestBoundingClientRect.bottom);
1445
+ const start = Date.now();
1084
1446
  const tempCanvas = new OffscreenCanvas(tempCanvasWidth, tempCanvasHeight);
1085
1447
  const context2 = tempCanvas.getContext("2d");
1086
1448
  if (!context2) {
@@ -1090,8 +1452,10 @@ var drawElementToCanvas = async ({
1090
1452
  element,
1091
1453
  context: context2,
1092
1454
  offsetLeft: canvasOffsetLeft,
1093
- offsetTop: canvasOffsetTop
1455
+ offsetTop: canvasOffsetTop,
1456
+ logLevel
1094
1457
  });
1458
+ const afterCompose = Date.now();
1095
1459
  const transformed = transformIn3d({
1096
1460
  canvasWidth: tempCanvasWidth,
1097
1461
  canvasHeight: tempCanvasHeight,
@@ -1101,7 +1465,12 @@ var drawElementToCanvas = async ({
1101
1465
  offsetTop: canvasOffsetTop
1102
1466
  });
1103
1467
  context.drawImage(transformed, 0, 0);
1468
+ const afterDraw = Date.now();
1104
1469
  reset();
1470
+ Internals4.Log.trace({
1471
+ logLevel,
1472
+ tag: "@remotion/web-renderer"
1473
+ }, `Transforming element in 3D - canvas size: ${tempCanvasWidth}x${tempCanvasHeight} - compose: ${afterCompose - start}ms - draw: ${afterDraw - afterCompose}ms`);
1105
1474
  return "skip-children";
1106
1475
  }
1107
1476
  await drawElement({
@@ -1117,7 +1486,7 @@ var drawElementToCanvas = async ({
1117
1486
  };
1118
1487
 
1119
1488
  // src/drawing/text/draw-text.ts
1120
- import { Internals as Internals3 } from "remotion";
1489
+ import { Internals as Internals5 } from "remotion";
1121
1490
 
1122
1491
  // src/drawing/text/apply-text-transform.ts
1123
1492
  var applyTextTransform = (text, transform) => {
@@ -1239,7 +1608,6 @@ var drawText = (span) => {
1239
1608
  fontSize,
1240
1609
  fontWeight,
1241
1610
  color,
1242
- lineHeight,
1243
1611
  direction,
1244
1612
  writingMode,
1245
1613
  letterSpacing,
@@ -1247,22 +1615,20 @@ var drawText = (span) => {
1247
1615
  } = computedStyle;
1248
1616
  const isVertical = writingMode !== "horizontal-tb";
1249
1617
  if (isVertical) {
1250
- Internals3.Log.warn({
1618
+ Internals5.Log.warn({
1251
1619
  logLevel: "warn",
1252
1620
  tag: "@remotion/web-renderer"
1253
1621
  }, 'Detected "writing-mode" CSS property. Vertical text is not yet supported in @remotion/web-renderer');
1254
1622
  return;
1255
1623
  }
1256
1624
  contextToDraw.save();
1257
- contextToDraw.font = `${fontWeight} ${fontSize} ${fontFamily}`;
1625
+ const fontSizePx = parseFloat(fontSize);
1626
+ contextToDraw.font = `${fontWeight} ${fontSizePx}px ${fontFamily}`;
1258
1627
  contextToDraw.fillStyle = color;
1259
1628
  contextToDraw.letterSpacing = letterSpacing;
1260
- const fontSizePx = parseFloat(fontSize);
1261
- const lineHeightPx = lineHeight === "normal" ? 1.2 * fontSizePx : parseFloat(lineHeight);
1262
- const baselineOffset = (lineHeightPx - fontSizePx) / 2;
1263
1629
  const isRTL = direction === "rtl";
1264
1630
  contextToDraw.textAlign = isRTL ? "right" : "left";
1265
- contextToDraw.textBaseline = "top";
1631
+ contextToDraw.textBaseline = "alphabetic";
1266
1632
  const originalText = span.textContent;
1267
1633
  const collapsedText = getCollapsedText(span);
1268
1634
  const transformedText = applyTextTransform(collapsedText, textTransform);
@@ -1270,8 +1636,9 @@ var drawText = (span) => {
1270
1636
  const xPosition = isRTL ? rect.right : rect.left;
1271
1637
  const lines = findLineBreaks(span, isRTL);
1272
1638
  let offsetTop = 0;
1639
+ const { fontBoundingBoxAscent } = contextToDraw.measureText(lines[0].text);
1273
1640
  for (const line of lines) {
1274
- contextToDraw.fillText(line.text, xPosition + line.offsetHorizontal, rect.top + baselineOffset + offsetTop);
1641
+ contextToDraw.fillText(line.text, xPosition + line.offsetHorizontal, rect.top + offsetTop + fontBoundingBoxAscent);
1275
1642
  offsetTop += line.offsetTop;
1276
1643
  }
1277
1644
  span.textContent = originalText;
@@ -1285,7 +1652,8 @@ var handleTextNode = async ({
1285
1652
  node,
1286
1653
  context,
1287
1654
  offsetLeft,
1288
- offsetTop
1655
+ offsetTop,
1656
+ logLevel
1289
1657
  }) => {
1290
1658
  const span = document.createElement("span");
1291
1659
  const parent = node.parentNode;
@@ -1299,7 +1667,8 @@ var handleTextNode = async ({
1299
1667
  element: span,
1300
1668
  draw: drawText(span),
1301
1669
  offsetLeft,
1302
- offsetTop
1670
+ offsetTop,
1671
+ logLevel
1303
1672
  });
1304
1673
  parent.insertBefore(node, span);
1305
1674
  parent.removeChild(span);
@@ -1324,7 +1693,8 @@ var walkOverNode = ({
1324
1693
  node,
1325
1694
  context,
1326
1695
  offsetLeft,
1327
- offsetTop
1696
+ offsetTop,
1697
+ logLevel
1328
1698
  }) => {
1329
1699
  if (node instanceof HTMLElement || node instanceof SVGElement) {
1330
1700
  return drawElementToCanvas({
@@ -1332,11 +1702,12 @@ var walkOverNode = ({
1332
1702
  context,
1333
1703
  draw: drawDomElement(node),
1334
1704
  offsetLeft,
1335
- offsetTop
1705
+ offsetTop,
1706
+ logLevel
1336
1707
  });
1337
1708
  }
1338
1709
  if (node instanceof Text) {
1339
- return handleTextNode({ node, context, offsetLeft, offsetTop });
1710
+ return handleTextNode({ node, context, offsetLeft, offsetTop, logLevel });
1340
1711
  }
1341
1712
  throw new Error("Unknown node type");
1342
1713
  };
@@ -1344,7 +1715,8 @@ var compose = async ({
1344
1715
  element,
1345
1716
  context,
1346
1717
  offsetLeft,
1347
- offsetTop
1718
+ offsetTop,
1719
+ logLevel
1348
1720
  }) => {
1349
1721
  const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, (node) => {
1350
1722
  if (node instanceof Element) {
@@ -1361,7 +1733,8 @@ var compose = async ({
1361
1733
  node: treeWalker.currentNode,
1362
1734
  context,
1363
1735
  offsetLeft,
1364
- offsetTop
1736
+ offsetTop,
1737
+ logLevel
1365
1738
  });
1366
1739
  if (val === "skip-children") {
1367
1740
  if (!skipToNextNonDescendant(treeWalker)) {
@@ -1377,23 +1750,25 @@ var compose = async ({
1377
1750
  var createFrame = async ({
1378
1751
  div,
1379
1752
  width,
1380
- height
1753
+ height,
1754
+ logLevel
1381
1755
  }) => {
1382
1756
  const canvas = new OffscreenCanvas(width, height);
1383
1757
  const context = canvas.getContext("2d");
1384
1758
  if (!context) {
1385
1759
  throw new Error("Could not get context");
1386
1760
  }
1387
- await compose({ element: div, context, offsetLeft: 0, offsetTop: 0 });
1761
+ await compose({ element: div, context, offsetLeft: 0, offsetTop: 0, logLevel });
1388
1762
  return canvas;
1389
1763
  };
1390
1764
  var takeScreenshot = async ({
1391
1765
  div,
1392
1766
  width,
1393
1767
  height,
1394
- imageFormat
1768
+ imageFormat,
1769
+ logLevel
1395
1770
  }) => {
1396
- const frame = await createFrame({ div, width, height });
1771
+ const frame = await createFrame({ div, width, height, logLevel });
1397
1772
  const imageData = await frame.convertToBlob({
1398
1773
  type: `image/${imageFormat}`
1399
1774
  });
@@ -1562,7 +1937,8 @@ var internalRenderMediaOnWeb = async ({
1562
1937
  transparent,
1563
1938
  onArtifact,
1564
1939
  onFrame,
1565
- outputTarget: userDesiredOutputTarget
1940
+ outputTarget: userDesiredOutputTarget,
1941
+ licenseKey
1566
1942
  }) => {
1567
1943
  const outputTarget = userDesiredOutputTarget === null ? await canUseWebFsWriter() ? "web-fs" : "arraybuffer" : userDesiredOutputTarget;
1568
1944
  if (outputTarget === "web-fs") {
@@ -1573,7 +1949,7 @@ var internalRenderMediaOnWeb = async ({
1573
1949
  if (codec && !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
1574
1950
  return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
1575
1951
  }
1576
- const resolved = await Internals4.resolveVideoConfig({
1952
+ const resolved = await Internals6.resolveVideoConfig({
1577
1953
  calculateMetadata: composition.calculateMetadata ?? null,
1578
1954
  signal: signal ?? new AbortController().signal,
1579
1955
  defaultProps: composition.defaultProps ?? {},
@@ -1683,7 +2059,8 @@ var internalRenderMediaOnWeb = async ({
1683
2059
  const imageData = await createFrame({
1684
2060
  div,
1685
2061
  width: resolved.width,
1686
- height: resolved.height
2062
+ height: resolved.height,
2063
+ logLevel
1687
2064
  });
1688
2065
  if (signal?.aborted) {
1689
2066
  throw new Error("renderMediaOnWeb() was cancelled");
@@ -1747,6 +2124,11 @@ var internalRenderMediaOnWeb = async ({
1747
2124
  if (!(target instanceof BufferTarget)) {
1748
2125
  throw new Error("Expected target to be a BufferTarget");
1749
2126
  }
2127
+ sendUsageEvent({
2128
+ licenseKey: licenseKey ?? null,
2129
+ succeeded: true,
2130
+ apiName: "renderMediaOnWeb"
2131
+ });
1750
2132
  return {
1751
2133
  getBlob: () => {
1752
2134
  if (!target.buffer) {
@@ -1755,6 +2137,15 @@ var internalRenderMediaOnWeb = async ({
1755
2137
  return Promise.resolve(new Blob([target.buffer], { type: mimeType }));
1756
2138
  }
1757
2139
  };
2140
+ } catch (err) {
2141
+ sendUsageEvent({
2142
+ succeeded: false,
2143
+ licenseKey: licenseKey ?? null,
2144
+ apiName: "renderMediaOnWeb"
2145
+ }).catch((err2) => {
2146
+ Internals6.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
2147
+ });
2148
+ throw err;
1758
2149
  } finally {
1759
2150
  cleanupFns.forEach((fn) => fn());
1760
2151
  }
@@ -1765,7 +2156,7 @@ var renderMediaOnWeb = (options) => {
1765
2156
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref.catch(() => Promise.resolve()).then(() => internalRenderMediaOnWeb({
1766
2157
  ...options,
1767
2158
  delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
1768
- logLevel: options.logLevel ?? "info",
2159
+ logLevel: options.logLevel ?? window.remotion_logLevel ?? "info",
1769
2160
  schema: options.schema ?? undefined,
1770
2161
  mediaCacheSizeInBytes: options.mediaCacheSizeInBytes ?? null,
1771
2162
  codec,
@@ -1779,13 +2170,14 @@ var renderMediaOnWeb = (options) => {
1779
2170
  transparent: options.transparent ?? false,
1780
2171
  onArtifact: options.onArtifact ?? null,
1781
2172
  onFrame: options.onFrame ?? null,
1782
- outputTarget: options.outputTarget ?? null
2173
+ outputTarget: options.outputTarget ?? null,
2174
+ licenseKey: options.licenseKey ?? undefined
1783
2175
  }));
1784
2176
  return onlyOneRenderAtATimeQueue.ref;
1785
2177
  };
1786
2178
  // src/render-still-on-web.tsx
1787
2179
  import {
1788
- Internals as Internals5
2180
+ Internals as Internals7
1789
2181
  } from "remotion";
1790
2182
  async function internalRenderStillOnWeb({
1791
2183
  frame,
@@ -1797,9 +2189,10 @@ async function internalRenderStillOnWeb({
1797
2189
  mediaCacheSizeInBytes,
1798
2190
  composition,
1799
2191
  signal,
1800
- onArtifact
2192
+ onArtifact,
2193
+ licenseKey
1801
2194
  }) {
1802
- const resolved = await Internals5.resolveVideoConfig({
2195
+ const resolved = await Internals7.resolveVideoConfig({
1803
2196
  calculateMetadata: composition.calculateMetadata ?? null,
1804
2197
  signal: signal ?? new AbortController().signal,
1805
2198
  defaultProps: composition.defaultProps ?? {},
@@ -1849,13 +2242,28 @@ async function internalRenderStillOnWeb({
1849
2242
  div,
1850
2243
  width: resolved.width,
1851
2244
  height: resolved.height,
1852
- imageFormat
2245
+ imageFormat,
2246
+ logLevel
1853
2247
  });
1854
2248
  const assets = collectAssets.current.collectAssets();
1855
2249
  if (onArtifact) {
1856
2250
  await artifactsHandler.handle({ imageData, frame, assets, onArtifact });
1857
2251
  }
2252
+ sendUsageEvent({
2253
+ licenseKey: licenseKey ?? null,
2254
+ succeeded: true,
2255
+ apiName: "renderStillOnWeb"
2256
+ });
1858
2257
  return imageData;
2258
+ } catch (err) {
2259
+ sendUsageEvent({
2260
+ succeeded: false,
2261
+ licenseKey: licenseKey ?? null,
2262
+ apiName: "renderStillOnWeb"
2263
+ }).catch((err2) => {
2264
+ Internals7.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
2265
+ });
2266
+ throw err;
1859
2267
  } finally {
1860
2268
  cleanupScaffold();
1861
2269
  }
@@ -1864,11 +2272,12 @@ var renderStillOnWeb = (options) => {
1864
2272
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref.catch(() => Promise.resolve()).then(() => internalRenderStillOnWeb({
1865
2273
  ...options,
1866
2274
  delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
1867
- logLevel: options.logLevel ?? "info",
2275
+ logLevel: options.logLevel ?? window.remotion_logLevel ?? "info",
1868
2276
  schema: options.schema ?? undefined,
1869
2277
  mediaCacheSizeInBytes: options.mediaCacheSizeInBytes ?? null,
1870
2278
  signal: options.signal ?? null,
1871
- onArtifact: options.onArtifact ?? null
2279
+ onArtifact: options.onArtifact ?? null,
2280
+ licenseKey: options.licenseKey ?? undefined
1872
2281
  }));
1873
2282
  return onlyOneRenderAtATimeQueue.ref;
1874
2283
  };