@remotion/studio 4.0.445 → 4.0.447

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/components/AssetSelectorItem.js +11 -1
  2. package/dist/components/Canvas.js +1 -1
  3. package/dist/components/CanvasOrLoading.js +4 -4
  4. package/dist/components/CompositionSelectorItem.js +15 -1
  5. package/dist/components/FilePreview.js +3 -0
  6. package/dist/components/InitialCompositionLoader.js +10 -4
  7. package/dist/components/NewComposition/MenuContent.js +58 -0
  8. package/dist/components/NewComposition/menu-typeahead.d.ts +5 -0
  9. package/dist/components/NewComposition/menu-typeahead.js +27 -0
  10. package/dist/components/Preview.d.ts +1 -0
  11. package/dist/components/Preview.js +14 -1
  12. package/dist/components/RenderButton.js +1 -0
  13. package/dist/components/RenderModal/OptionExplainer.js +10 -2
  14. package/dist/components/RenderModal/WebRenderModal.js +6 -2
  15. package/dist/components/RenderModal/WebRenderModalAdvanced.d.ts +2 -0
  16. package/dist/components/RenderModal/WebRenderModalAdvanced.js +10 -2
  17. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +4 -3
  18. package/dist/components/RenderQueue/client-side-render-types.d.ts +1 -0
  19. package/dist/components/Timeline/TimelineListItem.js +53 -2
  20. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +4 -1
  21. package/dist/components/Timeline/use-sequence-props-subscription.js +10 -1
  22. package/dist/error-overlay/remotion-overlay/ErrorDisplay.js +1 -1
  23. package/dist/error-overlay/remotion-overlay/Retry.d.ts +1 -0
  24. package/dist/error-overlay/remotion-overlay/Retry.js +2 -2
  25. package/dist/esm/{chunk-bqd9dhnk.js → chunk-ase93hmz.js} +4588 -4229
  26. package/dist/esm/internals.mjs +4588 -4229
  27. package/dist/esm/previewEntry.mjs +542 -185
  28. package/dist/esm/renderEntry.mjs +1 -1
  29. package/dist/helpers/get-asset-metadata.d.ts +3 -0
  30. package/dist/helpers/get-asset-metadata.js +51 -43
  31. package/dist/helpers/retry-payload.js +1 -0
  32. package/dist/helpers/sidebar-scroll-into-view.d.ts +13 -0
  33. package/dist/helpers/sidebar-scroll-into-view.js +83 -0
  34. package/dist/helpers/use-studio-canvas-dimensions.js +3 -1
  35. package/dist/state/modals.d.ts +1 -0
  36. package/package.json +9 -9
@@ -1499,10 +1499,10 @@ var OpenInEditor = ({ stack, canHaveKeyboardShortcuts }) => {
1499
1499
 
1500
1500
  // src/error-overlay/remotion-overlay/Retry.tsx
1501
1501
  import { jsx as jsx19 } from "react/jsx-runtime";
1502
- var RetryButton = ({ onClick }) => {
1502
+ var RetryButton = ({ onClick, label: label2 = "Retry" }) => {
1503
1503
  return /* @__PURE__ */ jsx19(Button, {
1504
1504
  onClick,
1505
- children: "Retry calculateMetadata()"
1505
+ children: label2
1506
1506
  });
1507
1507
  };
1508
1508
 
@@ -1781,7 +1781,8 @@ ${stackLines}`;
1781
1781
  style: spacer2
1782
1782
  }),
1783
1783
  /* @__PURE__ */ jsx23(RetryButton, {
1784
- onClick: onRetry
1784
+ onClick: onRetry,
1785
+ label: calculateMetadata ? "Retry calculateMetadata()" : "Retry"
1785
1786
  })
1786
1787
  ]
1787
1788
  }) : null,
@@ -2733,7 +2734,7 @@ var enableHotMiddleware = () => {
2733
2734
  };
2734
2735
 
2735
2736
  // src/Studio.tsx
2736
- import { useLayoutEffect as useLayoutEffect4 } from "react";
2737
+ import { useLayoutEffect as useLayoutEffect6 } from "react";
2737
2738
  import { createPortal } from "react-dom";
2738
2739
  import { Internals as Internals70 } from "remotion";
2739
2740
 
@@ -3710,7 +3711,96 @@ var ModalsContext = createContext9({
3710
3711
  });
3711
3712
 
3712
3713
  // src/components/CompositionSelectorItem.tsx
3713
- import { useCallback as useCallback25, useContext as useContext9, useMemo as useMemo25, useState as useState22 } from "react";
3714
+ import {
3715
+ useCallback as useCallback25,
3716
+ useContext as useContext9,
3717
+ useLayoutEffect as useLayoutEffect3,
3718
+ useMemo as useMemo25,
3719
+ useRef as useRef13,
3720
+ useState as useState22
3721
+ } from "react";
3722
+
3723
+ // src/helpers/sidebar-scroll-into-view.ts
3724
+ var getComputedOverflowY = (el) => {
3725
+ return getComputedStyle(el).overflowY;
3726
+ };
3727
+ var findVerticalScrollParent = (element) => {
3728
+ let cur = element?.parentElement ?? null;
3729
+ while (cur) {
3730
+ const overflowY = getComputedOverflowY(cur);
3731
+ if (overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay") {
3732
+ return cur;
3733
+ }
3734
+ cur = cur.parentElement;
3735
+ }
3736
+ return null;
3737
+ };
3738
+ var isVerticallyFullyVisibleInSidebarList = (element) => {
3739
+ const scrollParent = findVerticalScrollParent(element);
3740
+ const rect = element.getBoundingClientRect();
3741
+ if (!scrollParent) {
3742
+ return rect.top >= 0 && rect.bottom <= window.innerHeight;
3743
+ }
3744
+ const parentRect = scrollParent.getBoundingClientRect();
3745
+ return rect.top >= parentRect.top && rect.bottom <= parentRect.bottom;
3746
+ };
3747
+ var scrollSidebarRowIntoViewIfNeeded = (element) => {
3748
+ if (!element) {
3749
+ return;
3750
+ }
3751
+ if (isVerticallyFullyVisibleInSidebarList(element)) {
3752
+ return;
3753
+ }
3754
+ element.scrollIntoView({ block: "nearest", behavior: "auto" });
3755
+ };
3756
+ var skipCompositionScrollIntoViewForId = null;
3757
+ var markCompositionSidebarScrollFromRowClick = (compositionId) => {
3758
+ skipCompositionScrollIntoViewForId = compositionId;
3759
+ };
3760
+ var shouldSkipCompositionScrollIntoView = (compositionId) => {
3761
+ if (skipCompositionScrollIntoViewForId === compositionId) {
3762
+ skipCompositionScrollIntoViewForId = null;
3763
+ return true;
3764
+ }
3765
+ return false;
3766
+ };
3767
+ var maybeScrollCompositionSidebarRowIntoView = ({
3768
+ element,
3769
+ compositionId,
3770
+ selected
3771
+ }) => {
3772
+ if (!selected) {
3773
+ return;
3774
+ }
3775
+ if (shouldSkipCompositionScrollIntoView(compositionId)) {
3776
+ return;
3777
+ }
3778
+ scrollSidebarRowIntoViewIfNeeded(element);
3779
+ };
3780
+ var skipAssetScrollIntoViewForPath = null;
3781
+ var markAssetSidebarScrollFromRowClick = (assetPath) => {
3782
+ skipAssetScrollIntoViewForPath = assetPath;
3783
+ };
3784
+ var shouldSkipAssetScrollIntoView = (assetPath) => {
3785
+ if (skipAssetScrollIntoViewForPath === assetPath) {
3786
+ skipAssetScrollIntoViewForPath = null;
3787
+ return true;
3788
+ }
3789
+ return false;
3790
+ };
3791
+ var maybeScrollAssetSidebarRowIntoView = ({
3792
+ element,
3793
+ assetPath,
3794
+ selected
3795
+ }) => {
3796
+ if (!selected) {
3797
+ return;
3798
+ }
3799
+ if (shouldSkipAssetScrollIntoView(assetPath)) {
3800
+ return;
3801
+ }
3802
+ scrollSidebarRowIntoViewIfNeeded(element);
3803
+ };
3714
3804
 
3715
3805
  // src/icons/folder.tsx
3716
3806
  import { jsx as jsx33 } from "react/jsx-runtime";
@@ -4599,6 +4689,34 @@ var MenuSubItem = ({
4599
4689
  });
4600
4690
  };
4601
4691
 
4692
+ // src/components/NewComposition/menu-typeahead.ts
4693
+ var getLabelToMatch = (value) => {
4694
+ if (value.type === "divider" || value.disabled) {
4695
+ return null;
4696
+ }
4697
+ if (typeof value.label === "string") {
4698
+ return value.label;
4699
+ }
4700
+ return null;
4701
+ };
4702
+ var findTypeaheadMenuItem = ({
4703
+ query,
4704
+ values
4705
+ }) => {
4706
+ const normalizedQuery = query.trim().toLowerCase();
4707
+ if (normalizedQuery.length === 0) {
4708
+ return null;
4709
+ }
4710
+ const matched = values.find((value) => {
4711
+ const label2 = getLabelToMatch(value);
4712
+ return label2 ? label2.toLowerCase().startsWith(normalizedQuery) : false;
4713
+ });
4714
+ if (!matched || matched.type === "divider") {
4715
+ return null;
4716
+ }
4717
+ return matched.id;
4718
+ };
4719
+
4602
4720
  // src/components/NewComposition/MenuContent.tsx
4603
4721
  import { jsx as jsx46 } from "react/jsx-runtime";
4604
4722
  var BORDER_SIZE = 1;
@@ -4626,6 +4744,8 @@ var MenuContent = ({
4626
4744
  const containerRef = useRef10(null);
4627
4745
  const isMobileLayout = useMobileLayout();
4628
4746
  const [subMenuActivated, setSubMenuActivated] = useState19(false);
4747
+ const typeaheadQueryRef = useRef10("");
4748
+ const typeaheadTimeoutRef = useRef10(null);
4629
4749
  if (values[0].type === "divider") {
4630
4750
  throw new Error("first value cant be divide");
4631
4751
  }
@@ -4636,6 +4756,13 @@ var MenuContent = ({
4636
4756
  const onItemSelected = useCallback20((id) => {
4637
4757
  setSelectedItem(id);
4638
4758
  }, []);
4759
+ const clearTypeahead = useCallback20(() => {
4760
+ typeaheadQueryRef.current = "";
4761
+ if (typeaheadTimeoutRef.current !== null) {
4762
+ window.clearTimeout(typeaheadTimeoutRef.current);
4763
+ typeaheadTimeoutRef.current = null;
4764
+ }
4765
+ }, []);
4639
4766
  const isItemSelectable = useCallback20((v) => {
4640
4767
  return v.type !== "divider" && !v.disabled;
4641
4768
  }, []);
@@ -4709,6 +4836,30 @@ var MenuContent = ({
4709
4836
  }
4710
4837
  setSubMenuActivated("without-mouse");
4711
4838
  }, [onNextMenu, selectedItem, values]);
4839
+ const onTypeahead = useCallback20((event) => {
4840
+ if (event.ctrlKey || event.metaKey || event.altKey || event.key.length !== 1 || event.key.trim().length === 0) {
4841
+ return;
4842
+ }
4843
+ const { activeElement } = document;
4844
+ if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement) {
4845
+ return;
4846
+ }
4847
+ typeaheadQueryRef.current = `${typeaheadQueryRef.current}${event.key}`;
4848
+ const matchedId = findTypeaheadMenuItem({
4849
+ query: typeaheadQueryRef.current,
4850
+ values
4851
+ });
4852
+ if (matchedId !== null) {
4853
+ setSelectedItem(matchedId);
4854
+ }
4855
+ if (typeaheadTimeoutRef.current !== null) {
4856
+ window.clearTimeout(typeaheadTimeoutRef.current);
4857
+ }
4858
+ typeaheadTimeoutRef.current = window.setTimeout(() => {
4859
+ typeaheadQueryRef.current = "";
4860
+ typeaheadTimeoutRef.current = null;
4861
+ }, 700);
4862
+ }, [values]);
4712
4863
  const containerWithHeight = useMemo20(() => {
4713
4864
  const containerStyles = { ...container11 };
4714
4865
  if (fixedHeight === null) {
@@ -4721,6 +4872,24 @@ var MenuContent = ({
4721
4872
  }
4722
4873
  return containerStyles;
4723
4874
  }, [fixedHeight, isMobileLayout]);
4875
+ useEffect18(() => {
4876
+ if (!keybindings.isHighestContext || !process.env.KEYBOARD_SHORTCUTS_ENABLED) {
4877
+ return;
4878
+ }
4879
+ const onKeyDown = (event) => {
4880
+ onTypeahead(event);
4881
+ };
4882
+ window.addEventListener("keydown", onKeyDown);
4883
+ return () => {
4884
+ window.removeEventListener("keydown", onKeyDown);
4885
+ clearTypeahead();
4886
+ };
4887
+ }, [clearTypeahead, keybindings.isHighestContext, onTypeahead]);
4888
+ useEffect18(() => {
4889
+ return () => {
4890
+ clearTypeahead();
4891
+ };
4892
+ }, [clearTypeahead]);
4724
4893
  useEffect18(() => {
4725
4894
  const escapeBinding = keybindings.registerKeybinding({
4726
4895
  event: "keydown",
@@ -5280,6 +5449,18 @@ var CompositionSelectorItem = ({
5280
5449
  const onPointerLeave = useCallback25(() => {
5281
5450
  setHovered(false);
5282
5451
  }, []);
5452
+ const compositionRowRef = useRef13(null);
5453
+ const compositionId = item.type === "composition" ? item.composition.id : null;
5454
+ useLayoutEffect3(() => {
5455
+ if (compositionId === null) {
5456
+ return;
5457
+ }
5458
+ maybeScrollCompositionSidebarRowIntoView({
5459
+ element: compositionRowRef.current,
5460
+ compositionId,
5461
+ selected
5462
+ });
5463
+ }, [compositionId, selected]);
5283
5464
  const style3 = useMemo25(() => {
5284
5465
  return {
5285
5466
  ...itemStyle,
@@ -5296,6 +5477,7 @@ var CompositionSelectorItem = ({
5296
5477
  const onClick = useCallback25((evt) => {
5297
5478
  evt.preventDefault();
5298
5479
  if (item.type === "composition") {
5480
+ markCompositionSidebarScrollFromRowClick(item.composition.id);
5299
5481
  selectComposition(item.composition, true);
5300
5482
  } else {
5301
5483
  toggleFolder(item.folderName, item.parentName);
@@ -5430,6 +5612,7 @@ var CompositionSelectorItem = ({
5430
5612
  children: /* @__PURE__ */ jsx52(Row, {
5431
5613
  align: "center",
5432
5614
  children: /* @__PURE__ */ jsxs22("a", {
5615
+ ref: compositionRowRef,
5433
5616
  style: style3,
5434
5617
  onPointerEnter,
5435
5618
  onPointerLeave,
@@ -5740,7 +5923,7 @@ var writeStaticFile = async ({
5740
5923
  };
5741
5924
 
5742
5925
  // src/helpers/use-asset-drag-events.ts
5743
- import { useCallback as useCallback27, useEffect as useEffect20, useMemo as useMemo27, useRef as useRef13 } from "react";
5926
+ import { useCallback as useCallback27, useEffect as useEffect20, useMemo as useMemo27, useRef as useRef14 } from "react";
5744
5927
  import { NoReactInternals } from "remotion/no-react";
5745
5928
  function useAssetDragEvents({
5746
5929
  name,
@@ -5748,7 +5931,7 @@ function useAssetDragEvents({
5748
5931
  dropLocation,
5749
5932
  setDropLocation
5750
5933
  }) {
5751
- const dragDepthRef = useRef13(0);
5934
+ const dragDepthRef = useRef14(0);
5752
5935
  const combinedParents = useMemo27(() => {
5753
5936
  return [parentFolder, name].filter(NoReactInternals.truthy).join("/");
5754
5937
  }, [name, parentFolder]);
@@ -5781,7 +5964,14 @@ function useAssetDragEvents({
5781
5964
  var use_asset_drag_events_default = useAssetDragEvents;
5782
5965
 
5783
5966
  // src/components/AssetSelectorItem.tsx
5784
- import React39, { useCallback as useCallback28, useContext as useContext11, useMemo as useMemo28, useRef as useRef14, useState as useState23 } from "react";
5967
+ import React39, {
5968
+ useCallback as useCallback28,
5969
+ useContext as useContext11,
5970
+ useLayoutEffect as useLayoutEffect4,
5971
+ useMemo as useMemo28,
5972
+ useRef as useRef15,
5973
+ useState as useState23
5974
+ } from "react";
5785
5975
  import { Internals as Internals10 } from "remotion";
5786
5976
  import { NoReactInternals as NoReactInternals3 } from "remotion/no-react";
5787
5977
 
@@ -6165,7 +6355,7 @@ var AssetFolderItem = ({
6165
6355
  readOnlyStudio
6166
6356
  }) => {
6167
6357
  const [hovered, setHovered] = useState23(false);
6168
- const openFolderTimerRef = useRef14(null);
6358
+ const openFolderTimerRef = useRef15(null);
6169
6359
  const { isDropDiv, onDragEnter, onDragLeave } = use_asset_drag_events_default({
6170
6360
  name: item.name,
6171
6361
  parentFolder,
@@ -6312,7 +6502,16 @@ var AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio }
6312
6502
  const onPointerLeave = useCallback28(() => {
6313
6503
  setHovered(false);
6314
6504
  }, []);
6505
+ const rowRef = useRef15(null);
6506
+ useLayoutEffect4(() => {
6507
+ maybeScrollAssetSidebarRowIntoView({
6508
+ element: rowRef.current,
6509
+ assetPath: relativePath,
6510
+ selected
6511
+ });
6512
+ }, [relativePath, selected]);
6315
6513
  const onClick = useCallback28(() => {
6514
+ markAssetSidebarScrollFromRowClick(relativePath);
6316
6515
  setCanvasContent({ type: "asset", asset: relativePath });
6317
6516
  pushUrl(`/assets/${relativePath}`);
6318
6517
  if (isMobileLayout) {
@@ -6370,6 +6569,7 @@ var AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio }
6370
6569
  return /* @__PURE__ */ jsx57(Row, {
6371
6570
  align: "center",
6372
6571
  children: /* @__PURE__ */ jsxs25("div", {
6572
+ ref: rowRef,
6373
6573
  style: style3,
6374
6574
  onPointerEnter,
6375
6575
  onPointerLeave,
@@ -6998,7 +7198,7 @@ var ExplorerPanel = ({ readOnlyStudio }) => {
6998
7198
  var useSelectAsset = () => {
6999
7199
  const { setCanvasContent } = useContext16(Internals14.CompositionSetters);
7000
7200
  const { setAssetFoldersExpanded } = useContext16(FolderContext);
7001
- return (asset) => {
7201
+ return useCallback33((asset) => {
7002
7202
  setCanvasContent({ type: "asset", asset });
7003
7203
  explorerSidebarTabs.current?.selectAssetsPanel();
7004
7204
  setAssetFoldersExpanded((ex) => {
@@ -7014,7 +7214,7 @@ var useSelectAsset = () => {
7014
7214
  }
7015
7215
  return newState;
7016
7216
  });
7017
- };
7217
+ }, [setAssetFoldersExpanded, setCanvasContent]);
7018
7218
  };
7019
7219
  var useSelectComposition = () => {
7020
7220
  const { setCompositionFoldersExpanded } = useContext16(FolderContext);
@@ -7108,7 +7308,7 @@ var InitialCompositionLoader = () => {
7108
7308
  return file.name === newCanvas.asset;
7109
7309
  });
7110
7310
  if (exists) {
7111
- setCanvasContent(newCanvas);
7311
+ selectAsset(newCanvas.asset);
7112
7312
  }
7113
7313
  return;
7114
7314
  }
@@ -7116,7 +7316,13 @@ var InitialCompositionLoader = () => {
7116
7316
  };
7117
7317
  window.addEventListener("popstate", onchange);
7118
7318
  return () => window.removeEventListener("popstate", onchange);
7119
- }, [compositions, selectComposition, setCanvasContent, staticFiles]);
7319
+ }, [
7320
+ compositions,
7321
+ selectAsset,
7322
+ selectComposition,
7323
+ setCanvasContent,
7324
+ staticFiles
7325
+ ]);
7120
7326
  return null;
7121
7327
  };
7122
7328
 
@@ -7146,7 +7352,7 @@ import {
7146
7352
  useCallback as useCallback35,
7147
7353
  useEffect as useEffect24,
7148
7354
  useImperativeHandle as useImperativeHandle7,
7149
- useRef as useRef15,
7355
+ useRef as useRef16,
7150
7356
  useState as useState30
7151
7357
  } from "react";
7152
7358
  import { AbsoluteFill as AbsoluteFill3 } from "remotion";
@@ -7277,7 +7483,7 @@ var container18 = {
7277
7483
  var askAiModalRef = createRef7();
7278
7484
  var AskAiModal = () => {
7279
7485
  const [state, setState] = useState30("never-opened");
7280
- const iframe = useRef15(null);
7486
+ const iframe = useRef16(null);
7281
7487
  useImperativeHandle7(askAiModalRef, () => ({
7282
7488
  toggle: () => {
7283
7489
  setState((s) => {
@@ -7388,7 +7594,7 @@ var ControlButton = (props) => {
7388
7594
 
7389
7595
  // src/components/NewComposition/ComboBox.tsx
7390
7596
  import { PlayerInternals as PlayerInternals6 } from "@remotion/player";
7391
- import { useCallback as useCallback36, useEffect as useEffect25, useMemo as useMemo34, useRef as useRef16, useState as useState31 } from "react";
7597
+ import { useCallback as useCallback36, useEffect as useEffect25, useMemo as useMemo34, useRef as useRef17, useState as useState31 } from "react";
7392
7598
  import ReactDOM5 from "react-dom";
7393
7599
  import { jsx as jsx69, jsxs as jsxs31, Fragment as Fragment8 } from "react/jsx-runtime";
7394
7600
  var container19 = {
@@ -7409,7 +7615,7 @@ var label3 = {
7409
7615
  var Combobox = ({ values, selectedId, style: customStyle, title: title4 }) => {
7410
7616
  const [hovered, setIsHovered] = useState31(false);
7411
7617
  const [opened, setOpened] = useState31(false);
7412
- const ref = useRef16(null);
7618
+ const ref = useRef17(null);
7413
7619
  const { tabIndex, currentZIndex } = useZIndex();
7414
7620
  const size2 = PlayerInternals6.useElementSize(ref, {
7415
7621
  triggerOnWindowResize: true,
@@ -7575,7 +7781,7 @@ var Combobox = ({ values, selectedId, style: customStyle, title: title4 }) => {
7575
7781
 
7576
7782
  // src/components/Preview.tsx
7577
7783
  import { PlayerInternals as PlayerInternals7 } from "@remotion/player";
7578
- import { useContext as useContext20, useEffect as useEffect31, useMemo as useMemo38, useRef as useRef19 } from "react";
7784
+ import { useContext as useContext20, useEffect as useEffect31, useMemo as useMemo38, useRef as useRef20 } from "react";
7579
7785
  import { Internals as Internals15 } from "remotion";
7580
7786
 
7581
7787
  // src/helpers/checkerboard-background.ts
@@ -7644,56 +7850,63 @@ var getAssetMetadata = async (canvasContent, addTime) => {
7644
7850
  if (canvasContent.type === "composition") {
7645
7851
  throw new Error("cannot get dimensions for composition");
7646
7852
  }
7647
- const src = getSrcFromCanvasContent(canvasContent);
7648
- const file = await fetch(src, {
7649
- method: "HEAD"
7650
- });
7651
- if (file.status === 404) {
7652
- return { type: "not-found" };
7653
- }
7654
- if (file.status !== 200) {
7655
- throw new Error(`Expected status code 200 or 404 for file, got ${file.status}`);
7656
- }
7657
- const size2 = file.headers.get("content-length");
7658
- if (!size2) {
7659
- throw new Error("Unexpected error: content-length is null");
7660
- }
7661
- const fetchedAt = Date.now();
7662
- const srcWithTime = addTime ? `${src}?date=${fetchedAt}` : src;
7663
- const fileType = getPreviewFileType(src);
7664
- if (fileType === "video") {
7665
- const resolution = await getVideoMetadata(srcWithTime);
7853
+ try {
7854
+ const src = getSrcFromCanvasContent(canvasContent);
7855
+ const file = await fetch(src, {
7856
+ method: "HEAD"
7857
+ });
7858
+ if (file.status === 404) {
7859
+ return { type: "not-found" };
7860
+ }
7861
+ if (file.status !== 200) {
7862
+ throw new Error(`Expected status code 200 or 404 for file, got ${file.status}`);
7863
+ }
7864
+ const size2 = file.headers.get("content-length");
7865
+ if (!size2) {
7866
+ throw new Error("Unexpected error: content-length is null");
7867
+ }
7868
+ const fetchedAt = Date.now();
7869
+ const srcWithTime = addTime ? `${src}?date=${fetchedAt}` : src;
7870
+ const fileType = getPreviewFileType(src);
7871
+ if (fileType === "video") {
7872
+ const resolution = await getVideoMetadata(srcWithTime);
7873
+ return {
7874
+ type: "found",
7875
+ size: Number(size2),
7876
+ dimensions: { width: resolution.width, height: resolution.height },
7877
+ fetchedAt
7878
+ };
7879
+ }
7880
+ if (fileType === "image") {
7881
+ const resolution = await new Promise((resolve, reject) => {
7882
+ const img = new Image;
7883
+ img.onload = () => {
7884
+ resolve({
7885
+ type: "found",
7886
+ size: Number(size2),
7887
+ dimensions: { width: img.width, height: img.height },
7888
+ fetchedAt
7889
+ });
7890
+ };
7891
+ img.onerror = () => {
7892
+ reject(new Error("Failed to load image"));
7893
+ };
7894
+ img.src = srcWithTime;
7895
+ });
7896
+ return resolution;
7897
+ }
7666
7898
  return {
7667
7899
  type: "found",
7900
+ dimensions: "none",
7668
7901
  size: Number(size2),
7669
- dimensions: { width: resolution.width, height: resolution.height },
7670
7902
  fetchedAt
7671
7903
  };
7904
+ } catch (err) {
7905
+ return {
7906
+ type: "metadata-error",
7907
+ error: err instanceof Error ? err : new Error(String(err))
7908
+ };
7672
7909
  }
7673
- if (fileType === "image") {
7674
- const resolution = await new Promise((resolve, reject) => {
7675
- const img = new Image;
7676
- img.onload = () => {
7677
- resolve({
7678
- type: "found",
7679
- size: Number(size2),
7680
- dimensions: { width: img.width, height: img.height },
7681
- fetchedAt
7682
- });
7683
- };
7684
- img.onerror = () => {
7685
- reject(new Error("Failed to load image"));
7686
- };
7687
- img.src = srcWithTime;
7688
- });
7689
- return resolution;
7690
- }
7691
- return {
7692
- type: "found",
7693
- dimensions: "none",
7694
- size: Number(size2),
7695
- fetchedAt
7696
- };
7697
7910
  };
7698
7911
 
7699
7912
  // src/components/FilePreview.tsx
@@ -7708,7 +7921,7 @@ import {
7708
7921
  useEffect as useEffect27,
7709
7922
  useImperativeHandle as useImperativeHandle9,
7710
7923
  useMemo as useMemo36,
7711
- useRef as useRef18,
7924
+ useRef as useRef19,
7712
7925
  useState as useState33
7713
7926
  } from "react";
7714
7927
 
@@ -7718,7 +7931,7 @@ import {
7718
7931
  useEffect as useEffect26,
7719
7932
  useImperativeHandle as useImperativeHandle8,
7720
7933
  useMemo as useMemo35,
7721
- useRef as useRef17,
7934
+ useRef as useRef18,
7722
7935
  useState as useState32
7723
7936
  } from "react";
7724
7937
  import { jsx as jsx70 } from "react/jsx-runtime";
@@ -7747,7 +7960,7 @@ var getInputBorderColor = ({
7747
7960
  var RemInputForwardRef = ({ status, rightAlign, ...props }, ref) => {
7748
7961
  const [isFocused, setIsFocused] = useState32(false);
7749
7962
  const [isHovered, setIsHovered] = useState32(false);
7750
- const inputRef = useRef17(null);
7963
+ const inputRef = useRef18(null);
7751
7964
  const { tabIndex } = useZIndex();
7752
7965
  const style5 = useMemo35(() => {
7753
7966
  return {
@@ -7805,7 +8018,7 @@ var inputBaseStyle2 = {
7805
8018
  var RemTextareaFRFunction = ({ status, ...props }, ref) => {
7806
8019
  const [isFocused, setIsFocused] = useState33(false);
7807
8020
  const [isHovered, setIsHovered] = useState33(false);
7808
- const inputRef = useRef18(null);
8021
+ const inputRef = useRef19(null);
7809
8022
  const { tabIndex } = useZIndex();
7810
8023
  useImperativeHandle9(ref, () => {
7811
8024
  return inputRef.current;
@@ -7958,6 +8171,9 @@ var FilePreview = ({ fileType, src, currentAsset, assetMetadata }) => {
7958
8171
  if (assetMetadata.type === "not-found") {
7959
8172
  throw new Error('expected to have assetMetadata, got "not-found"');
7960
8173
  }
8174
+ if (assetMetadata.type === "metadata-error") {
8175
+ throw new Error("unexpected metadata-error in FilePreview");
8176
+ }
7961
8177
  if (fileType === "audio") {
7962
8178
  return /* @__PURE__ */ jsx73("audio", {
7963
8179
  src,
@@ -8198,6 +8414,14 @@ var label4 = {
8198
8414
  fontSize: 14,
8199
8415
  color: LIGHT_TEXT
8200
8416
  };
8417
+ var assetMetadataErrorContainer = {
8418
+ marginLeft: "auto",
8419
+ marginRight: "auto",
8420
+ width: "100%",
8421
+ position: "absolute",
8422
+ height: "100%",
8423
+ overflowY: "auto"
8424
+ };
8201
8425
  var getPreviewFileType = (fileName) => {
8202
8426
  if (!fileName) {
8203
8427
  return "other";
@@ -8242,7 +8466,13 @@ var containerStyle = (options) => {
8242
8466
  backgroundPosition: getCheckerboardBackgroundPos(checkerboardSize)
8243
8467
  };
8244
8468
  };
8245
- var VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata }) => {
8469
+ var VideoPreview = ({
8470
+ canvasSize,
8471
+ contentDimensions,
8472
+ canvasContent,
8473
+ assetMetadata,
8474
+ onRetryAssetMetadata
8475
+ }) => {
8246
8476
  if (assetMetadata && assetMetadata.type === "not-found") {
8247
8477
  return /* @__PURE__ */ jsx77("div", {
8248
8478
  style: centeredContainer,
@@ -8252,6 +8482,19 @@ var VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadat
8252
8482
  })
8253
8483
  });
8254
8484
  }
8485
+ if (assetMetadata && assetMetadata.type === "metadata-error") {
8486
+ return /* @__PURE__ */ jsx77("div", {
8487
+ style: assetMetadataErrorContainer,
8488
+ className: VERTICAL_SCROLLBAR_CLASSNAME,
8489
+ children: /* @__PURE__ */ jsx77(ErrorLoader, {
8490
+ canHaveDismissButton: false,
8491
+ keyboardShortcuts: false,
8492
+ error: assetMetadata.error,
8493
+ onRetry: onRetryAssetMetadata ?? null,
8494
+ calculateMetadata: false
8495
+ }, assetMetadata.error.stack)
8496
+ });
8497
+ }
8255
8498
  if (contentDimensions === null) {
8256
8499
  return /* @__PURE__ */ jsx77("div", {
8257
8500
  style: centeredContainer,
@@ -8373,7 +8616,7 @@ var PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions }) =
8373
8616
  current?.removeChild(Internals15.portalNode());
8374
8617
  };
8375
8618
  }, []);
8376
- const portalContainer = useRef19(null);
8619
+ const portalContainer = useRef20(null);
8377
8620
  return /* @__PURE__ */ jsx77("div", {
8378
8621
  ref: portalContainer,
8379
8622
  style: style5
@@ -9868,7 +10111,7 @@ var makeSearchResults = (actions, setSelectedModal) => {
9868
10111
 
9869
10112
  // src/components/Menu/MenuItem.tsx
9870
10113
  import { PlayerInternals as PlayerInternals9 } from "@remotion/player";
9871
- import { useCallback as useCallback38, useMemo as useMemo43, useRef as useRef20, useState as useState37 } from "react";
10114
+ import { useCallback as useCallback38, useMemo as useMemo43, useRef as useRef21, useState as useState37 } from "react";
9872
10115
  import ReactDOM6 from "react-dom";
9873
10116
  import { jsx as jsx84, jsxs as jsxs39, Fragment as Fragment13 } from "react/jsx-runtime";
9874
10117
  var container21 = {
@@ -9895,7 +10138,7 @@ var MenuItem = ({
9895
10138
  menu
9896
10139
  }) => {
9897
10140
  const [hovered, setHovered] = useState37(false);
9898
- const ref = useRef20(null);
10141
+ const ref = useRef21(null);
9899
10142
  const size2 = PlayerInternals9.useElementSize(ref, {
9900
10143
  triggerOnWindowResize: true,
9901
10144
  shouldApplyCssTransforms: true
@@ -10337,10 +10580,10 @@ import React125, { useCallback as useCallback96, useContext as useContext64, use
10337
10580
  import { Internals as Internals45 } from "remotion";
10338
10581
 
10339
10582
  // src/helpers/use-breakpoint.ts
10340
- import { useEffect as useEffect35, useRef as useRef21, useState as useState41 } from "react";
10583
+ import { useEffect as useEffect35, useRef as useRef22, useState as useState41 } from "react";
10341
10584
  function useBreakpoint(breakpoint2) {
10342
10585
  const [compactUI, setCompactUI] = useState41(window.innerWidth < breakpoint2);
10343
- const compactUIRef = useRef21(compactUI);
10586
+ const compactUIRef = useRef22(compactUI);
10344
10587
  useEffect35(() => {
10345
10588
  function handleResize() {
10346
10589
  const newValue = window.innerWidth < breakpoint2;
@@ -10370,7 +10613,7 @@ import {
10370
10613
  useContext as useContext33,
10371
10614
  useEffect as useEffect38,
10372
10615
  useMemo as useMemo52,
10373
- useRef as useRef24,
10616
+ useRef as useRef25,
10374
10617
  useState as useState43
10375
10618
  } from "react";
10376
10619
  import { Internals as Internals27, watchStaticFile } from "remotion";
@@ -10520,7 +10763,7 @@ var useStudioCanvasDimensions = ({
10520
10763
  }) => {
10521
10764
  const { size: previewSize } = useContext27(Internals23.PreviewSizeContext);
10522
10765
  const { centerX, centerY, scale } = useMemo46(() => {
10523
- if (contentDimensions === "none" || contentDimensions === null || assetMetadata && assetMetadata.type === "not-found" || !canvasSize) {
10766
+ if (contentDimensions === "none" || contentDimensions === null || assetMetadata && (assetMetadata.type === "not-found" || assetMetadata.type === "metadata-error") || !canvasSize) {
10524
10767
  return {
10525
10768
  centerX: previewSize.translation.x,
10526
10769
  centerY: previewSize.translation.y,
@@ -10732,7 +10975,7 @@ import {
10732
10975
  useContext as useContext31,
10733
10976
  useEffect as useEffect37,
10734
10977
  useMemo as useMemo51,
10735
- useRef as useRef23
10978
+ useRef as useRef24
10736
10979
  } from "react";
10737
10980
 
10738
10981
  // src/helpers/editor-ruler.ts
@@ -10947,7 +11190,7 @@ import {
10947
11190
  useContext as useContext30,
10948
11191
  useEffect as useEffect36,
10949
11192
  useMemo as useMemo50,
10950
- useRef as useRef22,
11193
+ useRef as useRef23,
10951
11194
  useState as useState42
10952
11195
  } from "react";
10953
11196
  import { Internals as Internals25 } from "remotion";
@@ -10964,7 +11207,7 @@ var Ruler = ({
10964
11207
  markingGaps,
10965
11208
  orientation
10966
11209
  }) => {
10967
- const rulerCanvasRef = useRef22(null);
11210
+ const rulerCanvasRef = useRef23(null);
10968
11211
  const isVerticalRuler = orientation === "vertical";
10969
11212
  const {
10970
11213
  shouldCreateGuideRef,
@@ -11128,7 +11371,7 @@ var EditorRulers = ({ contentDimensions, canvasSize, assetMetadata, containerRef
11128
11371
  rulerMarkingGaps,
11129
11372
  scale
11130
11373
  }), [verticalRulerScaleRange, rulerMarkingGaps, scale]);
11131
- const requestAnimationFrameRef = useRef23(null);
11374
+ const requestAnimationFrameRef = useRef24(null);
11132
11375
  const onMouseMove = useCallback43((e) => {
11133
11376
  if (requestAnimationFrameRef.current) {
11134
11377
  cancelAnimationFrame(requestAnimationFrameRef.current);
@@ -11291,14 +11534,14 @@ var ZOOM_PX_FACTOR = 0.003;
11291
11534
  var Canvas = ({ canvasContent, size: size2 }) => {
11292
11535
  const { setSize, size: previewSize } = useContext33(Internals27.PreviewSizeContext);
11293
11536
  const { editorZoomGestures } = useContext33(EditorZoomGesturesContext);
11294
- const previewSnapshotRef = useRef24({
11537
+ const previewSnapshotRef = useRef25({
11295
11538
  previewSize,
11296
11539
  canvasSize: size2,
11297
11540
  contentDimensions: null
11298
11541
  });
11299
- const pinchBaseZoomRef = useRef24(null);
11300
- const suppressWheelFromWebKitPinchRef = useRef24(false);
11301
- const touchPinchRef = useRef24(null);
11542
+ const pinchBaseZoomRef = useRef25(null);
11543
+ const suppressWheelFromWebKitPinchRef = useRef25(false);
11544
+ const touchPinchRef = useRef25(null);
11302
11545
  const keybindings = useKeybinding();
11303
11546
  const config = Internals27.useUnsafeVideoConfig();
11304
11547
  const areRulersVisible = useIsRulerVisible();
@@ -11669,7 +11912,8 @@ var Canvas = ({ canvasContent, size: size2 }) => {
11669
11912
  canvasContent,
11670
11913
  contentDimensions,
11671
11914
  canvasSize: size2,
11672
- assetMetadata: assetResolution
11915
+ assetMetadata: assetResolution,
11916
+ onRetryAssetMetadata: fetchMetadata
11673
11917
  }) : null,
11674
11918
  isFit ? null : /* @__PURE__ */ jsx93("div", {
11675
11919
  style: resetZoom,
@@ -11818,7 +12062,8 @@ var CanvasOrLoading = ({ size: size2 }) => {
11818
12062
  }, [resolved, setZoom]);
11819
12063
  if (renderError) {
11820
12064
  return /* @__PURE__ */ jsx96(ErrorLoading, {
11821
- error: renderError
12065
+ error: renderError,
12066
+ calculateMetadataContext: false
11822
12067
  });
11823
12068
  }
11824
12069
  if (!canvasContent) {
@@ -11861,7 +12106,8 @@ var CanvasOrLoading = ({ size: size2 }) => {
11861
12106
  }
11862
12107
  if (resolved.type === "error") {
11863
12108
  return /* @__PURE__ */ jsx96(ErrorLoading, {
11864
- error: resolved.error
12109
+ error: resolved.error,
12110
+ calculateMetadataContext: true
11865
12111
  });
11866
12112
  }
11867
12113
  return /* @__PURE__ */ jsxs45(Fragment18, {
@@ -11880,7 +12126,7 @@ var loaderContainer = {
11880
12126
  height: "100%",
11881
12127
  overflowY: "auto"
11882
12128
  };
11883
- var ErrorLoading = ({ error }) => {
12129
+ var ErrorLoading = ({ error, calculateMetadataContext }) => {
11884
12130
  return /* @__PURE__ */ jsx96("div", {
11885
12131
  style: loaderContainer,
11886
12132
  className: VERTICAL_SCROLLBAR_CLASSNAME,
@@ -11889,7 +12135,7 @@ var ErrorLoading = ({ error }) => {
11889
12135
  keyboardShortcuts: false,
11890
12136
  error,
11891
12137
  onRetry: () => Internals29.resolveCompositionsRef.current?.reloadCurrentlySelectedComposition(),
11892
- calculateMetadata: true
12138
+ calculateMetadata: calculateMetadataContext
11893
12139
  }, error.stack)
11894
12140
  });
11895
12141
  };
@@ -12182,7 +12428,7 @@ import {
12182
12428
  useEffect as useEffect44,
12183
12429
  useImperativeHandle as useImperativeHandle11,
12184
12430
  useMemo as useMemo56,
12185
- useRef as useRef25,
12431
+ useRef as useRef26,
12186
12432
  useState as useState46
12187
12433
  } from "react";
12188
12434
  import { useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
@@ -12322,7 +12568,7 @@ var SetVisualControlsContext = createContext18({
12322
12568
  }
12323
12569
  });
12324
12570
  var VisualControlsProvider = ({ children }) => {
12325
- const imperativeHandles = useRef25({});
12571
+ const imperativeHandles = useRef26({});
12326
12572
  const [handles, setHandles] = useState46({});
12327
12573
  const state = useMemo56(() => {
12328
12574
  return {
@@ -12351,7 +12597,7 @@ var VisualControlsProvider = ({ children }) => {
12351
12597
  };
12352
12598
  }, []);
12353
12599
  const z = useZodIfPossible();
12354
- const changedRef = useRef25(false);
12600
+ const changedRef = useRef26(false);
12355
12601
  const env = useRemotionEnvironment2();
12356
12602
  const visualControl = useCallback47(function(key, value, schema) {
12357
12603
  if (handles && false) {}
@@ -13819,7 +14065,7 @@ var ZodArrayItemEditor = ({ elementSchema, onChange, jsonPath, index, value, may
13819
14065
 
13820
14066
  // src/components/RenderModal/InfoBubble.tsx
13821
14067
  import { PlayerInternals as PlayerInternals11 } from "@remotion/player";
13822
- import { useCallback as useCallback54, useEffect as useEffect46, useMemo as useMemo67, useRef as useRef26, useState as useState50 } from "react";
14068
+ import { useCallback as useCallback54, useEffect as useEffect46, useMemo as useMemo67, useRef as useRef27, useState as useState50 } from "react";
13823
14069
  import ReactDOM8 from "react-dom";
13824
14070
 
13825
14071
  // src/components/RenderModal/InfoTooltip.tsx
@@ -13904,7 +14150,7 @@ var container28 = {
13904
14150
  var InfoBubble = ({ title: title4, children }) => {
13905
14151
  const [hovered, setIsHovered] = useState50(false);
13906
14152
  const [opened, setOpened] = useState50(false);
13907
- const ref2 = useRef26(null);
14153
+ const ref2 = useRef27(null);
13908
14154
  const { tabIndex, currentZIndex } = useZIndex();
13909
14155
  const size2 = PlayerInternals11.useElementSize(ref2, {
13910
14156
  triggerOnWindowResize: true,
@@ -14162,7 +14408,7 @@ var ZodArrayEditor = ({ schema, jsonPath, setValue, value, onRemove, mayPad }) =
14162
14408
  import { useCallback as useCallback56 } from "react";
14163
14409
 
14164
14410
  // src/components/Checkbox.tsx
14165
- import { useEffect as useEffect47, useMemo as useMemo69, useRef as useRef27 } from "react";
14411
+ import { useEffect as useEffect47, useMemo as useMemo69, useRef as useRef28 } from "react";
14166
14412
  import { jsx as jsx118, jsxs as jsxs58 } from "react/jsx-runtime";
14167
14413
  var size2 = 20;
14168
14414
  var background = {
@@ -14189,7 +14435,7 @@ var box = {
14189
14435
  color: "white"
14190
14436
  };
14191
14437
  var Checkbox = ({ checked, onChange, disabled, name, rounded }) => {
14192
- const ref2 = useRef27(null);
14438
+ const ref2 = useRef28(null);
14193
14439
  const input2 = useMemo69(() => {
14194
14440
  return {
14195
14441
  appearance: "none",
@@ -14275,7 +14521,7 @@ var colorWithNewOpacity = (color, opacity, zodTypes) => {
14275
14521
  };
14276
14522
 
14277
14523
  // src/components/NewComposition/InputDragger.tsx
14278
- import React82, { useCallback as useCallback57, useEffect as useEffect48, useMemo as useMemo70, useRef as useRef28, useState as useState52 } from "react";
14524
+ import React82, { useCallback as useCallback57, useEffect as useEffect48, useMemo as useMemo70, useRef as useRef29, useState as useState52 } from "react";
14279
14525
  import { interpolate as interpolate2 } from "remotion";
14280
14526
  import { jsx as jsx120 } from "react/jsx-runtime";
14281
14527
  var isInt = (num) => {
@@ -14297,8 +14543,8 @@ var InputDraggerForwardRefFn = ({
14297
14543
  }, ref2) => {
14298
14544
  const [inputFallback, setInputFallback] = useState52(false);
14299
14545
  const [dragging, setDragging] = useState52(false);
14300
- const fallbackRef = useRef28(null);
14301
- const pointerDownRef = useRef28(false);
14546
+ const fallbackRef = useRef29(null);
14547
+ const pointerDownRef = useRef29(false);
14302
14548
  const style8 = useMemo70(() => {
14303
14549
  return {
14304
14550
  ...inputBaseStyle,
@@ -14465,7 +14711,7 @@ import {
14465
14711
  useEffect as useEffect49,
14466
14712
  useImperativeHandle as useImperativeHandle12,
14467
14713
  useMemo as useMemo71,
14468
- useRef as useRef29,
14714
+ useRef as useRef30,
14469
14715
  useState as useState53
14470
14716
  } from "react";
14471
14717
  import { jsx as jsx121 } from "react/jsx-runtime";
@@ -14477,7 +14723,7 @@ var inputBaseStyle3 = {
14477
14723
  var RemInputTypeColorForwardRef = ({ status, ...props }, ref2) => {
14478
14724
  const [isFocused, setIsFocused] = useState53(false);
14479
14725
  const [isHovered, setIsHovered] = useState53(false);
14480
- const inputRef = useRef29(null);
14726
+ const inputRef = useRef30(null);
14481
14727
  const { tabIndex } = useZIndex();
14482
14728
  const style8 = useMemo71(() => {
14483
14729
  return {
@@ -16658,7 +16904,7 @@ var ClientRenderQueueProcessor = () => {
16658
16904
  if (!compositionRef) {
16659
16905
  throw new Error(`Composition not found for job ${job.id}`);
16660
16906
  }
16661
- const { blob } = await renderStillOnWeb({
16907
+ const blob = await (await renderStillOnWeb({
16662
16908
  composition: {
16663
16909
  component: compositionRef.component,
16664
16910
  width: compositionRef.width,
@@ -16670,15 +16916,15 @@ var ClientRenderQueueProcessor = () => {
16670
16916
  id: job.compositionId
16671
16917
  },
16672
16918
  frame: job.frame,
16673
- imageFormat: job.imageFormat,
16674
16919
  inputProps: job.inputProps,
16675
16920
  delayRenderTimeoutInMilliseconds: job.delayRenderTimeout,
16676
16921
  mediaCacheSizeInBytes: job.mediaCacheSizeInBytes,
16677
16922
  logLevel: job.logLevel,
16678
16923
  licenseKey: job.licenseKey ?? undefined,
16679
16924
  scale: job.scale,
16680
- signal
16681
- });
16925
+ signal,
16926
+ allowHtmlInCanvas: job.allowHtmlInCanvas
16927
+ })).blob({ format: job.imageFormat });
16682
16928
  return {
16683
16929
  getBlob: () => Promise.resolve(blob),
16684
16930
  width: compositionRef.width,
@@ -16728,7 +16974,8 @@ var ClientRenderQueueProcessor = () => {
16728
16974
  });
16729
16975
  },
16730
16976
  outputTarget: "web-fs",
16731
- licenseKey: job.licenseKey ?? undefined
16977
+ licenseKey: job.licenseKey ?? undefined,
16978
+ allowHtmlInCanvas: job.allowHtmlInCanvas
16732
16979
  });
16733
16980
  return {
16734
16981
  getBlob,
@@ -17406,7 +17653,8 @@ var makeClientRetryPayload = (job) => {
17406
17653
  initialStillImageFormat: job.type === "client-still" ? job.imageFormat : "png",
17407
17654
  initialKeyframeIntervalInSeconds: job.type === "client-video" ? job.keyframeIntervalInSeconds : null,
17408
17655
  initialMuted: job.type === "client-video" ? job.muted : null,
17409
- initialTransparent: job.type === "client-video" ? job.transparent : null
17656
+ initialTransparent: job.type === "client-video" ? job.transparent : null,
17657
+ initialAllowHtmlInCanvas: job.allowHtmlInCanvas
17410
17658
  };
17411
17659
  };
17412
17660
 
@@ -18224,7 +18472,7 @@ var OptionsPanel = ({ readOnlyStudio }) => {
18224
18472
  };
18225
18473
 
18226
18474
  // src/components/PreviewToolbar.tsx
18227
- import { useContext as useContext61, useEffect as useEffect60, useRef as useRef32, useState as useState66 } from "react";
18475
+ import { useContext as useContext61, useEffect as useEffect60, useRef as useRef33, useState as useState66 } from "react";
18228
18476
  import { Internals as Internals44 } from "remotion";
18229
18477
 
18230
18478
  // src/state/loop.ts
@@ -18277,9 +18525,9 @@ var CheckboardToggle = () => {
18277
18525
  // src/components/FpsCounter.tsx
18278
18526
  import {
18279
18527
  useEffect as useEffect55,
18280
- useLayoutEffect as useLayoutEffect3,
18528
+ useLayoutEffect as useLayoutEffect5,
18281
18529
  useMemo as useMemo98,
18282
- useRef as useRef30,
18530
+ useRef as useRef31,
18283
18531
  useState as useState63
18284
18532
  } from "react";
18285
18533
  import { Internals as Internals37 } from "remotion";
@@ -18300,15 +18548,15 @@ var FpsCounter = ({ playbackSpeed }) => {
18300
18548
  const frame2 = Internals37.Timeline.useTimelinePosition();
18301
18549
  const [marker, rerender] = useState63({});
18302
18550
  const [fps, setFps] = useState63(0);
18303
- const previousUpdates = useRef30([]);
18304
- const fpsRef = useRef30(0);
18305
- const playingRef = useRef30(playing);
18306
- useLayoutEffect3(() => {
18551
+ const previousUpdates = useRef31([]);
18552
+ const fpsRef = useRef31(0);
18553
+ const playingRef = useRef31(playing);
18554
+ useLayoutEffect5(() => {
18307
18555
  fpsRef.current = 0;
18308
18556
  previousUpdates.current = [];
18309
18557
  playingRef.current = playing;
18310
18558
  }, [playing]);
18311
- useLayoutEffect3(() => {
18559
+ useLayoutEffect5(() => {
18312
18560
  if (playingRef.current === false)
18313
18561
  return;
18314
18562
  previousUpdates.current = pushWithMaxSize(previousUpdates.current, performance.now(), 15);
@@ -19033,7 +19281,7 @@ var PlayPause = ({ playbackRate, loop, bufferStateDelayInMilliseconds }) => {
19033
19281
 
19034
19282
  // src/components/RenderButton.tsx
19035
19283
  import { PlayerInternals as PlayerInternals14 } from "@remotion/player";
19036
- import { useCallback as useCallback94, useContext as useContext59, useMemo as useMemo100, useRef as useRef31, useState as useState65 } from "react";
19284
+ import { useCallback as useCallback94, useContext as useContext59, useMemo as useMemo100, useRef as useRef32, useState as useState65 } from "react";
19037
19285
  import ReactDOM9 from "react-dom";
19038
19286
  import { Internals as Internals42 } from "remotion";
19039
19287
  import { jsx as jsx180, jsxs as jsxs84, Fragment as Fragment24 } from "react/jsx-runtime";
@@ -19107,8 +19355,8 @@ var RenderButton = ({
19107
19355
  const { setSelectedModal } = useContext59(ModalsContext);
19108
19356
  const [preferredRenderType, setPreferredRenderType] = useState65(() => getInitialRenderType(readOnlyStudio));
19109
19357
  const [dropdownOpened, setDropdownOpened] = useState65(false);
19110
- const dropdownRef = useRef31(null);
19111
- const containerRef = useRef31(null);
19358
+ const dropdownRef = useRef32(null);
19359
+ const containerRef = useRef32(null);
19112
19360
  const { currentZIndex } = useZIndex();
19113
19361
  const size4 = PlayerInternals14.useElementSize(dropdownRef, {
19114
19362
  triggerOnWindowResize: true,
@@ -19264,7 +19512,8 @@ var RenderButton = ({
19264
19512
  initialKeyframeIntervalInSeconds: null,
19265
19513
  initialTransparent: null,
19266
19514
  initialMuted: null,
19267
- initialMediaCacheSizeInBytes: defaults.mediaCacheSizeInBytes
19515
+ initialMediaCacheSizeInBytes: defaults.mediaCacheSizeInBytes,
19516
+ initialAllowHtmlInCanvas: defaults.allowHtmlInCanvas
19268
19517
  });
19269
19518
  }, [video, setSelectedModal, getCurrentFrame2, props, inFrame, outFrame]);
19270
19519
  const onClick = useCallback94(() => {
@@ -19660,9 +19909,9 @@ var PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
19660
19909
  const { setMediaMuted } = useContext61(Internals44.SetMediaVolumeContext);
19661
19910
  const { canvasContent } = useContext61(Internals44.CompositionManager);
19662
19911
  const isVideoComposition = useIsVideoComposition();
19663
- const previewToolbarRef = useRef32(null);
19664
- const leftScrollIndicatorRef = useRef32(null);
19665
- const rightScrollIndicatorRef = useRef32(null);
19912
+ const previewToolbarRef = useRef33(null);
19913
+ const leftScrollIndicatorRef = useRef33(null);
19914
+ const rightScrollIndicatorRef = useRef33(null);
19666
19915
  const isStill = useIsStill();
19667
19916
  const [loop, setLoop] = useState66(loadLoopOption());
19668
19917
  const isFullscreenSupported = checkFullscreenSupport();
@@ -19818,7 +20067,7 @@ var PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
19818
20067
  };
19819
20068
 
19820
20069
  // src/components/Splitter/SplitterContainer.tsx
19821
- import { useMemo as useMemo101, useRef as useRef33, useState as useState67 } from "react";
20070
+ import { useMemo as useMemo101, useRef as useRef34, useState as useState67 } from "react";
19822
20071
 
19823
20072
  // src/state/timeline.ts
19824
20073
  var localStorageKey4 = (id) => `remotion.editor.timelineFlex.${id}`;
@@ -19873,8 +20122,8 @@ var containerColumn = {
19873
20122
  var SplitterContainer = ({ orientation, children, defaultFlex, maxFlex, minFlex, id }) => {
19874
20123
  const [initialTimelineFlex, persistFlex] = useTimelineFlex(id);
19875
20124
  const [flexValue, setFlexValue] = useState67(initialTimelineFlex ?? defaultFlex);
19876
- const ref2 = useRef33(null);
19877
- const isDragging = useRef33(false);
20125
+ const ref2 = useRef34(null);
20126
+ const isDragging = useRef34(false);
19878
20127
  const value = useMemo101(() => {
19879
20128
  return {
19880
20129
  flexValue,
@@ -19947,7 +20196,7 @@ var SplitterElement = ({ children, type, sticky }) => {
19947
20196
 
19948
20197
  // src/components/Splitter/SplitterHandle.tsx
19949
20198
  import { PlayerInternals as PlayerInternals15 } from "@remotion/player";
19950
- import { useContext as useContext63, useEffect as useEffect61, useRef as useRef34, useState as useState68 } from "react";
20199
+ import { useContext as useContext63, useEffect as useEffect61, useRef as useRef35, useState as useState68 } from "react";
19951
20200
  import { jsx as jsx186 } from "react/jsx-runtime";
19952
20201
  var SPLITTER_HANDLE_SIZE = 3;
19953
20202
  var containerRow2 = {
@@ -19962,7 +20211,7 @@ var SplitterHandle = ({ allowToCollapse, onCollapse }) => {
19962
20211
  throw new Error("Cannot find splitter context");
19963
20212
  }
19964
20213
  const [lastPointerUp, setLastPointerUp] = useState68(() => Date.now());
19965
- const ref2 = useRef34(null);
20214
+ const ref2 = useRef35(null);
19966
20215
  useEffect61(() => {
19967
20216
  if (context.isDragging.current) {
19968
20217
  return;
@@ -20390,7 +20639,7 @@ import {
20390
20639
  useCallback as useCallback98,
20391
20640
  useContext as useContext66,
20392
20641
  useEffect as useEffect64,
20393
- useRef as useRef35,
20642
+ useRef as useRef36,
20394
20643
  useState as useState69
20395
20644
  } from "react";
20396
20645
 
@@ -20431,8 +20680,8 @@ var UndoRedoButtons = () => {
20431
20680
  const [redoFile, setRedoFile] = useState69(null);
20432
20681
  const { subscribeToEvent } = useContext66(StudioServerConnectionCtx);
20433
20682
  const keybindings = useKeybinding();
20434
- const undoInFlight = useRef35(false);
20435
- const redoInFlight = useRef35(false);
20683
+ const undoInFlight = useRef36(false);
20684
+ const redoInFlight = useRef36(false);
20436
20685
  useEffect64(() => {
20437
20686
  const unsub = subscribeToEvent("undo-redo-stack-changed", (event) => {
20438
20687
  if (event.type !== "undo-redo-stack-changed") {
@@ -20978,7 +21227,7 @@ import {
20978
21227
  useContext as useContext70,
20979
21228
  useEffect as useEffect66,
20980
21229
  useMemo as useMemo108,
20981
- useRef as useRef36,
21230
+ useRef as useRef37,
20982
21231
  useState as useState73
20983
21232
  } from "react";
20984
21233
  import { Internals as Internals47, useVideoConfig as useVideoConfig4 } from "remotion";
@@ -21142,7 +21391,7 @@ var Inner2 = () => {
21142
21391
  dragging: false
21143
21392
  });
21144
21393
  const { playing, play, pause, seek } = PlayerInternals16.usePlayer();
21145
- const scroller = useRef36(null);
21394
+ const scroller = useRef37(null);
21146
21395
  const stopInterval = () => {
21147
21396
  if (scroller.current) {
21148
21397
  clearInterval(scroller.current);
@@ -21518,7 +21767,7 @@ var Inner2 = () => {
21518
21767
 
21519
21768
  // src/components/Timeline/TimelineList.tsx
21520
21769
  import { PlayerInternals as PlayerInternals18 } from "@remotion/player";
21521
- import { useRef as useRef40 } from "react";
21770
+ import { useRef as useRef41 } from "react";
21522
21771
 
21523
21772
  // src/components/Timeline/TimelineListItem.tsx
21524
21773
  import { useCallback as useCallback111, useContext as useContext74, useMemo as useMemo116 } from "react";
@@ -22418,7 +22667,7 @@ import {
22418
22667
  useContext as useContext73,
22419
22668
  useEffect as useEffect67,
22420
22669
  useMemo as useMemo115,
22421
- useRef as useRef37,
22670
+ useRef as useRef38,
22422
22671
  useState as useState78
22423
22672
  } from "react";
22424
22673
  import { Internals as Internals49 } from "remotion";
@@ -22448,15 +22697,16 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22448
22697
  const locationSource = validatedLocation?.source ?? null;
22449
22698
  const locationLine = validatedLocation?.line ?? null;
22450
22699
  const locationColumn = validatedLocation?.column ?? null;
22451
- const currentLocationSource = useRef37(locationSource);
22700
+ const currentLocationSource = useRef38(locationSource);
22452
22701
  currentLocationSource.current = locationSource;
22453
- const currentLocationLine = useRef37(locationLine);
22702
+ const currentLocationLine = useRef38(locationLine);
22454
22703
  currentLocationLine.current = locationLine;
22455
- const currentLocationColumn = useRef37(locationColumn);
22704
+ const currentLocationColumn = useRef38(locationColumn);
22456
22705
  currentLocationColumn.current = locationColumn;
22457
- const nodePathRef = useRef37(null);
22706
+ const nodePathRef = useRef38(null);
22458
22707
  const [nodePath, setNodePath] = useState78(null);
22459
- const isMountedRef = useRef37(true);
22708
+ const [jsxInMapCallback, setJsxInMapCallback] = useState78(false);
22709
+ const isMountedRef = useRef38(true);
22460
22710
  const setNodePathBoth = useCallback110((next) => {
22461
22711
  nodePathRef.current = next;
22462
22712
  setNodePath(next);
@@ -22471,11 +22721,13 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22471
22721
  if (!visualModeEnabled) {
22472
22722
  setPropStatusesForSequence(null);
22473
22723
  setNodePathBoth(null);
22724
+ setJsxInMapCallback(false);
22474
22725
  return;
22475
22726
  }
22476
22727
  if (!clientId || !locationSource || !locationLine || locationColumn === null || !schemaKeysString) {
22477
22728
  setPropStatusesForSequence(null);
22478
22729
  setNodePathBoth(null);
22730
+ setJsxInMapCallback(false);
22479
22731
  return;
22480
22732
  }
22481
22733
  const keys = schemaKeysString.split(",");
@@ -22492,12 +22744,15 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22492
22744
  if (result.canUpdate) {
22493
22745
  setNodePathBoth(result.nodePath);
22494
22746
  setPropStatusesForSequence(result.props);
22747
+ setJsxInMapCallback(result.jsxInMapCallback);
22495
22748
  } else {
22496
22749
  setNodePathBoth(null);
22497
22750
  setPropStatusesForSequence(null);
22751
+ setJsxInMapCallback(false);
22498
22752
  }
22499
22753
  }).catch((err) => {
22500
22754
  setNodePathBoth(null);
22755
+ setJsxInMapCallback(false);
22501
22756
  Internals49.Log.error(err);
22502
22757
  setPropStatusesForSequence(null);
22503
22758
  });
@@ -22507,6 +22762,7 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22507
22762
  setPropStatusesForSequence(null);
22508
22763
  }
22509
22764
  setNodePathBoth(null);
22765
+ setJsxInMapCallback(false);
22510
22766
  if (currentNodePath) {
22511
22767
  callApi("/api/unsubscribe-from-sequence-props", {
22512
22768
  fileName: locationSource,
@@ -22541,9 +22797,11 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22541
22797
  }
22542
22798
  if (event.result.canUpdate) {
22543
22799
  setPropStatusesForSequence(event.result.props);
22800
+ setJsxInMapCallback(event.result.jsxInMapCallback);
22544
22801
  } else {
22545
22802
  setPropStatusesForSequence(null);
22546
22803
  setNodePathBoth(null);
22804
+ setJsxInMapCallback(false);
22547
22805
  }
22548
22806
  };
22549
22807
  const unsub = subscribeToEvent("sequence-props-updated", listener);
@@ -22559,7 +22817,7 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22559
22817
  setPropStatusesForSequence,
22560
22818
  setNodePathBoth
22561
22819
  ]);
22562
- return nodePath;
22820
+ return { nodePath, jsxInMapCallback };
22563
22821
  };
22564
22822
 
22565
22823
  // src/components/Timeline/TimelineListItem.tsx
@@ -22595,7 +22853,7 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22595
22853
  const { hidden, setHidden } = useContext74(Internals50.SequenceVisibilityToggleContext);
22596
22854
  const { expandedTracks, toggleTrack } = useContext74(ExpandedTracksContext);
22597
22855
  const originalLocation = useResolvedStack(sequence.stack ?? null);
22598
- const nodePath = useSequencePropsSubscription(sequence, originalLocation, visualModeActive);
22856
+ const { nodePath, jsxInMapCallback } = useSequencePropsSubscription(sequence, originalLocation, visualModeActive);
22599
22857
  const validatedLocation = useMemo116(() => {
22600
22858
  if (!originalLocation || !originalLocation.source || !originalLocation.line) {
22601
22859
  return null;
@@ -22608,6 +22866,31 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22608
22866
  }, [originalLocation]);
22609
22867
  const canDeleteFromSource = Boolean(nodePath && validatedLocation?.source);
22610
22868
  const deleteDisabled = useMemo116(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
22869
+ const duplicateDisabled = deleteDisabled;
22870
+ const onDuplicateSequenceFromSource = useCallback111(async () => {
22871
+ if (!validatedLocation?.source || !nodePath) {
22872
+ return;
22873
+ }
22874
+ if (jsxInMapCallback) {
22875
+ const message = "This sequence is rendered inside a .map() callback. Duplicating inserts another copy in that callback (affecting each list item). Continue?";
22876
+ if (!window.confirm(message)) {
22877
+ return;
22878
+ }
22879
+ }
22880
+ try {
22881
+ const result = await callApi("/api/duplicate-jsx-node", {
22882
+ fileName: validatedLocation.source,
22883
+ nodePath
22884
+ });
22885
+ if (result.success) {
22886
+ showNotification("Duplicated sequence in source file", 2000);
22887
+ } else {
22888
+ showNotification(result.reason, 4000);
22889
+ }
22890
+ } catch (err) {
22891
+ showNotification(err.message, 4000);
22892
+ }
22893
+ }, [jsxInMapCallback, nodePath, validatedLocation?.source]);
22611
22894
  const onDeleteSequenceFromSource = useCallback111(async () => {
22612
22895
  if (!validatedLocation?.source || !nodePath) {
22613
22896
  return;
@@ -22631,6 +22914,23 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22631
22914
  return [];
22632
22915
  }
22633
22916
  return [
22917
+ {
22918
+ type: "item",
22919
+ id: "duplicate-sequence",
22920
+ keyHint: null,
22921
+ label: "Duplicate",
22922
+ leftItem: null,
22923
+ disabled: duplicateDisabled,
22924
+ onClick: () => {
22925
+ if (duplicateDisabled) {
22926
+ return;
22927
+ }
22928
+ onDuplicateSequenceFromSource();
22929
+ },
22930
+ quickSwitcherLabel: null,
22931
+ subMenu: null,
22932
+ value: "duplicate-sequence"
22933
+ },
22634
22934
  {
22635
22935
  type: "item",
22636
22936
  id: "delete-sequence",
@@ -22649,7 +22949,13 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22649
22949
  value: "delete-sequence"
22650
22950
  }
22651
22951
  ];
22652
- }, [deleteDisabled, onDeleteSequenceFromSource, visualModeEnvEnabled]);
22952
+ }, [
22953
+ deleteDisabled,
22954
+ duplicateDisabled,
22955
+ onDeleteSequenceFromSource,
22956
+ onDuplicateSequenceFromSource,
22957
+ visualModeEnvEnabled
22958
+ ]);
22653
22959
  const isExpanded = visualModeActive && (expandedTracks[sequence.id] ?? false);
22654
22960
  const onToggleExpand = useCallback111(() => {
22655
22961
  toggleTrack(sequence.id);
@@ -22748,7 +23054,7 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22748
23054
  };
22749
23055
 
22750
23056
  // src/components/Timeline/TimelineTimeIndicators.tsx
22751
- import { useContext as useContext75, useEffect as useEffect69, useMemo as useMemo117, useRef as useRef39 } from "react";
23057
+ import { useContext as useContext75, useEffect as useEffect69, useMemo as useMemo117, useRef as useRef40 } from "react";
22752
23058
  import { Internals as Internals52 } from "remotion";
22753
23059
 
22754
23060
  // src/components/TimeValue.tsx
@@ -22757,7 +23063,7 @@ import {
22757
23063
  useCallback as useCallback112,
22758
23064
  useEffect as useEffect68,
22759
23065
  useImperativeHandle as useImperativeHandle14,
22760
- useRef as useRef38
23066
+ useRef as useRef39
22761
23067
  } from "react";
22762
23068
  import { Internals as Internals51, useCurrentFrame } from "remotion";
22763
23069
  import { jsx as jsx208, jsxs as jsxs100 } from "react/jsx-runtime";
@@ -22790,7 +23096,7 @@ var TimeValue = () => {
22790
23096
  const isStill = useIsStill();
22791
23097
  const { seek, play, pause, toggle } = PlayerInternals17.usePlayer();
22792
23098
  const keybindings = useKeybinding();
22793
- const ref2 = useRef38(null);
23099
+ const ref2 = useRef39(null);
22794
23100
  const onTextChange = useCallback112((newVal) => {
22795
23101
  seek(parseInt(newVal, 10));
22796
23102
  }, [seek]);
@@ -22918,7 +23224,7 @@ var TimelineTimeIndicators = () => {
22918
23224
  });
22919
23225
  };
22920
23226
  var Inner3 = ({ windowWidth, durationInFrames, fps }) => {
22921
- const ref2 = useRef39(null);
23227
+ const ref2 = useRef40(null);
22922
23228
  useEffect69(() => {
22923
23229
  const currentRef = ref2.current;
22924
23230
  if (!currentRef) {
@@ -23001,7 +23307,7 @@ var container42 = {
23001
23307
  background: BACKGROUND
23002
23308
  };
23003
23309
  var TimelineList = ({ timeline }) => {
23004
- const ref2 = useRef40(null);
23310
+ const ref2 = useRef41(null);
23005
23311
  const size4 = PlayerInternals18.useElementSize(ref2, {
23006
23312
  shouldApplyCssTransforms: false,
23007
23313
  triggerOnWindowResize: false
@@ -23026,7 +23332,7 @@ var TimelineList = ({ timeline }) => {
23026
23332
  };
23027
23333
 
23028
23334
  // src/components/Timeline/TimelinePinchZoom.tsx
23029
- import { useCallback as useCallback113, useContext as useContext76, useEffect as useEffect70, useRef as useRef41 } from "react";
23335
+ import { useCallback as useCallback113, useContext as useContext76, useEffect as useEffect70, useRef as useRef42 } from "react";
23030
23336
  import { Internals as Internals53 } from "remotion";
23031
23337
  var ZOOM_WHEEL_DELTA = 0.06;
23032
23338
  var TimelinePinchZoom = () => {
@@ -23035,11 +23341,11 @@ var TimelinePinchZoom = () => {
23035
23341
  const { canvasContent } = useContext76(Internals53.CompositionManager);
23036
23342
  const { zoom, setZoom } = useContext76(TimelineZoomCtx);
23037
23343
  const { editorZoomGestures } = useContext76(EditorZoomGesturesContext);
23038
- const zoomRef = useRef41(zoom);
23344
+ const zoomRef = useRef42(zoom);
23039
23345
  zoomRef.current = zoom;
23040
- const pinchBaseZoomRef = useRef41(null);
23041
- const suppressWheelFromWebKitPinchRef = useRef41(false);
23042
- const touchPinchRef = useRef41(null);
23346
+ const pinchBaseZoomRef = useRef42(null);
23347
+ const suppressWheelFromWebKitPinchRef = useRef42(false);
23348
+ const touchPinchRef = useRef42(null);
23043
23349
  const onWheel = useCallback113((e) => {
23044
23350
  if (!editorZoomGestures || !isVideoComposition) {
23045
23351
  return;
@@ -23458,7 +23764,7 @@ var useMaxMediaDuration = (s, fps) => {
23458
23764
  };
23459
23765
 
23460
23766
  // src/components/AudioWaveform.tsx
23461
- import { useEffect as useEffect73, useMemo as useMemo119, useRef as useRef42, useState as useState80 } from "react";
23767
+ import { useEffect as useEffect73, useMemo as useMemo119, useRef as useRef43, useState as useState80 } from "react";
23462
23768
  import { Internals as Internals55 } from "remotion";
23463
23769
 
23464
23770
  // src/components/parse-color.ts
@@ -23637,9 +23943,9 @@ var AudioWaveform = ({
23637
23943
  if (vidConf === null) {
23638
23944
  throw new Error("Expected video config");
23639
23945
  }
23640
- const containerRef = useRef42(null);
23641
- const waveformCanvas = useRef42(null);
23642
- const volumeCanvas = useRef42(null);
23946
+ const containerRef = useRef43(null);
23947
+ const waveformCanvas = useRef43(null);
23948
+ const volumeCanvas = useRef43(null);
23643
23949
  useEffect73(() => {
23644
23950
  const controller = new AbortController;
23645
23951
  setError(null);
@@ -23835,7 +24141,7 @@ var LoopedTimelineIndicator = ({ loops }) => {
23835
24141
  };
23836
24142
 
23837
24143
  // src/components/Timeline/TimelineImageInfo.tsx
23838
- import { useEffect as useEffect74, useRef as useRef43 } from "react";
24144
+ import { useEffect as useEffect74, useRef as useRef44 } from "react";
23839
24145
  import { jsx as jsx215 } from "react/jsx-runtime";
23840
24146
  var HEIGHT = getTimelineLayerHeight("image") - 2;
23841
24147
  var containerStyle3 = {
@@ -23847,7 +24153,7 @@ var containerStyle3 = {
23847
24153
  borderBottomLeftRadius: 2
23848
24154
  };
23849
24155
  var TimelineImageInfo = ({ src, visualizationWidth }) => {
23850
- const ref2 = useRef43(null);
24156
+ const ref2 = useRef44(null);
23851
24157
  useEffect74(() => {
23852
24158
  const { current } = ref2;
23853
24159
  if (!current) {
@@ -23912,7 +24218,7 @@ var TimelineSequenceFrame = ({ roundedFrame, premounted, postmounted }) => {
23912
24218
  };
23913
24219
 
23914
24220
  // src/components/Timeline/TimelineVideoInfo.tsx
23915
- import { useEffect as useEffect75, useMemo as useMemo120, useRef as useRef44, useState as useState81 } from "react";
24221
+ import { useEffect as useEffect75, useMemo as useMemo120, useRef as useRef45, useState as useState81 } from "react";
23916
24222
  import { useVideoConfig as useVideoConfig5 } from "remotion";
23917
24223
 
23918
24224
  // src/helpers/extract-frames.ts
@@ -24273,9 +24579,9 @@ var TimelineVideoInfo = ({
24273
24579
  postmountWidth
24274
24580
  }) => {
24275
24581
  const { fps } = useVideoConfig5();
24276
- const ref2 = useRef44(null);
24582
+ const ref2 = useRef45(null);
24277
24583
  const [error, setError] = useState81(null);
24278
- const aspectRatio = useRef44(getAspectRatioFromCache(src));
24584
+ const aspectRatio = useRef45(getAspectRatioFromCache(src));
24279
24585
  useEffect75(() => {
24280
24586
  if (error) {
24281
24587
  return;
@@ -26250,7 +26556,7 @@ import {
26250
26556
  useContext as useContext91,
26251
26557
  useEffect as useEffect81,
26252
26558
  useMemo as useMemo131,
26253
- useRef as useRef46,
26559
+ useRef as useRef47,
26254
26560
  useState as useState87
26255
26561
  } from "react";
26256
26562
  import { Internals as Internals64 } from "remotion";
@@ -27148,7 +27454,7 @@ var QuickSwitcherNoResults = ({ query, mode }) => {
27148
27454
  };
27149
27455
 
27150
27456
  // src/components/QuickSwitcher/QuickSwitcherResult.tsx
27151
- import { useEffect as useEffect80, useMemo as useMemo130, useRef as useRef45, useState as useState86 } from "react";
27457
+ import { useEffect as useEffect80, useMemo as useMemo130, useRef as useRef46, useState as useState86 } from "react";
27152
27458
  import { jsx as jsx239, jsxs as jsxs122, Fragment as Fragment37 } from "react/jsx-runtime";
27153
27459
  var container50 = {
27154
27460
  paddingLeft: 16,
@@ -27178,7 +27484,7 @@ var labelContainer = {
27178
27484
  };
27179
27485
  var QuickSwitcherResult = ({ result, selected }) => {
27180
27486
  const [hovered, setIsHovered] = useState86(false);
27181
- const ref2 = useRef45(null);
27487
+ const ref2 = useRef46(null);
27182
27488
  const keybindings = useKeybinding();
27183
27489
  useEffect80(() => {
27184
27490
  const { current } = ref2;
@@ -27356,7 +27662,7 @@ var QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio }
27356
27662
  selectedIndex: 0
27357
27663
  });
27358
27664
  }, [initialMode, invocationTimestamp]);
27359
- const inputRef = useRef46(null);
27665
+ const inputRef = useRef47(null);
27360
27666
  const selectComposition = useSelectComposition();
27361
27667
  const closeMenu = useCallback122(() => {
27362
27668
  return;
@@ -28132,7 +28438,7 @@ import {
28132
28438
  useEffect as useEffect84,
28133
28439
  useMemo as useMemo142,
28134
28440
  useReducer as useReducer2,
28135
- useRef as useRef48,
28441
+ useRef as useRef49,
28136
28442
  useState as useState93
28137
28443
  } from "react";
28138
28444
 
@@ -28640,8 +28946,9 @@ var padding3 = {
28640
28946
  var title6 = {
28641
28947
  fontSize: 14
28642
28948
  };
28949
+ var DESCRIPTION_FONT_SIZE_PX = 14;
28643
28950
  var description = {
28644
- fontSize: 14,
28951
+ fontSize: DESCRIPTION_FONT_SIZE_PX,
28645
28952
  maxWidth: 400
28646
28953
  };
28647
28954
  var link3 = {
@@ -28700,9 +29007,22 @@ var OptionExplainer = ({ option }) => {
28700
29007
  }) : null
28701
29008
  ]
28702
29009
  }),
28703
- /* @__PURE__ */ jsx253("div", {
29010
+ /* @__PURE__ */ jsxs127("div", {
28704
29011
  style: description,
28705
- children: option.description("ssr")
29012
+ children: [
29013
+ /* @__PURE__ */ jsx253("style", {
29014
+ children: `
29015
+ .__remotion-option-explainer-description a,
29016
+ .__remotion-option-explainer-description code {
29017
+ font-size: ${DESCRIPTION_FONT_SIZE_PX}px;
29018
+ }
29019
+ `
29020
+ }),
29021
+ /* @__PURE__ */ jsx253("div", {
29022
+ className: "__remotion-option-explainer-description",
29023
+ children: option.description("ssr")
29024
+ })
29025
+ ]
28706
29026
  })
28707
29027
  ]
28708
29028
  }),
@@ -30121,12 +30441,12 @@ import { BrowserSafeApis as BrowserSafeApis7 } from "@remotion/renderer/client";
30121
30441
  import { useCallback as useCallback134, useMemo as useMemo137 } from "react";
30122
30442
 
30123
30443
  // src/helpers/use-file-existence.ts
30124
- import { useContext as useContext93, useEffect as useEffect83, useRef as useRef47, useState as useState92 } from "react";
30444
+ import { useContext as useContext93, useEffect as useEffect83, useRef as useRef48, useState as useState92 } from "react";
30125
30445
  var useFileExistence = (outName) => {
30126
30446
  const [exists, setExists] = useState92(false);
30127
30447
  const { previewServerState: state, subscribeToEvent } = useContext93(StudioServerConnectionCtx);
30128
30448
  const clientId = state.type === "connected" ? state.clientId : undefined;
30129
- const currentOutName = useRef47("");
30449
+ const currentOutName = useRef48("");
30130
30450
  currentOutName.current = outName;
30131
30451
  useEffect83(() => {
30132
30452
  if (!clientId) {
@@ -31519,7 +31839,7 @@ var RenderModal = ({
31519
31839
  resolved: { result: resolvedComposition },
31520
31840
  unresolved: unresolvedComposition
31521
31841
  } = context;
31522
- const isMounted = useRef48(true);
31842
+ const isMounted = useRef49(true);
31523
31843
  const [isVideo] = useState93(() => {
31524
31844
  return typeof resolvedComposition.durationInFrames === "undefined" ? true : resolvedComposition.durationInFrames > 1;
31525
31845
  });
@@ -32665,9 +32985,9 @@ import {
32665
32985
  getEncodableAudioCodecs,
32666
32986
  getSupportedAudioCodecsForContainer
32667
32987
  } from "@remotion/web-renderer";
32668
- import { useEffect as useEffect85, useRef as useRef49, useState as useState94 } from "react";
32988
+ import { useEffect as useEffect85, useRef as useRef50, useState as useState94 } from "react";
32669
32989
  var useEncodableAudioCodecs = (container61) => {
32670
- const cacheRef = useRef49({});
32990
+ const cacheRef = useRef50({});
32671
32991
  const [codecsByContainer, setCodecsByContainer] = useState94(() => {
32672
32992
  return {
32673
32993
  [container61]: getSupportedAudioCodecsForContainer(container61)
@@ -32707,9 +33027,9 @@ import {
32707
33027
  getEncodableVideoCodecs,
32708
33028
  getSupportedVideoCodecsForContainer
32709
33029
  } from "@remotion/web-renderer";
32710
- import { useEffect as useEffect86, useRef as useRef50, useState as useState95 } from "react";
33030
+ import { useEffect as useEffect86, useRef as useRef51, useState as useState95 } from "react";
32711
33031
  var useEncodableVideoCodecs = (container61) => {
32712
- const cacheRef = useRef50({});
33032
+ const cacheRef = useRef51({});
32713
33033
  const [codecsByContainer, setCodecsByContainer] = useState95(() => {
32714
33034
  return {
32715
33035
  [container61]: getSupportedVideoCodecsForContainer(container61)
@@ -32820,7 +33140,9 @@ var WebRenderModalAdvanced = ({
32820
33140
  mediaCacheSizeInBytes,
32821
33141
  setMediaCacheSizeInBytes,
32822
33142
  hardwareAcceleration,
32823
- setHardwareAcceleration
33143
+ setHardwareAcceleration,
33144
+ allowHtmlInCanvas,
33145
+ setAllowHtmlInCanvas
32824
33146
  }) => {
32825
33147
  const toggleCustomMediaCacheSizeInBytes = useCallback143(() => {
32826
33148
  setMediaCacheSizeInBytes((previous) => {
@@ -32830,6 +33152,9 @@ var WebRenderModalAdvanced = ({
32830
33152
  return null;
32831
33153
  });
32832
33154
  }, [setMediaCacheSizeInBytes]);
33155
+ const toggleAllowHtmlInCanvas = useCallback143(() => {
33156
+ setAllowHtmlInCanvas((prev) => !prev);
33157
+ }, [setAllowHtmlInCanvas]);
32833
33158
  const changeMediaCacheSizeInBytes = useCallback143((cb) => {
32834
33159
  setMediaCacheSizeInBytes((prev) => {
32835
33160
  if (prev === null) {
@@ -32941,7 +33266,32 @@ var WebRenderModalAdvanced = ({
32941
33266
  })
32942
33267
  })
32943
33268
  ]
32944
- }) : null
33269
+ }) : null,
33270
+ /* @__PURE__ */ jsxs146("div", {
33271
+ style: optionRow,
33272
+ children: [
33273
+ /* @__PURE__ */ jsxs146("div", {
33274
+ style: label6,
33275
+ children: [
33276
+ "Allow HTML-in-canvas ",
33277
+ /* @__PURE__ */ jsx278(Spacing, {
33278
+ x: 0.5
33279
+ }),
33280
+ /* @__PURE__ */ jsx278(OptionExplainerBubble, {
33281
+ id: "allowHtmlInCanvasOption"
33282
+ })
33283
+ ]
33284
+ }),
33285
+ /* @__PURE__ */ jsx278("div", {
33286
+ style: rightRow,
33287
+ children: /* @__PURE__ */ jsx278(Checkbox, {
33288
+ checked: allowHtmlInCanvas,
33289
+ onChange: toggleAllowHtmlInCanvas,
33290
+ name: "allow-html-in-canvas"
33291
+ })
33292
+ })
33293
+ ]
33294
+ })
32945
33295
  ]
32946
33296
  });
32947
33297
  };
@@ -33958,7 +34308,8 @@ var WebRenderModal = ({
33958
34308
  initialHardwareAcceleration,
33959
34309
  initialKeyframeIntervalInSeconds,
33960
34310
  initialTransparent,
33961
- initialMuted
34311
+ initialMuted,
34312
+ initialAllowHtmlInCanvas
33962
34313
  }) => {
33963
34314
  const context = useContext95(ResolvedCompositionContext);
33964
34315
  const { setSelectedModal } = useContext95(ModalsContext);
@@ -33998,6 +34349,7 @@ var WebRenderModal = ({
33998
34349
  const [muted, setMuted] = useState97(initialMuted ?? false);
33999
34350
  const [scale, setScale] = useState97(initialScale ?? 1);
34000
34351
  const [licenseKey, setLicenseKey] = useState97(initialLicenseKey);
34352
+ const [allowHtmlInCanvas, setAllowHtmlInCanvas] = useState97(initialAllowHtmlInCanvas ?? false);
34001
34353
  const encodableAudioCodecs = useEncodableAudioCodecs(container62);
34002
34354
  const encodableVideoCodecs = useEncodableVideoCodecs(container62);
34003
34355
  const effectiveAudioCodec = useMemo147(() => {
@@ -34190,7 +34542,8 @@ var WebRenderModal = ({
34190
34542
  mediaCacheSizeInBytes,
34191
34543
  logLevel,
34192
34544
  licenseKey,
34193
- scale
34545
+ scale,
34546
+ allowHtmlInCanvas
34194
34547
  }, compositionRef);
34195
34548
  } else {
34196
34549
  addClientVideoJob({
@@ -34213,7 +34566,8 @@ var WebRenderModal = ({
34213
34566
  mediaCacheSizeInBytes,
34214
34567
  logLevel,
34215
34568
  licenseKey,
34216
- scale
34569
+ scale,
34570
+ allowHtmlInCanvas
34217
34571
  }, compositionRef);
34218
34572
  }
34219
34573
  setSidebarCollapsedState({ left: null, right: "expanded" });
@@ -34253,7 +34607,8 @@ var WebRenderModal = ({
34253
34607
  setSelectedModal,
34254
34608
  addClientStillJob,
34255
34609
  addClientVideoJob,
34256
- scale
34610
+ scale,
34611
+ allowHtmlInCanvas
34257
34612
  ]);
34258
34613
  return /* @__PURE__ */ jsxs152("div", {
34259
34614
  style: outerModalStyle,
@@ -34448,7 +34803,9 @@ var WebRenderModal = ({
34448
34803
  mediaCacheSizeInBytes,
34449
34804
  setMediaCacheSizeInBytes,
34450
34805
  hardwareAcceleration,
34451
- setHardwareAcceleration
34806
+ setHardwareAcceleration,
34807
+ allowHtmlInCanvas,
34808
+ setAllowHtmlInCanvas
34452
34809
  }) : /* @__PURE__ */ jsx286(WebRenderModalLicense, {
34453
34810
  licenseKey,
34454
34811
  setLicenseKey,
@@ -35094,15 +35451,15 @@ var SetTimelineInOutProvider = ({ children }) => {
35094
35451
  };
35095
35452
 
35096
35453
  // src/components/ShowGuidesProvider.tsx
35097
- import { useCallback as useCallback153, useMemo as useMemo156, useRef as useRef51, useState as useState106 } from "react";
35454
+ import { useCallback as useCallback153, useMemo as useMemo156, useRef as useRef52, useState as useState106 } from "react";
35098
35455
  import { jsx as jsx298 } from "react/jsx-runtime";
35099
35456
  var ShowGuidesProvider = ({ children }) => {
35100
35457
  const [guidesList, setGuidesList] = useState106(() => loadGuidesList());
35101
35458
  const [selectedGuideId, setSelectedGuideId] = useState106(null);
35102
35459
  const [hoveredGuideId, setHoveredGuideId] = useState106(null);
35103
35460
  const [editorShowGuides, setEditorShowGuidesState] = useState106(() => loadEditorShowGuidesOption());
35104
- const shouldCreateGuideRef = useRef51(false);
35105
- const shouldDeleteGuideRef = useRef51(false);
35461
+ const shouldCreateGuideRef = useRef52(false);
35462
+ const shouldDeleteGuideRef = useRef52(false);
35106
35463
  const setEditorShowGuides = useCallback153((newValue) => {
35107
35464
  setEditorShowGuidesState((prevState) => {
35108
35465
  const newVal = newValue(prevState);
@@ -35817,7 +36174,7 @@ var StudioInner = ({ rootComponent, readOnly, visualModeEnabled }) => {
35817
36174
  });
35818
36175
  };
35819
36176
  var Studio = ({ rootComponent, readOnly, visualModeEnabled }) => {
35820
- useLayoutEffect4(() => {
36177
+ useLayoutEffect6(() => {
35821
36178
  injectCSS();
35822
36179
  }, []);
35823
36180
  return /* @__PURE__ */ jsx305(FastRefreshProvider, {