@remotion/studio 4.0.505 → 4.0.507

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 (208) hide show
  1. package/dist/api/copy-render-output-to-asset.d.ts +4 -0
  2. package/dist/api/copy-render-output-to-asset.js +11 -0
  3. package/dist/api/install-package.d.ts +2 -3
  4. package/dist/api/install-package.js +1 -3
  5. package/dist/api/visual-control.d.ts +3 -0
  6. package/dist/api/visual-control.js +3 -0
  7. package/dist/components/AssetSelector.js +19 -4
  8. package/dist/components/AssetSelectorItem.js +3 -3
  9. package/dist/components/Canvas.js +2 -0
  10. package/dist/components/CodingAgentIcon.d.ts +4 -0
  11. package/dist/components/CodingAgentIcon.js +17 -0
  12. package/dist/components/CompositionSelector.js +1 -1
  13. package/dist/components/CompositionSelectorItem.js +1 -1
  14. package/dist/components/ConfigureDefaultEditorModal.d.ts +1 -1
  15. package/dist/components/ConfigureDefaultEditorModal.js +117 -69
  16. package/dist/components/ConfigureLicenseModal.d.ts +1 -3
  17. package/dist/components/ConfigureLicenseModal.js +105 -89
  18. package/dist/components/ConfirmationDialog.js +2 -2
  19. package/dist/components/ContextMenu.js +10 -8
  20. package/dist/components/Editor.js +2 -0
  21. package/dist/components/EditorContexts.js +6 -5
  22. package/dist/components/EffectPickerModal.js +1 -1
  23. package/dist/components/ExpandedTracksProvider.js +10 -53
  24. package/dist/components/GlobalKeybindings.js +3 -2
  25. package/dist/components/InlineCaptionInspector.d.ts +2 -2
  26. package/dist/components/InlineDropdown.d.ts +2 -1
  27. package/dist/components/InlineDropdown.js +10 -4
  28. package/dist/components/InspectorLocationCopy.js +8 -8
  29. package/dist/components/InspectorOpenInEditor.d.ts +2 -0
  30. package/dist/components/InspectorOpenInEditor.js +63 -49
  31. package/dist/components/InspectorPanel/AlignmentControls.js +5 -2
  32. package/dist/components/InspectorPanel/CompositionInspector.js +15 -1
  33. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +1 -1
  34. package/dist/components/InspectorPanel/EasingInspector.js +7 -4
  35. package/dist/components/InspectorPanel/KeyframeInspector.js +5 -1
  36. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +3 -0
  37. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +22 -4
  38. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +1 -1
  39. package/dist/components/InspectorPanel/common.d.ts +1 -0
  40. package/dist/components/InspectorPanel/common.js +2 -2
  41. package/dist/components/InspectorPanel/use-composition-actions.js +4 -1
  42. package/dist/components/InspectorSequenceSection.js +4 -4
  43. package/dist/components/InstallPackage.js +1 -1
  44. package/dist/components/Menu/MenuSectionHeader.d.ts +4 -0
  45. package/dist/components/Menu/MenuSectionHeader.js +20 -0
  46. package/dist/components/Menu/SubMenu.js +13 -2
  47. package/dist/components/Menu/menu-tree-context.d.ts +3 -0
  48. package/dist/components/Menu/menu-tree-context.js +13 -0
  49. package/dist/components/MenuBuildIndicator.js +1 -0
  50. package/dist/components/MenuToolbar.js +1 -1
  51. package/dist/components/ModalFooter.d.ts +1 -0
  52. package/dist/components/ModalFooter.js +6 -2
  53. package/dist/components/ModalHeader.js +1 -1
  54. package/dist/components/Modals.js +18 -7
  55. package/dist/components/ModalsProvider.js +5 -6
  56. package/dist/components/NewComposition/CodemodFooter.js +1 -1
  57. package/dist/components/NewComposition/ComboBox.d.ts +6 -1
  58. package/dist/components/NewComposition/DismissableModal.js +1 -1
  59. package/dist/components/NewComposition/MenuContent.js +27 -19
  60. package/dist/components/NewComposition/RenameStaticFile.js +1 -1
  61. package/dist/components/NewComposition/menu-typeahead.js +2 -2
  62. package/dist/components/OverrideInputProps.js +1 -1
  63. package/dist/components/PlayPause.js +2 -1
  64. package/dist/components/PlaybackKeyboardShortcutsManager.js +7 -5
  65. package/dist/components/Preview.js +29 -4
  66. package/dist/components/PreviewToolbarOverflowButton.js +4 -2
  67. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +1 -1
  68. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +1 -1
  69. package/dist/components/RenderButton.d.ts +3 -3
  70. package/dist/components/RenderButton.js +42 -7
  71. package/dist/components/RenderModal/RenderStatusModal.js +1 -1
  72. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.d.ts +1 -0
  73. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.js +2 -2
  74. package/dist/components/RenderModal/SchemaEditor/ZodOrNullishEditor.js +3 -3
  75. package/dist/components/RenderModal/SchemaEditor/ZodSwitch.js +1 -1
  76. package/dist/components/RenderModal/ServerRenderModal.js +5 -1
  77. package/dist/components/RenderModal/WebRenderModal.js +3 -2
  78. package/dist/components/RenderQueue/RenderQueueError.js +1 -1
  79. package/dist/components/RenderQueue/RenderQueueItem.js +8 -2
  80. package/dist/components/RenderQueue/RenderQueueItemStatus.js +1 -1
  81. package/dist/components/RenderQueue/RenderQueueProgressMessage.js +1 -1
  82. package/dist/components/RenderQueue/RenderQueueRepeat.js +1 -1
  83. package/dist/components/RenderQueue/actions.d.ts +4 -2
  84. package/dist/components/RenderQueue/actions.js +4 -2
  85. package/dist/components/RenderQueue/index.js +3 -4
  86. package/dist/components/RenderQueue/use-render-output-file-drag.d.ts +8 -0
  87. package/dist/components/RenderQueue/use-render-output-file-drag.js +121 -0
  88. package/dist/components/SegmentedControl.js +0 -1
  89. package/dist/components/SelectedOutlineElement.d.ts +14 -17
  90. package/dist/components/SelectedOutlineElement.js +113 -931
  91. package/dist/components/SelectedOutlineKeyboardControls.d.ts +7 -0
  92. package/dist/components/SelectedOutlineKeyboardControls.js +261 -0
  93. package/dist/components/SelectedOutlineOverlay.d.ts +6 -13
  94. package/dist/components/SelectedOutlineOverlay.js +360 -832
  95. package/dist/components/SelectedOutlinePolygon.d.ts +25 -0
  96. package/dist/components/SelectedOutlinePolygon.js +359 -0
  97. package/dist/components/SelectedOutlineRenderer.d.ts +18 -0
  98. package/dist/components/SelectedOutlineRenderer.js +208 -0
  99. package/dist/components/SelectedOutlineRotationCornerHandle.d.ts +16 -0
  100. package/dist/components/SelectedOutlineRotationCornerHandle.js +269 -0
  101. package/dist/components/SelectedOutlineScaleEdgeLine.d.ts +16 -0
  102. package/dist/components/SelectedOutlineScaleEdgeLine.js +211 -0
  103. package/dist/components/SelectedOutlineSnapIndicators.d.ts +9 -0
  104. package/dist/components/SelectedOutlineSnapIndicators.js +29 -0
  105. package/dist/components/SelectedOutlineTransformOriginHandle.d.ts +9 -0
  106. package/dist/components/SelectedOutlineTransformOriginHandle.js +286 -0
  107. package/dist/components/SelectedOutlineUvControls.d.ts +3 -9
  108. package/dist/components/SelectedOutlineUvControls.js +57 -12
  109. package/dist/components/SettingsContext.d.ts +15 -0
  110. package/dist/components/SettingsContext.js +116 -0
  111. package/dist/components/SettingsModal.d.ts +7 -0
  112. package/dist/components/SettingsModal.js +56 -0
  113. package/dist/components/SettingsModalFooter.d.ts +2 -0
  114. package/dist/components/SettingsModalFooter.js +44 -0
  115. package/dist/components/ShowOutlinesProvider.js +2 -3
  116. package/dist/components/SidebarRenderButton.js +1 -1
  117. package/dist/components/SvgImportDialog.js +2 -2
  118. package/dist/components/TimeValue.js +1 -1
  119. package/dist/components/Timeline/EasingEditorModal.js +66 -22
  120. package/dist/components/Timeline/Timeline.js +23 -5
  121. package/dist/components/Timeline/TimelineAssetField.js +1 -1
  122. package/dist/components/Timeline/TimelineDragHandler.js +3 -3
  123. package/dist/components/Timeline/TimelineDuplicateCount.d.ts +4 -0
  124. package/dist/components/Timeline/TimelineDuplicateCount.js +28 -0
  125. package/dist/components/Timeline/TimelineEffectPropItem.js +5 -3
  126. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +3 -23
  127. package/dist/components/Timeline/TimelineExpandedRow.d.ts +4 -2
  128. package/dist/components/Timeline/TimelineExpandedRow.js +2 -2
  129. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.d.ts +4 -2
  130. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +11 -1
  131. package/dist/components/Timeline/TimelineFontFamilyField.js +3 -1
  132. package/dist/components/Timeline/TimelineKeyframeControls.js +1 -0
  133. package/dist/components/Timeline/TimelineSelection.js +1 -0
  134. package/dist/components/Timeline/TimelineSequence.js +28 -25
  135. package/dist/components/Timeline/TimelineSequenceItem.js +74 -58
  136. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +1 -1
  137. package/dist/components/Timeline/TimelineTrack.js +2 -1
  138. package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +6 -3
  139. package/dist/components/Timeline/get-sequence-context-menu-items.js +58 -53
  140. package/dist/components/Timeline/reset-selected-timeline-props.js +1 -1
  141. package/dist/components/Timeline/should-subscribe-to-sequence-props.d.ts +1 -1
  142. package/dist/components/Timeline/timeline-asset-link.d.ts +2 -2
  143. package/dist/components/Timeline/timeline-asset-link.js +2 -2
  144. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +38 -2
  145. package/dist/components/Timeline/{use-open-sequence-in-editor.d.ts → use-open-sequence-in-apps.d.ts} +4 -1
  146. package/dist/components/Timeline/{use-open-sequence-in-editor.js → use-open-sequence-in-apps.js} +20 -4
  147. package/dist/components/Timeline/use-timeline-asset-drop.js +1 -0
  148. package/dist/components/Timeline/use-timeline-expanded-tree.d.ts +5 -0
  149. package/dist/components/Timeline/use-timeline-expanded-tree.js +50 -1
  150. package/dist/components/Timeline/use-timeline-height.js +20 -0
  151. package/dist/components/TimelineInOutToggle.js +5 -1
  152. package/dist/components/TopPanel.js +16 -0
  153. package/dist/components/UpdateCheck.js +1 -1
  154. package/dist/components/effect-drag-and-drop.js +1 -1
  155. package/dist/components/get-open-in-menu-items.d.ts +12 -0
  156. package/dist/components/get-open-in-menu-items.js +83 -0
  157. package/dist/components/handle-drop.d.ts +2 -1
  158. package/dist/components/handle-drop.js +12 -2
  159. package/dist/components/import-assets.d.ts +18 -6
  160. package/dist/components/import-assets.js +76 -32
  161. package/dist/components/selected-outline-measurement.d.ts +2 -2
  162. package/dist/components/selected-outline-order.d.ts +12 -0
  163. package/dist/components/selected-outline-order.js +251 -0
  164. package/dist/components/selected-outline-types.d.ts +9 -10
  165. package/dist/components/svg-point-to-client-point.d.ts +2 -0
  166. package/dist/components/svg-point-to-client-point.js +10 -0
  167. package/dist/components/use-auto-save-config.d.ts +8 -0
  168. package/dist/components/use-auto-save-config.js +74 -0
  169. package/dist/components/use-default-editor-info.d.ts +1 -0
  170. package/dist/components/use-default-editor-info.js +10 -30
  171. package/dist/esm/{chunk-jefhcs5z.js → chunk-fgedsvhb.js} +1 -2
  172. package/dist/esm/{chunk-7pgk8h5m.js → chunk-ptnd65a9.js} +14596 -12725
  173. package/dist/esm/internals.mjs +14595 -12724
  174. package/dist/esm/previewEntry.mjs +12726 -10855
  175. package/dist/esm/renderEntry.mjs +2 -2
  176. package/dist/helpers/are-sequence-node-path-infos-equal.d.ts +2 -0
  177. package/dist/helpers/are-sequence-node-path-infos-equal.js +27 -0
  178. package/dist/helpers/calculate-timeline.js +3 -3
  179. package/dist/helpers/client-id.d.ts +3 -1
  180. package/dist/helpers/client-id.js +28 -4
  181. package/dist/helpers/format-file-location.d.ts +1 -1
  182. package/dist/helpers/format-file-location.js +3 -3
  183. package/dist/helpers/install-required-package.d.ts +3 -3
  184. package/dist/helpers/install-required-package.js +1 -6
  185. package/dist/helpers/migrate-expanded-tracks-for-subscription-key.js +3 -3
  186. package/dist/helpers/open-in-editor.d.ts +1 -0
  187. package/dist/helpers/open-in-editor.js +5 -1
  188. package/dist/helpers/studio-fit-padding.d.ts +1 -1
  189. package/dist/helpers/studio-fit-padding.js +1 -1
  190. package/dist/helpers/studio-runtime-config.js +3 -0
  191. package/dist/helpers/timeline-layout.d.ts +2 -1
  192. package/dist/helpers/timeline-layout.js +5 -2
  193. package/dist/helpers/timeline-node-path-key.d.ts +2 -0
  194. package/dist/helpers/timeline-node-path-key.js +3 -1
  195. package/dist/helpers/use-asset-drag-events.d.ts +2 -1
  196. package/dist/helpers/use-asset-drag-events.js +14 -6
  197. package/dist/helpers/use-menu-structure.js +25 -35
  198. package/dist/helpers/use-runtime-values.d.ts +9 -0
  199. package/dist/helpers/use-runtime-values.js +76 -0
  200. package/dist/icons/apps.d.ts +2 -0
  201. package/dist/icons/apps.js +7 -0
  202. package/dist/icons/browse-elements.d.ts +4 -0
  203. package/dist/icons/browse-elements.js +10 -0
  204. package/dist/state/modals.d.ts +5 -6
  205. package/dist/state/modals.js +5 -3
  206. package/dist/state/timeline-sequence-hover.d.ts +9 -3
  207. package/dist/state/timeline-sequence-hover.js +63 -12
  208. package/package.json +12 -12
@@ -7,7 +7,7 @@ const editor_outlines_1 = require("../state/editor-outlines");
7
7
  const timeline_sequence_hover_1 = require("../state/timeline-sequence-hover");
8
8
  const ShowOutlinesProvider = ({ children }) => {
9
9
  const [editorShowOutlines, setEditorShowOutlinesState] = (0, react_1.useState)(() => (0, editor_outlines_1.loadEditorShowOutlinesOption)());
10
- const [hoveredSequence, setHoveredSequence] = (0, react_1.useState)(null);
10
+ const timelineSequenceHoverStore = (0, react_1.useMemo)(() => (0, timeline_sequence_hover_1.createTimelineSequenceHoverStore)(), []);
11
11
  const setEditorShowOutlines = (0, react_1.useCallback)((newValue) => {
12
12
  setEditorShowOutlinesState((prevState) => {
13
13
  const newVal = newValue(prevState);
@@ -21,7 +21,6 @@ const ShowOutlinesProvider = ({ children }) => {
21
21
  setEditorShowOutlines,
22
22
  };
23
23
  }, [editorShowOutlines, setEditorShowOutlines]);
24
- const timelineSequenceHoverCtx = (0, react_1.useMemo)(() => ({ hoveredSequence, setHoveredSequence }), [hoveredSequence]);
25
- return (jsx_runtime_1.jsx(editor_outlines_1.EditorShowOutlinesContext.Provider, { value: editorShowOutlinesCtx, children: jsx_runtime_1.jsx(timeline_sequence_hover_1.TimelineSequenceHoverContext.Provider, { value: timelineSequenceHoverCtx, children: children }) }));
24
+ return (jsx_runtime_1.jsx(editor_outlines_1.EditorShowOutlinesContext.Provider, { value: editorShowOutlinesCtx, children: jsx_runtime_1.jsx(timeline_sequence_hover_1.TimelineSequenceHoverContext.Provider, { value: timelineSequenceHoverStore, children: children }) }));
26
25
  };
27
26
  exports.ShowOutlinesProvider = ShowOutlinesProvider;
@@ -9,7 +9,7 @@ const render_1 = require("../icons/render");
9
9
  const modals_1 = require("../state/modals");
10
10
  const InlineAction_1 = require("./InlineAction");
11
11
  const SidebarRenderButton = ({ composition, visible }) => {
12
- const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
12
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
13
13
  const iconStyle = (0, react_1.useMemo)(() => {
14
14
  return {
15
15
  style: {
@@ -25,7 +25,7 @@ const inlineCode = {
25
25
  color: 'inherit',
26
26
  };
27
27
  const useSvgImportDialog = () => {
28
- const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
28
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
29
29
  return (0, react_1.useCallback)(() => {
30
30
  return new Promise((resolve) => {
31
31
  let settled = false;
@@ -48,7 +48,7 @@ const useSvgImportDialog = () => {
48
48
  };
49
49
  exports.useSvgImportDialog = useSvgImportDialog;
50
50
  const SvgImportDialog = ({ state }) => {
51
- const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
51
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
52
52
  const settledRef = (0, react_1.useRef)(false);
53
53
  const closeCurrentModal = (0, react_1.useCallback)(() => {
54
54
  setSelectedModal((modal) => (modal === null || modal === void 0 ? void 0 : modal.type) === 'svg-import-dialog' && modal.id === state.id
@@ -52,7 +52,7 @@ const TimeValue = () => {
52
52
  const frame = (0, remotion_1.useCurrentFrame)();
53
53
  const config = remotion_1.Internals.useUnsafeVideoConfig();
54
54
  const isStill = (0, is_current_selected_still_1.useIsStill)();
55
- const { seek, play, pause, toggle } = player_1.PlayerInternals.usePlayer();
55
+ const { seek, play, pause, toggle } = player_1.PlayerInternals.usePlayerMethods();
56
56
  const keybindings = (0, use_keybinding_1.useKeybinding)();
57
57
  const ref = (0, react_1.useRef)(null);
58
58
  const onTextChange = (0, react_1.useCallback)((newVal) => {
@@ -75,8 +75,9 @@ const SPRING_FALLBACKS = {
75
75
  stiffness: DEFAULT_SPRING_EASING.stiffness,
76
76
  };
77
77
  const inlineContainer = {
78
- width: '100%',
79
78
  minWidth: 0,
79
+ paddingBottom: 12,
80
+ width: '100%',
80
81
  };
81
82
  const segmentedControlWrapper = {
82
83
  display: 'flex',
@@ -85,27 +86,27 @@ const segmentedControlWrapper = {
85
86
  padding: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
86
87
  };
87
88
  const presetButtonsWrapper = {
88
- display: 'flex',
89
- flexWrap: 'wrap',
90
- gap: 6,
91
- justifyContent: 'flex-start',
92
- marginBottom: 8,
93
- padding: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
89
+ border: `1px solid ${colors_1.BLACK_ALPHA_60}`,
90
+ borderRadius: 4,
91
+ boxSizing: 'border-box',
92
+ display: 'grid',
93
+ gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
94
+ margin: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 8px`,
95
+ overflow: 'hidden',
94
96
  };
95
97
  const inspectorPresetButtonsWrapper = {
96
98
  ...presetButtonsWrapper,
97
- padding: `8px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 0`,
99
+ margin: `8px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 0`,
98
100
  };
99
101
  const presetButtonBase = {
100
102
  alignItems: 'center',
101
- backgroundColor: colors_1.INPUT_BACKGROUND,
102
- border: `1px solid ${colors_1.WHITE_ALPHA_05}`,
103
- borderRadius: 4,
103
+ backgroundColor: colors_1.TRANSPARENT,
104
+ border: 'none',
104
105
  display: 'inline-flex',
105
106
  height: 34,
106
107
  justifyContent: 'center',
107
108
  padding: 0,
108
- width: 52,
109
+ width: '100%',
109
110
  };
110
111
  const presetPreviewSvgStyle = {
111
112
  display: 'block',
@@ -172,7 +173,10 @@ const easingToSpring = (easing) => {
172
173
  : DEFAULT_SPRING_EASING;
173
174
  };
174
175
  const easingToMode = (easing) => {
175
- return isSpringEasing(easing) ? 'spring' : 'bezier';
176
+ if (isSpringEasing(easing)) {
177
+ return 'spring';
178
+ }
179
+ return easing.type === 'step1' ? 'hold' : 'bezier';
176
180
  };
177
181
  const roundToDecimalPlaces = (value, decimalPlaces) => {
178
182
  const factor = 10 ** decimalPlaces;
@@ -243,6 +247,7 @@ const areEasingsEqual = (first, second) => {
243
247
  }
244
248
  switch (first.type) {
245
249
  case 'linear':
250
+ case 'step1':
246
251
  return true;
247
252
  case 'spring':
248
253
  return (second.type === 'spring' &&
@@ -322,6 +327,8 @@ const getEasingFunction = (easing) => {
322
327
  switch (easing.type) {
323
328
  case 'linear':
324
329
  return remotion_1.Easing.linear;
330
+ case 'step1':
331
+ return remotion_1.Easing.step1;
325
332
  case 'bezier':
326
333
  return remotion_1.Easing.bezier(easing.x1, easing.y1, easing.x2, easing.y2);
327
334
  case 'spring':
@@ -338,6 +345,13 @@ const getEasingFunction = (easing) => {
338
345
  }
339
346
  };
340
347
  const getPresetPreviewPath = (easing) => {
348
+ if (easing.type === 'step1') {
349
+ const startX = presetPreviewXToSvg(0);
350
+ const endX = presetPreviewXToSvg(1);
351
+ const startY = presetPreviewYToSvg(0);
352
+ const endY = presetPreviewYToSvg(1);
353
+ return `M ${startX} ${startY} L ${endX} ${startY} L ${endX} ${endY}`;
354
+ }
341
355
  const easingFunction = getEasingFunction(easing);
342
356
  const samples = 36;
343
357
  const points = [];
@@ -386,18 +400,24 @@ const EasingGraphScaffold = ({ labels }) => {
386
400
  };
387
401
  const EasingPresetButton = ({ currentEasing, disabled, onClick, preset }) => {
388
402
  const selected = areEasingsEqual(currentEasing, preset.easing);
403
+ const [hovered, setHovered] = (0, react_1.useState)(false);
389
404
  const path = (0, react_1.useMemo)(() => getPresetPreviewPath(preset.easing), [preset.easing]);
405
+ const onPointerEnter = (0, react_1.useCallback)(() => {
406
+ setHovered(true);
407
+ }, []);
408
+ const onPointerLeave = (0, react_1.useCallback)(() => {
409
+ setHovered(false);
410
+ }, []);
390
411
  const style = (0, react_1.useMemo)(() => ({
391
412
  ...presetButtonBase,
392
- backgroundColor: selected ? colors_1.EASING_SELECTED_BACKGROUND : colors_1.INPUT_BACKGROUND,
393
- borderColor: selected ? colors_1.BLUE : colors_1.WHITE_ALPHA_05,
394
- cursor: disabled ? 'not-allowed' : 'pointer',
413
+ backgroundColor: selected ? colors_1.INPUT_BACKGROUND : colors_1.TRANSPARENT,
414
+ cursor: disabled ? 'not-allowed' : undefined,
395
415
  opacity: disabled ? 0.45 : 1,
396
416
  }), [disabled, selected]);
397
417
  const handleClick = (0, react_1.useCallback)(() => {
398
418
  onClick(preset.easing);
399
419
  }, [onClick, preset.easing]);
400
- return (jsx_runtime_1.jsx("button", { type: "button", style: style, title: preset.label, "aria-label": `Apply ${preset.label} easing`, disabled: disabled, onClick: handleClick, children: jsx_runtime_1.jsx("svg", { width: PRESET_PREVIEW_WIDTH, height: PRESET_PREVIEW_HEIGHT, viewBox: `0 0 ${PRESET_PREVIEW_WIDTH} ${PRESET_PREVIEW_HEIGHT}`, style: presetPreviewSvgStyle, "aria-hidden": "true", focusable: false, children: jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: colors_1.WHITE, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
420
+ return (jsx_runtime_1.jsx("button", { type: "button", style: style, title: preset.label, "aria-label": `Apply ${preset.label} easing`, disabled: disabled, onClick: handleClick, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, children: jsx_runtime_1.jsx("svg", { width: PRESET_PREVIEW_WIDTH, height: PRESET_PREVIEW_HEIGHT, viewBox: `0 0 ${PRESET_PREVIEW_WIDTH} ${PRESET_PREVIEW_HEIGHT}`, style: presetPreviewSvgStyle, "aria-hidden": "true", focusable: false, children: jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
401
421
  };
402
422
  const EasingEditor = ({ state, renderHeader }) => {
403
423
  var _a, _b;
@@ -590,7 +610,9 @@ const EasingEditor = ({ state, renderHeader }) => {
590
610
  }
591
611
  const easing = nextMode === 'spring'
592
612
  ? serializeSpring(springRef.current)
593
- : serializeBezier(bezierRef.current);
613
+ : nextMode === 'hold'
614
+ ? studio_shared_1.HOLD_KEYFRAME_EASING
615
+ : serializeBezier(bezierRef.current);
594
616
  const version = applyLiveEasing(easing);
595
617
  commitEasing(easing, version);
596
618
  }, [applyLiveEasing, commitEasing, mode, previewServerState.type]);
@@ -605,11 +627,18 @@ const EasingEditor = ({ state, renderHeader }) => {
605
627
  commitEasing(serializeSpring(nextSpring), springVersion);
606
628
  return;
607
629
  }
630
+ if (easing.type === 'step1') {
631
+ setMode('hold');
632
+ const holdVersion = applyLiveEasing(studio_shared_1.HOLD_KEYFRAME_EASING);
633
+ commitEasing(studio_shared_1.HOLD_KEYFRAME_EASING, holdVersion);
634
+ return;
635
+ }
608
636
  const nextBezier = easingToBezier(easing);
609
637
  setMode('bezier');
610
638
  const bezierVersion = setBezierAndPreview(nextBezier);
611
639
  commitEasing(serializeBezier(nextBezier), bezierVersion);
612
640
  }, [
641
+ applyLiveEasing,
613
642
  commitEasing,
614
643
  previewServerState.type,
615
644
  setBezierAndPreview,
@@ -709,9 +738,15 @@ const EasingEditor = ({ state, renderHeader }) => {
709
738
  }
710
739
  return points.join(' ');
711
740
  }, [spring]);
741
+ const holdPath = (0, react_1.useMemo)(() => `M ${startPoint.x} ${startPoint.y} L ${endPoint.x} ${startPoint.y} L ${endPoint.x} ${endPoint.y}`, [endPoint, startPoint]);
712
742
  const disabled = previewServerState.type !== 'connected';
713
743
  const graphLabels = getEasingGraphLabels(getCurrentEasingUpdates());
714
- const currentEasing = (0, react_1.useMemo)(() => mode === 'spring' ? serializeSpring(spring) : serializeBezier(bezier), [bezier, mode, spring]);
744
+ const currentEasing = (0, react_1.useMemo)(() => {
745
+ if (mode === 'spring') {
746
+ return serializeSpring(spring);
747
+ }
748
+ return mode === 'hold' ? studio_shared_1.HOLD_KEYFRAME_EASING : serializeBezier(bezier);
749
+ }, [bezier, mode, spring]);
715
750
  const modeItems = (0, react_1.useMemo)(() => {
716
751
  return [
717
752
  {
@@ -726,12 +761,18 @@ const EasingEditor = ({ state, renderHeader }) => {
726
761
  onClick: () => switchMode('spring'),
727
762
  selected: mode === 'spring',
728
763
  },
764
+ {
765
+ key: 'hold',
766
+ label: 'Hold',
767
+ onClick: () => switchMode('hold'),
768
+ selected: mode === 'hold',
769
+ },
729
770
  ];
730
771
  }, [mode, switchMode]);
731
772
  const coordinatesGrid = (0, react_1.useMemo)(() => ({
732
773
  ...coordinatesGridBase,
733
774
  gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
734
- padding: '0 12px 12px',
775
+ padding: '0 12px',
735
776
  }), []);
736
777
  const modeSwitcher = (jsx_runtime_1.jsx("div", { style: segmentedControlWrapper, children: jsx_runtime_1.jsx(SegmentedControl_1.SegmentedControl, { items: modeItems, needsWrapping: false }) }));
737
778
  return (jsx_runtime_1.jsxs("div", { style: inlineContainer, children: [renderHeader ? renderHeader(modeItems) : null, jsx_runtime_1.jsx("div", { style: renderHeader ? inspectorPresetButtonsWrapper : presetButtonsWrapper, children: EDITOR_EASING_PRESETS.map((preset) => (jsx_runtime_1.jsx(EasingPresetButton, { currentEasing: currentEasing, disabled: disabled, onClick: applyPreset, preset: preset }, preset.id))) }), mode === 'bezier' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
@@ -748,7 +789,7 @@ const EasingEditor = ({ state, renderHeader }) => {
748
789
  jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Y2" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[3], status: "ok", onValueChange: (value) => setCoordinate(1, 'y', value, false), onValueChangeEnd: (value) => setCoordinate(1, 'y', value, true), onTextChange: () => undefined, min: Y_MIN, max: Y_MAX, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false, disabled: disabled }) })
749
790
  ] })
750
791
  ] })
751
- ] })) : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
792
+ ] })) : mode === 'spring' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
752
793
  jsx_runtime_1.jsxs("svg", { width: SVG_WIDTH, height: SVG_HEIGHT, viewBox: `0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`, style: svgStyle, "aria-label": "Spring easing curve", children: [
753
794
  jsx_runtime_1.jsx(EasingGraphScaffold, { labels: graphLabels }), jsx_runtime_1.jsx("path", { d: springPath, fill: "none", stroke: colors_1.BLUE, strokeWidth: 3 }), jsx_runtime_1.jsx("circle", { cx: xToSvg(0), cy: yToSvg(0), r: 4, fill: colors_1.WHITE }), jsx_runtime_1.jsx("circle", { cx: xToSvg(1), cy: yToSvg(1), r: 4, fill: colors_1.WHITE })
754
795
  ] }), modeSwitcher, jsx_runtime_1.jsxs("div", { style: coordinatesGrid, children: [
@@ -766,6 +807,9 @@ const EasingEditor = ({ state, renderHeader }) => {
766
807
  jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Allow tail" }), jsx_runtime_1.jsx("div", { style: checkboxWrapper, children: jsx_runtime_1.jsx(Checkbox_1.Checkbox, { checked: (_b = spring.allowTail) !== null && _b !== void 0 ? _b : false, onChange: setAllowTail, name: "spring-allow-tail", disabled: disabled, variant: "small" }) })
767
808
  ] })
768
809
  ] })
769
- ] }))] }));
810
+ ] })) : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
811
+ jsx_runtime_1.jsxs("svg", { width: SVG_WIDTH, height: SVG_HEIGHT, viewBox: `0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`, style: svgStyle, "aria-label": "Hold easing curve", children: [
812
+ jsx_runtime_1.jsx(EasingGraphScaffold, { labels: graphLabels }), jsx_runtime_1.jsx("path", { d: holdPath, fill: "none", stroke: colors_1.BLUE, strokeWidth: 3 }), jsx_runtime_1.jsx("circle", { cx: startPoint.x, cy: startPoint.y, r: 4, fill: colors_1.WHITE }), jsx_runtime_1.jsx("circle", { cx: endPoint.x, cy: endPoint.y, r: 4, fill: colors_1.WHITE })
813
+ ] }), modeSwitcher] }))] }));
770
814
  };
771
815
  exports.EasingEditor = EasingEditor;
@@ -45,6 +45,7 @@ const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
45
45
  const is_current_selected_still_1 = require("../../helpers/is-current-selected-still");
46
46
  const open_in_editor_1 = require("../../helpers/open-in-editor");
47
47
  const studio_runtime_config_1 = require("../../helpers/studio-runtime-config");
48
+ const timeline_node_path_key_1 = require("../../helpers/timeline-node-path-key");
48
49
  const call_api_1 = require("../call-api");
49
50
  const ContextMenu_1 = require("../ContextMenu");
50
51
  const import_assets_1 = require("../import-assets");
@@ -188,6 +189,7 @@ const TimelineContextMenuArea = ({ children }) => {
188
189
  destinationDimensions: null,
189
190
  dropPosition: null,
190
191
  from: null,
192
+ preferCompositionStart: null,
191
193
  svgImportMode: 'image',
192
194
  });
193
195
  }
@@ -255,13 +257,29 @@ const TimelineInner = () => {
255
257
  const filtered = (0, react_1.useMemo)(() => {
256
258
  return timeline.filter((t) => (0, should_show_track_in_timeline_1.shouldShowTrackInTimeline)(t, durationInFrames));
257
259
  }, [durationInFrames, timeline]);
260
+ // Keep `filtered` complete so a future toggle can show every programmatic
261
+ // instance without recalculating the timeline or losing its instance index.
262
+ const collapsed = (0, react_1.useMemo)(() => {
263
+ const seenNodePaths = new Set();
264
+ return filtered.filter((track) => {
265
+ if (track.nodePathInfo === null) {
266
+ return true;
267
+ }
268
+ const key = (0, timeline_node_path_key_1.timelineSequenceNodePathToKey)(track.nodePathInfo.sequenceSubscriptionKey);
269
+ if (seenNodePaths.has(key)) {
270
+ return false;
271
+ }
272
+ seenNodePaths.add(key);
273
+ return true;
274
+ });
275
+ }, [filtered]);
258
276
  const maxTimelineTracks = (0, studio_runtime_config_1.getStudioMaxTimelineTracks)();
259
277
  const shown = (0, react_1.useMemo)(() => {
260
- return filtered.length > maxTimelineTracks
261
- ? filtered.slice(0, maxTimelineTracks)
262
- : filtered;
263
- }, [filtered, maxTimelineTracks]);
264
- const hasBeenCut = filtered.length > shown.length;
278
+ return collapsed.length > maxTimelineTracks
279
+ ? collapsed.slice(0, maxTimelineTracks)
280
+ : collapsed;
281
+ }, [collapsed, maxTimelineTracks]);
282
+ const hasBeenCut = collapsed.length > shown.length;
265
283
  return (jsx_runtime_1.jsxs(TimelineContextMenuArea, { children: [sequences.map((sequence) => {
266
284
  if (!(0, should_subscribe_to_sequence_props_1.shouldSubscribeToSequenceProps)(sequence, previewInteractive)) {
267
285
  return null;
@@ -34,7 +34,7 @@ const TimelineAssetField = ({ field, effectiveValue, propStatus, onSave, onDragV
34
34
  if (field.fieldSchema.type !== 'asset') {
35
35
  throw new Error('TimelineAssetField rendered for non-asset field');
36
36
  }
37
- const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
37
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
38
38
  const staticFiles = (0, use_static_files_1.useStaticFiles)();
39
39
  const { getSourceAction, initialQuery, sourceAction } = (0, react_1.useContext)(exports.AssetSelectionContext);
40
40
  const inlineSourceAction = (0, react_1.useMemo)(() => {
@@ -108,7 +108,7 @@ const TimelineDragHandlerInner = () => {
108
108
  const [dragging, setDragging] = (0, react_1.useState)({
109
109
  dragging: false,
110
110
  });
111
- const { playing, play, pause, seek } = player_1.PlayerInternals.usePlayer();
111
+ const { isPlaying, play, pause, seek } = player_1.PlayerInternals.usePlayerMethods();
112
112
  const scroller = (0, react_1.useRef)(null);
113
113
  const stopInterval = () => {
114
114
  if (scroller.current) {
@@ -140,14 +140,14 @@ const TimelineDragHandlerInner = () => {
140
140
  seek(frame);
141
141
  setDragging({
142
142
  dragging: true,
143
- wasPlaying: playing,
143
+ wasPlaying: isPlaying(),
144
144
  button: e.button,
145
145
  pointerId: e.pointerId,
146
146
  target: e.currentTarget,
147
147
  });
148
148
  (_b = (_a = e.currentTarget).setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
149
149
  pause();
150
- }, [isHighestContext, videoConfig, left, width, seek, playing, pause]);
150
+ }, [isHighestContext, videoConfig, left, width, seek, isPlaying, pause]);
151
151
  const onPointerMoveScrubbing = (0, react_1.useCallback)((e) => {
152
152
  var _a;
153
153
  if (!videoConfig) {
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const TimelineDuplicateCount: React.FC<{
3
+ readonly count: number;
4
+ }>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineDuplicateCount = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const colors_1 = require("../../helpers/colors");
6
+ const badgeStyle = {
7
+ alignItems: 'center',
8
+ border: `1px solid ${colors_1.WHITE_ALPHA_20}`,
9
+ borderRadius: 4,
10
+ boxSizing: 'border-box',
11
+ color: colors_1.WHITE_ALPHA_60,
12
+ display: 'inline-flex',
13
+ flexShrink: 0,
14
+ fontSize: 10,
15
+ fontWeight: 300,
16
+ height: 14,
17
+ justifyContent: 'center',
18
+ lineHeight: '12px',
19
+ minWidth: 18,
20
+ padding: '0 3px',
21
+ userSelect: 'none',
22
+ WebkitUserSelect: 'none',
23
+ };
24
+ const TimelineDuplicateCount = ({ count }) => {
25
+ const label = `${count} other programmatically duplicated ${count === 1 ? 'instance is' : 'instances are'} hidden`;
26
+ return (jsx_runtime_1.jsxs("span", { style: badgeStyle, title: label, "aria-label": label, children: ["+", count] }));
27
+ };
28
+ exports.TimelineDuplicateCount = TimelineDuplicateCount;
@@ -209,6 +209,10 @@ const TimelineEffectPropValue = ({ field, nodePath, validatedLocation, sourceFra
209
209
  return (jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineFieldValue, { field: field, propStatus: propStatus, onSave: onSave, onDragValueChange: onDragValueChange, onDragEnd: onDragEnd, effectiveValue: effectiveValue, scaleLockNodePath: null }));
210
210
  };
211
211
  exports.TimelineEffectPropValue = TimelineEffectPropValue;
212
+ const TimelineEffectPropValueAtCurrentFrame = ({ field, nodePath, validatedLocation, keyframeDisplayOffset }) => {
213
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
214
+ return (jsx_runtime_1.jsx(exports.TimelineEffectPropValue, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, sourceFrame: timelinePosition - keyframeDisplayOffset }));
215
+ };
212
216
  const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath, nodePathInfo, keyframeDisplayOffset, keyframeControlsMode = 'timeline', }) => {
213
217
  var _a;
214
218
  var _b;
@@ -217,8 +221,6 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
217
221
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
218
222
  const { getEffectDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
219
223
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
220
- const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
221
- const sourceFrame = timelinePosition - keyframeDisplayOffset;
222
224
  const style = (0, react_1.useMemo)(() => {
223
225
  return field.typeName === 'text-content'
224
226
  ? fieldRowBase
@@ -324,7 +326,7 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
324
326
  property: field.key,
325
327
  }).catch(() => undefined);
326
328
  }, [field.key, previewServerState.type, validatedLocation]);
327
- const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, children: jsx_runtime_1.jsx(exports.TimelineEffectPropValue, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, sourceFrame: sourceFrame }) }) }));
329
+ const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, children: jsx_runtime_1.jsx(TimelineEffectPropValueAtCurrentFrame, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, keyframeDisplayOffset: keyframeDisplayOffset }) }) }));
328
330
  return jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { getItems: getContextMenuItems, children: row });
329
331
  };
330
332
  exports.TimelineEffectPropItem = TimelineEffectPropItem;
@@ -35,8 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.TimelineExpandedKeyframeRow = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
- const studio_shared_1 = require("@remotion/studio-shared");
39
38
  const react_1 = __importStar(require("react"));
39
+ const are_sequence_node_path_infos_equal_1 = require("../../helpers/are-sequence-node-path-infos-equal");
40
40
  const timeline_layout_1 = require("../../helpers/timeline-layout");
41
41
  const get_timeline_easing_segments_1 = require("./get-timeline-easing-segments");
42
42
  const TimelineKeyframeDiamond_1 = require("./TimelineKeyframeDiamond");
@@ -71,29 +71,9 @@ const areTimelineExpandedKeyframeRowPropsEqual = (prevProps, nextProps) => {
71
71
  prevProps.canEditEasing !== nextProps.canEditEasing ||
72
72
  prevProps.showSeparator !== nextProps.showSeparator ||
73
73
  prevProps.keyframes.length !== nextProps.keyframes.length ||
74
- prevProps.nodePathInfo.index !== nextProps.nodePathInfo.index ||
75
- prevProps.nodePathInfo.numberOfSequencesWithThisNodePath !==
76
- nextProps.nodePathInfo.numberOfSequencesWithThisNodePath ||
77
- prevProps.nodePathInfo.supportsEffects !==
78
- nextProps.nodePathInfo.supportsEffects ||
79
- (0, studio_shared_1.stringifySequenceSubscriptionKey)(prevProps.nodePathInfo.sequenceSubscriptionKey) !==
80
- (0, studio_shared_1.stringifySequenceSubscriptionKey)(nextProps.nodePathInfo.sequenceSubscriptionKey) ||
81
- prevProps.nodePathInfo.auxiliaryKeys.length !==
82
- nextProps.nodePathInfo.auxiliaryKeys.length) {
74
+ !(0, are_sequence_node_path_infos_equal_1.areSequenceNodePathInfosEqual)(prevProps.nodePathInfo, nextProps.nodePathInfo)) {
83
75
  return false;
84
76
  }
85
- const prevVideoConfig = prevProps.nodePathInfo.sequenceSubscriptionKey.videoConfigValues;
86
- const nextVideoConfig = nextProps.nodePathInfo.sequenceSubscriptionKey.videoConfigValues;
87
- if (prevVideoConfig !== nextVideoConfig &&
88
- (prevVideoConfig === null ||
89
- nextVideoConfig === null ||
90
- prevVideoConfig.durationInFrames !== nextVideoConfig.durationInFrames ||
91
- prevVideoConfig.fps !== nextVideoConfig.fps ||
92
- prevVideoConfig.height !== nextVideoConfig.height ||
93
- prevVideoConfig.width !== nextVideoConfig.width)) {
94
- return false;
95
- }
96
- return (prevProps.keyframes.every((keyframe, index) => keyframe.frame === nextProps.keyframes[index].frame) &&
97
- prevProps.nodePathInfo.auxiliaryKeys.every((key, index) => key === nextProps.nodePathInfo.auxiliaryKeys[index]));
77
+ return prevProps.keyframes.every((keyframe, index) => keyframe.frame === nextProps.keyframes[index].frame);
98
78
  };
99
79
  exports.TimelineExpandedKeyframeRow = react_1.default.memo(TimelineExpandedKeyframeRowUnmemoized, areTimelineExpandedKeyframeRowPropsEqual);
@@ -5,7 +5,7 @@ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-s
5
5
  import type { TimelineTreeNode } from '../../helpers/timeline-layout';
6
6
  import type { GetIsExpanded } from '../ExpandedTracksProvider';
7
7
  import type { TimelineKeyframeControlsMode } from './TimelineKeyframeControls';
8
- export declare const TimelineExpandedRow: React.FC<{
8
+ type TimelineExpandedRowProps = {
9
9
  readonly node: TimelineTreeNode;
10
10
  readonly depth: number;
11
11
  readonly nestedDepth: number;
@@ -17,4 +17,6 @@ export declare const TimelineExpandedRow: React.FC<{
17
17
  readonly schema: InteractivitySchema;
18
18
  readonly keyframeDisplayOffset: number;
19
19
  readonly keyframeControlsMode?: TimelineKeyframeControlsMode;
20
- }>;
20
+ };
21
+ export declare const TimelineExpandedRow: React.NamedExoticComponent<TimelineExpandedRowProps>;
22
+ export {};
@@ -21,7 +21,7 @@ const rowLabel = {
21
21
  color: colors_1.WHITE_ALPHA_80,
22
22
  userSelect: 'none',
23
23
  };
24
- const TimelineExpandedRow = ({ node, depth, nestedDepth, rowDepthBase, getIsExpanded, toggleTrack, validatedLocation, nodePath, schema, keyframeDisplayOffset, keyframeControlsMode, }) => {
24
+ const TimelineExpandedRowInner = ({ node, depth, nestedDepth, rowDepthBase, getIsExpanded, toggleTrack, validatedLocation, nodePath, schema, keyframeDisplayOffset, keyframeControlsMode, }) => {
25
25
  const rowDepth = (rowDepthBase !== null && rowDepthBase !== void 0 ? rowDepthBase : (0, timeline_row_layout_1.getExpandedRowDepth)({ nestedDepth, treeDepth: 0 })) + depth;
26
26
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(node.nodePathInfo);
27
27
  const labelStyle = react_1.default.useMemo(() => ({
@@ -60,4 +60,4 @@ const TimelineExpandedRow = ({ node, depth, nestedDepth, rowDepthBase, getIsExpa
60
60
  height: (0, timeline_layout_1.getTreeRowHeight)(node),
61
61
  }, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: jsx_runtime_1.jsx("span", { style: labelStyle, children: node.label }) }));
62
62
  };
63
- exports.TimelineExpandedRow = TimelineExpandedRow;
63
+ exports.TimelineExpandedRow = react_1.default.memo(TimelineExpandedRowInner);
@@ -1,8 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { TSequence } from 'remotion';
3
3
  import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
4
- export declare const TimelineExpandedTrackKeyframes: React.NamedExoticComponent<{
4
+ type TimelineExpandedTrackKeyframesProps = {
5
5
  readonly sequence: TSequence;
6
6
  readonly nodePathInfo: SequenceNodePathInfo;
7
7
  readonly keyframeDisplayOffset: number;
8
- }>;
8
+ };
9
+ export declare const TimelineExpandedTrackKeyframes: React.NamedExoticComponent<TimelineExpandedTrackKeyframesProps>;
10
+ export {};
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TimelineExpandedTrackKeyframes = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = __importDefault(require("react"));
9
+ const are_sequence_node_path_infos_equal_1 = require("../../helpers/are-sequence-node-path-infos-equal");
9
10
  const TimelineExpandedKeyframeRow_1 = require("./TimelineExpandedKeyframeRow");
10
11
  const use_expanded_track_keyframe_rows_1 = require("./use-expanded-track-keyframe-rows");
11
12
  const TimelineExpandedTrackKeyframesInner = ({ nodePathInfo, sequence, keyframeDisplayOffset }) => {
@@ -16,4 +17,13 @@ const TimelineExpandedTrackKeyframesInner = ({ nodePathInfo, sequence, keyframeD
16
17
  });
17
18
  return (jsx_runtime_1.jsx("div", { style: { height: expandedHeight }, children: rows.map((row, index) => (jsx_runtime_1.jsx(TimelineExpandedKeyframeRow_1.TimelineExpandedKeyframeRow, { height: row.height, keyframes: row.keyframes, canEditEasing: row.canEditEasing, nodePathInfo: row.nodePathInfo, showSeparator: index > 0 }, row.rowKey))) }));
18
19
  };
19
- exports.TimelineExpandedTrackKeyframes = react_1.default.memo(TimelineExpandedTrackKeyframesInner);
20
+ const areTimelineExpandedTrackKeyframesPropsEqual = (first, second) => {
21
+ var _a, _b, _c, _d;
22
+ return (first.keyframeDisplayOffset === second.keyframeDisplayOffset &&
23
+ ((_a = first.sequence.controls) === null || _a === void 0 ? void 0 : _a.schema) === ((_b = second.sequence.controls) === null || _b === void 0 ? void 0 : _b.schema) &&
24
+ ((_c = first.sequence.controls) === null || _c === void 0 ? void 0 : _c.runtimeValues) ===
25
+ ((_d = second.sequence.controls) === null || _d === void 0 ? void 0 : _d.runtimeValues) &&
26
+ first.sequence.effects === second.sequence.effects &&
27
+ (0, are_sequence_node_path_infos_equal_1.areSequenceNodePathInfosEqual)(first.nodePathInfo, second.nodePathInfo));
28
+ };
29
+ exports.TimelineExpandedTrackKeyframes = react_1.default.memo(TimelineExpandedTrackKeyframesInner, areTimelineExpandedTrackKeyframesPropsEqual);
@@ -343,7 +343,9 @@ const TimelineFontFamilyField = ({ field, propStatus, effectiveValue, onSave, on
343
343
  await onSave(option.value);
344
344
  return;
345
345
  }
346
- await (0, install_required_package_1.installRequiredPackages)(['@remotion/google-fonts']);
346
+ await (0, install_required_package_1.installRequiredPackages)([
347
+ { name: '@remotion/google-fonts', version: null },
348
+ ]);
347
349
  const googleFont = getGoogleFontSourceEdit({
348
350
  fontFamily: (_a = option.value) !== null && _a !== void 0 ? _a : option.label,
349
351
  importName: option.googleFontImportName,
@@ -131,6 +131,7 @@ const resolveKeyframeControlTarget = ({ nodePathInfo, tracks, propStatuses, getD
131
131
  propStatuses,
132
132
  includeTextContent: false,
133
133
  includeSourceControls: false,
134
+ runtimeValues: null,
134
135
  });
135
136
  const fieldNode = findFieldNode(tree, (0, timeline_node_path_key_1.timelineNodePathInfoToKey)(nodePathInfo));
136
137
  if (fieldNode === null || fieldNode.field === null) {
@@ -448,6 +448,7 @@ const getSelectableTimelineItems = ({ getDragOverrides, getEffectDragOverrides,
448
448
  propStatuses,
449
449
  includeTextContent: false,
450
450
  includeSourceControls: false,
451
+ runtimeValues: null,
451
452
  });
452
453
  const filteredTree = (0, timeline_expanded_filter_1.filterTimelineExpandedTree)({
453
454
  nodes: tree,