@remotion/studio 4.0.432 → 4.0.434

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 (68) hide show
  1. package/dist/Studio.js +1 -3
  2. package/dist/components/CompositionSelector.js +16 -9
  3. package/dist/components/CurrentComposition.js +2 -5
  4. package/dist/components/CurrentCompositionSideEffects.js +2 -4
  5. package/dist/components/EditorContent.js +4 -5
  6. package/dist/components/Modals.js +3 -2
  7. package/dist/components/NewComposition/DuplicateComposition.js +4 -1
  8. package/dist/components/NewComposition/InputDragger.d.ts +1 -0
  9. package/dist/components/NewComposition/InputDragger.js +27 -8
  10. package/dist/components/OptionsPanel.js +1 -1
  11. package/dist/components/PlaybackRatePersistor.js +1 -1
  12. package/dist/components/PreviewToolbar.js +5 -4
  13. package/dist/components/RenderButton.d.ts +1 -1
  14. package/dist/components/RenderButton.js +64 -17
  15. package/dist/components/RenderModal/RenderModalBasic.d.ts +1 -0
  16. package/dist/components/RenderModal/RenderModalBasic.js +2 -2
  17. package/dist/components/RenderModal/SchemaEditor/SchemaLabel.js +3 -1
  18. package/dist/components/RenderModal/SchemaEditor/ZodArrayEditor.js +3 -1
  19. package/dist/components/RenderModal/SchemaEditor/ZodFieldValidation.js +3 -1
  20. package/dist/components/RenderModal/SchemaEditor/ZodTupleEditor.js +3 -1
  21. package/dist/components/RenderModal/ServerRenderModal.d.ts +1 -0
  22. package/dist/components/RenderModal/ServerRenderModal.js +170 -5
  23. package/dist/components/RenderModal/WebRenderModalAudio.js +5 -2
  24. package/dist/components/RenderModal/WebRenderModalBasic.js +8 -1
  25. package/dist/components/RendersTab.js +1 -9
  26. package/dist/components/SidebarRenderButton.js +1 -0
  27. package/dist/components/Timeline/TimelineBooleanField.d.ts +9 -0
  28. package/dist/components/Timeline/TimelineBooleanField.js +20 -0
  29. package/dist/components/Timeline/TimelineEmptyState.d.ts +2 -0
  30. package/dist/components/Timeline/TimelineEmptyState.js +15 -0
  31. package/dist/components/Timeline/TimelineExpandedSection.d.ts +5 -0
  32. package/dist/components/Timeline/TimelineExpandedSection.js +45 -7
  33. package/dist/components/Timeline/TimelineFieldRow.d.ts +3 -0
  34. package/dist/components/Timeline/TimelineFieldRow.js +17 -12
  35. package/dist/components/Timeline/TimelineListItem.d.ts +1 -0
  36. package/dist/components/Timeline/TimelineListItem.js +7 -7
  37. package/dist/components/Timeline/TimelineNumberField.d.ts +11 -0
  38. package/dist/components/Timeline/TimelineNumberField.js +53 -0
  39. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +1 -1
  40. package/dist/components/Timeline/TimelineRotationField.d.ts +11 -0
  41. package/dist/components/Timeline/TimelineRotationField.js +64 -0
  42. package/dist/components/Timeline/TimelineSchemaField.d.ts +1 -3
  43. package/dist/components/Timeline/TimelineSchemaField.js +19 -74
  44. package/dist/components/Timeline/TimelineTranslateField.d.ts +11 -0
  45. package/dist/components/Timeline/TimelineTranslateField.js +115 -0
  46. package/dist/components/Timeline/timeline-field-utils.d.ts +2 -0
  47. package/dist/components/Timeline/timeline-field-utils.js +12 -0
  48. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +2 -1
  49. package/dist/components/Timeline/use-sequence-props-subscription.js +32 -12
  50. package/dist/esm/{chunk-t28xqw5n.js → chunk-t3wtt582.js} +3198 -2341
  51. package/dist/esm/internals.mjs +3198 -2341
  52. package/dist/esm/previewEntry.mjs +3203 -2346
  53. package/dist/esm/renderEntry.mjs +1 -3
  54. package/dist/helpers/calculate-timeline.js +17 -11
  55. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +1 -1
  56. package/dist/helpers/get-timeline-sequence-sort-key.js +6 -3
  57. package/dist/helpers/inject-css.js +6 -1
  58. package/dist/helpers/make-render-command.d.ts +51 -0
  59. package/dist/helpers/make-render-command.js +201 -0
  60. package/dist/helpers/retry-payload.js +3 -0
  61. package/dist/helpers/sort-by-nonce-history.d.ts +5 -0
  62. package/dist/helpers/sort-by-nonce-history.js +73 -0
  63. package/dist/helpers/timeline-layout.js +8 -2
  64. package/dist/renderEntry.js +2 -2
  65. package/dist/state/modals.d.ts +1 -0
  66. package/package.json +11 -11
  67. package/dist/helpers/should-show-render-button.d.ts +0 -1
  68. package/dist/helpers/should-show-render-button.js +0 -11
package/dist/Studio.js CHANGED
@@ -9,7 +9,6 @@ const Editor_1 = require("./components/Editor");
9
9
  const EditorContexts_1 = require("./components/EditorContexts");
10
10
  const ServerDisconnected_1 = require("./components/Notifications/ServerDisconnected");
11
11
  const use_static_files_1 = require("./components/use-static-files");
12
- const fast_refresh_context_1 = require("./fast-refresh-context");
13
12
  const FastRefreshProvider_1 = require("./FastRefreshProvider");
14
13
  const inject_css_1 = require("./helpers/inject-css");
15
14
  const ResolveCompositionConfigInStudio_1 = require("./ResolveCompositionConfigInStudio");
@@ -18,8 +17,7 @@ const getServerDisconnectedDomElement = () => {
18
17
  };
19
18
  const StudioInner = ({ rootComponent, readOnly, visualModeEnabled }) => {
20
19
  var _a;
21
- const { fastRefreshes, manualRefreshes } = (0, react_1.useContext)(fast_refresh_context_1.FastRefreshContext);
22
- return (jsx_runtime_1.jsx(remotion_1.Internals.CompositionManagerProvider, { onlyRenderComposition: null, currentCompositionMetadata: null, initialCompositions: [], initialCanvasContent: null, children: jsx_runtime_1.jsx(remotion_1.Internals.RemotionRootContexts, { visualModeEnabled: visualModeEnabled, frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel, numberOfAudioTags: window.remotion_numberOfAudioTags, audioLatencyHint: (_a = window.remotion_audioLatencyHint) !== null && _a !== void 0 ? _a : 'interactive', nonceContextSeed: fastRefreshes + manualRefreshes, children: jsx_runtime_1.jsx(use_static_files_1.StaticFilesProvider, { children: jsx_runtime_1.jsx(ResolveCompositionConfigInStudio_1.ResolveCompositionConfigInStudio, { children: jsx_runtime_1.jsxs(EditorContexts_1.EditorContexts, { readOnlyStudio: readOnly, children: [
20
+ return (jsx_runtime_1.jsx(remotion_1.Internals.CompositionManagerProvider, { onlyRenderComposition: null, currentCompositionMetadata: null, initialCompositions: [], initialCanvasContent: null, children: jsx_runtime_1.jsx(remotion_1.Internals.RemotionRootContexts, { visualModeEnabled: visualModeEnabled, frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel, numberOfAudioTags: window.remotion_numberOfAudioTags, audioLatencyHint: (_a = window.remotion_audioLatencyHint) !== null && _a !== void 0 ? _a : 'interactive', children: jsx_runtime_1.jsx(use_static_files_1.StaticFilesProvider, { children: jsx_runtime_1.jsx(ResolveCompositionConfigInStudio_1.ResolveCompositionConfigInStudio, { children: jsx_runtime_1.jsxs(EditorContexts_1.EditorContexts, { readOnlyStudio: readOnly, children: [
23
21
  jsx_runtime_1.jsx(Editor_1.Editor, { readOnlyStudio: readOnly, Root: rootComponent }), readOnly
24
22
  ? null
25
23
  : (0, react_dom_1.createPortal)(jsx_runtime_1.jsx(ServerDisconnected_1.ServerDisconnected, {}), getServerDisconnectedDomElement())] }) }) }) }) }));
@@ -7,6 +7,7 @@ const remotion_1 = require("remotion");
7
7
  const colors_1 = require("../helpers/colors");
8
8
  const create_folder_tree_1 = require("../helpers/create-folder-tree");
9
9
  const persist_open_folders_1 = require("../helpers/persist-open-folders");
10
+ const sort_by_nonce_history_1 = require("../helpers/sort-by-nonce-history");
10
11
  const z_index_1 = require("../state/z-index");
11
12
  const CompositionSelectorItem_1 = require("./CompositionSelectorItem");
12
13
  const CurrentComposition_1 = require("./CurrentComposition");
@@ -72,24 +73,30 @@ const CompositionSelector = () => {
72
73
  const { foldersExpanded } = (0, react_1.useContext)(persist_open_folders_1.ExpandedFoldersContext);
73
74
  const { tabIndex } = (0, z_index_1.useZIndex)();
74
75
  const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
76
+ const sortedCompositions = (0, react_1.useMemo)(() => {
77
+ return (0, sort_by_nonce_history_1.sortItemsByNonceHistory)(compositions);
78
+ }, [compositions]);
79
+ const sortedFolders = (0, react_1.useMemo)(() => {
80
+ return (0, sort_by_nonce_history_1.sortItemsByNonceHistory)(folders);
81
+ }, [folders]);
75
82
  const items = (0, react_1.useMemo)(() => {
76
- return (0, create_folder_tree_1.createFolderTree)(compositions, folders, foldersExpanded);
77
- }, [compositions, folders, foldersExpanded]);
78
- const showCurrentComposition = canvasContent && canvasContent.type === 'composition';
83
+ return (0, create_folder_tree_1.createFolderTree)(sortedCompositions, sortedFolders, foldersExpanded);
84
+ }, [sortedCompositions, sortedFolders, foldersExpanded]);
79
85
  const list = (0, react_1.useMemo)(() => {
80
86
  return {
81
- height: showCurrentComposition
82
- ? `calc(100% - ${CurrentComposition_1.CURRENT_COMPOSITION_HEIGHT}px)`
83
- : '100%',
87
+ height: `calc(100% - ${CurrentComposition_1.CURRENT_COMPOSITION_HEIGHT}px)`,
84
88
  overflowY: 'auto',
85
89
  };
86
- }, [showCurrentComposition]);
90
+ }, []);
87
91
  const toggleFolder = (0, react_1.useCallback)((folderName, parentName) => {
88
92
  var _a;
89
93
  (_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.toggleFolder(folderName, parentName);
90
94
  }, []);
91
- return (jsx_runtime_1.jsxs("div", { style: container, children: [showCurrentComposition ? jsx_runtime_1.jsx(CurrentComposition_1.CurrentComposition, {}) : null, jsx_runtime_1.jsx("div", { className: "__remotion-vertical-scrollbar", style: list, children: items.map((c) => {
92
- return (jsx_runtime_1.jsx(CompositionSelectorItem_1.CompositionSelectorItem, { level: 0, currentComposition: showCurrentComposition ? canvasContent.compositionId : null, selectComposition: selectComposition, toggleFolder: toggleFolder, tabIndex: tabIndex, item: c }, c.key + c.type));
95
+ return (jsx_runtime_1.jsxs("div", { style: container, children: [
96
+ jsx_runtime_1.jsx(CurrentComposition_1.CurrentComposition, {}), jsx_runtime_1.jsx("div", { className: "__remotion-vertical-scrollbar", style: list, children: items.map((c) => {
97
+ return (jsx_runtime_1.jsx(CompositionSelectorItem_1.CompositionSelectorItem, { level: 0, currentComposition: canvasContent && canvasContent.type === 'composition'
98
+ ? canvasContent.compositionId
99
+ : null, selectComposition: selectComposition, toggleFolder: toggleFolder, tabIndex: tabIndex, item: c }, c.key + c.type));
93
100
  }) })
94
101
  ] }));
95
102
  };
@@ -37,10 +37,7 @@ const row = {
37
37
  };
38
38
  const CurrentComposition = () => {
39
39
  const video = remotion_1.Internals.useVideo();
40
- if (!video) {
41
- return jsx_runtime_1.jsx("div", { style: container });
42
- }
43
- return (jsx_runtime_1.jsx("div", { style: container, children: jsx_runtime_1.jsx("div", { style: row, children: jsx_runtime_1.jsxs("div", { children: [
44
- jsx_runtime_1.jsx("div", { style: title, children: video.id }), jsx_runtime_1.jsxs("div", { style: subtitle, children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx("div", { style: subtitle, children: "Still" })) : (jsx_runtime_1.jsxs("div", { style: subtitle, children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] }) }) }));
40
+ return (jsx_runtime_1.jsx("div", { style: container, children: video ? (jsx_runtime_1.jsx("div", { style: row, children: jsx_runtime_1.jsxs("div", { children: [
41
+ jsx_runtime_1.jsx("div", { style: title, children: video.id }), jsx_runtime_1.jsxs("div", { style: subtitle, children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx("div", { style: subtitle, children: "Still" })) : (jsx_runtime_1.jsxs("div", { style: subtitle, children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] }) })) : null }));
45
42
  };
46
43
  exports.CurrentComposition = CurrentComposition;
@@ -5,6 +5,7 @@ const react_1 = require("react");
5
5
  const remotion_1 = require("remotion");
6
6
  const client_id_1 = require("../helpers/client-id");
7
7
  const document_title_1 = require("../helpers/document-title");
8
+ const show_browser_rendering_1 = require("../helpers/show-browser-rendering");
8
9
  const use_keybinding_1 = require("../helpers/use-keybinding");
9
10
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
10
11
  const context_1 = require("./RenderQueue/context");
@@ -45,10 +46,7 @@ const CurrentCompositionKeybindings = ({ readOnlyStudio }) => {
45
46
  if (!video) {
46
47
  return;
47
48
  }
48
- if (readOnlyStudio) {
49
- return (0, NotificationCenter_1.showNotification)('Studio is read-only', 2000);
50
- }
51
- if (type !== 'connected') {
49
+ if (type !== 'connected' && !show_browser_rendering_1.SHOW_BROWSER_RENDERING && !readOnlyStudio) {
52
50
  (0, NotificationCenter_1.showNotification)('Studio server is offline', 2000);
53
51
  return;
54
52
  }
@@ -11,6 +11,7 @@ const SplitterContainer_1 = require("./Splitter/SplitterContainer");
11
11
  const SplitterElement_1 = require("./Splitter/SplitterElement");
12
12
  const SplitterHandle_1 = require("./Splitter/SplitterHandle");
13
13
  const Timeline_1 = require("./Timeline/Timeline");
14
+ const TimelineEmptyState_1 = require("./Timeline/TimelineEmptyState");
14
15
  const noop = () => undefined;
15
16
  const container = {
16
17
  display: 'flex',
@@ -21,13 +22,11 @@ const container = {
21
22
  const EditorContent = ({ readOnlyStudio, children }) => {
22
23
  const isStill = (0, is_current_selected_still_1.useIsStill)();
23
24
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
24
- // Preventing multiple renders so the update check doesn't get rendered twice and needs to be aborted
25
- const onlyTopPanel = canvasContent === null || isStill || canvasContent.type !== 'composition';
25
+ const showTimeline = canvasContent !== null && !isStill && canvasContent.type === 'composition';
26
26
  return (jsx_runtime_1.jsxs("div", { style: container, children: [
27
27
  jsx_runtime_1.jsx(InitialCompositionLoader_1.InitialCompositionLoader, {}), jsx_runtime_1.jsx(MenuToolbar_1.MenuToolbar, { readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { orientation: "horizontal", id: "top-to-bottom", maxFlex: 0.9, minFlex: 0.2, defaultFlex: 0.75, children: [
28
- jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: children }), onlyTopPanel ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
29
- jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "none", onCollapse: noop }), jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: jsx_runtime_1.jsx(Timeline_1.Timeline, {}) })
30
- ] }))] })
28
+ jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: children }), jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "none", onCollapse: noop }), jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: showTimeline ? jsx_runtime_1.jsx(Timeline_1.Timeline, {}) : jsx_runtime_1.jsx(TimelineEmptyState_1.TimelineEmptyState, {}) })
29
+ ] })
31
30
  ] }));
32
31
  };
33
32
  exports.EditorContent = EditorContent;
@@ -20,11 +20,12 @@ const ServerRenderModal_1 = require("./RenderModal/ServerRenderModal");
20
20
  const WebRenderModal_1 = require("./RenderModal/WebRenderModal");
21
21
  const UpdateModal_1 = require("./UpdateModal/UpdateModal");
22
22
  const Modals = ({ readOnlyStudio }) => {
23
+ var _a;
23
24
  const { selectedModal: modalContextType } = (0, react_1.useContext)(modals_1.ModalsContext);
24
25
  const canRender = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx).previewServerState.type ===
25
26
  'connected';
26
27
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [modalContextType && modalContextType.type === 'duplicate-comp' && (jsx_runtime_1.jsx(DuplicateComposition_1.DuplicateComposition, { compositionType: modalContextType.compositionType, compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'delete-comp' && (jsx_runtime_1.jsx(DeleteComposition_1.DeleteComposition, { compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'rename-comp' && (jsx_runtime_1.jsx(RenameComposition_1.RenameComposition, { compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'input-props-override' && (jsx_runtime_1.jsx(OverrideInputProps_1.OverrideInputPropsModal, {})), modalContextType && modalContextType.type === 'web-render' && (jsx_runtime_1.jsx(WebRenderModal_1.WebRenderModalWithLoader, { ...modalContextType })), modalContextType &&
27
- canRender &&
28
- modalContextType.type === 'server-render' && (jsx_runtime_1.jsx(ServerRenderModal_1.RenderModalWithLoader, { initialFrame: modalContextType.initialFrame, initialDarkMode: modalContextType.initialDarkMode, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialScale: modalContextType.initialScale, initialLogLevel: modalContextType.initialLogLevel, initialOffthreadVideoCacheSizeInBytes: modalContextType.initialOffthreadVideoCacheSizeInBytes, initialOffthreadVideoThreads: modalContextType.initialOffthreadVideoThreads, initialMediaCacheSizeInBytes: modalContextType.initialMediaCacheSizeInBytes, initialConcurrency: modalContextType.initialConcurrency, maxConcurrency: modalContextType.maxConcurrency, minConcurrency: modalContextType.minConcurrency, initialStillImageFormat: modalContextType.initialStillImageFormat, initialMuted: modalContextType.initialMuted, initialEnforceAudioTrack: modalContextType.initialEnforceAudioTrack, initialProResProfile: modalContextType.initialProResProfile, initialx264Preset: modalContextType.initialx264Preset, initialPixelFormat: modalContextType.initialPixelFormat, initialAudioBitrate: modalContextType.initialAudioBitrate, initialVideoBitrate: modalContextType.initialVideoBitrate, initialEveryNthFrame: modalContextType.initialEveryNthFrame, initialNumberOfGifLoops: modalContextType.initialNumberOfGifLoops, initialDelayRenderTimeout: modalContextType.initialDelayRenderTimeout, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, initialEncodingBufferSize: modalContextType.initialEncodingBufferSize, initialEncodingMaxRate: modalContextType.initialEncodingMaxRate, initialUserAgent: modalContextType.initialUserAgent, initialColorSpace: modalContextType.initialColorSpace, initialMultiProcessOnLinux: modalContextType.initialMultiProcessOnLinux, initialRepro: modalContextType.initialRepro, initialBeep: modalContextType.initialBeep, initialForSeamlessAacConcatenation: modalContextType.initialForSeamlessAacConcatenation, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark, defaultConfigurationAudioCodec: modalContextType.defaultConfigurationAudioCodec, defaultConfigurationVideoCodec: modalContextType.defaultConfigurationVideoCodec, renderTypeOfLastRender: modalContextType.renderTypeOfLastRender, defaultMetadata: modalContextType.defaulMetadata, initialHardwareAcceleration: modalContextType.initialHardwareAcceleration, initialChromeMode: modalContextType.initialChromeMode, renderDefaults: modalContextType.renderDefaults })), modalContextType && modalContextType.type === 'render-progress' && (jsx_runtime_1.jsx(RenderStatusModal_1.RenderStatusModal, { jobId: modalContextType.jobId })), modalContextType && modalContextType.type === 'update' && (jsx_runtime_1.jsx(UpdateModal_1.UpdateModal, { info: modalContextType.info, knownBugs: modalContextType.knownBugs })), modalContextType && modalContextType.type === 'install-packages' && (jsx_runtime_1.jsx(InstallPackage_1.InstallPackageModal, { packageManager: modalContextType.packageManager })), modalContextType && modalContextType.type === 'quick-switcher' && (jsx_runtime_1.jsx(QuickSwitcher_1.default, { readOnlyStudio: readOnlyStudio, invocationTimestamp: modalContextType.invocationTimestamp, initialMode: modalContextType.mode })), process.env.ASK_AI_ENABLED && jsx_runtime_1.jsx(AskAiModal_1.AskAiModal, {})] }));
28
+ modalContextType.type === 'server-render' &&
29
+ (canRender || modalContextType.readOnlyStudio) ? (jsx_runtime_1.jsx(ServerRenderModal_1.RenderModalWithLoader, { readOnlyStudio: (_a = modalContextType.readOnlyStudio) !== null && _a !== void 0 ? _a : false, initialFrame: modalContextType.initialFrame, initialDarkMode: modalContextType.initialDarkMode, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialScale: modalContextType.initialScale, initialLogLevel: modalContextType.initialLogLevel, initialOffthreadVideoCacheSizeInBytes: modalContextType.initialOffthreadVideoCacheSizeInBytes, initialOffthreadVideoThreads: modalContextType.initialOffthreadVideoThreads, initialMediaCacheSizeInBytes: modalContextType.initialMediaCacheSizeInBytes, initialConcurrency: modalContextType.initialConcurrency, maxConcurrency: modalContextType.maxConcurrency, minConcurrency: modalContextType.minConcurrency, initialStillImageFormat: modalContextType.initialStillImageFormat, initialMuted: modalContextType.initialMuted, initialEnforceAudioTrack: modalContextType.initialEnforceAudioTrack, initialProResProfile: modalContextType.initialProResProfile, initialx264Preset: modalContextType.initialx264Preset, initialPixelFormat: modalContextType.initialPixelFormat, initialAudioBitrate: modalContextType.initialAudioBitrate, initialVideoBitrate: modalContextType.initialVideoBitrate, initialEveryNthFrame: modalContextType.initialEveryNthFrame, initialNumberOfGifLoops: modalContextType.initialNumberOfGifLoops, initialDelayRenderTimeout: modalContextType.initialDelayRenderTimeout, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, initialEncodingBufferSize: modalContextType.initialEncodingBufferSize, initialEncodingMaxRate: modalContextType.initialEncodingMaxRate, initialUserAgent: modalContextType.initialUserAgent, initialColorSpace: modalContextType.initialColorSpace, initialMultiProcessOnLinux: modalContextType.initialMultiProcessOnLinux, initialRepro: modalContextType.initialRepro, initialBeep: modalContextType.initialBeep, initialForSeamlessAacConcatenation: modalContextType.initialForSeamlessAacConcatenation, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark, defaultConfigurationAudioCodec: modalContextType.defaultConfigurationAudioCodec, defaultConfigurationVideoCodec: modalContextType.defaultConfigurationVideoCodec, renderTypeOfLastRender: modalContextType.renderTypeOfLastRender, defaultMetadata: modalContextType.defaulMetadata, initialHardwareAcceleration: modalContextType.initialHardwareAcceleration, initialChromeMode: modalContextType.initialChromeMode, renderDefaults: modalContextType.renderDefaults })) : null, modalContextType && modalContextType.type === 'render-progress' && (jsx_runtime_1.jsx(RenderStatusModal_1.RenderStatusModal, { jobId: modalContextType.jobId })), modalContextType && modalContextType.type === 'update' && (jsx_runtime_1.jsx(UpdateModal_1.UpdateModal, { info: modalContextType.info, knownBugs: modalContextType.knownBugs })), modalContextType && modalContextType.type === 'install-packages' && (jsx_runtime_1.jsx(InstallPackage_1.InstallPackageModal, { packageManager: modalContextType.packageManager })), modalContextType && modalContextType.type === 'quick-switcher' && (jsx_runtime_1.jsx(QuickSwitcher_1.default, { readOnlyStudio: readOnlyStudio, invocationTimestamp: modalContextType.invocationTimestamp, initialMode: modalContextType.mode })), process.env.ASK_AI_ENABLED && jsx_runtime_1.jsx(AskAiModal_1.AskAiModal, {})] }));
29
30
  };
30
31
  exports.Modals = Modals;
@@ -175,7 +175,10 @@ const DuplicateCompositionLoaded = ({ initialType }) => {
175
175
  }, []);
176
176
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
177
177
  jsx_runtime_1.jsx(ModalHeader_1.ModalHeader, { title: `Duplicate ${resolved.result.id}` }), jsx_runtime_1.jsxs("form", { onSubmit: onSubmit, children: [
178
- jsx_runtime_1.jsxs("div", { style: content, children: [initialCompType === 'composition' ? (jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
178
+ jsx_runtime_1.jsxs("div", { style: content, children: [initialCompType === 'composition' ? (
179
+ // We allow converting from a composition to a still, but
180
+ // not the other way around
181
+ jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
179
182
  jsx_runtime_1.jsx("div", { style: layout_2.label, children: "Type" }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(ComboBox_1.Combobox, { title: "Type of composition", style: comboBoxStyle, values: typeValues, selectedId: type }) })
180
183
  ] })) : null, jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
181
184
  jsx_runtime_1.jsx("div", { style: layout_2.label, children: "ID" }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsxs("div", { children: [
@@ -8,4 +8,5 @@ export declare const InputDragger: React.ForwardRefExoticComponent<InputHTMLAttr
8
8
  readonly status: RemInputStatus;
9
9
  readonly formatter?: ((str: string | number) => string) | undefined;
10
10
  readonly rightAlign: boolean;
11
+ readonly small?: boolean | undefined;
11
12
  } & React.RefAttributes<HTMLButtonElement>>;
@@ -45,27 +45,34 @@ const RemInput_1 = require("./RemInput");
45
45
  const isInt = (num) => {
46
46
  return num % 1 === 0;
47
47
  };
48
- const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min, max: _max, step: _step, value, onTextChange, formatter = (q) => String(q), status, rightAlign, ...props }, ref) => {
48
+ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min, max: _max, step: _step, value, onTextChange, formatter = (q) => String(q), status, rightAlign, small, ...props }, ref) => {
49
49
  const [inputFallback, setInputFallback] = (0, react_1.useState)(false);
50
+ const [dragging, setDragging] = (0, react_1.useState)(false);
50
51
  const fallbackRef = (0, react_1.useRef)(null);
52
+ const pointerDownRef = (0, react_1.useRef)(false);
51
53
  const style = (0, react_1.useMemo)(() => {
52
54
  return {
53
55
  ...RemInput_1.inputBaseStyle,
54
56
  backgroundColor: 'transparent',
55
57
  borderColor: 'transparent',
56
58
  padding: '4px 6px',
59
+ ...{ outline: 'none' },
57
60
  };
58
61
  }, []);
59
62
  const span = (0, react_1.useMemo)(() => ({
60
- borderBottom: '1px dotted ' + colors_1.BLUE,
61
- paddingBottom: 1,
62
- color: colors_1.BLUE,
63
+ color: dragging ? 'var(--remotion-cli-internals-blue-hovered)' : colors_1.BLUE,
63
64
  cursor: 'ew-resize',
64
65
  userSelect: 'none',
65
66
  WebkitUserSelect: 'none',
66
- fontSize: 13,
67
+ fontSize: small ? 12 : 14,
67
68
  fontVariantNumeric: 'tabular-nums',
68
- }), []);
69
+ }), [dragging, small]);
70
+ const onFocus = (0, react_1.useCallback)(() => {
71
+ if (!small || pointerDownRef.current) {
72
+ return;
73
+ }
74
+ setInputFallback(true);
75
+ }, [small]);
69
76
  const onClick = (0, react_1.useCallback)((e) => {
70
77
  if (!(0, input_dragger_click_lock_1.getClickLock)()) {
71
78
  e.stopPropagation();
@@ -78,6 +85,12 @@ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min,
78
85
  const onEscape = (0, react_1.useCallback)(() => {
79
86
  setInputFallback(false);
80
87
  }, []);
88
+ const onInputChange = (0, react_1.useCallback)((e) => {
89
+ const parsed = Number(e.target.value);
90
+ if (e.target.value !== '' && !Number.isNaN(parsed)) {
91
+ onValueChange(parsed);
92
+ }
93
+ }, [onValueChange]);
81
94
  const onBlur = (0, react_1.useCallback)(() => {
82
95
  if (!fallbackRef.current) {
83
96
  return;
@@ -106,6 +119,8 @@ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min,
106
119
  return Math.ceil(val * factor) / factor;
107
120
  };
108
121
  const onPointerDown = (0, react_1.useCallback)((e) => {
122
+ pointerDownRef.current = true;
123
+ const target = e.currentTarget;
109
124
  const { pageX, pageY, button } = e;
110
125
  if (button !== 0) {
111
126
  return;
@@ -119,6 +134,8 @@ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min,
119
134
  const max = Number(_max !== null && _max !== void 0 ? _max : Infinity);
120
135
  if (distanceFromStart > 4) {
121
136
  (0, input_dragger_click_lock_1.setClickLock)(true);
137
+ setDragging(true);
138
+ target.blur();
122
139
  }
123
140
  const diff = (0, remotion_1.interpolate)(xDistance, [-5, -4, 0, 4, 5], [-step, 0, 0, 0, step]);
124
141
  const newValue = Math.min(max, Math.max(min, Number(value) + diff));
@@ -129,6 +146,8 @@ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min,
129
146
  window.addEventListener('mousemove', moveListener);
130
147
  window.addEventListener('pointerup', () => {
131
148
  window.removeEventListener('mousemove', moveListener);
149
+ pointerDownRef.current = false;
150
+ setDragging(false);
132
151
  if (lastDragValue !== null && onValueChangeEnd) {
133
152
  onValueChangeEnd(lastDragValue);
134
153
  }
@@ -155,8 +174,8 @@ const InputDraggerForwardRefFn = ({ onValueChange, onValueChangeEnd, min: _min,
155
174
  return 0.0001;
156
175
  }, [_min, _step]);
157
176
  if (inputFallback) {
158
- return (jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onEscape: onEscape, onOutsideClick: noop_1.noop, children: jsx_runtime_1.jsx(RemInput_1.RemotionInput, { ref: fallbackRef, autoFocus: true, onKeyPress: onKeyPress, onBlur: onBlur, min: _min, max: _max, step: deriveStep, defaultValue: value, status: status, pattern: '[0-9]*[.]?[0-9]*', rightAlign: rightAlign, ...props }) }));
177
+ return (jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onEscape: onEscape, onOutsideClick: noop_1.noop, children: jsx_runtime_1.jsx(RemInput_1.RemotionInput, { ref: fallbackRef, autoFocus: true, onKeyPress: onKeyPress, onBlur: onBlur, onChange: onInputChange, min: _min, max: _max, step: deriveStep, defaultValue: value, status: status, pattern: '[0-9]*[.]?[0-9]*', rightAlign: rightAlign, ...props, ...(small ? { style: { padding: '4px 6px', fontSize: 12 } } : {}) }) }));
159
178
  }
160
- return (jsx_runtime_1.jsx("button", { ref: ref, type: "button", style: style, onClick: onClick, onPointerDown: onPointerDown, children: jsx_runtime_1.jsx("span", { style: span, children: formatter(value) }) }));
179
+ return (jsx_runtime_1.jsx("button", { ref: ref, type: "button", className: '__remotion_input_dragger', style: style, onClick: onClick, onFocus: onFocus, onPointerDown: onPointerDown, children: jsx_runtime_1.jsx("span", { style: span, children: formatter(value) }) }));
161
180
  };
162
181
  exports.InputDragger = react_1.default.forwardRef(InputDraggerForwardRefFn);
@@ -120,6 +120,6 @@ const OptionsPanel = ({ readOnlyStudio }) => {
120
120
  };
121
121
  }, [reset]);
122
122
  return (jsx_runtime_1.jsxs("div", { style: container, className: "css-reset", children: [
123
- jsx_runtime_1.jsx("div", { style: tabsContainer, children: jsx_runtime_1.jsxs(Tabs_1.Tabs, { children: [visualControlsTabActivated ? (jsx_runtime_1.jsx(Tabs_1.Tab, { selected: panel === 'visual-controls', onClick: onVisualControlsSelected, children: "Controls" })) : null, composition ? (jsx_runtime_1.jsxs(Tabs_1.Tab, { selected: panel === 'input-props', onClick: onPropsSelected, style: { justifyContent: 'space-between' }, children: ["Props", unsavedChangesExist ? (jsx_runtime_1.jsx(GlobalPropsEditorUpdateButton_1.GlobalPropsEditorUpdateButton, { compositionId: composition.id, currentDefaultProps: currentDefaultProps })) : null] })) : null, renderingAvailable ? (jsx_runtime_1.jsx(RendersTab_1.RendersTab, { onClick: onRendersSelected, selected: panel === 'renders' })) : null] }) }), panel === `input-props` && composition ? (jsx_runtime_1.jsx(DataEditor_1.DataEditor, { unresolvedComposition: composition, defaultProps: currentDefaultProps, setDefaultProps: setDefaultProps, mayShowSaveButton: true, propsEditType: "default-props", saving: saving, setSaving: setSaving, readOnlyStudio: readOnlyStudio }, composition.id)) : panel === 'visual-controls' && visualControlsTabActivated ? (jsx_runtime_1.jsx(VisualControlsContent_1.VisualControlsContent, {})) : !renderingAvailable ? null : (jsx_runtime_1.jsx(RenderQueue_1.RenderQueue, {}))] }));
123
+ jsx_runtime_1.jsx("div", { style: tabsContainer, children: jsx_runtime_1.jsxs(Tabs_1.Tabs, { children: [visualControlsTabActivated ? (jsx_runtime_1.jsx(Tabs_1.Tab, { selected: panel === 'visual-controls', onClick: onVisualControlsSelected, children: "Controls" })) : null, jsx_runtime_1.jsxs(Tabs_1.Tab, { selected: panel === 'input-props', onClick: onPropsSelected, style: { justifyContent: 'space-between' }, children: ["Props", unsavedChangesExist && composition ? (jsx_runtime_1.jsx(GlobalPropsEditorUpdateButton_1.GlobalPropsEditorUpdateButton, { compositionId: composition.id, currentDefaultProps: currentDefaultProps })) : null] }), renderingAvailable ? (jsx_runtime_1.jsx(RendersTab_1.RendersTab, { onClick: onRendersSelected, selected: panel === 'renders' })) : null] }) }), panel === 'input-props' ? (composition ? (jsx_runtime_1.jsx(DataEditor_1.DataEditor, { unresolvedComposition: composition, defaultProps: currentDefaultProps, setDefaultProps: setDefaultProps, mayShowSaveButton: true, propsEditType: "default-props", saving: saving, setSaving: setSaving, readOnlyStudio: readOnlyStudio }, composition.id)) : null) : panel === 'visual-controls' && visualControlsTabActivated ? (jsx_runtime_1.jsx(VisualControlsContent_1.VisualControlsContent, {})) : !renderingAvailable ? null : (jsx_runtime_1.jsx(RenderQueue_1.RenderQueue, {}))] }));
124
124
  };
125
125
  exports.OptionsPanel = OptionsPanel;
@@ -5,7 +5,7 @@ const react_1 = require("react");
5
5
  const remotion_1 = require("remotion");
6
6
  const playbackrate_1 = require("../state/playbackrate");
7
7
  const PlaybackRatePersistor = () => {
8
- const { setPlaybackRate, playbackRate } = (0, react_1.useContext)(remotion_1.Internals.TimelineContext);
8
+ const { setPlaybackRate, playbackRate } = remotion_1.Internals.useTimelineContext();
9
9
  (0, react_1.useEffect)(() => {
10
10
  setPlaybackRate((0, playbackrate_1.loadPlaybackRate)());
11
11
  }, [setPlaybackRate]);
@@ -8,7 +8,6 @@ const check_fullscreen_support_1 = require("../helpers/check-fullscreen-support"
8
8
  const colors_1 = require("../helpers/colors");
9
9
  const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
10
10
  const mobile_layout_1 = require("../helpers/mobile-layout");
11
- const should_show_render_button_1 = require("../helpers/should-show-render-button");
12
11
  const timeline_layout_1 = require("../helpers/timeline-layout");
13
12
  const loop_1 = require("../state/loop");
14
13
  const CheckboardToggle_1 = require("./CheckboardToggle");
@@ -25,6 +24,7 @@ const RenderButton_1 = require("./RenderButton");
25
24
  const SizeSelector_1 = require("./SizeSelector");
26
25
  const TimelineZoomControls_1 = require("./Timeline/TimelineZoomControls");
27
26
  const TimelineInOutToggle_1 = require("./TimelineInOutToggle");
27
+ const TOOLBAR_HEIGHT = 56;
28
28
  const container = {
29
29
  display: 'flex',
30
30
  justifyContent: 'center',
@@ -34,6 +34,7 @@ const container = {
34
34
  alignItems: 'center',
35
35
  flexDirection: 'row',
36
36
  background: colors_1.BACKGROUND,
37
+ height: TOOLBAR_HEIGHT,
37
38
  };
38
39
  const mobileContainer = {
39
40
  ...container,
@@ -72,7 +73,7 @@ const padding = {
72
73
  width: timeline_layout_1.TIMELINE_PADDING,
73
74
  };
74
75
  const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
75
- const { playbackRate, setPlaybackRate } = (0, react_1.useContext)(remotion_1.Internals.TimelineContext);
76
+ const { playbackRate, setPlaybackRate } = remotion_1.Internals.useTimelineContext();
76
77
  const { mediaMuted } = (0, react_1.useContext)(remotion_1.Internals.MediaVolumeContext);
77
78
  const { setMediaMuted } = (0, react_1.useContext)(remotion_1.Internals.SetMediaVolumeContext);
78
79
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
@@ -140,9 +141,9 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
140
141
  jsx_runtime_1.jsx("div", { style: padding }), jsx_runtime_1.jsx(TimelineZoomControls_1.TimelineZoomControls, {})
141
142
  ] }), jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(SizeSelector_1.SizeSelector, {}), isStill || isVideoComposition ? (jsx_runtime_1.jsx(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate })) : null] })), isVideoComposition ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
142
143
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PlayPause_1.PlayPause, { bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds, loop: loop, playbackRate: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(LoopToggle_1.LoopToggle, { loop: loop, setLoop: setLoop }), jsx_runtime_1.jsx(MuteToggle_1.MuteToggle, { muted: mediaMuted, setMuted: setMediaMuted }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(TimelineInOutToggle_1.TimelineInOutPointToggle, {}), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 })
143
- ] })) : null, (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition' ? jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), isFullscreenSupported && jsx_runtime_1.jsx(FullscreenToggle_1.FullScreenToggle, {}), jsx_runtime_1.jsx(layout_1.Flex, {}), isMobileLayout && (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
144
+ ] })) : null, (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition' ? jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), canvasContent && isFullscreenSupported ? jsx_runtime_1.jsx(FullscreenToggle_1.FullScreenToggle, {}) : null, jsx_runtime_1.jsx(layout_1.Flex, {}), isMobileLayout && (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
144
145
  jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(SizeSelector_1.SizeSelector, {}), isStill || isVideoComposition ? (jsx_runtime_1.jsx(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate })) : null] })), jsx_runtime_1.jsxs("div", { style: sideContainer, children: [
145
- jsx_runtime_1.jsx(layout_1.Flex, {}), !isMobileLayout && jsx_runtime_1.jsx(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), (0, should_show_render_button_1.shouldShowRenderButton)(readOnlyStudio) ? (jsx_runtime_1.jsx(RenderButton_1.RenderButton, { readOnlyStudio: readOnlyStudio })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
146
+ jsx_runtime_1.jsx(layout_1.Flex, {}), !isMobileLayout && jsx_runtime_1.jsx(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(RenderButton_1.RenderButton, { readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
146
147
  ] }), jsx_runtime_1.jsx(PlaybackKeyboardShortcutsManager_1.PlaybackKeyboardShortcutsManager, { setPlaybackRate: setPlaybackRate }), jsx_runtime_1.jsx(PlaybackRatePersistor_1.PlaybackRatePersistor, {}), jsx_runtime_1.jsx("div", { ref: rightScrollIndicatorRef, style: scrollIndicatorRight })
147
148
  ] }));
148
149
  };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- export type RenderType = 'server-render' | 'client-render';
2
+ export type RenderType = 'server-render' | 'client-render' | 'render-command';
3
3
  export declare const RenderButton: React.FC<{
4
4
  readonly readOnlyStudio: boolean;
5
5
  }>;
@@ -73,7 +73,7 @@ const label = {
73
73
  const RENDER_TYPE_STORAGE_KEY = 'remotion.renderType';
74
74
  const getInitialRenderType = (readOnlyStudio) => {
75
75
  if (!show_browser_rendering_1.SHOW_BROWSER_RENDERING) {
76
- return 'server-render';
76
+ return readOnlyStudio ? 'render-command' : 'server-render';
77
77
  }
78
78
  if (readOnlyStudio) {
79
79
  return 'client-render';
@@ -132,8 +132,17 @@ const RenderButton = ({ readOnlyStudio, }) => {
132
132
  }, [refresh]);
133
133
  const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
134
134
  .previewServerState.type;
135
- const canRender = connectionStatus === 'connected' || show_browser_rendering_1.SHOW_BROWSER_RENDERING;
135
+ const canServerRender = connectionStatus === 'connected';
136
+ const canRender = canServerRender || show_browser_rendering_1.SHOW_BROWSER_RENDERING || readOnlyStudio;
136
137
  const renderType = (0, react_1.useMemo)(() => {
138
+ if (readOnlyStudio) {
139
+ if (!show_browser_rendering_1.SHOW_BROWSER_RENDERING) {
140
+ return 'render-command';
141
+ }
142
+ return preferredRenderType === 'render-command'
143
+ ? 'render-command'
144
+ : 'client-render';
145
+ }
137
146
  if (connectionStatus === 'disconnected' && show_browser_rendering_1.SHOW_BROWSER_RENDERING) {
138
147
  return 'client-render';
139
148
  }
@@ -141,11 +150,13 @@ const RenderButton = ({ readOnlyStudio, }) => {
141
150
  return 'server-render';
142
151
  }
143
152
  return preferredRenderType;
144
- }, [connectionStatus, preferredRenderType]);
153
+ }, [connectionStatus, preferredRenderType, readOnlyStudio]);
145
154
  const shortcut = (0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? '' : '(R)';
146
- const tooltip = canRender
147
- ? 'Export the current composition ' + shortcut
148
- : 'Connect to the Studio server to render';
155
+ const tooltip = renderType === 'render-command'
156
+ ? 'Copy a CLI command to render this composition ' + shortcut
157
+ : canRender
158
+ ? 'Export the current composition ' + shortcut
159
+ : 'Connect to the Studio server to render';
149
160
  const iconStyle = (0, react_1.useMemo)(() => {
150
161
  return {
151
162
  style: {
@@ -157,7 +168,7 @@ const RenderButton = ({ readOnlyStudio, }) => {
157
168
  const video = remotion_1.Internals.useVideo();
158
169
  const getCurrentFrame = player_1.PlayerInternals.useFrameImperative();
159
170
  const { props } = (0, react_1.useContext)(remotion_1.Internals.EditorPropsContext);
160
- const openServerRenderModal = (0, react_1.useCallback)(() => {
171
+ const openServerRenderModal = (0, react_1.useCallback)((copyCommandOnly) => {
161
172
  var _a;
162
173
  var _b, _c;
163
174
  if (!video) {
@@ -169,6 +180,7 @@ const RenderButton = ({ readOnlyStudio, }) => {
169
180
  }
170
181
  setSelectedModal({
171
182
  type: 'server-render',
183
+ readOnlyStudio: copyCommandOnly,
172
184
  compositionId: video.id,
173
185
  initialFrame: getCurrentFrame(),
174
186
  initialStillImageFormat: defaults.stillImageFormat,
@@ -253,8 +265,12 @@ const RenderButton = ({ readOnlyStudio, }) => {
253
265
  });
254
266
  }, [video, setSelectedModal, getCurrentFrame, props, inFrame, outFrame]);
255
267
  const onClick = (0, react_1.useCallback)(() => {
268
+ if (renderType === 'render-command') {
269
+ openServerRenderModal(true);
270
+ return;
271
+ }
256
272
  if (!show_browser_rendering_1.SHOW_BROWSER_RENDERING || renderType === 'server-render') {
257
- openServerRenderModal();
273
+ openServerRenderModal(false);
258
274
  }
259
275
  else {
260
276
  openClientRenderModal();
@@ -273,13 +289,42 @@ const RenderButton = ({ readOnlyStudio, }) => {
273
289
  }
274
290
  setDropdownOpened(false);
275
291
  if (newType === 'server-render') {
276
- openServerRenderModal();
292
+ openServerRenderModal(false);
293
+ }
294
+ else if (newType === 'render-command') {
295
+ openServerRenderModal(true);
277
296
  }
278
297
  else {
279
298
  openClientRenderModal();
280
299
  }
281
- }, [openServerRenderModal, openClientRenderModal]);
300
+ }, [openClientRenderModal, openServerRenderModal]);
282
301
  const dropdownValues = (0, react_1.useMemo)(() => {
302
+ if (readOnlyStudio) {
303
+ return [
304
+ {
305
+ type: 'item',
306
+ id: 'client-render',
307
+ label: 'Render on web',
308
+ value: 'client-render',
309
+ onClick: () => handleRenderTypeChange('client-render'),
310
+ keyHint: null,
311
+ leftItem: null,
312
+ subMenu: null,
313
+ quickSwitcherLabel: null,
314
+ },
315
+ {
316
+ type: 'item',
317
+ id: 'render-command',
318
+ label: 'Render via CLI',
319
+ value: 'render-command',
320
+ onClick: () => handleRenderTypeChange('render-command'),
321
+ keyHint: null,
322
+ leftItem: null,
323
+ subMenu: null,
324
+ quickSwitcherLabel: null,
325
+ },
326
+ ];
327
+ }
283
328
  return [
284
329
  {
285
330
  type: 'item',
@@ -304,7 +349,7 @@ const RenderButton = ({ readOnlyStudio, }) => {
304
349
  quickSwitcherLabel: null,
305
350
  },
306
351
  ];
307
- }, [handleRenderTypeChange]);
352
+ }, [handleRenderTypeChange, readOnlyStudio]);
308
353
  const spaceToBottom = (0, react_1.useMemo)(() => {
309
354
  const margin = 10;
310
355
  if (size && dropdownOpened) {
@@ -348,13 +393,15 @@ const RenderButton = ({ readOnlyStudio, }) => {
348
393
  cursor: canRender ? 'pointer' : 'inherit',
349
394
  };
350
395
  }, [canRender]);
351
- const renderLabel = renderType === 'server-render' ? 'Render' : 'Render on web';
396
+ const renderLabel = renderType === 'server-render'
397
+ ? 'Render'
398
+ : renderType === 'render-command'
399
+ ? 'Render via CLI'
400
+ : 'Render on web';
352
401
  const shouldShowDropdown = (0, react_1.useMemo)(() => {
353
- // Server render is not available
354
402
  if (readOnlyStudio) {
355
- return false;
403
+ return show_browser_rendering_1.SHOW_BROWSER_RENDERING;
356
404
  }
357
- // client render is not available
358
405
  if (!show_browser_rendering_1.SHOW_BROWSER_RENDERING) {
359
406
  return false;
360
407
  }
@@ -364,11 +411,11 @@ const RenderButton = ({ readOnlyStudio, }) => {
364
411
  return null;
365
412
  }
366
413
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
367
- jsx_runtime_1.jsx("button", { style: { display: 'none' }, id: "render-modal-button-server", disabled: !canRender, onClick: openServerRenderModal, type: "button" }), ' ', jsx_runtime_1.jsx("button", { style: { display: 'none' }, id: "render-modal-button-client", onClick: openClientRenderModal, type: "button" }), jsx_runtime_1.jsxs("div", { ref: containerRef, style: containerStyle, title: tooltip, children: [
414
+ jsx_runtime_1.jsx("button", { style: { display: 'none' }, id: "render-modal-button-server", disabled: !canServerRender, onClick: () => openServerRenderModal(false), type: "button" }), ' ', jsx_runtime_1.jsx("button", { style: { display: 'none' }, id: "render-modal-button-client", onClick: openClientRenderModal, type: "button" }), jsx_runtime_1.jsxs("div", { ref: containerRef, style: containerStyle, title: tooltip, children: [
368
415
  jsx_runtime_1.jsx("button", { type: "button", style: mainButtonStyle, onClick: onClick, id: "render-modal-button", disabled: !canRender, children: jsx_runtime_1.jsxs(layout_1.Row, { align: "center", style: mainButtonContent, children: [
369
416
  jsx_runtime_1.jsx(render_1.ThinRenderIcon, { fill: "currentcolor", svgProps: iconStyle }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("span", { style: label, children: renderLabel })
370
417
  ] }) }), shouldShowDropdown ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
371
- jsx_runtime_1.jsx("div", { style: dividerStyle }), jsx_runtime_1.jsx("button", { ref: dropdownRef, type: "button", style: dropdownTriggerStyle, disabled: connectionStatus !== 'connected', className: is_menu_item_1.MENU_INITIATOR_CLASSNAME, onPointerDown: onPointerDown, onClick: onClickDropdown, children: jsx_runtime_1.jsx(caret_1.CaretDown, {}) })
418
+ jsx_runtime_1.jsx("div", { style: dividerStyle }), jsx_runtime_1.jsx("button", { ref: dropdownRef, type: "button", style: dropdownTriggerStyle, disabled: !readOnlyStudio && connectionStatus !== 'connected', className: is_menu_item_1.MENU_INITIATOR_CLASSNAME, onPointerDown: onPointerDown, onClick: onClickDropdown, children: jsx_runtime_1.jsx(caret_1.CaretDown, {}) })
372
419
  ] })) : null] }), portalStyle
373
420
  ? react_dom_1.default.createPortal(jsx_runtime_1.jsx("div", { style: styles_1.fullScreenOverlay, children: jsx_runtime_1.jsx("div", { style: styles_1.outerPortal, className: "css-reset", children: jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onOutsideClick: onHideDropdown, onEscape: onHideDropdown, children: jsx_runtime_1.jsx("div", { style: portalStyle, children: jsx_runtime_1.jsx(MenuContent_1.MenuContent, { onNextMenu: () => { }, onPreviousMenu: () => { }, values: dropdownValues, onHide: onHideDropdown, leaveLeftSpace: false, preselectIndex: dropdownValues.findIndex((v) => v.id === renderType), topItemCanBeUnselected: false, fixedHeight: derivedMaxHeight }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
374
421
  : null] }));
@@ -22,4 +22,5 @@ export declare const RenderModalBasic: React.FC<{
22
22
  readonly validationMessage: string | null;
23
23
  readonly setVerboseLogging: React.Dispatch<React.SetStateAction<LogLevel>>;
24
24
  readonly logLevel: LogLevel;
25
+ readonly showOutputName: boolean;
25
26
  }>;
@@ -22,7 +22,7 @@ const RenderModalOutputName_1 = require("./RenderModalOutputName");
22
22
  const container = {
23
23
  flex: 1,
24
24
  };
25
- const RenderModalBasic = ({ renderMode, imageFormatOptions, outName, codec, setVideoCodec: setCodec, proResProfile, setProResProfile, frame, setFrame, resolvedComposition, setOutName, setEndFrame, endFrame, setStartFrame, startFrame, validationMessage, setVerboseLogging, logLevel, }) => {
25
+ const RenderModalBasic = ({ renderMode, imageFormatOptions, outName, codec, setVideoCodec: setCodec, proResProfile, setProResProfile, frame, setFrame, resolvedComposition, setOutName, setEndFrame, endFrame, setStartFrame, startFrame, validationMessage, setVerboseLogging, logLevel, showOutputName, }) => {
26
26
  const existence = (0, use_file_existence_1.useFileExistence)(outName);
27
27
  const videoCodecOptions = (0, react_1.useMemo)(() => {
28
28
  return client_1.BrowserSafeApis.validCodecs
@@ -101,7 +101,7 @@ const RenderModalBasic = ({ renderMode, imageFormatOptions, outName, codec, setV
101
101
  jsx_runtime_1.jsx("div", { style: layout_2.label, children: "Frame" }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(RemInput_1.RightAlignInput, { children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { value: frame, onTextChange: onFrameChanged, placeholder: `0-${resolvedComposition.durationInFrames - 1}`, onValueChange: onFrameSetDirectly, name: "frame", step: 1, min: 0, status: "ok", max: resolvedComposition.durationInFrames - 1, rightAlign: true }) }) })
102
102
  ] })) : null, renderMode === 'video' && codec === 'prores' ? (jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
103
103
  jsx_runtime_1.jsx("div", { style: layout_2.label, children: "ProRes profile" }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(ComboBox_1.Combobox, { title: 'proResProfile', selectedId: proResProfile, values: proResProfileOptions }) })
104
- ] })) : null, renderMode === 'still' ? null : (jsx_runtime_1.jsx(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame })), jsx_runtime_1.jsx(RenderModalOutputName_1.RenderModalOutputName, { existence: existence, inputStyle: layout_2.input, outName: outName, onValueChange: onValueChange, validationMessage: validationMessage, label: renderMode === 'sequence' ? 'Folder name' : 'Output name' }), jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
104
+ ] })) : null, renderMode === 'still' ? null : (jsx_runtime_1.jsx(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame })), showOutputName ? (jsx_runtime_1.jsx(RenderModalOutputName_1.RenderModalOutputName, { existence: existence, inputStyle: layout_2.input, outName: outName, onValueChange: onValueChange, validationMessage: validationMessage, label: renderMode === 'sequence' ? 'Folder name' : 'Output name' })) : null, jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
105
105
  jsx_runtime_1.jsxs("div", { style: layout_2.label, children: ["Log Level ",
106
106
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(OptionExplainerBubble_1.OptionExplainerBubble, { id: "logLevelOption" })
107
107
  ] }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(ComboBox_1.Combobox, { values: logLevelOptions, selectedId: logLevel, title: "Log Level" }) })
@@ -41,6 +41,8 @@ const SchemaLabel = ({ jsonPath, isDefaultValue, onReset, onSave, showSaveButton
41
41
  setClickableButtonHovered(false);
42
42
  }, []);
43
43
  const labelContent = (jsx_runtime_1.jsxs("span", { style: labelStyle, children: [(0, get_schema_label_1.getSchemaLabel)(jsonPath), " ", suffix ? suffix : null] }));
44
- return (jsx_runtime_1.jsxs("div", { style: compactStyles, className: scroll_to_default_props_path_1.DEFAULT_PROPS_PATH_CLASSNAME, "data-json-path": jsonPath.join('.'), children: [handleClick ? (jsx_runtime_1.jsx("button", { onPointerEnter: onClickablePointerEnter, onPointerLeave: onClickablePointerLeave, type: "button", onClick: handleClick, style: { border: 'none', padding: 0 }, children: labelContent })) : (labelContent), jsx_runtime_1.jsx(layout_1.Flex, {}), isDefaultValue ? null : jsx_runtime_1.jsx(SchemaResetButton_1.SchemaResetButton, { onClick: onReset }), isDefaultValue ? null : showSaveButton ? (jsx_runtime_1.jsx(SchemaSaveButton_1.SchemaSaveButton, { onClick: onSave, disabled: disableSave })) : null, onRemove ? jsx_runtime_1.jsx(InlineRemoveButton_1.InlineRemoveButton, { onClick: onRemove }) : null] }));
44
+ return (jsx_runtime_1.jsxs("div", { style: compactStyles, className: scroll_to_default_props_path_1.DEFAULT_PROPS_PATH_CLASSNAME, "data-json-path": jsonPath.join('.'), children: [handleClick ? (
45
+ // Minus the padding that a button has (user agent padding-line-start)
46
+ jsx_runtime_1.jsx("button", { onPointerEnter: onClickablePointerEnter, onPointerLeave: onClickablePointerLeave, type: "button", onClick: handleClick, style: { border: 'none', padding: 0 }, children: labelContent })) : (labelContent), jsx_runtime_1.jsx(layout_1.Flex, {}), isDefaultValue ? null : jsx_runtime_1.jsx(SchemaResetButton_1.SchemaResetButton, { onClick: onReset }), isDefaultValue ? null : showSaveButton ? (jsx_runtime_1.jsx(SchemaSaveButton_1.SchemaSaveButton, { onClick: onSave, disabled: disableSave })) : null, onRemove ? jsx_runtime_1.jsx(InlineRemoveButton_1.InlineRemoveButton, { onClick: onRemove }) : null] }));
45
47
  };
46
48
  exports.SchemaLabel = SchemaLabel;
@@ -75,7 +75,9 @@ const ZodArrayEditor = ({ schema, jsonPath, setValue, defaultValue, value, onSav
75
75
  onSave(() => localValue.value, false, false);
76
76
  }, saveDisabledByParent: saveDisabledByParent, saving: saving, showSaveButton: showSaveButton, valid: localValue.zodValidation.success, handleClick: () => setExpanded(!expanded) }) }), expanded ? (jsx_runtime_1.jsx(RevisionContextProvider, { children: jsx_runtime_1.jsxs(SchemaVerticalGuide_1.SchemaVerticalGuide, { isRoot: false, children: [localValue.value.map((child, i) => {
77
77
  var _a;
78
- return (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [
78
+ return (
79
+ // eslint-disable-next-line react/no-array-index-key
80
+ jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [
79
81
  jsx_runtime_1.jsx(ZodArrayItemEditor_1.ZodArrayItemEditor, { onChange: onChange, value: child, elementSchema: arrayElement, index: i, jsonPath: jsonPath, defaultValue: (_a = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue[i]) !== null && _a !== void 0 ? _a : (0, create_zod_values_1.createZodValues)(arrayElement, z, zodTypes), onSave: onSave, showSaveButton: showSaveButton, saving: saving, saveDisabledByParent: saveDisabledByParent, mayPad: mayPad, mayRemove: true }), jsx_runtime_1.jsx(SchemaSeparationLine_1.SchemaArrayItemSeparationLine, { schema: schema, index: i, onChange: onChange, isLast: i === localValue.value.length - 1, showAddButton: true })
80
82
  ] }, `${i}${localValue.keyStabilityRevision}`));
81
83
  }), value.length === 0 ? (jsx_runtime_1.jsx(SchemaSeparationLine_1.SchemaArrayItemSeparationLine, { schema: schema, index: 0, onChange: onChange, isLast: true, showAddButton: true })) : null] }) })) : null, jsx_runtime_1.jsx(ZodFieldValidation_1.ZodFieldValidation, { path: jsonPath, localValue: localValue })
@@ -23,7 +23,9 @@ const ZodFieldValidation = ({ localValue, path }) => {
23
23
  }
24
24
  return (jsx_runtime_1.jsxs("div", { style: legend, children: [
25
25
  jsx_runtime_1.jsx(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: zodValidation.error.format()._errors[0], type: "error" }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(InfoBubble_1.InfoBubble, { title: "Zod validation failure", children: jsx_runtime_1.jsxs("div", { style: stackTrace, children: [
26
- jsx_runtime_1.jsx("div", { style: stackTraceLabel, children: "Zod Validation has failed:" }), zodValidation.error.issues.map((error, index) => (jsx_runtime_1.jsxs("div", { style: stackTraceLabel, children: ["Type: ", error.code, " ",
26
+ jsx_runtime_1.jsx("div", { style: stackTraceLabel, children: "Zod Validation has failed:" }), zodValidation.error.issues.map((error, index) => (
27
+ // eslint-disable-next-line react/no-array-index-key
28
+ jsx_runtime_1.jsxs("div", { style: stackTraceLabel, children: ["Type: ", error.code, " ",
27
29
  jsx_runtime_1.jsx("br", {}),
28
30
  "Message: ", error.message, jsx_runtime_1.jsx("br", {}),
29
31
  "Path: ", path.join('.')] }, index)))] }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 })
@@ -75,7 +75,9 @@ const ZodTupleEditor = ({ schema, jsonPath, setValue, defaultValue, value, onSav
75
75
  onSave(() => localValue.value, false, false);
76
76
  }, saveDisabledByParent: saveDisabledByParent, saving: saving, showSaveButton: showSaveButton, valid: localValue.zodValidation.success, handleClick: () => setExpanded(!expanded) }) }), expanded ? (jsx_runtime_1.jsx(RevisionContextProvider, { children: jsx_runtime_1.jsxs(SchemaVerticalGuide_1.SchemaVerticalGuide, { isRoot: false, children: [localValue.value.map((child, i) => {
77
77
  var _a;
78
- return (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [
78
+ return (
79
+ // eslint-disable-next-line react/no-array-index-key
80
+ jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [
79
81
  jsx_runtime_1.jsx(ZodTupleItemEditor_1.ZodTupleItemEditor, { onChange: onChange, value: child, tupleItems: tupleItems, index: i, jsonPath: jsonPath, defaultValue: (_a = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue[i]) !== null && _a !== void 0 ? _a : (0, create_zod_values_1.createZodValues)(tupleItems[i], z, zodTypes), onSave: onSave, showSaveButton: showSaveButton, saving: saving, saveDisabledByParent: saveDisabledByParent, mayPad: mayPad }), jsx_runtime_1.jsx(SchemaSeparationLine_1.SchemaArrayItemSeparationLine, { schema: schema, index: i, onChange: onChange, isLast: i === localValue.value.length - 1, showAddButton: false })
80
82
  ] }, `${i}${localValue.keyStabilityRevision}`));
81
83
  }), value.length === 0 ? (jsx_runtime_1.jsx(SchemaSeparationLine_1.SchemaArrayItemSeparationLine, { schema: schema, index: 0, onChange: onChange, isLast: true, showAddButton: false })) : null] }) })) : null, jsx_runtime_1.jsx(ZodFieldValidation_1.ZodFieldValidation, { path: jsonPath, localValue: localValue })