@remotion/studio 4.0.526 → 4.0.527

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 (98) hide show
  1. package/dist/components/Canvas.js +88 -26
  2. package/dist/components/CanvasCaptureDropHandler.js +63 -0
  3. package/dist/components/CanvasOrLoading.js +10 -2
  4. package/dist/components/CompositionSelectorItem.js +1 -0
  5. package/dist/components/CurrentAsset.js +2 -1
  6. package/dist/components/InitialCompositionLoader.js +1 -1
  7. package/dist/components/InlineDropdown.js +26 -2
  8. package/dist/components/InlineEditableTitle.js +1 -0
  9. package/dist/components/InspectorPanel/CollapsibleInspectorSectionHeader.js +1 -0
  10. package/dist/components/InspectorPanel/CompositionInspector.js +3 -3
  11. package/dist/components/InspectorPanel/CompositionMetadata.js +4 -0
  12. package/dist/components/InspectorPanel/ElementLibraryButton.js +1 -0
  13. package/dist/components/InspectorPanel/MultiSequenceInspector.js +32 -1
  14. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +41 -1
  15. package/dist/components/InspectorPanel/common.js +1 -0
  16. package/dist/components/InspectorPanel/styles.js +2 -0
  17. package/dist/components/InspectorPanel/use-composition-actions.js +1 -0
  18. package/dist/components/InspectorSourceLocation.js +3 -0
  19. package/dist/components/MenuBuildIndicator.js +1 -0
  20. package/dist/components/NewComposition/CancelButton.js +1 -1
  21. package/dist/components/Preview.js +3 -0
  22. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +1 -0
  23. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +1 -0
  24. package/dist/components/RadioButton.js +1 -0
  25. package/dist/components/RenderModal/DataEditor.js +4 -1
  26. package/dist/components/RenderQueue/CaptionQueueItem.js +5 -2
  27. package/dist/components/RenderQueue/CaptionQueueProcessor.js +35 -8
  28. package/dist/components/RenderQueue/VideoMattingQueueItem.js +1 -0
  29. package/dist/components/RenderQueue/caption-job-types.d.ts +6 -0
  30. package/dist/components/RenderQueue/index.js +1 -0
  31. package/dist/components/RendersTab.js +2 -0
  32. package/dist/components/SelectedOutlineSnapIndicators.d.ts +6 -0
  33. package/dist/components/SelectedOutlineSnapIndicators.js +16 -12
  34. package/dist/components/SequencePropsSubscriptionProvider.d.ts +3 -0
  35. package/dist/components/SequencePropsSubscriptionProvider.js +8 -6
  36. package/dist/components/Timeline/TimelineDeleteKeybindings.js +6 -9
  37. package/dist/components/Timeline/TimelineEffectItem.js +1 -0
  38. package/dist/components/Timeline/TimelineExpandArrowButton.js +1 -0
  39. package/dist/components/Timeline/TimelineExpandedRow.js +1 -0
  40. package/dist/components/Timeline/TimelineFieldLabel.js +1 -0
  41. package/dist/components/Timeline/TimelineKeyframeControls.js +1 -0
  42. package/dist/components/Timeline/TimelineSequence.js +26 -0
  43. package/dist/components/Timeline/TimelineSequenceFrame.js +1 -0
  44. package/dist/components/Timeline/TimelineSequenceItem.js +28 -0
  45. package/dist/components/Timeline/TimelineViewport.d.ts +1 -0
  46. package/dist/components/Timeline/TimelineViewport.js +10 -1
  47. package/dist/components/Timeline/delete-selected-timeline-item.js +2 -2
  48. package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +3 -1
  49. package/dist/components/Timeline/get-sequence-context-menu-items.js +13 -1
  50. package/dist/components/Timeline/split-selected-timeline-item.d.ts +13 -10
  51. package/dist/components/Timeline/split-selected-timeline-item.js +58 -35
  52. package/dist/components/TimelineCombobox.js +1 -0
  53. package/dist/components/Transcription/TranscriptionModal.js +16 -11
  54. package/dist/components/Transcription/TranscriptionModalWithOptionalWhisper.js +1 -1
  55. package/dist/components/WebMcp.js +1 -0
  56. package/dist/components/composition-drop-preview.d.ts +9 -2
  57. package/dist/components/composition-drop-preview.js +7 -4
  58. package/dist/components/composition-menu-items.js +4 -4
  59. package/dist/components/delete-jsx-nodes-api.d.ts +2 -0
  60. package/dist/components/{delete-jsx-node-api.js → delete-jsx-nodes-api.js} +5 -5
  61. package/dist/components/get-open-in-menu-items.js +7 -7
  62. package/dist/components/keyboard-shortcuts.d.ts +4 -4
  63. package/dist/components/keyboard-shortcuts.js +3 -1
  64. package/dist/components/public-output-name.d.ts +1 -0
  65. package/dist/components/public-output-name.js +7 -3
  66. package/dist/esm/{CaptionQueueProcessor-k0yrm3dj.mjs → CaptionQueueProcessor-npa6szn1.mjs} +39 -8
  67. package/dist/esm/{LazyModels-nk7py0zt.mjs → LazyModels-nh3c8h9p.mjs} +4 -3
  68. package/dist/esm/{LazyModels-mtggyjye.mjs → LazyModels-rr5v8h5y.mjs} +4 -3
  69. package/dist/esm/{TranscriptionModal-ymnx1c7m.mjs → TranscriptionModal-79m5wgcj.mjs} +25 -17
  70. package/dist/esm/{VideoMattingModal-05vpczks.mjs → VideoMattingModal-31pew0xj.mjs} +9 -6
  71. package/dist/esm/index-21hxsfaa.mjs +239 -0
  72. package/dist/esm/{index-0gewwxse.mjs → index-4zen9prq.mjs} +2293 -2203
  73. package/dist/esm/index-5t2dwxsk.mjs +530 -0
  74. package/dist/esm/{index-5gd8k9yv.mjs → index-614tdz2q.mjs} +1 -1
  75. package/dist/esm/{index-cdy8v54v.mjs → index-9xxg6218.mjs} +20 -541
  76. package/dist/esm/{index-5bfxbpca.mjs → index-ac5550e7.mjs} +1 -1
  77. package/dist/esm/{index-eb5txqp6.mjs → index-e855w59j.mjs} +8 -86
  78. package/dist/esm/{index-4dsz9035.mjs → index-n5gmcvhz.mjs} +1 -1
  79. package/dist/esm/{index-bs39wngg.mjs → index-ppspzgn9.mjs} +3134 -2994
  80. package/dist/esm/{index-g7k2dvar.mjs → index-r0ejh5sy.mjs} +1 -1
  81. package/dist/esm/index-r1gr3j3a.mjs +80 -0
  82. package/dist/esm/{index-x40wwfmt.mjs → index-s7qa3xbw.mjs} +6 -4
  83. package/dist/esm/{index-f97r9e2g.mjs → index-vxwg66ar.mjs} +5 -3
  84. package/dist/esm/index.mjs +3 -2
  85. package/dist/esm/internals.mjs +10 -7
  86. package/dist/esm/previewEntry.mjs +10 -7
  87. package/dist/esm/{resolve-composition-component-location-bt2d6qxq.mjs → resolve-composition-component-location-qrp05g62.mjs} +1 -1
  88. package/dist/helpers/copy-text.js +1 -16
  89. package/dist/helpers/hoverable.js +2 -1
  90. package/dist/helpers/open-in-editor.js +1 -1
  91. package/dist/helpers/studio-runtime-config.d.ts +1 -1
  92. package/dist/helpers/use-keybinding.d.ts +1 -1
  93. package/dist/helpers/use-keyboard-shortcut-label.d.ts +2 -2
  94. package/dist/helpers/use-menu-structure.js +15 -9
  95. package/dist/state/modals.d.ts +5 -0
  96. package/dist/state/timeline-zoom.js +4 -0
  97. package/package.json +19 -19
  98. package/dist/components/delete-jsx-node-api.d.ts +0 -2
@@ -6,15 +6,19 @@ const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const client_id_1 = require("../../helpers/client-id");
8
8
  const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
9
+ const use_media_metadata_1 = require("../../helpers/use-media-metadata");
9
10
  const audio_1 = require("../../icons/audio");
10
11
  const duplicate_1 = require("../../icons/duplicate");
11
12
  const scissors_1 = require("../../icons/scissors");
12
13
  const snowflake_1 = require("../../icons/snowflake");
14
+ const transcription_1 = require("../../icons/transcription");
13
15
  const trash_1 = require("../../icons/trash");
16
+ const modals_1 = require("../../state/modals");
14
17
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
15
18
  const InspectorSequenceSection_1 = require("../InspectorSequenceSection");
16
19
  const is_menu_item_1 = require("../Menu/is-menu-item");
17
20
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
21
+ const public_output_name_1 = require("../public-output-name");
18
22
  const split_video_from_audio_api_1 = require("../split-video-from-audio-api");
19
23
  const duplicate_selected_timeline_item_1 = require("../Timeline/duplicate-selected-timeline-item");
20
24
  const split_selected_timeline_item_1 = require("../Timeline/split-selected-timeline-item");
@@ -70,8 +74,10 @@ const SplitSequenceQuickAction = ({ selection, track }) => {
70
74
  return (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: !canSplit, onClick: onSplit, title: disabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(scissors_1.ScissorsIcon, { style: actionIconStyle, color: color })), children: "Split clip" }));
71
75
  };
72
76
  const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
77
+ var _a;
73
78
  const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
74
79
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
80
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
75
81
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
76
82
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
77
83
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
@@ -90,6 +96,40 @@ const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
90
96
  validatedSource,
91
97
  });
92
98
  const sourceActionsDisabled = previewServerState.type !== 'connected' || !(0, interactivity_enabled_1.isStudioInteractivityEnabled)();
99
+ const mediaSequence = track.sequence.type === 'video' || track.sequence.type === 'audio'
100
+ ? track.sequence
101
+ : null;
102
+ const mediaMetadata = (0, use_media_metadata_1.useMediaMetadata)((_a = mediaSequence === null || mediaSequence === void 0 ? void 0 : mediaSequence.src) !== null && _a !== void 0 ? _a : null);
103
+ const transcriptionDisabledReason = sourceActionsDisabled
104
+ ? 'Studio is read-only'
105
+ : selection.nodePathInfo.numberOfSequencesWithThisNodePath > 1
106
+ ? 'Programmatically duplicated media cannot be transcribed from source'
107
+ : undefined;
108
+ const onGenerateCaptions = (0, react_1.useCallback)(() => {
109
+ if (transcriptionDisabledReason !== undefined || mediaSequence === null) {
110
+ return;
111
+ }
112
+ const nodePath = selection.nodePathInfo.sequenceSubscriptionKey;
113
+ setSelectedModal({
114
+ type: 'transcribe',
115
+ src: mediaSequence.src,
116
+ displayName: (0, public_output_name_1.getMediaFileName)(mediaSequence.src, mediaSequence.displayName),
117
+ audioStreamIndex: null,
118
+ requestInit: null,
119
+ target: {
120
+ fileName: nodePath.absolutePath,
121
+ nodePath,
122
+ durationInFrames: Number.isFinite(mediaSequence.duration)
123
+ ? mediaSequence.duration
124
+ : null,
125
+ },
126
+ });
127
+ }, [
128
+ selection.nodePathInfo,
129
+ setSelectedModal,
130
+ mediaSequence,
131
+ transcriptionDisabledReason,
132
+ ]);
93
133
  const onDuplicate = (0, react_1.useCallback)(() => {
94
134
  if (sourceActionsDisabled) {
95
135
  return;
@@ -125,7 +165,7 @@ const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
125
165
  (0, NotificationCenter_1.showNotification)(err.message, 4000);
126
166
  });
127
167
  }, [selection.nodePathInfo, splitVideoFromAudioDisabledReason]);
128
- return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [(freezeFrameMenuItem === null || freezeFrameMenuItem === void 0 ? void 0 : freezeFrameMenuItem.type) === 'item' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: Boolean(freezeFrameMenuItem.disabled), onClick: () => freezeFrameMenuItem.onClick(freezeFrameMenuItem.id, null), renderIcon: (color) => (jsx_runtime_1.jsx(snowflake_1.SnowflakeIcon, { style: largeActionIconStyle, color: color })), children: freezeFrameMenuItem.label })) : null, track.sequence.type === 'video' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: splitVideoFromAudioDisabledReason !== undefined, onClick: onSplitVideoFromAudio, title: splitVideoFromAudioDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(audio_1.AudioIcon, { style: actionIconStyle, color: color })), children: "Split video from audio" })) : null, jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDuplicate, renderIcon: (color) => (jsx_runtime_1.jsx(duplicate_1.DuplicateIcon, { style: largeActionIconStyle, color: color })), children: "Duplicate" }), jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDelete, renderIcon: (color) => (jsx_runtime_1.jsx(trash_1.TrashIcon, { style: actionIconStyle, color: color })), children: "Delete" })] }));
168
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [(freezeFrameMenuItem === null || freezeFrameMenuItem === void 0 ? void 0 : freezeFrameMenuItem.type) === 'item' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: Boolean(freezeFrameMenuItem.disabled), onClick: () => freezeFrameMenuItem.onClick(freezeFrameMenuItem.id, null), renderIcon: (color) => (jsx_runtime_1.jsx(snowflake_1.SnowflakeIcon, { style: largeActionIconStyle, color: color })), children: freezeFrameMenuItem.label })) : null, track.sequence.type === 'video' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: splitVideoFromAudioDisabledReason !== undefined, onClick: onSplitVideoFromAudio, title: splitVideoFromAudioDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(audio_1.AudioIcon, { style: actionIconStyle, color: color })), children: "Split video from audio" })) : null, mediaSequence !== null && (mediaMetadata === null || mediaMetadata === void 0 ? void 0 : mediaMetadata.hasAudioTrack) !== false ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: transcriptionDisabledReason !== undefined, onClick: onGenerateCaptions, title: transcriptionDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(transcription_1.TranscriptionIcon, { style: actionIconStyle, color: color })), children: "Generate captions" })) : null, jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDuplicate, renderIcon: (color) => (jsx_runtime_1.jsx(duplicate_1.DuplicateIcon, { style: largeActionIconStyle, color: color })), children: "Duplicate" }), jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDelete, renderIcon: (color) => (jsx_runtime_1.jsx(trash_1.TrashIcon, { style: actionIconStyle, color: color })), children: "Delete" })] }));
129
169
  };
130
170
  const SequenceExpandedInspector = ({ track, readOnlyStudio }) => {
131
171
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
@@ -89,6 +89,7 @@ const inlineLabelText = {
89
89
  overflow: 'hidden',
90
90
  textOverflow: 'ellipsis',
91
91
  userSelect: 'none',
92
+ WebkitUserSelect: 'none',
92
93
  whiteSpace: 'nowrap',
93
94
  };
94
95
  const inlineLabelIcon = {
@@ -40,6 +40,7 @@ exports.sectionHeader = {
40
40
  lineHeight: '24px',
41
41
  padding: `4px 0 4px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
42
42
  userSelect: 'none',
43
+ WebkitUserSelect: 'none',
43
44
  };
44
45
  exports.inspectorSectionBody = {
45
46
  display: 'flex',
@@ -144,6 +145,7 @@ exports.detailLabel = {
144
145
  overflow: 'hidden',
145
146
  textOverflow: 'ellipsis',
146
147
  userSelect: 'none',
148
+ WebkitUserSelect: 'none',
147
149
  whiteSpace: 'nowrap',
148
150
  };
149
151
  exports.detailValue = {
@@ -59,6 +59,7 @@ const useCompositionActions = () => {
59
59
  const canInsertComposition = canShowInsertComposition && !isAddingComposition;
60
60
  const canShowGenerateWithAgent = previewInteractive &&
61
61
  !window.remotion_isReadOnlyStudio &&
62
+ browserStudioOperations === null &&
62
63
  currentCompositionId !== null;
63
64
  const insertSolid = (0, react_1.useCallback)(async () => {
64
65
  if (!canInsertSolid ||
@@ -28,11 +28,13 @@ const sourceLocationStyle = {
28
28
  textDecoration: 'none',
29
29
  textOverflow: 'ellipsis',
30
30
  userSelect: 'none',
31
+ WebkitUserSelect: 'none',
31
32
  whiteSpace: 'nowrap',
32
33
  width: 'fit-content',
33
34
  };
34
35
  const quickActionStyle = {
35
36
  userSelect: 'none',
37
+ WebkitUserSelect: 'none',
36
38
  };
37
39
  const sourceLocationLabelStyle = {
38
40
  color: 'inherit',
@@ -44,6 +46,7 @@ const sourceLocationLabelStyle = {
44
46
  overflow: 'hidden',
45
47
  textOverflow: 'ellipsis',
46
48
  userSelect: 'none',
49
+ WebkitUserSelect: 'none',
47
50
  whiteSpace: 'nowrap',
48
51
  };
49
52
  const InspectorSourceLocation = ({ location, canOpen, onOpen, renderIcon, size = 'default' }) => {
@@ -15,6 +15,7 @@ const cwd = {
15
15
  alignItems: 'center',
16
16
  justifyContent: 'center',
17
17
  userSelect: 'none',
18
+ WebkitUserSelect: 'none',
18
19
  whiteSpace: 'nowrap',
19
20
  };
20
21
  const spinnerSize = 14;
@@ -15,7 +15,7 @@ const style = {
15
15
  alignItems: 'center',
16
16
  };
17
17
  const CancelIcon = (props) => {
18
- return (jsx_runtime_1.jsx("svg", { viewBox: "0 0 320 512", ...props, children: jsx_runtime_1.jsx("path", { fill: colors_1.CURRENT_COLOR, d: "M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z" }) }));
18
+ return (jsx_runtime_1.jsx("svg", { viewBox: "0 0 640 640", ...props, children: jsx_runtime_1.jsx("path", { fill: colors_1.CURRENT_COLOR, d: "M507.3 155.3C513.5 149.1 513.5 138.9 507.3 132.7C501.1 126.5 490.9 126.5 484.7 132.7L320 297.4L155.3 132.7C149.1 126.5 138.9 126.5 132.7 132.7C126.5 138.9 126.5 149.1 132.7 155.3L297.4 320L132.7 484.7C126.5 490.9 126.5 501.1 132.7 507.3C138.9 513.5 149.1 513.5 155.3 507.3L320 342.6L484.7 507.3C490.9 513.5 501.1 513.5 507.3 507.3C513.5 501.1 513.5 490.9 507.3 484.7L342.6 320L507.3 155.3z" }) }));
19
19
  };
20
20
  exports.CancelIcon = CancelIcon;
21
21
  const CancelButton = ({ onPress, ...props }) => {
@@ -47,6 +47,9 @@ const PIXEL_GRID_MIN_SCALE = 4;
47
47
  const containerStyle = (options) => {
48
48
  return {
49
49
  transform: `scale(${options.scale})`,
50
+ // Keep the scaled composition on its own layer so the checkerboard does
51
+ // not bleed through its edges at fractional preview scales.
52
+ willChange: 'transform',
50
53
  marginLeft: options.xCorrection,
51
54
  marginTop: options.yCorrection,
52
55
  width: options.width,
@@ -29,6 +29,7 @@ const quickSwitcherTrigger = {
29
29
  flex: 1,
30
30
  appearance: 'none',
31
31
  userSelect: 'none',
32
+ WebkitUserSelect: 'none',
32
33
  ...(0, hoverable_1.hoverableStyle)({
33
34
  idleBackground: colors_1.WHITE_ALPHA_06,
34
35
  hoverBackground: colors_1.WHITE_ALPHA_06,
@@ -49,6 +49,7 @@ const modeItem = {
49
49
  fontSize: 13,
50
50
  cursor: 'pointer',
51
51
  userSelect: 'none',
52
+ WebkitUserSelect: 'none',
52
53
  };
53
54
  const modeInactive = {
54
55
  ...modeItem,
@@ -29,6 +29,7 @@ const row = {
29
29
  padding: '4px 8px',
30
30
  textAlign: 'left',
31
31
  userSelect: 'none',
32
+ WebkitUserSelect: 'none',
32
33
  width: 'calc(100% + 16px)',
33
34
  };
34
35
  const circle = {
@@ -274,6 +274,9 @@ const DataEditor = ({ unresolvedComposition, defaultProps, setDefaultProps, prop
274
274
  if (!unresolvedComposition.defaultProps) {
275
275
  return jsx_runtime_1.jsx(SchemaErrorMessages_1.NoDefaultProps, { mode: schemaErrorMode });
276
276
  }
277
+ // <Composition> normalizes omitted defaultProps to an empty object.
278
+ // Avoid rendering field editors with undefined values in that case.
279
+ const emptyDefaultPropsAreInvalid = Object.keys(defaultProps).length === 0 && !zodValidationResult.success;
277
280
  const shouldRenderControlRow = !hideModeControls || (!hideWarningButton && warnings.length > 0);
278
281
  const shouldRenderWarningMessages = showWarning && warnings.length > 0;
279
282
  const compactLayout = layout === 'inspector';
@@ -284,6 +287,6 @@ const DataEditor = ({ unresolvedComposition, defaultProps, setDefaultProps, prop
284
287
  jsx_runtime_1.jsx(layout_1.Spacing, { y: 1 }), jsx_runtime_1.jsx(ValidationMessage_1.ValidationMessage, { message: warning.message, align: "flex-start", type: "warning", size: compactLayout ? 'compact' : 'default', action: warning.resolveLink ? (jsx_runtime_1.jsx("a", { href: warning.resolveLink, target: "_blank", rel: "noopener noreferrer", style: compactLayout
285
288
  ? compactResolveLinkStyle
286
289
  : resolveLinkStyle, children: "Resolve" })) : null })] }, warning.id)))
287
- : null] })) : null, mode === 'schema' ? (jsx_runtime_1.jsx(SchemaEditor_1.SchemaEditor, { value: defaultProps, setValue: setDefaultProps, schema: schema, scrollableContainer: !compactLayout, contentInset: compactLayout ? InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING : undefined, errorMode: schemaErrorMode })) : (jsx_runtime_1.jsx(RenderModalJSONPropsEditor_1.RenderModalJSONPropsEditor, { value: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}, setValue: jsonEditorSetValue, onSave: onSave, serializedJSON: serializedJSON, defaultProps: unresolvedComposition.defaultProps, schema: schema, compositionId: unresolvedComposition.id, layout: layout }))] }));
290
+ : null] })) : null, mode === 'schema' ? (emptyDefaultPropsAreInvalid ? (jsx_runtime_1.jsx(SchemaErrorMessages_1.InvalidDefaultProps, { zodValidationResult: zodValidationResult })) : (jsx_runtime_1.jsx(SchemaEditor_1.SchemaEditor, { value: defaultProps, setValue: setDefaultProps, schema: schema, scrollableContainer: !compactLayout, contentInset: compactLayout ? InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING : undefined, errorMode: schemaErrorMode }))) : (jsx_runtime_1.jsx(RenderModalJSONPropsEditor_1.RenderModalJSONPropsEditor, { value: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}, setValue: jsonEditorSetValue, onSave: onSave, serializedJSON: serializedJSON, defaultProps: unresolvedComposition.defaultProps, schema: schema, compositionId: unresolvedComposition.id, layout: layout }))] }));
288
291
  };
289
292
  exports.DataEditor = DataEditor;
@@ -68,7 +68,7 @@ const CaptionQueueItem = ({ job, selected }) => {
68
68
  const [hovered, setHovered] = (0, react_1.useState)(false);
69
69
  const { removeCaptionJob } = (0, react_1.useContext)(context_1.RenderQueueContext);
70
70
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
71
- const isHoverable = job.status === 'done';
71
+ const isHoverable = job.status === 'done' && job.target === null;
72
72
  const containerStyle = (0, react_1.useMemo)(() => {
73
73
  return {
74
74
  ...container,
@@ -95,6 +95,9 @@ const CaptionQueueItem = ({ job, selected }) => {
95
95
  if (job.status !== 'done') {
96
96
  return;
97
97
  }
98
+ if (job.target !== null) {
99
+ return;
100
+ }
98
101
  selectAsset(job.outName);
99
102
  (0, url_state_1.pushUrl)(`/assets/${job.outName}`);
100
103
  }, [job, selectAsset]);
@@ -120,7 +123,7 @@ const CaptionQueueItem = ({ job, selected }) => {
120
123
  if (job.status === 'failed') {
121
124
  return job.error.message;
122
125
  }
123
- return job.outName;
126
+ return job.target === null ? job.outName : 'Captions added to composition';
124
127
  }, [job]);
125
128
  return (jsx_runtime_1.jsxs(layout_1.Row, { "data-render-queue-item": job.id, style: containerStyle, align: "center", onClick: onClick, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, className: selected ? item_style_1.RENDER_QUEUE_ITEM_SELECTED_CLASSNAME : undefined, children: [
126
129
  jsx_runtime_1.jsx(CaptionJobStatus, { job: job }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsxs("div", { style: right, children: [
@@ -4,6 +4,9 @@ exports.CaptionQueueProcessor = void 0;
4
4
  const whisper_webgpu_1 = require("@remotion/whisper-webgpu");
5
5
  const react_1 = require("react");
6
6
  const write_static_file_1 = require("../../api/write-static-file");
7
+ const browser_studio_operations_1 = require("../../helpers/browser-studio-operations");
8
+ const install_required_package_1 = require("../../helpers/install-required-package");
9
+ const call_api_1 = require("../call-api");
7
10
  const resample_media_to_16_khz_1 = require("../Transcription/resample-media-to-16-khz");
8
11
  const context_1 = require("./context");
9
12
  const load_model_for_job_1 = require("./load-model-for-job");
@@ -73,14 +76,38 @@ const CaptionQueueProcessor = () => {
73
76
  const { captions } = (0, whisper_webgpu_1.toCaptions)({
74
77
  whisperWebGpuOutput: transcription,
75
78
  });
76
- updateCaptionJobProgress(job.id, {
77
- message: `Saving ${job.outName}...`,
78
- value: 0.95,
79
- });
80
- await (0, write_static_file_1.writeStaticFile)({
81
- contents: JSON.stringify(captions, null, 2),
82
- filePath: job.outName,
83
- });
79
+ if (job.target === null) {
80
+ updateCaptionJobProgress(job.id, {
81
+ message: `Saving ${job.outName}...`,
82
+ value: 0.95,
83
+ });
84
+ await (0, write_static_file_1.writeStaticFile)({
85
+ contents: JSON.stringify(captions, null, 2),
86
+ filePath: job.outName,
87
+ });
88
+ }
89
+ else {
90
+ updateCaptionJobProgress(job.id, {
91
+ message: 'Adding Basic captions...',
92
+ value: 0.95,
93
+ });
94
+ await (0, install_required_package_1.installRequiredPackages)([
95
+ { name: '@remotion/captions', version: null },
96
+ ]);
97
+ const request = {
98
+ fileName: job.target.fileName,
99
+ nodePath: job.target.nodePath.nodePath,
100
+ durationInFrames: job.target.durationInFrames,
101
+ captions,
102
+ };
103
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
104
+ const response = browserStudioOperations
105
+ ? await browserStudioOperations.insertBasicCaptions(request)
106
+ : await (0, call_api_1.callApi)('/api/insert-basic-captions', request);
107
+ if (!response.success) {
108
+ throw new Error(response.reason);
109
+ }
110
+ }
84
111
  captionCount = captions.length;
85
112
  }
86
113
  catch (error) {
@@ -71,6 +71,7 @@ const VideoMattingQueueItem = ({ job, selected }) => {
71
71
  selected,
72
72
  }),
73
73
  userSelect: 'none',
74
+ WebkitUserSelect: 'none',
74
75
  }), [done, hovered, selected]);
75
76
  const messages = job.status === 'idle'
76
77
  ? ['Queued for video matting']
@@ -1,4 +1,5 @@
1
1
  import type { WhisperWebGpuModel, WhisperWebGpuTask } from '@remotion/whisper-webgpu';
2
+ import type { SequencePropsSubscriptionKey } from 'remotion';
2
3
  export type CaptionJobProgress = {
3
4
  message: string;
4
5
  value: number;
@@ -24,6 +25,11 @@ export type AddCaptionJobParams = {
24
25
  audioStreamIndex: number | null;
25
26
  requestInit: Omit<RequestInit, 'signal'> | null;
26
27
  outName: string;
28
+ target: {
29
+ fileName: string;
30
+ nodePath: SequencePropsSubscriptionKey;
31
+ durationInFrames: number | null;
32
+ } | null;
27
33
  model: WhisperWebGpuModel;
28
34
  language: string | null;
29
35
  task: WhisperWebGpuTask;
@@ -108,6 +108,7 @@ const RenderQueue = () => {
108
108
  for (let i = 0; i < allJobs.length; i++) {
109
109
  const job = allJobs[i];
110
110
  if ((0, caption_job_types_1.isCaptionJob)(job) &&
111
+ job.target === null &&
111
112
  job.status === 'done' &&
112
113
  canvasContent.asset === job.outName) {
113
114
  return i;
@@ -15,6 +15,7 @@ const row = {
15
15
  alignItems: 'center',
16
16
  flex: 1,
17
17
  userSelect: 'none',
18
+ WebkitUserSelect: 'none',
18
19
  };
19
20
  const badge = {
20
21
  height: 16,
@@ -25,6 +26,7 @@ const badge = {
25
26
  justifyContent: 'center',
26
27
  alignItems: 'center',
27
28
  userSelect: 'none',
29
+ WebkitUserSelect: 'none',
28
30
  };
29
31
  const RendersTab = ({ selected, onClick }) => {
30
32
  const { jobs, captionJobs } = (0, react_1.useContext)(context_1.RenderQueueContext);
@@ -1,6 +1,12 @@
1
1
  import React from 'react';
2
2
  import { type SelectedOutlineSnapPoint } from './selected-outline-snap';
3
3
  export type UpdateSelectedOutlineSnapPoints = (snapPoints: readonly SelectedOutlineSnapPoint[]) => void;
4
+ export declare const SelectedOutlineSnapLines: React.FC<{
5
+ readonly compositionHeight: number;
6
+ readonly compositionWidth: number;
7
+ readonly scale: number;
8
+ readonly snapPoints: readonly SelectedOutlineSnapPoint[];
9
+ }>;
4
10
  export declare const SelectedOutlineSnapIndicators: React.FC<{
5
11
  readonly compositionHeight: number;
6
12
  readonly compositionWidth: number;
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SelectedOutlineSnapIndicators = void 0;
3
+ exports.SelectedOutlineSnapIndicators = exports.SelectedOutlineSnapLines = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const selected_outline_snap_1 = require("./selected-outline-snap");
7
+ const SelectedOutlineSnapLines = ({ compositionHeight, compositionWidth, scale, snapPoints }) => {
8
+ if (snapPoints.length === 0) {
9
+ return null;
10
+ }
11
+ return (jsx_runtime_1.jsx("g", { pointerEvents: "none", children: snapPoints.map((snapPoint) => {
12
+ if (snapPoint.target.axis === 'x') {
13
+ const x = snapPoint.target.position * scale;
14
+ return (jsx_runtime_1.jsx("line", { x1: x, x2: x, y1: 0, y2: compositionHeight * scale, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
15
+ }
16
+ const y = snapPoint.target.position * scale;
17
+ return (jsx_runtime_1.jsx("line", { x1: 0, x2: compositionWidth * scale, y1: y, y2: y, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
18
+ }) }));
19
+ };
20
+ exports.SelectedOutlineSnapLines = SelectedOutlineSnapLines;
7
21
  const SelectedOutlineSnapIndicators = ({ compositionHeight, compositionWidth, scale, updateSnapPointsRef }) => {
8
22
  const [activeSnapPoints, setActiveSnapPoints] = (0, react_1.useState)([]);
9
23
  (0, react_1.useLayoutEffect)(() => {
@@ -14,16 +28,6 @@ const SelectedOutlineSnapIndicators = ({ compositionHeight, compositionWidth, sc
14
28
  }
15
29
  };
16
30
  }, [updateSnapPointsRef]);
17
- if (activeSnapPoints.length === 0) {
18
- return null;
19
- }
20
- return (jsx_runtime_1.jsx("g", { pointerEvents: "none", children: activeSnapPoints.map((snapPoint) => {
21
- if (snapPoint.target.axis === 'x') {
22
- const x = snapPoint.target.position * scale;
23
- return (jsx_runtime_1.jsx("line", { x1: x, x2: x, y1: 0, y2: compositionHeight * scale, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
24
- }
25
- const y = snapPoint.target.position * scale;
26
- return (jsx_runtime_1.jsx("line", { x1: 0, x2: compositionWidth * scale, y1: y, y2: y, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
27
- }) }));
31
+ return (jsx_runtime_1.jsx(exports.SelectedOutlineSnapLines, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, scale: scale, snapPoints: activeSnapPoints }));
28
32
  };
29
33
  exports.SelectedOutlineSnapIndicators = SelectedOutlineSnapIndicators;
@@ -1,4 +1,7 @@
1
1
  import type { OverrideIdToNodePaths, TSequence } from 'remotion';
2
+ export declare const OverrideIdToNodePathMappingsRefContext: import("react").Context<{
3
+ readonly current: OverrideIdToNodePaths;
4
+ }>;
2
5
  export declare const getReadOnlyOverrideIdToNodePathMappings: (sequences: readonly TSequence[]) => OverrideIdToNodePaths;
3
6
  export declare const SequencePropsSubscriptionProvider: React.FC<{
4
7
  readonly children: React.ReactNode;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SequencePropsSubscriptionProvider = exports.getReadOnlyOverrideIdToNodePathMappings = void 0;
3
+ exports.SequencePropsSubscriptionProvider = exports.getReadOnlyOverrideIdToNodePathMappings = exports.OverrideIdToNodePathMappingsRefContext = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
+ exports.OverrideIdToNodePathMappingsRefContext = (0, react_1.createContext)({ current: {} });
7
8
  const getReadOnlyOverrideIdToNodePathMappings = (sequences) => {
8
9
  return Object.fromEntries(sequences.flatMap((sequence) => {
9
10
  var _a;
@@ -32,6 +33,9 @@ const SequencePropsSubscriptionProvider = ({ children }) => {
32
33
  const readOnlyOverrideToNodePathMap = (0, react_1.useMemo)(() => window.remotion_isReadOnlyStudio
33
34
  ? (0, exports.getReadOnlyOverrideIdToNodePathMappings)(sequences)
34
35
  : null, [sequences]);
36
+ const overrideIdToNodePathMappings = readOnlyOverrideToNodePathMap !== null && readOnlyOverrideToNodePathMap !== void 0 ? readOnlyOverrideToNodePathMap : overrideToNodePathMap;
37
+ const overrideIdToNodePathMappingsRef = (0, react_1.useRef)(overrideIdToNodePathMappings);
38
+ overrideIdToNodePathMappingsRef.current = overrideIdToNodePathMappings;
35
39
  const setOverrideIdToNodePath = (0, react_1.useCallback)((overrideId, state) => {
36
40
  setOverrideIdToNodePathMap((prev) => {
37
41
  const existing = prev[overrideId];
@@ -50,13 +54,11 @@ const SequencePropsSubscriptionProvider = ({ children }) => {
50
54
  });
51
55
  }, []);
52
56
  const getters = (0, react_1.useMemo)(() => {
53
- return {
54
- overrideIdToNodePathMappings: readOnlyOverrideToNodePathMap !== null && readOnlyOverrideToNodePathMap !== void 0 ? readOnlyOverrideToNodePathMap : overrideToNodePathMap,
55
- };
56
- }, [overrideToNodePathMap, readOnlyOverrideToNodePathMap]);
57
+ return { overrideIdToNodePathMappings };
58
+ }, [overrideIdToNodePathMappings]);
57
59
  const setters = (0, react_1.useMemo)(() => {
58
60
  return { setOverrideIdToNodePath };
59
61
  }, [setOverrideIdToNodePath]);
60
- return (jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsGettersContext.Provider, { value: getters, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsSettersContext.Provider, { value: setters, children: children }) }));
62
+ return (jsx_runtime_1.jsx(exports.OverrideIdToNodePathMappingsRefContext.Provider, { value: overrideIdToNodePathMappingsRef, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsGettersContext.Provider, { value: getters, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsSettersContext.Provider, { value: setters, children: children }) }) }));
61
63
  };
62
64
  exports.SequencePropsSubscriptionProvider = SequencePropsSubscriptionProvider;
@@ -6,6 +6,7 @@ const remotion_1 = require("remotion");
6
6
  const client_id_1 = require("../../helpers/client-id");
7
7
  const use_keybinding_1 = require("../../helpers/use-keybinding");
8
8
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
9
+ const SequencePropsSubscriptionProvider_1 = require("../SequencePropsSubscriptionProvider");
9
10
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
10
11
  const imperative_state_1 = require("./imperative-state");
11
12
  const split_selected_timeline_item_1 = require("./split-selected-timeline-item");
@@ -15,7 +16,7 @@ const TimelineDeleteKeybindings = () => {
15
16
  const keybindings = (0, use_keybinding_1.useKeybinding)();
16
17
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
17
18
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
18
- const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
19
+ const overrideIdToNodePathMappingsRef = (0, react_1.useContext)(SequencePropsSubscriptionProvider_1.OverrideIdToNodePathMappingsRefContext);
19
20
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
20
21
  const { canSelect } = (0, TimelineSelection_1.useTimelineSelection)();
21
22
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
@@ -56,11 +57,8 @@ const TimelineDeleteKeybindings = () => {
56
57
  });
57
58
  const split = keybindings.registerKeybinding({
58
59
  event: 'keydown',
59
- key: 'd',
60
- callback: (event) => {
61
- if (!(0, split_selected_timeline_item_1.shouldHandleTimelineSplitShortcut)(event)) {
62
- return;
63
- }
60
+ action: 'splitSequences',
61
+ callback: () => {
64
62
  const { selectedItems } = currentSelection.current;
65
63
  if (selectedItems.length === 0) {
66
64
  return;
@@ -68,7 +66,7 @@ const TimelineDeleteKeybindings = () => {
68
66
  const splitPromise = (0, split_selected_timeline_item_1.splitSelectedTimelineItems)({
69
67
  selections: selectedItems,
70
68
  sequences: sequencesRef.current,
71
- overrideIdsToNodePaths: overrideIdToNodePathMappings,
69
+ overrideIdsToNodePaths: overrideIdToNodePathMappingsRef.current,
72
70
  propStatuses: propStatusesRef.current,
73
71
  splitFrame: (0, imperative_state_1.getCurrentFrame)(),
74
72
  });
@@ -77,7 +75,6 @@ const TimelineDeleteKeybindings = () => {
77
75
  }
78
76
  splitPromise.catch(() => undefined);
79
77
  },
80
- commandCtrlKey: true,
81
78
  preventDefault: true,
82
79
  triggerIfInputFieldFocused: false,
83
80
  keepRegisteredWhenNotHighestContext: false,
@@ -93,7 +90,7 @@ const TimelineDeleteKeybindings = () => {
93
90
  currentSelection,
94
91
  deleteTimelineItems,
95
92
  keybindings,
96
- overrideIdToNodePathMappings,
93
+ overrideIdToNodePathMappingsRef,
97
94
  propStatusesRef,
98
95
  previewServerState,
99
96
  sequencesRef,
@@ -24,6 +24,7 @@ const rowLabel = {
24
24
  fontSize: 12,
25
25
  color: colors_1.WHITE_ALPHA_80,
26
26
  userSelect: 'none',
27
+ WebkitUserSelect: 'none',
27
28
  };
28
29
  const rowStyle = {
29
30
  height: timeline_layout_1.TREE_GROUP_ROW_HEIGHT,
@@ -52,6 +52,7 @@ const arrowButton = {
52
52
  fontSize: 8,
53
53
  marginRight: 4,
54
54
  userSelect: 'none',
55
+ WebkitUserSelect: 'none',
55
56
  outline: 'none',
56
57
  lineHeight: 1,
57
58
  };
@@ -20,6 +20,7 @@ const rowLabel = {
20
20
  fontSize: 12,
21
21
  color: colors_1.WHITE_ALPHA_80,
22
22
  userSelect: 'none',
23
+ WebkitUserSelect: 'none',
23
24
  };
24
25
  const TimelineExpandedRowInner = ({ node, depth, nestedDepth, rowDepthBase, getIsExpanded, toggleTrack, validatedLocation, nodePath, schema, keyframeDisplayOffset, keyframeControlsMode, }) => {
25
26
  const rowDepth = (rowDepthBase !== null && rowDepthBase !== void 0 ? rowDepthBase : (0, timeline_row_layout_1.getExpandedRowDepth)({ nestedDepth, treeDepth: 0 })) + depth;
@@ -12,6 +12,7 @@ const fieldNameBase = {
12
12
  lineHeight: `${timeline_field_row_layout_1.TIMELINE_STACKED_FIELD_HEADER_HEIGHT}px`,
13
13
  color: colors_1.WHITE_ALPHA_80,
14
14
  userSelect: 'none',
15
+ WebkitUserSelect: 'none',
15
16
  whiteSpace: 'nowrap',
16
17
  overflow: 'hidden',
17
18
  textOverflow: 'ellipsis',
@@ -52,6 +52,7 @@ const navButtonStyle = {
52
52
  outline: 'none',
53
53
  padding: 0,
54
54
  userSelect: 'none',
55
+ WebkitUserSelect: 'none',
55
56
  width: NAV_BUTTON_SIZE,
56
57
  };
57
58
  const inspectorNavButtonStyle = {