@remotion/studio 4.0.445 → 4.0.446

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.
@@ -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";
@@ -5280,6 +5370,18 @@ var CompositionSelectorItem = ({
5280
5370
  const onPointerLeave = useCallback25(() => {
5281
5371
  setHovered(false);
5282
5372
  }, []);
5373
+ const compositionRowRef = useRef13(null);
5374
+ const compositionId = item.type === "composition" ? item.composition.id : null;
5375
+ useLayoutEffect3(() => {
5376
+ if (compositionId === null) {
5377
+ return;
5378
+ }
5379
+ maybeScrollCompositionSidebarRowIntoView({
5380
+ element: compositionRowRef.current,
5381
+ compositionId,
5382
+ selected
5383
+ });
5384
+ }, [compositionId, selected]);
5283
5385
  const style3 = useMemo25(() => {
5284
5386
  return {
5285
5387
  ...itemStyle,
@@ -5296,6 +5398,7 @@ var CompositionSelectorItem = ({
5296
5398
  const onClick = useCallback25((evt) => {
5297
5399
  evt.preventDefault();
5298
5400
  if (item.type === "composition") {
5401
+ markCompositionSidebarScrollFromRowClick(item.composition.id);
5299
5402
  selectComposition(item.composition, true);
5300
5403
  } else {
5301
5404
  toggleFolder(item.folderName, item.parentName);
@@ -5430,6 +5533,7 @@ var CompositionSelectorItem = ({
5430
5533
  children: /* @__PURE__ */ jsx52(Row, {
5431
5534
  align: "center",
5432
5535
  children: /* @__PURE__ */ jsxs22("a", {
5536
+ ref: compositionRowRef,
5433
5537
  style: style3,
5434
5538
  onPointerEnter,
5435
5539
  onPointerLeave,
@@ -5740,7 +5844,7 @@ var writeStaticFile = async ({
5740
5844
  };
5741
5845
 
5742
5846
  // src/helpers/use-asset-drag-events.ts
5743
- import { useCallback as useCallback27, useEffect as useEffect20, useMemo as useMemo27, useRef as useRef13 } from "react";
5847
+ import { useCallback as useCallback27, useEffect as useEffect20, useMemo as useMemo27, useRef as useRef14 } from "react";
5744
5848
  import { NoReactInternals } from "remotion/no-react";
5745
5849
  function useAssetDragEvents({
5746
5850
  name,
@@ -5748,7 +5852,7 @@ function useAssetDragEvents({
5748
5852
  dropLocation,
5749
5853
  setDropLocation
5750
5854
  }) {
5751
- const dragDepthRef = useRef13(0);
5855
+ const dragDepthRef = useRef14(0);
5752
5856
  const combinedParents = useMemo27(() => {
5753
5857
  return [parentFolder, name].filter(NoReactInternals.truthy).join("/");
5754
5858
  }, [name, parentFolder]);
@@ -5781,7 +5885,14 @@ function useAssetDragEvents({
5781
5885
  var use_asset_drag_events_default = useAssetDragEvents;
5782
5886
 
5783
5887
  // src/components/AssetSelectorItem.tsx
5784
- import React39, { useCallback as useCallback28, useContext as useContext11, useMemo as useMemo28, useRef as useRef14, useState as useState23 } from "react";
5888
+ import React39, {
5889
+ useCallback as useCallback28,
5890
+ useContext as useContext11,
5891
+ useLayoutEffect as useLayoutEffect4,
5892
+ useMemo as useMemo28,
5893
+ useRef as useRef15,
5894
+ useState as useState23
5895
+ } from "react";
5785
5896
  import { Internals as Internals10 } from "remotion";
5786
5897
  import { NoReactInternals as NoReactInternals3 } from "remotion/no-react";
5787
5898
 
@@ -6165,7 +6276,7 @@ var AssetFolderItem = ({
6165
6276
  readOnlyStudio
6166
6277
  }) => {
6167
6278
  const [hovered, setHovered] = useState23(false);
6168
- const openFolderTimerRef = useRef14(null);
6279
+ const openFolderTimerRef = useRef15(null);
6169
6280
  const { isDropDiv, onDragEnter, onDragLeave } = use_asset_drag_events_default({
6170
6281
  name: item.name,
6171
6282
  parentFolder,
@@ -6312,7 +6423,16 @@ var AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio }
6312
6423
  const onPointerLeave = useCallback28(() => {
6313
6424
  setHovered(false);
6314
6425
  }, []);
6426
+ const rowRef = useRef15(null);
6427
+ useLayoutEffect4(() => {
6428
+ maybeScrollAssetSidebarRowIntoView({
6429
+ element: rowRef.current,
6430
+ assetPath: relativePath,
6431
+ selected
6432
+ });
6433
+ }, [relativePath, selected]);
6315
6434
  const onClick = useCallback28(() => {
6435
+ markAssetSidebarScrollFromRowClick(relativePath);
6316
6436
  setCanvasContent({ type: "asset", asset: relativePath });
6317
6437
  pushUrl(`/assets/${relativePath}`);
6318
6438
  if (isMobileLayout) {
@@ -6370,6 +6490,7 @@ var AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio }
6370
6490
  return /* @__PURE__ */ jsx57(Row, {
6371
6491
  align: "center",
6372
6492
  children: /* @__PURE__ */ jsxs25("div", {
6493
+ ref: rowRef,
6373
6494
  style: style3,
6374
6495
  onPointerEnter,
6375
6496
  onPointerLeave,
@@ -6998,7 +7119,7 @@ var ExplorerPanel = ({ readOnlyStudio }) => {
6998
7119
  var useSelectAsset = () => {
6999
7120
  const { setCanvasContent } = useContext16(Internals14.CompositionSetters);
7000
7121
  const { setAssetFoldersExpanded } = useContext16(FolderContext);
7001
- return (asset) => {
7122
+ return useCallback33((asset) => {
7002
7123
  setCanvasContent({ type: "asset", asset });
7003
7124
  explorerSidebarTabs.current?.selectAssetsPanel();
7004
7125
  setAssetFoldersExpanded((ex) => {
@@ -7014,7 +7135,7 @@ var useSelectAsset = () => {
7014
7135
  }
7015
7136
  return newState;
7016
7137
  });
7017
- };
7138
+ }, [setAssetFoldersExpanded, setCanvasContent]);
7018
7139
  };
7019
7140
  var useSelectComposition = () => {
7020
7141
  const { setCompositionFoldersExpanded } = useContext16(FolderContext);
@@ -7108,7 +7229,7 @@ var InitialCompositionLoader = () => {
7108
7229
  return file.name === newCanvas.asset;
7109
7230
  });
7110
7231
  if (exists) {
7111
- setCanvasContent(newCanvas);
7232
+ selectAsset(newCanvas.asset);
7112
7233
  }
7113
7234
  return;
7114
7235
  }
@@ -7116,7 +7237,13 @@ var InitialCompositionLoader = () => {
7116
7237
  };
7117
7238
  window.addEventListener("popstate", onchange);
7118
7239
  return () => window.removeEventListener("popstate", onchange);
7119
- }, [compositions, selectComposition, setCanvasContent, staticFiles]);
7240
+ }, [
7241
+ compositions,
7242
+ selectAsset,
7243
+ selectComposition,
7244
+ setCanvasContent,
7245
+ staticFiles
7246
+ ]);
7120
7247
  return null;
7121
7248
  };
7122
7249
 
@@ -7146,7 +7273,7 @@ import {
7146
7273
  useCallback as useCallback35,
7147
7274
  useEffect as useEffect24,
7148
7275
  useImperativeHandle as useImperativeHandle7,
7149
- useRef as useRef15,
7276
+ useRef as useRef16,
7150
7277
  useState as useState30
7151
7278
  } from "react";
7152
7279
  import { AbsoluteFill as AbsoluteFill3 } from "remotion";
@@ -7277,7 +7404,7 @@ var container18 = {
7277
7404
  var askAiModalRef = createRef7();
7278
7405
  var AskAiModal = () => {
7279
7406
  const [state, setState] = useState30("never-opened");
7280
- const iframe = useRef15(null);
7407
+ const iframe = useRef16(null);
7281
7408
  useImperativeHandle7(askAiModalRef, () => ({
7282
7409
  toggle: () => {
7283
7410
  setState((s) => {
@@ -7388,7 +7515,7 @@ var ControlButton = (props) => {
7388
7515
 
7389
7516
  // src/components/NewComposition/ComboBox.tsx
7390
7517
  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";
7518
+ import { useCallback as useCallback36, useEffect as useEffect25, useMemo as useMemo34, useRef as useRef17, useState as useState31 } from "react";
7392
7519
  import ReactDOM5 from "react-dom";
7393
7520
  import { jsx as jsx69, jsxs as jsxs31, Fragment as Fragment8 } from "react/jsx-runtime";
7394
7521
  var container19 = {
@@ -7409,7 +7536,7 @@ var label3 = {
7409
7536
  var Combobox = ({ values, selectedId, style: customStyle, title: title4 }) => {
7410
7537
  const [hovered, setIsHovered] = useState31(false);
7411
7538
  const [opened, setOpened] = useState31(false);
7412
- const ref = useRef16(null);
7539
+ const ref = useRef17(null);
7413
7540
  const { tabIndex, currentZIndex } = useZIndex();
7414
7541
  const size2 = PlayerInternals6.useElementSize(ref, {
7415
7542
  triggerOnWindowResize: true,
@@ -7575,7 +7702,7 @@ var Combobox = ({ values, selectedId, style: customStyle, title: title4 }) => {
7575
7702
 
7576
7703
  // src/components/Preview.tsx
7577
7704
  import { PlayerInternals as PlayerInternals7 } from "@remotion/player";
7578
- import { useContext as useContext20, useEffect as useEffect31, useMemo as useMemo38, useRef as useRef19 } from "react";
7705
+ import { useContext as useContext20, useEffect as useEffect31, useMemo as useMemo38, useRef as useRef20 } from "react";
7579
7706
  import { Internals as Internals15 } from "remotion";
7580
7707
 
7581
7708
  // src/helpers/checkerboard-background.ts
@@ -7644,56 +7771,63 @@ var getAssetMetadata = async (canvasContent, addTime) => {
7644
7771
  if (canvasContent.type === "composition") {
7645
7772
  throw new Error("cannot get dimensions for composition");
7646
7773
  }
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);
7774
+ try {
7775
+ const src = getSrcFromCanvasContent(canvasContent);
7776
+ const file = await fetch(src, {
7777
+ method: "HEAD"
7778
+ });
7779
+ if (file.status === 404) {
7780
+ return { type: "not-found" };
7781
+ }
7782
+ if (file.status !== 200) {
7783
+ throw new Error(`Expected status code 200 or 404 for file, got ${file.status}`);
7784
+ }
7785
+ const size2 = file.headers.get("content-length");
7786
+ if (!size2) {
7787
+ throw new Error("Unexpected error: content-length is null");
7788
+ }
7789
+ const fetchedAt = Date.now();
7790
+ const srcWithTime = addTime ? `${src}?date=${fetchedAt}` : src;
7791
+ const fileType = getPreviewFileType(src);
7792
+ if (fileType === "video") {
7793
+ const resolution = await getVideoMetadata(srcWithTime);
7794
+ return {
7795
+ type: "found",
7796
+ size: Number(size2),
7797
+ dimensions: { width: resolution.width, height: resolution.height },
7798
+ fetchedAt
7799
+ };
7800
+ }
7801
+ if (fileType === "image") {
7802
+ const resolution = await new Promise((resolve, reject) => {
7803
+ const img = new Image;
7804
+ img.onload = () => {
7805
+ resolve({
7806
+ type: "found",
7807
+ size: Number(size2),
7808
+ dimensions: { width: img.width, height: img.height },
7809
+ fetchedAt
7810
+ });
7811
+ };
7812
+ img.onerror = () => {
7813
+ reject(new Error("Failed to load image"));
7814
+ };
7815
+ img.src = srcWithTime;
7816
+ });
7817
+ return resolution;
7818
+ }
7666
7819
  return {
7667
7820
  type: "found",
7821
+ dimensions: "none",
7668
7822
  size: Number(size2),
7669
- dimensions: { width: resolution.width, height: resolution.height },
7670
7823
  fetchedAt
7671
7824
  };
7825
+ } catch (err) {
7826
+ return {
7827
+ type: "metadata-error",
7828
+ error: err instanceof Error ? err : new Error(String(err))
7829
+ };
7672
7830
  }
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
7831
  };
7698
7832
 
7699
7833
  // src/components/FilePreview.tsx
@@ -7708,7 +7842,7 @@ import {
7708
7842
  useEffect as useEffect27,
7709
7843
  useImperativeHandle as useImperativeHandle9,
7710
7844
  useMemo as useMemo36,
7711
- useRef as useRef18,
7845
+ useRef as useRef19,
7712
7846
  useState as useState33
7713
7847
  } from "react";
7714
7848
 
@@ -7718,7 +7852,7 @@ import {
7718
7852
  useEffect as useEffect26,
7719
7853
  useImperativeHandle as useImperativeHandle8,
7720
7854
  useMemo as useMemo35,
7721
- useRef as useRef17,
7855
+ useRef as useRef18,
7722
7856
  useState as useState32
7723
7857
  } from "react";
7724
7858
  import { jsx as jsx70 } from "react/jsx-runtime";
@@ -7747,7 +7881,7 @@ var getInputBorderColor = ({
7747
7881
  var RemInputForwardRef = ({ status, rightAlign, ...props }, ref) => {
7748
7882
  const [isFocused, setIsFocused] = useState32(false);
7749
7883
  const [isHovered, setIsHovered] = useState32(false);
7750
- const inputRef = useRef17(null);
7884
+ const inputRef = useRef18(null);
7751
7885
  const { tabIndex } = useZIndex();
7752
7886
  const style5 = useMemo35(() => {
7753
7887
  return {
@@ -7805,7 +7939,7 @@ var inputBaseStyle2 = {
7805
7939
  var RemTextareaFRFunction = ({ status, ...props }, ref) => {
7806
7940
  const [isFocused, setIsFocused] = useState33(false);
7807
7941
  const [isHovered, setIsHovered] = useState33(false);
7808
- const inputRef = useRef18(null);
7942
+ const inputRef = useRef19(null);
7809
7943
  const { tabIndex } = useZIndex();
7810
7944
  useImperativeHandle9(ref, () => {
7811
7945
  return inputRef.current;
@@ -7958,6 +8092,9 @@ var FilePreview = ({ fileType, src, currentAsset, assetMetadata }) => {
7958
8092
  if (assetMetadata.type === "not-found") {
7959
8093
  throw new Error('expected to have assetMetadata, got "not-found"');
7960
8094
  }
8095
+ if (assetMetadata.type === "metadata-error") {
8096
+ throw new Error("unexpected metadata-error in FilePreview");
8097
+ }
7961
8098
  if (fileType === "audio") {
7962
8099
  return /* @__PURE__ */ jsx73("audio", {
7963
8100
  src,
@@ -8198,6 +8335,14 @@ var label4 = {
8198
8335
  fontSize: 14,
8199
8336
  color: LIGHT_TEXT
8200
8337
  };
8338
+ var assetMetadataErrorContainer = {
8339
+ marginLeft: "auto",
8340
+ marginRight: "auto",
8341
+ width: "100%",
8342
+ position: "absolute",
8343
+ height: "100%",
8344
+ overflowY: "auto"
8345
+ };
8201
8346
  var getPreviewFileType = (fileName) => {
8202
8347
  if (!fileName) {
8203
8348
  return "other";
@@ -8242,7 +8387,13 @@ var containerStyle = (options) => {
8242
8387
  backgroundPosition: getCheckerboardBackgroundPos(checkerboardSize)
8243
8388
  };
8244
8389
  };
8245
- var VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata }) => {
8390
+ var VideoPreview = ({
8391
+ canvasSize,
8392
+ contentDimensions,
8393
+ canvasContent,
8394
+ assetMetadata,
8395
+ onRetryAssetMetadata
8396
+ }) => {
8246
8397
  if (assetMetadata && assetMetadata.type === "not-found") {
8247
8398
  return /* @__PURE__ */ jsx77("div", {
8248
8399
  style: centeredContainer,
@@ -8252,6 +8403,19 @@ var VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadat
8252
8403
  })
8253
8404
  });
8254
8405
  }
8406
+ if (assetMetadata && assetMetadata.type === "metadata-error") {
8407
+ return /* @__PURE__ */ jsx77("div", {
8408
+ style: assetMetadataErrorContainer,
8409
+ className: VERTICAL_SCROLLBAR_CLASSNAME,
8410
+ children: /* @__PURE__ */ jsx77(ErrorLoader, {
8411
+ canHaveDismissButton: false,
8412
+ keyboardShortcuts: false,
8413
+ error: assetMetadata.error,
8414
+ onRetry: onRetryAssetMetadata ?? null,
8415
+ calculateMetadata: false
8416
+ }, assetMetadata.error.stack)
8417
+ });
8418
+ }
8255
8419
  if (contentDimensions === null) {
8256
8420
  return /* @__PURE__ */ jsx77("div", {
8257
8421
  style: centeredContainer,
@@ -8373,7 +8537,7 @@ var PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions }) =
8373
8537
  current?.removeChild(Internals15.portalNode());
8374
8538
  };
8375
8539
  }, []);
8376
- const portalContainer = useRef19(null);
8540
+ const portalContainer = useRef20(null);
8377
8541
  return /* @__PURE__ */ jsx77("div", {
8378
8542
  ref: portalContainer,
8379
8543
  style: style5
@@ -9868,7 +10032,7 @@ var makeSearchResults = (actions, setSelectedModal) => {
9868
10032
 
9869
10033
  // src/components/Menu/MenuItem.tsx
9870
10034
  import { PlayerInternals as PlayerInternals9 } from "@remotion/player";
9871
- import { useCallback as useCallback38, useMemo as useMemo43, useRef as useRef20, useState as useState37 } from "react";
10035
+ import { useCallback as useCallback38, useMemo as useMemo43, useRef as useRef21, useState as useState37 } from "react";
9872
10036
  import ReactDOM6 from "react-dom";
9873
10037
  import { jsx as jsx84, jsxs as jsxs39, Fragment as Fragment13 } from "react/jsx-runtime";
9874
10038
  var container21 = {
@@ -9895,7 +10059,7 @@ var MenuItem = ({
9895
10059
  menu
9896
10060
  }) => {
9897
10061
  const [hovered, setHovered] = useState37(false);
9898
- const ref = useRef20(null);
10062
+ const ref = useRef21(null);
9899
10063
  const size2 = PlayerInternals9.useElementSize(ref, {
9900
10064
  triggerOnWindowResize: true,
9901
10065
  shouldApplyCssTransforms: true
@@ -10337,10 +10501,10 @@ import React125, { useCallback as useCallback96, useContext as useContext64, use
10337
10501
  import { Internals as Internals45 } from "remotion";
10338
10502
 
10339
10503
  // src/helpers/use-breakpoint.ts
10340
- import { useEffect as useEffect35, useRef as useRef21, useState as useState41 } from "react";
10504
+ import { useEffect as useEffect35, useRef as useRef22, useState as useState41 } from "react";
10341
10505
  function useBreakpoint(breakpoint2) {
10342
10506
  const [compactUI, setCompactUI] = useState41(window.innerWidth < breakpoint2);
10343
- const compactUIRef = useRef21(compactUI);
10507
+ const compactUIRef = useRef22(compactUI);
10344
10508
  useEffect35(() => {
10345
10509
  function handleResize() {
10346
10510
  const newValue = window.innerWidth < breakpoint2;
@@ -10370,7 +10534,7 @@ import {
10370
10534
  useContext as useContext33,
10371
10535
  useEffect as useEffect38,
10372
10536
  useMemo as useMemo52,
10373
- useRef as useRef24,
10537
+ useRef as useRef25,
10374
10538
  useState as useState43
10375
10539
  } from "react";
10376
10540
  import { Internals as Internals27, watchStaticFile } from "remotion";
@@ -10520,7 +10684,7 @@ var useStudioCanvasDimensions = ({
10520
10684
  }) => {
10521
10685
  const { size: previewSize } = useContext27(Internals23.PreviewSizeContext);
10522
10686
  const { centerX, centerY, scale } = useMemo46(() => {
10523
- if (contentDimensions === "none" || contentDimensions === null || assetMetadata && assetMetadata.type === "not-found" || !canvasSize) {
10687
+ if (contentDimensions === "none" || contentDimensions === null || assetMetadata && (assetMetadata.type === "not-found" || assetMetadata.type === "metadata-error") || !canvasSize) {
10524
10688
  return {
10525
10689
  centerX: previewSize.translation.x,
10526
10690
  centerY: previewSize.translation.y,
@@ -10732,7 +10896,7 @@ import {
10732
10896
  useContext as useContext31,
10733
10897
  useEffect as useEffect37,
10734
10898
  useMemo as useMemo51,
10735
- useRef as useRef23
10899
+ useRef as useRef24
10736
10900
  } from "react";
10737
10901
 
10738
10902
  // src/helpers/editor-ruler.ts
@@ -10947,7 +11111,7 @@ import {
10947
11111
  useContext as useContext30,
10948
11112
  useEffect as useEffect36,
10949
11113
  useMemo as useMemo50,
10950
- useRef as useRef22,
11114
+ useRef as useRef23,
10951
11115
  useState as useState42
10952
11116
  } from "react";
10953
11117
  import { Internals as Internals25 } from "remotion";
@@ -10964,7 +11128,7 @@ var Ruler = ({
10964
11128
  markingGaps,
10965
11129
  orientation
10966
11130
  }) => {
10967
- const rulerCanvasRef = useRef22(null);
11131
+ const rulerCanvasRef = useRef23(null);
10968
11132
  const isVerticalRuler = orientation === "vertical";
10969
11133
  const {
10970
11134
  shouldCreateGuideRef,
@@ -11128,7 +11292,7 @@ var EditorRulers = ({ contentDimensions, canvasSize, assetMetadata, containerRef
11128
11292
  rulerMarkingGaps,
11129
11293
  scale
11130
11294
  }), [verticalRulerScaleRange, rulerMarkingGaps, scale]);
11131
- const requestAnimationFrameRef = useRef23(null);
11295
+ const requestAnimationFrameRef = useRef24(null);
11132
11296
  const onMouseMove = useCallback43((e) => {
11133
11297
  if (requestAnimationFrameRef.current) {
11134
11298
  cancelAnimationFrame(requestAnimationFrameRef.current);
@@ -11291,14 +11455,14 @@ var ZOOM_PX_FACTOR = 0.003;
11291
11455
  var Canvas = ({ canvasContent, size: size2 }) => {
11292
11456
  const { setSize, size: previewSize } = useContext33(Internals27.PreviewSizeContext);
11293
11457
  const { editorZoomGestures } = useContext33(EditorZoomGesturesContext);
11294
- const previewSnapshotRef = useRef24({
11458
+ const previewSnapshotRef = useRef25({
11295
11459
  previewSize,
11296
11460
  canvasSize: size2,
11297
11461
  contentDimensions: null
11298
11462
  });
11299
- const pinchBaseZoomRef = useRef24(null);
11300
- const suppressWheelFromWebKitPinchRef = useRef24(false);
11301
- const touchPinchRef = useRef24(null);
11463
+ const pinchBaseZoomRef = useRef25(null);
11464
+ const suppressWheelFromWebKitPinchRef = useRef25(false);
11465
+ const touchPinchRef = useRef25(null);
11302
11466
  const keybindings = useKeybinding();
11303
11467
  const config = Internals27.useUnsafeVideoConfig();
11304
11468
  const areRulersVisible = useIsRulerVisible();
@@ -11669,7 +11833,8 @@ var Canvas = ({ canvasContent, size: size2 }) => {
11669
11833
  canvasContent,
11670
11834
  contentDimensions,
11671
11835
  canvasSize: size2,
11672
- assetMetadata: assetResolution
11836
+ assetMetadata: assetResolution,
11837
+ onRetryAssetMetadata: fetchMetadata
11673
11838
  }) : null,
11674
11839
  isFit ? null : /* @__PURE__ */ jsx93("div", {
11675
11840
  style: resetZoom,
@@ -11818,7 +11983,8 @@ var CanvasOrLoading = ({ size: size2 }) => {
11818
11983
  }, [resolved, setZoom]);
11819
11984
  if (renderError) {
11820
11985
  return /* @__PURE__ */ jsx96(ErrorLoading, {
11821
- error: renderError
11986
+ error: renderError,
11987
+ calculateMetadataContext: false
11822
11988
  });
11823
11989
  }
11824
11990
  if (!canvasContent) {
@@ -11861,7 +12027,8 @@ var CanvasOrLoading = ({ size: size2 }) => {
11861
12027
  }
11862
12028
  if (resolved.type === "error") {
11863
12029
  return /* @__PURE__ */ jsx96(ErrorLoading, {
11864
- error: resolved.error
12030
+ error: resolved.error,
12031
+ calculateMetadataContext: true
11865
12032
  });
11866
12033
  }
11867
12034
  return /* @__PURE__ */ jsxs45(Fragment18, {
@@ -11880,7 +12047,7 @@ var loaderContainer = {
11880
12047
  height: "100%",
11881
12048
  overflowY: "auto"
11882
12049
  };
11883
- var ErrorLoading = ({ error }) => {
12050
+ var ErrorLoading = ({ error, calculateMetadataContext }) => {
11884
12051
  return /* @__PURE__ */ jsx96("div", {
11885
12052
  style: loaderContainer,
11886
12053
  className: VERTICAL_SCROLLBAR_CLASSNAME,
@@ -11889,7 +12056,7 @@ var ErrorLoading = ({ error }) => {
11889
12056
  keyboardShortcuts: false,
11890
12057
  error,
11891
12058
  onRetry: () => Internals29.resolveCompositionsRef.current?.reloadCurrentlySelectedComposition(),
11892
- calculateMetadata: true
12059
+ calculateMetadata: calculateMetadataContext
11893
12060
  }, error.stack)
11894
12061
  });
11895
12062
  };
@@ -12182,7 +12349,7 @@ import {
12182
12349
  useEffect as useEffect44,
12183
12350
  useImperativeHandle as useImperativeHandle11,
12184
12351
  useMemo as useMemo56,
12185
- useRef as useRef25,
12352
+ useRef as useRef26,
12186
12353
  useState as useState46
12187
12354
  } from "react";
12188
12355
  import { useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
@@ -12322,7 +12489,7 @@ var SetVisualControlsContext = createContext18({
12322
12489
  }
12323
12490
  });
12324
12491
  var VisualControlsProvider = ({ children }) => {
12325
- const imperativeHandles = useRef25({});
12492
+ const imperativeHandles = useRef26({});
12326
12493
  const [handles, setHandles] = useState46({});
12327
12494
  const state = useMemo56(() => {
12328
12495
  return {
@@ -12351,7 +12518,7 @@ var VisualControlsProvider = ({ children }) => {
12351
12518
  };
12352
12519
  }, []);
12353
12520
  const z = useZodIfPossible();
12354
- const changedRef = useRef25(false);
12521
+ const changedRef = useRef26(false);
12355
12522
  const env = useRemotionEnvironment2();
12356
12523
  const visualControl = useCallback47(function(key, value, schema) {
12357
12524
  if (handles && false) {}
@@ -13819,7 +13986,7 @@ var ZodArrayItemEditor = ({ elementSchema, onChange, jsonPath, index, value, may
13819
13986
 
13820
13987
  // src/components/RenderModal/InfoBubble.tsx
13821
13988
  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";
13989
+ import { useCallback as useCallback54, useEffect as useEffect46, useMemo as useMemo67, useRef as useRef27, useState as useState50 } from "react";
13823
13990
  import ReactDOM8 from "react-dom";
13824
13991
 
13825
13992
  // src/components/RenderModal/InfoTooltip.tsx
@@ -13904,7 +14071,7 @@ var container28 = {
13904
14071
  var InfoBubble = ({ title: title4, children }) => {
13905
14072
  const [hovered, setIsHovered] = useState50(false);
13906
14073
  const [opened, setOpened] = useState50(false);
13907
- const ref2 = useRef26(null);
14074
+ const ref2 = useRef27(null);
13908
14075
  const { tabIndex, currentZIndex } = useZIndex();
13909
14076
  const size2 = PlayerInternals11.useElementSize(ref2, {
13910
14077
  triggerOnWindowResize: true,
@@ -14162,7 +14329,7 @@ var ZodArrayEditor = ({ schema, jsonPath, setValue, value, onRemove, mayPad }) =
14162
14329
  import { useCallback as useCallback56 } from "react";
14163
14330
 
14164
14331
  // src/components/Checkbox.tsx
14165
- import { useEffect as useEffect47, useMemo as useMemo69, useRef as useRef27 } from "react";
14332
+ import { useEffect as useEffect47, useMemo as useMemo69, useRef as useRef28 } from "react";
14166
14333
  import { jsx as jsx118, jsxs as jsxs58 } from "react/jsx-runtime";
14167
14334
  var size2 = 20;
14168
14335
  var background = {
@@ -14189,7 +14356,7 @@ var box = {
14189
14356
  color: "white"
14190
14357
  };
14191
14358
  var Checkbox = ({ checked, onChange, disabled, name, rounded }) => {
14192
- const ref2 = useRef27(null);
14359
+ const ref2 = useRef28(null);
14193
14360
  const input2 = useMemo69(() => {
14194
14361
  return {
14195
14362
  appearance: "none",
@@ -14275,7 +14442,7 @@ var colorWithNewOpacity = (color, opacity, zodTypes) => {
14275
14442
  };
14276
14443
 
14277
14444
  // 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";
14445
+ import React82, { useCallback as useCallback57, useEffect as useEffect48, useMemo as useMemo70, useRef as useRef29, useState as useState52 } from "react";
14279
14446
  import { interpolate as interpolate2 } from "remotion";
14280
14447
  import { jsx as jsx120 } from "react/jsx-runtime";
14281
14448
  var isInt = (num) => {
@@ -14297,8 +14464,8 @@ var InputDraggerForwardRefFn = ({
14297
14464
  }, ref2) => {
14298
14465
  const [inputFallback, setInputFallback] = useState52(false);
14299
14466
  const [dragging, setDragging] = useState52(false);
14300
- const fallbackRef = useRef28(null);
14301
- const pointerDownRef = useRef28(false);
14467
+ const fallbackRef = useRef29(null);
14468
+ const pointerDownRef = useRef29(false);
14302
14469
  const style8 = useMemo70(() => {
14303
14470
  return {
14304
14471
  ...inputBaseStyle,
@@ -14465,7 +14632,7 @@ import {
14465
14632
  useEffect as useEffect49,
14466
14633
  useImperativeHandle as useImperativeHandle12,
14467
14634
  useMemo as useMemo71,
14468
- useRef as useRef29,
14635
+ useRef as useRef30,
14469
14636
  useState as useState53
14470
14637
  } from "react";
14471
14638
  import { jsx as jsx121 } from "react/jsx-runtime";
@@ -14477,7 +14644,7 @@ var inputBaseStyle3 = {
14477
14644
  var RemInputTypeColorForwardRef = ({ status, ...props }, ref2) => {
14478
14645
  const [isFocused, setIsFocused] = useState53(false);
14479
14646
  const [isHovered, setIsHovered] = useState53(false);
14480
- const inputRef = useRef29(null);
14647
+ const inputRef = useRef30(null);
14481
14648
  const { tabIndex } = useZIndex();
14482
14649
  const style8 = useMemo71(() => {
14483
14650
  return {
@@ -18224,7 +18391,7 @@ var OptionsPanel = ({ readOnlyStudio }) => {
18224
18391
  };
18225
18392
 
18226
18393
  // src/components/PreviewToolbar.tsx
18227
- import { useContext as useContext61, useEffect as useEffect60, useRef as useRef32, useState as useState66 } from "react";
18394
+ import { useContext as useContext61, useEffect as useEffect60, useRef as useRef33, useState as useState66 } from "react";
18228
18395
  import { Internals as Internals44 } from "remotion";
18229
18396
 
18230
18397
  // src/state/loop.ts
@@ -18277,9 +18444,9 @@ var CheckboardToggle = () => {
18277
18444
  // src/components/FpsCounter.tsx
18278
18445
  import {
18279
18446
  useEffect as useEffect55,
18280
- useLayoutEffect as useLayoutEffect3,
18447
+ useLayoutEffect as useLayoutEffect5,
18281
18448
  useMemo as useMemo98,
18282
- useRef as useRef30,
18449
+ useRef as useRef31,
18283
18450
  useState as useState63
18284
18451
  } from "react";
18285
18452
  import { Internals as Internals37 } from "remotion";
@@ -18300,15 +18467,15 @@ var FpsCounter = ({ playbackSpeed }) => {
18300
18467
  const frame2 = Internals37.Timeline.useTimelinePosition();
18301
18468
  const [marker, rerender] = useState63({});
18302
18469
  const [fps, setFps] = useState63(0);
18303
- const previousUpdates = useRef30([]);
18304
- const fpsRef = useRef30(0);
18305
- const playingRef = useRef30(playing);
18306
- useLayoutEffect3(() => {
18470
+ const previousUpdates = useRef31([]);
18471
+ const fpsRef = useRef31(0);
18472
+ const playingRef = useRef31(playing);
18473
+ useLayoutEffect5(() => {
18307
18474
  fpsRef.current = 0;
18308
18475
  previousUpdates.current = [];
18309
18476
  playingRef.current = playing;
18310
18477
  }, [playing]);
18311
- useLayoutEffect3(() => {
18478
+ useLayoutEffect5(() => {
18312
18479
  if (playingRef.current === false)
18313
18480
  return;
18314
18481
  previousUpdates.current = pushWithMaxSize(previousUpdates.current, performance.now(), 15);
@@ -19033,7 +19200,7 @@ var PlayPause = ({ playbackRate, loop, bufferStateDelayInMilliseconds }) => {
19033
19200
 
19034
19201
  // src/components/RenderButton.tsx
19035
19202
  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";
19203
+ import { useCallback as useCallback94, useContext as useContext59, useMemo as useMemo100, useRef as useRef32, useState as useState65 } from "react";
19037
19204
  import ReactDOM9 from "react-dom";
19038
19205
  import { Internals as Internals42 } from "remotion";
19039
19206
  import { jsx as jsx180, jsxs as jsxs84, Fragment as Fragment24 } from "react/jsx-runtime";
@@ -19107,8 +19274,8 @@ var RenderButton = ({
19107
19274
  const { setSelectedModal } = useContext59(ModalsContext);
19108
19275
  const [preferredRenderType, setPreferredRenderType] = useState65(() => getInitialRenderType(readOnlyStudio));
19109
19276
  const [dropdownOpened, setDropdownOpened] = useState65(false);
19110
- const dropdownRef = useRef31(null);
19111
- const containerRef = useRef31(null);
19277
+ const dropdownRef = useRef32(null);
19278
+ const containerRef = useRef32(null);
19112
19279
  const { currentZIndex } = useZIndex();
19113
19280
  const size4 = PlayerInternals14.useElementSize(dropdownRef, {
19114
19281
  triggerOnWindowResize: true,
@@ -19660,9 +19827,9 @@ var PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
19660
19827
  const { setMediaMuted } = useContext61(Internals44.SetMediaVolumeContext);
19661
19828
  const { canvasContent } = useContext61(Internals44.CompositionManager);
19662
19829
  const isVideoComposition = useIsVideoComposition();
19663
- const previewToolbarRef = useRef32(null);
19664
- const leftScrollIndicatorRef = useRef32(null);
19665
- const rightScrollIndicatorRef = useRef32(null);
19830
+ const previewToolbarRef = useRef33(null);
19831
+ const leftScrollIndicatorRef = useRef33(null);
19832
+ const rightScrollIndicatorRef = useRef33(null);
19666
19833
  const isStill = useIsStill();
19667
19834
  const [loop, setLoop] = useState66(loadLoopOption());
19668
19835
  const isFullscreenSupported = checkFullscreenSupport();
@@ -19818,7 +19985,7 @@ var PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
19818
19985
  };
19819
19986
 
19820
19987
  // src/components/Splitter/SplitterContainer.tsx
19821
- import { useMemo as useMemo101, useRef as useRef33, useState as useState67 } from "react";
19988
+ import { useMemo as useMemo101, useRef as useRef34, useState as useState67 } from "react";
19822
19989
 
19823
19990
  // src/state/timeline.ts
19824
19991
  var localStorageKey4 = (id) => `remotion.editor.timelineFlex.${id}`;
@@ -19873,8 +20040,8 @@ var containerColumn = {
19873
20040
  var SplitterContainer = ({ orientation, children, defaultFlex, maxFlex, minFlex, id }) => {
19874
20041
  const [initialTimelineFlex, persistFlex] = useTimelineFlex(id);
19875
20042
  const [flexValue, setFlexValue] = useState67(initialTimelineFlex ?? defaultFlex);
19876
- const ref2 = useRef33(null);
19877
- const isDragging = useRef33(false);
20043
+ const ref2 = useRef34(null);
20044
+ const isDragging = useRef34(false);
19878
20045
  const value = useMemo101(() => {
19879
20046
  return {
19880
20047
  flexValue,
@@ -19947,7 +20114,7 @@ var SplitterElement = ({ children, type, sticky }) => {
19947
20114
 
19948
20115
  // src/components/Splitter/SplitterHandle.tsx
19949
20116
  import { PlayerInternals as PlayerInternals15 } from "@remotion/player";
19950
- import { useContext as useContext63, useEffect as useEffect61, useRef as useRef34, useState as useState68 } from "react";
20117
+ import { useContext as useContext63, useEffect as useEffect61, useRef as useRef35, useState as useState68 } from "react";
19951
20118
  import { jsx as jsx186 } from "react/jsx-runtime";
19952
20119
  var SPLITTER_HANDLE_SIZE = 3;
19953
20120
  var containerRow2 = {
@@ -19962,7 +20129,7 @@ var SplitterHandle = ({ allowToCollapse, onCollapse }) => {
19962
20129
  throw new Error("Cannot find splitter context");
19963
20130
  }
19964
20131
  const [lastPointerUp, setLastPointerUp] = useState68(() => Date.now());
19965
- const ref2 = useRef34(null);
20132
+ const ref2 = useRef35(null);
19966
20133
  useEffect61(() => {
19967
20134
  if (context.isDragging.current) {
19968
20135
  return;
@@ -20390,7 +20557,7 @@ import {
20390
20557
  useCallback as useCallback98,
20391
20558
  useContext as useContext66,
20392
20559
  useEffect as useEffect64,
20393
- useRef as useRef35,
20560
+ useRef as useRef36,
20394
20561
  useState as useState69
20395
20562
  } from "react";
20396
20563
 
@@ -20431,8 +20598,8 @@ var UndoRedoButtons = () => {
20431
20598
  const [redoFile, setRedoFile] = useState69(null);
20432
20599
  const { subscribeToEvent } = useContext66(StudioServerConnectionCtx);
20433
20600
  const keybindings = useKeybinding();
20434
- const undoInFlight = useRef35(false);
20435
- const redoInFlight = useRef35(false);
20601
+ const undoInFlight = useRef36(false);
20602
+ const redoInFlight = useRef36(false);
20436
20603
  useEffect64(() => {
20437
20604
  const unsub = subscribeToEvent("undo-redo-stack-changed", (event) => {
20438
20605
  if (event.type !== "undo-redo-stack-changed") {
@@ -20978,7 +21145,7 @@ import {
20978
21145
  useContext as useContext70,
20979
21146
  useEffect as useEffect66,
20980
21147
  useMemo as useMemo108,
20981
- useRef as useRef36,
21148
+ useRef as useRef37,
20982
21149
  useState as useState73
20983
21150
  } from "react";
20984
21151
  import { Internals as Internals47, useVideoConfig as useVideoConfig4 } from "remotion";
@@ -21142,7 +21309,7 @@ var Inner2 = () => {
21142
21309
  dragging: false
21143
21310
  });
21144
21311
  const { playing, play, pause, seek } = PlayerInternals16.usePlayer();
21145
- const scroller = useRef36(null);
21312
+ const scroller = useRef37(null);
21146
21313
  const stopInterval = () => {
21147
21314
  if (scroller.current) {
21148
21315
  clearInterval(scroller.current);
@@ -21518,7 +21685,7 @@ var Inner2 = () => {
21518
21685
 
21519
21686
  // src/components/Timeline/TimelineList.tsx
21520
21687
  import { PlayerInternals as PlayerInternals18 } from "@remotion/player";
21521
- import { useRef as useRef40 } from "react";
21688
+ import { useRef as useRef41 } from "react";
21522
21689
 
21523
21690
  // src/components/Timeline/TimelineListItem.tsx
21524
21691
  import { useCallback as useCallback111, useContext as useContext74, useMemo as useMemo116 } from "react";
@@ -22418,7 +22585,7 @@ import {
22418
22585
  useContext as useContext73,
22419
22586
  useEffect as useEffect67,
22420
22587
  useMemo as useMemo115,
22421
- useRef as useRef37,
22588
+ useRef as useRef38,
22422
22589
  useState as useState78
22423
22590
  } from "react";
22424
22591
  import { Internals as Internals49 } from "remotion";
@@ -22448,15 +22615,16 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22448
22615
  const locationSource = validatedLocation?.source ?? null;
22449
22616
  const locationLine = validatedLocation?.line ?? null;
22450
22617
  const locationColumn = validatedLocation?.column ?? null;
22451
- const currentLocationSource = useRef37(locationSource);
22618
+ const currentLocationSource = useRef38(locationSource);
22452
22619
  currentLocationSource.current = locationSource;
22453
- const currentLocationLine = useRef37(locationLine);
22620
+ const currentLocationLine = useRef38(locationLine);
22454
22621
  currentLocationLine.current = locationLine;
22455
- const currentLocationColumn = useRef37(locationColumn);
22622
+ const currentLocationColumn = useRef38(locationColumn);
22456
22623
  currentLocationColumn.current = locationColumn;
22457
- const nodePathRef = useRef37(null);
22624
+ const nodePathRef = useRef38(null);
22458
22625
  const [nodePath, setNodePath] = useState78(null);
22459
- const isMountedRef = useRef37(true);
22626
+ const [jsxInMapCallback, setJsxInMapCallback] = useState78(false);
22627
+ const isMountedRef = useRef38(true);
22460
22628
  const setNodePathBoth = useCallback110((next) => {
22461
22629
  nodePathRef.current = next;
22462
22630
  setNodePath(next);
@@ -22471,11 +22639,13 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22471
22639
  if (!visualModeEnabled) {
22472
22640
  setPropStatusesForSequence(null);
22473
22641
  setNodePathBoth(null);
22642
+ setJsxInMapCallback(false);
22474
22643
  return;
22475
22644
  }
22476
22645
  if (!clientId || !locationSource || !locationLine || locationColumn === null || !schemaKeysString) {
22477
22646
  setPropStatusesForSequence(null);
22478
22647
  setNodePathBoth(null);
22648
+ setJsxInMapCallback(false);
22479
22649
  return;
22480
22650
  }
22481
22651
  const keys = schemaKeysString.split(",");
@@ -22492,12 +22662,15 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22492
22662
  if (result.canUpdate) {
22493
22663
  setNodePathBoth(result.nodePath);
22494
22664
  setPropStatusesForSequence(result.props);
22665
+ setJsxInMapCallback(result.jsxInMapCallback);
22495
22666
  } else {
22496
22667
  setNodePathBoth(null);
22497
22668
  setPropStatusesForSequence(null);
22669
+ setJsxInMapCallback(false);
22498
22670
  }
22499
22671
  }).catch((err) => {
22500
22672
  setNodePathBoth(null);
22673
+ setJsxInMapCallback(false);
22501
22674
  Internals49.Log.error(err);
22502
22675
  setPropStatusesForSequence(null);
22503
22676
  });
@@ -22507,6 +22680,7 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22507
22680
  setPropStatusesForSequence(null);
22508
22681
  }
22509
22682
  setNodePathBoth(null);
22683
+ setJsxInMapCallback(false);
22510
22684
  if (currentNodePath) {
22511
22685
  callApi("/api/unsubscribe-from-sequence-props", {
22512
22686
  fileName: locationSource,
@@ -22541,9 +22715,11 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22541
22715
  }
22542
22716
  if (event.result.canUpdate) {
22543
22717
  setPropStatusesForSequence(event.result.props);
22718
+ setJsxInMapCallback(event.result.jsxInMapCallback);
22544
22719
  } else {
22545
22720
  setPropStatusesForSequence(null);
22546
22721
  setNodePathBoth(null);
22722
+ setJsxInMapCallback(false);
22547
22723
  }
22548
22724
  };
22549
22725
  const unsub = subscribeToEvent("sequence-props-updated", listener);
@@ -22559,7 +22735,7 @@ var useSequencePropsSubscription = (sequence, originalLocation, visualModeEnable
22559
22735
  setPropStatusesForSequence,
22560
22736
  setNodePathBoth
22561
22737
  ]);
22562
- return nodePath;
22738
+ return { nodePath, jsxInMapCallback };
22563
22739
  };
22564
22740
 
22565
22741
  // src/components/Timeline/TimelineListItem.tsx
@@ -22595,7 +22771,7 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22595
22771
  const { hidden, setHidden } = useContext74(Internals50.SequenceVisibilityToggleContext);
22596
22772
  const { expandedTracks, toggleTrack } = useContext74(ExpandedTracksContext);
22597
22773
  const originalLocation = useResolvedStack(sequence.stack ?? null);
22598
- const nodePath = useSequencePropsSubscription(sequence, originalLocation, visualModeActive);
22774
+ const { nodePath, jsxInMapCallback } = useSequencePropsSubscription(sequence, originalLocation, visualModeActive);
22599
22775
  const validatedLocation = useMemo116(() => {
22600
22776
  if (!originalLocation || !originalLocation.source || !originalLocation.line) {
22601
22777
  return null;
@@ -22608,6 +22784,31 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22608
22784
  }, [originalLocation]);
22609
22785
  const canDeleteFromSource = Boolean(nodePath && validatedLocation?.source);
22610
22786
  const deleteDisabled = useMemo116(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
22787
+ const duplicateDisabled = deleteDisabled;
22788
+ const onDuplicateSequenceFromSource = useCallback111(async () => {
22789
+ if (!validatedLocation?.source || !nodePath) {
22790
+ return;
22791
+ }
22792
+ if (jsxInMapCallback) {
22793
+ const message = "This sequence is rendered inside a .map() callback. Duplicating inserts another copy in that callback (affecting each list item). Continue?";
22794
+ if (!window.confirm(message)) {
22795
+ return;
22796
+ }
22797
+ }
22798
+ try {
22799
+ const result = await callApi("/api/duplicate-jsx-node", {
22800
+ fileName: validatedLocation.source,
22801
+ nodePath
22802
+ });
22803
+ if (result.success) {
22804
+ showNotification("Duplicated sequence in source file", 2000);
22805
+ } else {
22806
+ showNotification(result.reason, 4000);
22807
+ }
22808
+ } catch (err) {
22809
+ showNotification(err.message, 4000);
22810
+ }
22811
+ }, [jsxInMapCallback, nodePath, validatedLocation?.source]);
22611
22812
  const onDeleteSequenceFromSource = useCallback111(async () => {
22612
22813
  if (!validatedLocation?.source || !nodePath) {
22613
22814
  return;
@@ -22631,6 +22832,23 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22631
22832
  return [];
22632
22833
  }
22633
22834
  return [
22835
+ {
22836
+ type: "item",
22837
+ id: "duplicate-sequence",
22838
+ keyHint: null,
22839
+ label: "Duplicate",
22840
+ leftItem: null,
22841
+ disabled: duplicateDisabled,
22842
+ onClick: () => {
22843
+ if (duplicateDisabled) {
22844
+ return;
22845
+ }
22846
+ onDuplicateSequenceFromSource();
22847
+ },
22848
+ quickSwitcherLabel: null,
22849
+ subMenu: null,
22850
+ value: "duplicate-sequence"
22851
+ },
22634
22852
  {
22635
22853
  type: "item",
22636
22854
  id: "delete-sequence",
@@ -22649,7 +22867,13 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22649
22867
  value: "delete-sequence"
22650
22868
  }
22651
22869
  ];
22652
- }, [deleteDisabled, onDeleteSequenceFromSource, visualModeEnvEnabled]);
22870
+ }, [
22871
+ deleteDisabled,
22872
+ duplicateDisabled,
22873
+ onDeleteSequenceFromSource,
22874
+ onDuplicateSequenceFromSource,
22875
+ visualModeEnvEnabled
22876
+ ]);
22653
22877
  const isExpanded = visualModeActive && (expandedTracks[sequence.id] ?? false);
22654
22878
  const onToggleExpand = useCallback111(() => {
22655
22879
  toggleTrack(sequence.id);
@@ -22748,7 +22972,7 @@ var TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
22748
22972
  };
22749
22973
 
22750
22974
  // src/components/Timeline/TimelineTimeIndicators.tsx
22751
- import { useContext as useContext75, useEffect as useEffect69, useMemo as useMemo117, useRef as useRef39 } from "react";
22975
+ import { useContext as useContext75, useEffect as useEffect69, useMemo as useMemo117, useRef as useRef40 } from "react";
22752
22976
  import { Internals as Internals52 } from "remotion";
22753
22977
 
22754
22978
  // src/components/TimeValue.tsx
@@ -22757,7 +22981,7 @@ import {
22757
22981
  useCallback as useCallback112,
22758
22982
  useEffect as useEffect68,
22759
22983
  useImperativeHandle as useImperativeHandle14,
22760
- useRef as useRef38
22984
+ useRef as useRef39
22761
22985
  } from "react";
22762
22986
  import { Internals as Internals51, useCurrentFrame } from "remotion";
22763
22987
  import { jsx as jsx208, jsxs as jsxs100 } from "react/jsx-runtime";
@@ -22790,7 +23014,7 @@ var TimeValue = () => {
22790
23014
  const isStill = useIsStill();
22791
23015
  const { seek, play, pause, toggle } = PlayerInternals17.usePlayer();
22792
23016
  const keybindings = useKeybinding();
22793
- const ref2 = useRef38(null);
23017
+ const ref2 = useRef39(null);
22794
23018
  const onTextChange = useCallback112((newVal) => {
22795
23019
  seek(parseInt(newVal, 10));
22796
23020
  }, [seek]);
@@ -22918,7 +23142,7 @@ var TimelineTimeIndicators = () => {
22918
23142
  });
22919
23143
  };
22920
23144
  var Inner3 = ({ windowWidth, durationInFrames, fps }) => {
22921
- const ref2 = useRef39(null);
23145
+ const ref2 = useRef40(null);
22922
23146
  useEffect69(() => {
22923
23147
  const currentRef = ref2.current;
22924
23148
  if (!currentRef) {
@@ -23001,7 +23225,7 @@ var container42 = {
23001
23225
  background: BACKGROUND
23002
23226
  };
23003
23227
  var TimelineList = ({ timeline }) => {
23004
- const ref2 = useRef40(null);
23228
+ const ref2 = useRef41(null);
23005
23229
  const size4 = PlayerInternals18.useElementSize(ref2, {
23006
23230
  shouldApplyCssTransforms: false,
23007
23231
  triggerOnWindowResize: false
@@ -23026,7 +23250,7 @@ var TimelineList = ({ timeline }) => {
23026
23250
  };
23027
23251
 
23028
23252
  // src/components/Timeline/TimelinePinchZoom.tsx
23029
- import { useCallback as useCallback113, useContext as useContext76, useEffect as useEffect70, useRef as useRef41 } from "react";
23253
+ import { useCallback as useCallback113, useContext as useContext76, useEffect as useEffect70, useRef as useRef42 } from "react";
23030
23254
  import { Internals as Internals53 } from "remotion";
23031
23255
  var ZOOM_WHEEL_DELTA = 0.06;
23032
23256
  var TimelinePinchZoom = () => {
@@ -23035,11 +23259,11 @@ var TimelinePinchZoom = () => {
23035
23259
  const { canvasContent } = useContext76(Internals53.CompositionManager);
23036
23260
  const { zoom, setZoom } = useContext76(TimelineZoomCtx);
23037
23261
  const { editorZoomGestures } = useContext76(EditorZoomGesturesContext);
23038
- const zoomRef = useRef41(zoom);
23262
+ const zoomRef = useRef42(zoom);
23039
23263
  zoomRef.current = zoom;
23040
- const pinchBaseZoomRef = useRef41(null);
23041
- const suppressWheelFromWebKitPinchRef = useRef41(false);
23042
- const touchPinchRef = useRef41(null);
23264
+ const pinchBaseZoomRef = useRef42(null);
23265
+ const suppressWheelFromWebKitPinchRef = useRef42(false);
23266
+ const touchPinchRef = useRef42(null);
23043
23267
  const onWheel = useCallback113((e) => {
23044
23268
  if (!editorZoomGestures || !isVideoComposition) {
23045
23269
  return;
@@ -23458,7 +23682,7 @@ var useMaxMediaDuration = (s, fps) => {
23458
23682
  };
23459
23683
 
23460
23684
  // src/components/AudioWaveform.tsx
23461
- import { useEffect as useEffect73, useMemo as useMemo119, useRef as useRef42, useState as useState80 } from "react";
23685
+ import { useEffect as useEffect73, useMemo as useMemo119, useRef as useRef43, useState as useState80 } from "react";
23462
23686
  import { Internals as Internals55 } from "remotion";
23463
23687
 
23464
23688
  // src/components/parse-color.ts
@@ -23637,9 +23861,9 @@ var AudioWaveform = ({
23637
23861
  if (vidConf === null) {
23638
23862
  throw new Error("Expected video config");
23639
23863
  }
23640
- const containerRef = useRef42(null);
23641
- const waveformCanvas = useRef42(null);
23642
- const volumeCanvas = useRef42(null);
23864
+ const containerRef = useRef43(null);
23865
+ const waveformCanvas = useRef43(null);
23866
+ const volumeCanvas = useRef43(null);
23643
23867
  useEffect73(() => {
23644
23868
  const controller = new AbortController;
23645
23869
  setError(null);
@@ -23835,7 +24059,7 @@ var LoopedTimelineIndicator = ({ loops }) => {
23835
24059
  };
23836
24060
 
23837
24061
  // src/components/Timeline/TimelineImageInfo.tsx
23838
- import { useEffect as useEffect74, useRef as useRef43 } from "react";
24062
+ import { useEffect as useEffect74, useRef as useRef44 } from "react";
23839
24063
  import { jsx as jsx215 } from "react/jsx-runtime";
23840
24064
  var HEIGHT = getTimelineLayerHeight("image") - 2;
23841
24065
  var containerStyle3 = {
@@ -23847,7 +24071,7 @@ var containerStyle3 = {
23847
24071
  borderBottomLeftRadius: 2
23848
24072
  };
23849
24073
  var TimelineImageInfo = ({ src, visualizationWidth }) => {
23850
- const ref2 = useRef43(null);
24074
+ const ref2 = useRef44(null);
23851
24075
  useEffect74(() => {
23852
24076
  const { current } = ref2;
23853
24077
  if (!current) {
@@ -23912,7 +24136,7 @@ var TimelineSequenceFrame = ({ roundedFrame, premounted, postmounted }) => {
23912
24136
  };
23913
24137
 
23914
24138
  // src/components/Timeline/TimelineVideoInfo.tsx
23915
- import { useEffect as useEffect75, useMemo as useMemo120, useRef as useRef44, useState as useState81 } from "react";
24139
+ import { useEffect as useEffect75, useMemo as useMemo120, useRef as useRef45, useState as useState81 } from "react";
23916
24140
  import { useVideoConfig as useVideoConfig5 } from "remotion";
23917
24141
 
23918
24142
  // src/helpers/extract-frames.ts
@@ -24273,9 +24497,9 @@ var TimelineVideoInfo = ({
24273
24497
  postmountWidth
24274
24498
  }) => {
24275
24499
  const { fps } = useVideoConfig5();
24276
- const ref2 = useRef44(null);
24500
+ const ref2 = useRef45(null);
24277
24501
  const [error, setError] = useState81(null);
24278
- const aspectRatio = useRef44(getAspectRatioFromCache(src));
24502
+ const aspectRatio = useRef45(getAspectRatioFromCache(src));
24279
24503
  useEffect75(() => {
24280
24504
  if (error) {
24281
24505
  return;
@@ -26250,7 +26474,7 @@ import {
26250
26474
  useContext as useContext91,
26251
26475
  useEffect as useEffect81,
26252
26476
  useMemo as useMemo131,
26253
- useRef as useRef46,
26477
+ useRef as useRef47,
26254
26478
  useState as useState87
26255
26479
  } from "react";
26256
26480
  import { Internals as Internals64 } from "remotion";
@@ -27148,7 +27372,7 @@ var QuickSwitcherNoResults = ({ query, mode }) => {
27148
27372
  };
27149
27373
 
27150
27374
  // src/components/QuickSwitcher/QuickSwitcherResult.tsx
27151
- import { useEffect as useEffect80, useMemo as useMemo130, useRef as useRef45, useState as useState86 } from "react";
27375
+ import { useEffect as useEffect80, useMemo as useMemo130, useRef as useRef46, useState as useState86 } from "react";
27152
27376
  import { jsx as jsx239, jsxs as jsxs122, Fragment as Fragment37 } from "react/jsx-runtime";
27153
27377
  var container50 = {
27154
27378
  paddingLeft: 16,
@@ -27178,7 +27402,7 @@ var labelContainer = {
27178
27402
  };
27179
27403
  var QuickSwitcherResult = ({ result, selected }) => {
27180
27404
  const [hovered, setIsHovered] = useState86(false);
27181
- const ref2 = useRef45(null);
27405
+ const ref2 = useRef46(null);
27182
27406
  const keybindings = useKeybinding();
27183
27407
  useEffect80(() => {
27184
27408
  const { current } = ref2;
@@ -27356,7 +27580,7 @@ var QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio }
27356
27580
  selectedIndex: 0
27357
27581
  });
27358
27582
  }, [initialMode, invocationTimestamp]);
27359
- const inputRef = useRef46(null);
27583
+ const inputRef = useRef47(null);
27360
27584
  const selectComposition = useSelectComposition();
27361
27585
  const closeMenu = useCallback122(() => {
27362
27586
  return;
@@ -28132,7 +28356,7 @@ import {
28132
28356
  useEffect as useEffect84,
28133
28357
  useMemo as useMemo142,
28134
28358
  useReducer as useReducer2,
28135
- useRef as useRef48,
28359
+ useRef as useRef49,
28136
28360
  useState as useState93
28137
28361
  } from "react";
28138
28362
 
@@ -30121,12 +30345,12 @@ import { BrowserSafeApis as BrowserSafeApis7 } from "@remotion/renderer/client";
30121
30345
  import { useCallback as useCallback134, useMemo as useMemo137 } from "react";
30122
30346
 
30123
30347
  // src/helpers/use-file-existence.ts
30124
- import { useContext as useContext93, useEffect as useEffect83, useRef as useRef47, useState as useState92 } from "react";
30348
+ import { useContext as useContext93, useEffect as useEffect83, useRef as useRef48, useState as useState92 } from "react";
30125
30349
  var useFileExistence = (outName) => {
30126
30350
  const [exists, setExists] = useState92(false);
30127
30351
  const { previewServerState: state, subscribeToEvent } = useContext93(StudioServerConnectionCtx);
30128
30352
  const clientId = state.type === "connected" ? state.clientId : undefined;
30129
- const currentOutName = useRef47("");
30353
+ const currentOutName = useRef48("");
30130
30354
  currentOutName.current = outName;
30131
30355
  useEffect83(() => {
30132
30356
  if (!clientId) {
@@ -31519,7 +31743,7 @@ var RenderModal = ({
31519
31743
  resolved: { result: resolvedComposition },
31520
31744
  unresolved: unresolvedComposition
31521
31745
  } = context;
31522
- const isMounted = useRef48(true);
31746
+ const isMounted = useRef49(true);
31523
31747
  const [isVideo] = useState93(() => {
31524
31748
  return typeof resolvedComposition.durationInFrames === "undefined" ? true : resolvedComposition.durationInFrames > 1;
31525
31749
  });
@@ -32665,9 +32889,9 @@ import {
32665
32889
  getEncodableAudioCodecs,
32666
32890
  getSupportedAudioCodecsForContainer
32667
32891
  } from "@remotion/web-renderer";
32668
- import { useEffect as useEffect85, useRef as useRef49, useState as useState94 } from "react";
32892
+ import { useEffect as useEffect85, useRef as useRef50, useState as useState94 } from "react";
32669
32893
  var useEncodableAudioCodecs = (container61) => {
32670
- const cacheRef = useRef49({});
32894
+ const cacheRef = useRef50({});
32671
32895
  const [codecsByContainer, setCodecsByContainer] = useState94(() => {
32672
32896
  return {
32673
32897
  [container61]: getSupportedAudioCodecsForContainer(container61)
@@ -32707,9 +32931,9 @@ import {
32707
32931
  getEncodableVideoCodecs,
32708
32932
  getSupportedVideoCodecsForContainer
32709
32933
  } from "@remotion/web-renderer";
32710
- import { useEffect as useEffect86, useRef as useRef50, useState as useState95 } from "react";
32934
+ import { useEffect as useEffect86, useRef as useRef51, useState as useState95 } from "react";
32711
32935
  var useEncodableVideoCodecs = (container61) => {
32712
- const cacheRef = useRef50({});
32936
+ const cacheRef = useRef51({});
32713
32937
  const [codecsByContainer, setCodecsByContainer] = useState95(() => {
32714
32938
  return {
32715
32939
  [container61]: getSupportedVideoCodecsForContainer(container61)
@@ -35094,15 +35318,15 @@ var SetTimelineInOutProvider = ({ children }) => {
35094
35318
  };
35095
35319
 
35096
35320
  // src/components/ShowGuidesProvider.tsx
35097
- import { useCallback as useCallback153, useMemo as useMemo156, useRef as useRef51, useState as useState106 } from "react";
35321
+ import { useCallback as useCallback153, useMemo as useMemo156, useRef as useRef52, useState as useState106 } from "react";
35098
35322
  import { jsx as jsx298 } from "react/jsx-runtime";
35099
35323
  var ShowGuidesProvider = ({ children }) => {
35100
35324
  const [guidesList, setGuidesList] = useState106(() => loadGuidesList());
35101
35325
  const [selectedGuideId, setSelectedGuideId] = useState106(null);
35102
35326
  const [hoveredGuideId, setHoveredGuideId] = useState106(null);
35103
35327
  const [editorShowGuides, setEditorShowGuidesState] = useState106(() => loadEditorShowGuidesOption());
35104
- const shouldCreateGuideRef = useRef51(false);
35105
- const shouldDeleteGuideRef = useRef51(false);
35328
+ const shouldCreateGuideRef = useRef52(false);
35329
+ const shouldDeleteGuideRef = useRef52(false);
35106
35330
  const setEditorShowGuides = useCallback153((newValue) => {
35107
35331
  setEditorShowGuidesState((prevState) => {
35108
35332
  const newVal = newValue(prevState);
@@ -35817,7 +36041,7 @@ var StudioInner = ({ rootComponent, readOnly, visualModeEnabled }) => {
35817
36041
  });
35818
36042
  };
35819
36043
  var Studio = ({ rootComponent, readOnly, visualModeEnabled }) => {
35820
- useLayoutEffect4(() => {
36044
+ useLayoutEffect6(() => {
35821
36045
  injectCSS();
35822
36046
  }, []);
35823
36047
  return /* @__PURE__ */ jsx305(FastRefreshProvider, {