@remotion/studio 4.0.433 → 4.0.435

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 (34) hide show
  1. package/dist/components/CompositionSelector.js +36 -2
  2. package/dist/components/CompositionSelectorItem.js +1 -0
  3. package/dist/components/CurrentComposition.d.ts +1 -1
  4. package/dist/components/CurrentComposition.js +2 -3
  5. package/dist/components/CurrentCompositionSideEffects.js +2 -4
  6. package/dist/components/Modals.js +3 -2
  7. package/dist/components/PreviewToolbar.js +1 -2
  8. package/dist/components/RenderButton.d.ts +1 -1
  9. package/dist/components/RenderButton.js +64 -17
  10. package/dist/components/RenderModal/ClientRenderProgress.js +13 -9
  11. package/dist/components/RenderModal/RenderModalBasic.d.ts +1 -0
  12. package/dist/components/RenderModal/RenderModalBasic.js +2 -2
  13. package/dist/components/RenderModal/ServerRenderModal.d.ts +1 -0
  14. package/dist/components/RenderModal/ServerRenderModal.js +170 -5
  15. package/dist/components/RenderModal/WebRenderModalAudio.js +3 -2
  16. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +3 -0
  17. package/dist/components/RenderQueue/RenderQueueItemStatus.js +1 -2
  18. package/dist/components/RenderQueue/RenderQueueProgressMessage.js +2 -3
  19. package/dist/components/RenderQueue/client-render-progress.d.ts +3 -0
  20. package/dist/components/RenderQueue/client-render-progress.js +31 -0
  21. package/dist/components/RenderQueue/client-side-render-types.d.ts +3 -0
  22. package/dist/components/RenderQueue/context.js +7 -1
  23. package/dist/components/SidebarRenderButton.js +1 -0
  24. package/dist/esm/{chunk-bd1bkakk.js → chunk-x88z6n54.js} +1063 -535
  25. package/dist/esm/internals.mjs +1063 -535
  26. package/dist/esm/previewEntry.mjs +634 -106
  27. package/dist/esm/renderEntry.mjs +1 -1
  28. package/dist/helpers/make-render-command.d.ts +51 -0
  29. package/dist/helpers/make-render-command.js +201 -0
  30. package/dist/helpers/retry-payload.js +3 -0
  31. package/dist/state/modals.d.ts +1 -0
  32. package/package.json +9 -9
  33. package/dist/helpers/should-show-render-button.d.ts +0 -1
  34. package/dist/helpers/should-show-render-button.js +0 -11
@@ -4,10 +4,13 @@ exports.CompositionSelector = exports.getKeysToExpand = exports.useCompositionNa
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
+ const ShortcutHint_1 = require("../error-overlay/remotion-overlay/ShortcutHint");
7
8
  const colors_1 = require("../helpers/colors");
8
9
  const create_folder_tree_1 = require("../helpers/create-folder-tree");
9
10
  const persist_open_folders_1 = require("../helpers/persist-open-folders");
10
11
  const sort_by_nonce_history_1 = require("../helpers/sort-by-nonce-history");
12
+ const use_keybinding_1 = require("../helpers/use-keybinding");
13
+ const modals_1 = require("../state/modals");
11
14
  const z_index_1 = require("../state/z-index");
12
15
  const CompositionSelectorItem_1 = require("./CompositionSelectorItem");
13
16
  const CurrentComposition_1 = require("./CurrentComposition");
@@ -56,6 +59,29 @@ const container = {
56
59
  overflow: 'hidden',
57
60
  backgroundColor: colors_1.BACKGROUND,
58
61
  };
62
+ const QUICK_SWITCHER_TRIGGER_HEIGHT = 38;
63
+ const quickSwitcherArea = {
64
+ padding: '4px 12px',
65
+ borderBottom: `1px solid ${colors_1.BORDER_COLOR}`,
66
+ };
67
+ const quickSwitcherTrigger = {
68
+ backgroundColor: 'rgba(255, 255, 255, 0.06)',
69
+ borderRadius: 5,
70
+ padding: '4px 10px',
71
+ color: colors_1.LIGHT_TEXT,
72
+ fontSize: 12,
73
+ cursor: 'pointer',
74
+ display: 'flex',
75
+ alignItems: 'center',
76
+ justifyContent: 'space-between',
77
+ border: 'none',
78
+ width: '100%',
79
+ appearance: 'none',
80
+ };
81
+ const shortcutLabel = {
82
+ fontSize: 11,
83
+ opacity: 0.6,
84
+ };
59
85
  const getKeysToExpand = (initialFolderName, parentFolderName, initial = []) => {
60
86
  initial.push((0, persist_open_folders_1.openFolderKey)({
61
87
  folderName: initialFolderName,
@@ -71,6 +97,7 @@ exports.getKeysToExpand = getKeysToExpand;
71
97
  const CompositionSelector = () => {
72
98
  const { compositions, canvasContent, folders } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
73
99
  const { foldersExpanded } = (0, react_1.useContext)(persist_open_folders_1.ExpandedFoldersContext);
100
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
74
101
  const { tabIndex } = (0, z_index_1.useZIndex)();
75
102
  const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
76
103
  const sortedCompositions = (0, react_1.useMemo)(() => {
@@ -84,7 +111,7 @@ const CompositionSelector = () => {
84
111
  }, [sortedCompositions, sortedFolders, foldersExpanded]);
85
112
  const list = (0, react_1.useMemo)(() => {
86
113
  return {
87
- height: `calc(100% - ${CurrentComposition_1.CURRENT_COMPOSITION_HEIGHT}px)`,
114
+ height: `calc(100% - ${CurrentComposition_1.CURRENT_COMPOSITION_HEIGHT}px - ${QUICK_SWITCHER_TRIGGER_HEIGHT}px)`,
88
115
  overflowY: 'auto',
89
116
  };
90
117
  }, []);
@@ -92,8 +119,15 @@ const CompositionSelector = () => {
92
119
  var _a;
93
120
  (_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.toggleFolder(folderName, parentName);
94
121
  }, []);
122
+ const openQuickSwitcher = (0, react_1.useCallback)(() => {
123
+ setSelectedModal({
124
+ type: 'quick-switcher',
125
+ mode: 'compositions',
126
+ invocationTimestamp: Date.now(),
127
+ });
128
+ }, [setSelectedModal]);
95
129
  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) => {
130
+ jsx_runtime_1.jsx(CurrentComposition_1.CurrentComposition, {}), jsx_runtime_1.jsx("div", { style: quickSwitcherArea, children: jsx_runtime_1.jsxs("button", { type: "button", style: quickSwitcherTrigger, onClick: openQuickSwitcher, tabIndex: tabIndex, children: ["Search...", (0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? null : (jsx_runtime_1.jsxs("span", { style: shortcutLabel, children: [ShortcutHint_1.cmdOrCtrlCharacter, "+K"] }))] }) }), jsx_runtime_1.jsx("div", { className: "__remotion-vertical-scrollbar", style: list, children: items.map((c) => {
97
131
  return (jsx_runtime_1.jsx(CompositionSelectorItem_1.CompositionSelectorItem, { level: 0, currentComposition: canvasContent && canvasContent.type === 'composition'
98
132
  ? canvasContent.compositionId
99
133
  : null, selectComposition: selectComposition, toggleFolder: toggleFolder, tabIndex: tabIndex, item: c }, c.key + c.type));
@@ -31,6 +31,7 @@ const itemStyle = {
31
31
  textAlign: 'left',
32
32
  backgroundColor: colors_1.BACKGROUND,
33
33
  height: COMPOSITION_ITEM_HEIGHT,
34
+ userSelect: 'none',
34
35
  };
35
36
  const labelStyle = {
36
37
  textAlign: 'left',
@@ -1,2 +1,2 @@
1
- export declare const CURRENT_COMPOSITION_HEIGHT = 80;
1
+ export declare const CURRENT_COMPOSITION_HEIGHT = 64;
2
2
  export declare const CurrentComposition: () => import("react/jsx-runtime").JSX.Element;
@@ -6,12 +6,11 @@ const remotion_1 = require("remotion");
6
6
  const colors_1 = require("../helpers/colors");
7
7
  const is_composition_still_1 = require("../helpers/is-composition-still");
8
8
  const render_frame_1 = require("../state/render-frame");
9
- exports.CURRENT_COMPOSITION_HEIGHT = 80;
9
+ exports.CURRENT_COMPOSITION_HEIGHT = 64;
10
10
  const container = {
11
11
  height: exports.CURRENT_COMPOSITION_HEIGHT,
12
12
  display: 'block',
13
- borderBottom: `1px solid ${colors_1.BORDER_COLOR}`,
14
- padding: 12,
13
+ padding: '6px 12px',
15
14
  color: 'white',
16
15
  backgroundColor: colors_1.BACKGROUND,
17
16
  };
@@ -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
  }
@@ -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;
@@ -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");
@@ -144,7 +143,7 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
144
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 })
145
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: [
146
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: [
147
- 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 })
148
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 })
149
148
  ] }));
150
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] }));
@@ -6,6 +6,7 @@ const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const colors_1 = require("../../helpers/colors");
7
7
  const layout_1 = require("../layout");
8
8
  const CircularProgress_1 = require("../RenderQueue/CircularProgress");
9
+ const client_render_progress_1 = require("../RenderQueue/client-render-progress");
9
10
  const SuccessIcon_1 = require("../RenderQueue/SuccessIcon");
10
11
  const progressItem = {
11
12
  padding: 10,
@@ -24,13 +25,16 @@ const right = {
24
25
  textAlign: 'right',
25
26
  flex: 1,
26
27
  };
27
- const EncodingProgress = ({ encodedFrames, totalFrames }) => {
28
- const done = encodedFrames === totalFrames;
29
- const progress = totalFrames > 0 ? encodedFrames / totalFrames : 0;
30
- return (jsx_runtime_1.jsxs("div", { style: progressItem, children: [done ? jsx_runtime_1.jsx(SuccessIcon_1.SuccessIcon, {}) : jsx_runtime_1.jsx(CircularProgress_1.CircularProgress, { progress: progress }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: label, children: done
31
- ? `Encoded ${totalFrames} frames`
32
- : `Encoding ${encodedFrames} / ${totalFrames} frames` })
33
- ] }));
28
+ const ProgressStatus = ({ encodedFrames, totalFrames, doneIn, renderEstimatedTime, progress }) => {
29
+ const done = doneIn !== null;
30
+ const message = (0, client_render_progress_1.getClientRenderProgressMessage)({
31
+ encodedFrames,
32
+ totalFrames,
33
+ doneIn,
34
+ renderEstimatedTime,
35
+ progress,
36
+ });
37
+ return (jsx_runtime_1.jsxs("div", { style: progressItem, children: [done ? jsx_runtime_1.jsx(SuccessIcon_1.SuccessIcon, {}) : jsx_runtime_1.jsx(CircularProgress_1.CircularProgress, { progress: progress }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: label, children: message }), doneIn !== null ? jsx_runtime_1.jsxs("div", { style: right, children: [doneIn, "ms"] }) : null] }));
34
38
  };
35
39
  const DoneStatus = ({ job }) => {
36
40
  return (jsx_runtime_1.jsxs("div", { style: progressItem, children: [
@@ -53,9 +57,9 @@ const ClientRenderProgress = ({ job }) => {
53
57
  jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5 }), jsx_runtime_1.jsx("div", { style: label, children: "Saving to out/..." }), jsx_runtime_1.jsx(layout_1.Spacing, { y: 1 })
54
58
  ] }));
55
59
  }
56
- const { encodedFrames, totalFrames } = job.progress;
60
+ const { encodedFrames, totalFrames, doneIn, renderEstimatedTime, progress } = job.progress;
57
61
  return (jsx_runtime_1.jsxs("div", { children: [
58
- jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5 }), job.type === 'client-video' && (jsx_runtime_1.jsx(EncodingProgress, { encodedFrames: encodedFrames, totalFrames: totalFrames })), jsx_runtime_1.jsx(layout_1.Spacing, { y: 1 })
62
+ jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5 }), job.type === 'client-video' && (jsx_runtime_1.jsx(ProgressStatus, { encodedFrames: encodedFrames, totalFrames: totalFrames, doneIn: doneIn, renderEstimatedTime: renderEstimatedTime, progress: progress })), jsx_runtime_1.jsx(layout_1.Spacing, { y: 1 })
59
63
  ] }));
60
64
  };
61
65
  exports.ClientRenderProgress = ClientRenderProgress;
@@ -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" }) })
@@ -5,6 +5,7 @@ import React from 'react';
5
5
  import type { _InternalTypes } from 'remotion';
6
6
  import type { RenderType } from './RenderModalAdvanced';
7
7
  type RenderModalProps = {
8
+ readonly readOnlyStudio: boolean;
8
9
  readonly compositionId: string;
9
10
  readonly initialFrame: number;
10
11
  readonly initialVideoImageFormat: VideoImageFormat | null;