@remotion/studio 4.0.431 → 4.0.433

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 (62) hide show
  1. package/dist/Studio.d.ts +1 -0
  2. package/dist/Studio.js +4 -6
  3. package/dist/components/AssetSelectorItem.js +6 -8
  4. package/dist/components/CompositionSelector.js +16 -9
  5. package/dist/components/CurrentComposition.js +2 -5
  6. package/dist/components/EditorContent.js +4 -5
  7. package/dist/components/NewComposition/InputDragger.d.ts +1 -0
  8. package/dist/components/NewComposition/InputDragger.js +27 -8
  9. package/dist/components/OptionsPanel.js +1 -1
  10. package/dist/components/PlaybackRatePersistor.js +1 -1
  11. package/dist/components/PreviewToolbar.js +4 -2
  12. package/dist/components/RenderModal/WebRenderModal.d.ts +1 -1
  13. package/dist/components/RenderModal/WebRenderModal.js +55 -26
  14. package/dist/components/RenderModal/WebRenderModalAudio.d.ts +2 -0
  15. package/dist/components/RenderModal/WebRenderModalAudio.js +13 -5
  16. package/dist/components/RenderModal/WebRenderModalBasic.js +42 -35
  17. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +3 -3
  18. package/dist/components/RenderQueue/client-side-render-types.d.ts +1 -1
  19. package/dist/components/RendersTab.js +1 -9
  20. package/dist/components/Timeline/TimelineBooleanField.d.ts +9 -0
  21. package/dist/components/Timeline/TimelineBooleanField.js +20 -0
  22. package/dist/components/Timeline/TimelineEmptyState.d.ts +2 -0
  23. package/dist/components/Timeline/TimelineEmptyState.js +15 -0
  24. package/dist/components/Timeline/TimelineExpandedSection.d.ts +5 -0
  25. package/dist/components/Timeline/TimelineExpandedSection.js +54 -152
  26. package/dist/components/Timeline/TimelineFieldRow.d.ts +11 -0
  27. package/dist/components/Timeline/TimelineFieldRow.js +83 -0
  28. package/dist/components/Timeline/TimelineListItem.d.ts +1 -0
  29. package/dist/components/Timeline/TimelineListItem.js +12 -23
  30. package/dist/components/Timeline/TimelineNumberField.d.ts +11 -0
  31. package/dist/components/Timeline/TimelineNumberField.js +53 -0
  32. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +1 -1
  33. package/dist/components/Timeline/TimelineRotationField.d.ts +11 -0
  34. package/dist/components/Timeline/TimelineRotationField.js +64 -0
  35. package/dist/components/Timeline/TimelineSchemaField.d.ts +3 -4
  36. package/dist/components/Timeline/TimelineSchemaField.js +20 -77
  37. package/dist/components/Timeline/TimelineTranslateField.d.ts +11 -0
  38. package/dist/components/Timeline/TimelineTranslateField.js +115 -0
  39. package/dist/components/Timeline/timeline-field-utils.d.ts +2 -0
  40. package/dist/components/Timeline/timeline-field-utils.js +12 -0
  41. package/dist/components/Timeline/use-resolved-stack.d.ts +2 -0
  42. package/dist/components/Timeline/use-resolved-stack.js +54 -0
  43. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +4 -0
  44. package/dist/components/Timeline/use-sequence-props-subscription.js +150 -0
  45. package/dist/error-overlay/react-overlay/utils/get-source-map.d.ts +5 -0
  46. package/dist/esm/{chunk-3msfwcwh.js → chunk-bd1bkakk.js} +3001 -2433
  47. package/dist/esm/internals.mjs +3001 -2433
  48. package/dist/esm/previewEntry.mjs +3011 -2442
  49. package/dist/esm/renderEntry.mjs +5 -4
  50. package/dist/helpers/calculate-timeline.js +17 -11
  51. package/dist/helpers/get-timeline-sequence-layout.js +3 -3
  52. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +1 -1
  53. package/dist/helpers/get-timeline-sequence-sort-key.js +6 -3
  54. package/dist/helpers/inject-css.js +6 -1
  55. package/dist/helpers/sort-by-nonce-history.d.ts +5 -0
  56. package/dist/helpers/sort-by-nonce-history.js +73 -0
  57. package/dist/helpers/timeline-layout.d.ts +2 -2
  58. package/dist/helpers/timeline-layout.js +10 -4
  59. package/dist/internals.d.ts +1 -0
  60. package/dist/previewEntry.js +1 -1
  61. package/dist/renderEntry.js +3 -3
  62. package/package.json +10 -10
package/dist/Studio.d.ts CHANGED
@@ -2,4 +2,5 @@ import React from 'react';
2
2
  export declare const Studio: React.FC<{
3
3
  readonly rootComponent: React.FC;
4
4
  readonly readOnly: boolean;
5
+ readonly visualModeEnabled: boolean;
5
6
  }>;
package/dist/Studio.js CHANGED
@@ -9,25 +9,23 @@ 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");
16
15
  const getServerDisconnectedDomElement = () => {
17
16
  return document.getElementById('server-disconnected-overlay');
18
17
  };
19
- const StudioInner = ({ rootComponent, readOnly }) => {
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, { 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())] }) }) }) }) }));
26
24
  };
27
- const Studio = ({ rootComponent, readOnly }) => {
25
+ const Studio = ({ rootComponent, readOnly, visualModeEnabled }) => {
28
26
  (0, react_1.useLayoutEffect)(() => {
29
27
  (0, inject_css_1.injectCSS)();
30
28
  }, []);
31
- return (jsx_runtime_1.jsx(FastRefreshProvider_1.FastRefreshProvider, { children: jsx_runtime_1.jsx(StudioInner, { rootComponent: rootComponent, readOnly: readOnly }) }));
29
+ return (jsx_runtime_1.jsx(FastRefreshProvider_1.FastRefreshProvider, { children: jsx_runtime_1.jsx(StudioInner, { rootComponent: rootComponent, readOnly: readOnly, visualModeEnabled: visualModeEnabled }) }));
32
30
  };
33
31
  exports.Studio = Studio;
@@ -161,20 +161,19 @@ const AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio
161
161
  }, []);
162
162
  const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
163
163
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
164
+ const relativePath = (0, react_1.useMemo)(() => {
165
+ return parentFolder ? parentFolder + '/' + item.name : item.name;
166
+ }, [parentFolder, item.name]);
164
167
  const selected = (0, react_1.useMemo)(() => {
165
168
  if (canvasContent && canvasContent.type === 'asset') {
166
- const nameWOParent = canvasContent.asset.split('/').pop();
167
- return nameWOParent === item.name;
169
+ return canvasContent.asset === relativePath;
168
170
  }
169
171
  return false;
170
- }, [canvasContent, item.name]);
172
+ }, [canvasContent, relativePath]);
171
173
  const onPointerLeave = (0, react_1.useCallback)(() => {
172
174
  setHovered(false);
173
175
  }, []);
174
176
  const onClick = (0, react_1.useCallback)(() => {
175
- const relativePath = parentFolder
176
- ? parentFolder + '/' + item.name
177
- : item.name;
178
177
  setCanvasContent({ type: 'asset', asset: relativePath });
179
178
  (0, url_state_1.pushUrl)(`/assets/${relativePath}`);
180
179
  if (isMobileLayout) {
@@ -182,8 +181,7 @@ const AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio
182
181
  }
183
182
  }, [
184
183
  isMobileLayout,
185
- item.name,
186
- parentFolder,
184
+ relativePath,
187
185
  setCanvasContent,
188
186
  setSidebarCollapsedState,
189
187
  ]);
@@ -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;
@@ -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;
@@ -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]);
@@ -25,6 +25,7 @@ const RenderButton_1 = require("./RenderButton");
25
25
  const SizeSelector_1 = require("./SizeSelector");
26
26
  const TimelineZoomControls_1 = require("./Timeline/TimelineZoomControls");
27
27
  const TimelineInOutToggle_1 = require("./TimelineInOutToggle");
28
+ const TOOLBAR_HEIGHT = 56;
28
29
  const container = {
29
30
  display: 'flex',
30
31
  justifyContent: 'center',
@@ -34,6 +35,7 @@ const container = {
34
35
  alignItems: 'center',
35
36
  flexDirection: 'row',
36
37
  background: colors_1.BACKGROUND,
38
+ height: TOOLBAR_HEIGHT,
37
39
  };
38
40
  const mobileContainer = {
39
41
  ...container,
@@ -72,7 +74,7 @@ const padding = {
72
74
  width: timeline_layout_1.TIMELINE_PADDING,
73
75
  };
74
76
  const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
75
- const { playbackRate, setPlaybackRate } = (0, react_1.useContext)(remotion_1.Internals.TimelineContext);
77
+ const { playbackRate, setPlaybackRate } = remotion_1.Internals.useTimelineContext();
76
78
  const { mediaMuted } = (0, react_1.useContext)(remotion_1.Internals.MediaVolumeContext);
77
79
  const { setMediaMuted } = (0, react_1.useContext)(remotion_1.Internals.SetMediaVolumeContext);
78
80
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
@@ -140,7 +142,7 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
140
142
  jsx_runtime_1.jsx("div", { style: padding }), jsx_runtime_1.jsx(TimelineZoomControls_1.TimelineZoomControls, {})
141
143
  ] }), 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
144
  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: [
145
+ ] })) : 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
146
  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
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
148
  ] }), 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 })
@@ -1,3 +1,3 @@
1
1
  import type { WebRenderModalState } from '../../state/modals';
2
- export type RenderType = 'still' | 'video';
2
+ export type RenderType = 'still' | 'video' | 'audio';
3
3
  export declare const WebRenderModalWithLoader: React.FC<WebRenderModalState>;
@@ -77,7 +77,6 @@ const validateOutnameForStill = ({ outName, stillImageFormat, }) => {
77
77
  };
78
78
  // TODO: Switch to server-side rendering
79
79
  // TODO: Filter out codecs that are not supported for the container
80
- // TODO: Add more containers
81
80
  // TODO: Shortcut: Shift + R
82
81
  // TODO: Apply defaultCodec
83
82
  // TODO: Apply defaultOutName
@@ -96,7 +95,11 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
96
95
  ? true
97
96
  : resolvedComposition.durationInFrames > 1;
98
97
  });
99
- const [renderMode, setRenderMode] = (0, react_1.useState)(isVideo ? 'video' : 'still');
98
+ const [renderMode, setRenderMode] = (0, react_1.useState)(initialContainer && (0, web_renderer_1.isAudioOnlyContainer)(initialContainer)
99
+ ? 'audio'
100
+ : isVideo
101
+ ? 'video'
102
+ : 'still');
100
103
  const [tab, setTab] = (0, react_1.useState)('general');
101
104
  const [imageFormat, setImageFormat] = (0, react_1.useState)(() => initialStillImageFormat !== null && initialStillImageFormat !== void 0 ? initialStillImageFormat : 'png');
102
105
  const [frame, setFrame] = (0, react_1.useState)(() => initialFrame);
@@ -170,36 +173,52 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
170
173
  return defaultOut;
171
174
  });
172
175
  const [outName, setOutName] = (0, react_1.useState)(() => initialOutNameState);
176
+ const updateOutNameExtension = (0, react_1.useCallback)((extension) => {
177
+ setOutName((prev) => (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + extension);
178
+ }, []);
173
179
  const setStillFormat = (0, react_1.useCallback)((format) => {
174
180
  setImageFormat(format);
175
- setOutName((prev) => {
176
- const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + format;
177
- return newFileName;
178
- });
179
- }, []);
181
+ updateOutNameExtension(format);
182
+ }, [updateOutNameExtension]);
180
183
  const setContainerFormat = (0, react_1.useCallback)((newContainer) => {
184
+ setContainer(newContainer);
185
+ const defaultVideoCodec = (0, web_renderer_1.getDefaultVideoCodecForContainer)(newContainer);
186
+ if (defaultVideoCodec) {
187
+ setCodec(defaultVideoCodec);
188
+ }
189
+ setAudioCodec((0, web_renderer_1.getDefaultAudioCodecForContainer)(newContainer));
190
+ updateOutNameExtension(newContainer);
191
+ }, [updateOutNameExtension]);
192
+ const setCodecWithContainer = (0, react_1.useCallback)((newCodec) => {
193
+ setCodec(newCodec);
194
+ const newContainer = (0, web_renderer_1.getDefaultContainerForCodec)(newCodec);
181
195
  setContainer(newContainer);
182
196
  setAudioCodec((0, web_renderer_1.getDefaultAudioCodecForContainer)(newContainer));
183
- setOutName((prev) => {
184
- const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + newContainer;
185
- return newFileName;
186
- });
187
- }, []);
197
+ updateOutNameExtension(newContainer);
198
+ }, [updateOutNameExtension]);
188
199
  const onRenderModeChange = (0, react_1.useCallback)((newMode) => {
189
200
  setRenderMode(newMode);
190
201
  if (newMode === 'video') {
191
- setOutName((prev) => {
192
- const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + container;
193
- return newFileName;
194
- });
202
+ const newContainer = (0, web_renderer_1.isAudioOnlyContainer)(container)
203
+ ? 'mp4'
204
+ : container;
205
+ setContainer(newContainer);
206
+ setAudioCodec((0, web_renderer_1.getDefaultAudioCodecForContainer)(newContainer));
207
+ updateOutNameExtension(newContainer);
208
+ }
209
+ else if (newMode === 'audio') {
210
+ const newContainer = 'wav';
211
+ setContainer(newContainer);
212
+ setMuted(false);
213
+ setAudioCodec((0, web_renderer_1.getDefaultAudioCodecForContainer)(newContainer));
214
+ updateOutNameExtension(newContainer);
215
+ setTab((prev) => (prev === 'picture' ? 'general' : prev));
195
216
  }
196
217
  else if (newMode === 'still') {
197
- setOutName((prev) => {
198
- const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + imageFormat;
199
- return newFileName;
200
- });
218
+ updateOutNameExtension(imageFormat);
219
+ setTab((prev) => (prev === 'audio' ? 'general' : prev));
201
220
  }
202
- }, [container, imageFormat]);
221
+ }, [container, imageFormat, updateOutNameExtension]);
203
222
  const renderTabOptions = (0, react_1.useMemo)(() => {
204
223
  const options = [
205
224
  {
@@ -211,7 +230,7 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
211
230
  selected: renderMode === 'still',
212
231
  },
213
232
  ];
214
- // Only show video option if composition has more than 1 frame
233
+ // Only show video/audio options if composition has more than 1 frame
215
234
  if (resolvedComposition.durationInFrames > 1) {
216
235
  options.push({
217
236
  label: 'Video',
@@ -221,6 +240,14 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
221
240
  key: 'video',
222
241
  selected: renderMode === 'video',
223
242
  });
243
+ options.push({
244
+ label: 'Audio',
245
+ onClick: () => {
246
+ onRenderModeChange('audio');
247
+ },
248
+ key: 'audio',
249
+ selected: renderMode === 'audio',
250
+ });
224
251
  }
225
252
  return options;
226
253
  }, [renderMode, resolvedComposition.durationInFrames, onRenderModeChange]);
@@ -315,7 +342,9 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
315
342
  compositionId: resolvedComposition.id,
316
343
  outName,
317
344
  container,
318
- videoCodec: effectiveVideoCodec,
345
+ videoCodec: (0, web_renderer_1.isAudioOnlyContainer)(container)
346
+ ? null
347
+ : effectiveVideoCodec,
319
348
  audioCodec: effectiveAudioCodec,
320
349
  startFrame: finalStartFrame,
321
350
  endFrame: finalEndFrame,
@@ -382,16 +411,16 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
382
411
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(file_1.FileIcon, { style: render_modals_1.icon }) }),
383
412
  "General"] }), jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [
384
413
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(data_1.DataIcon, { style: render_modals_1.icon }) }),
385
- "Input Props"] }), jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [
414
+ "Input Props"] }), renderMode !== 'audio' ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [
386
415
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(frame_1.PicIcon, { style: render_modals_1.icon }) }),
387
- "Picture"] }), renderMode === 'video' ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [
416
+ "Picture"] })) : null, renderMode === 'video' || renderMode === 'audio' ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [
388
417
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(audio_1.AudioIcon, { style: render_modals_1.icon }) }),
389
418
  "Audio"] })) : null, jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [
390
419
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(gear_1.GearIcon, { style: render_modals_1.icon }) }),
391
420
  "Other"] }), jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'license', onClick: () => setTab('license'), children: [
392
421
  jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(certificate_1.CertificateIcon, { style: render_modals_1.icon }) }),
393
422
  "License"] })
394
- ] }), jsx_runtime_1.jsx("div", { style: render_modals_1.optionsPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? (jsx_runtime_1.jsx(WebRenderModalBasic_1.WebRenderModalBasic, { renderMode: renderMode, resolvedComposition: resolvedComposition, imageFormat: imageFormat, setStillFormat: setStillFormat, frame: frame, onFrameChanged: onFrameChanged, onFrameSetDirectly: onFrameSetDirectly, container: container, setContainerFormat: setContainerFormat, setCodec: setCodec, encodableVideoCodecs: encodableVideoCodecs, effectiveVideoCodec: effectiveVideoCodec, startFrame: finalStartFrame, setStartFrame: setStartFrame, endFrame: finalEndFrame, setEndFrame: setEndFrame, outName: outName, onOutNameChange: onOutNameChange, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message, logLevel: logLevel, setLogLevel: setLogLevel })) : tab === 'data' ? (jsx_runtime_1.jsx(DataEditor_1.DataEditor, { defaultProps: inputProps, setDefaultProps: setInputProps, unresolvedComposition: unresolvedComposition, mayShowSaveButton: false, propsEditType: "input-props", saving: saving, setSaving: setSaving, readOnlyStudio: false })) : tab === 'picture' ? (jsx_runtime_1.jsx(WebRenderModalPicture_1.WebRenderModalPicture, { renderMode: renderMode, videoBitrate: videoBitrate, setVideoBitrate: setVideoBitrate, keyframeIntervalInSeconds: keyframeIntervalInSeconds, setKeyframeIntervalInSeconds: setKeyframeIntervalInSeconds, transparent: transparent, setTransparent: setTransparent, scale: scale, setScale: setScale, compositionWidth: resolvedComposition.width, compositionHeight: resolvedComposition.height })) : tab === 'audio' ? (jsx_runtime_1.jsx(WebRenderModalAudio_1.WebRenderModalAudio, { muted: muted, setMuted: setMuted, audioCodec: audioCodec, setAudioCodec: setAudioCodec, audioBitrate: audioBitrate, setAudioBitrate: setAudioBitrate, container: container, encodableCodecs: encodableAudioCodecs, effectiveAudioCodec: effectiveAudioCodec })) : tab === 'advanced' ? (jsx_runtime_1.jsx(WebRenderModalAdvanced_1.WebRenderModalAdvanced, { renderMode: renderMode, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, mediaCacheSizeInBytes: mediaCacheSizeInBytes, setMediaCacheSizeInBytes: setMediaCacheSizeInBytes, hardwareAcceleration: hardwareAcceleration, setHardwareAcceleration: setHardwareAcceleration })) : (jsx_runtime_1.jsx(WebRenderModalLicense_1.WebRenderModalLicense, { licenseKey: licenseKey, setLicenseKey: setLicenseKey, initialPublicLicenseKey: initialLicenseKey })) })
423
+ ] }), jsx_runtime_1.jsx("div", { style: render_modals_1.optionsPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? (jsx_runtime_1.jsx(WebRenderModalBasic_1.WebRenderModalBasic, { renderMode: renderMode, resolvedComposition: resolvedComposition, imageFormat: imageFormat, setStillFormat: setStillFormat, frame: frame, onFrameChanged: onFrameChanged, onFrameSetDirectly: onFrameSetDirectly, container: container, setContainerFormat: setContainerFormat, setCodec: setCodecWithContainer, encodableVideoCodecs: encodableVideoCodecs, effectiveVideoCodec: effectiveVideoCodec, startFrame: finalStartFrame, setStartFrame: setStartFrame, endFrame: finalEndFrame, setEndFrame: setEndFrame, outName: outName, onOutNameChange: onOutNameChange, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message, logLevel: logLevel, setLogLevel: setLogLevel })) : tab === 'data' ? (jsx_runtime_1.jsx(DataEditor_1.DataEditor, { defaultProps: inputProps, setDefaultProps: setInputProps, unresolvedComposition: unresolvedComposition, mayShowSaveButton: false, propsEditType: "input-props", saving: saving, setSaving: setSaving, readOnlyStudio: false })) : tab === 'picture' ? (jsx_runtime_1.jsx(WebRenderModalPicture_1.WebRenderModalPicture, { renderMode: renderMode, videoBitrate: videoBitrate, setVideoBitrate: setVideoBitrate, keyframeIntervalInSeconds: keyframeIntervalInSeconds, setKeyframeIntervalInSeconds: setKeyframeIntervalInSeconds, transparent: transparent, setTransparent: setTransparent, scale: scale, setScale: setScale, compositionWidth: resolvedComposition.width, compositionHeight: resolvedComposition.height })) : tab === 'audio' ? (jsx_runtime_1.jsx(WebRenderModalAudio_1.WebRenderModalAudio, { renderMode: renderMode, muted: muted, setMuted: setMuted, audioCodec: audioCodec, setAudioCodec: setAudioCodec, audioBitrate: audioBitrate, setAudioBitrate: setAudioBitrate, container: container, encodableCodecs: encodableAudioCodecs, effectiveAudioCodec: effectiveAudioCodec })) : tab === 'advanced' ? (jsx_runtime_1.jsx(WebRenderModalAdvanced_1.WebRenderModalAdvanced, { renderMode: renderMode, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, mediaCacheSizeInBytes: mediaCacheSizeInBytes, setMediaCacheSizeInBytes: setMediaCacheSizeInBytes, hardwareAcceleration: hardwareAcceleration, setHardwareAcceleration: setHardwareAcceleration })) : (jsx_runtime_1.jsx(WebRenderModalLicense_1.WebRenderModalLicense, { licenseKey: licenseKey, setLicenseKey: setLicenseKey, initialPublicLicenseKey: initialLicenseKey })) })
395
424
  ] })
396
425
  ] }));
397
426
  };
@@ -1,6 +1,8 @@
1
1
  import type { WebRendererAudioCodec, WebRendererContainer, WebRendererQuality } from '@remotion/web-renderer';
2
2
  import React from 'react';
3
+ import type { RenderType } from './WebRenderModal';
3
4
  export declare const WebRenderModalAudio: React.FC<{
5
+ readonly renderMode: RenderType;
4
6
  readonly muted: boolean;
5
7
  readonly setMuted: React.Dispatch<React.SetStateAction<boolean>>;
6
8
  readonly audioCodec: WebRendererAudioCodec;
@@ -34,11 +34,19 @@ const humanReadableWebAudioCodec = (audioCodec) => {
34
34
  return 'AAC';
35
35
  case 'opus':
36
36
  return 'Opus';
37
+ case 'mp3':
38
+ return 'MP3';
39
+ case 'vorbis':
40
+ return 'Vorbis';
41
+ case 'pcm-s16':
42
+ return 'Lossless (PCM)';
43
+ case 'flac':
44
+ return 'FLAC';
37
45
  default:
38
- return audioCodec;
46
+ throw new Error(`Unsupported audio codec: ${audioCodec}`);
39
47
  }
40
48
  };
41
- const WebRenderModalAudio = ({ muted, setMuted, audioCodec, setAudioCodec, audioBitrate, setAudioBitrate, container: videoContainer, encodableCodecs, effectiveAudioCodec, }) => {
49
+ const WebRenderModalAudio = ({ renderMode, muted, setMuted, audioCodec, setAudioCodec, audioBitrate, setAudioBitrate, container: videoContainer, encodableCodecs, effectiveAudioCodec, }) => {
42
50
  const containerSupported = (0, react_1.useMemo)(() => (0, web_renderer_1.getSupportedAudioCodecsForContainer)(videoContainer), [videoContainer]);
43
51
  const audioCodecOptions = (0, react_1.useMemo)(() => {
44
52
  return containerSupported.map((codec) => {
@@ -58,9 +66,9 @@ const WebRenderModalAudio = ({ muted, setMuted, audioCodec, setAudioCodec, audio
58
66
  });
59
67
  }, [containerSupported, encodableCodecs, audioCodec, setAudioCodec]);
60
68
  const audioBitrateOptions = (0, react_1.useMemo)(() => (0, quality_options_1.getQualityOptions)(audioBitrate, setAudioBitrate), [audioBitrate, setAudioBitrate]);
61
- return (jsx_runtime_1.jsxs("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [
62
- jsx_runtime_1.jsx(MutedSetting_1.MutedSetting, { enforceAudioTrack: false, muted: muted, setMuted: setMuted }), !muted ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
63
- jsx_runtime_1.jsx(RenderModalHr_1.RenderModalHr, {}), jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
69
+ const isAudioOnly = renderMode === 'audio';
70
+ const showAudioSettings = isAudioOnly || !muted;
71
+ return (jsx_runtime_1.jsxs("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [isAudioOnly ? null : (jsx_runtime_1.jsx(MutedSetting_1.MutedSetting, { enforceAudioTrack: false, muted: muted, setMuted: setMuted })), showAudioSettings ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [isAudioOnly ? null : jsx_runtime_1.jsx(RenderModalHr_1.RenderModalHr, {}), jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
64
72
  jsx_runtime_1.jsxs("div", { style: layout_2.label, children: ["Audio Quality",
65
73
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 })
66
74
  ] }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(ComboBox_1.Combobox, { values: audioBitrateOptions, selectedId: audioBitrate, title: "Audio Quality" }) })