@remotion/cli 4.0.21 → 4.0.22

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 (48) hide show
  1. package/dist/benchmark.js +2 -1
  2. package/dist/config/image-format.d.ts +1 -1
  3. package/dist/config/index.d.ts +3 -1
  4. package/dist/config/index.js +4 -0
  5. package/dist/config/presets-profile.d.ts +3 -0
  6. package/dist/config/presets-profile.js +12 -0
  7. package/dist/config/x264-preset.d.ts +3 -0
  8. package/dist/config/x264-preset.js +12 -0
  9. package/dist/editor/components/Editor.js +14 -1
  10. package/dist/editor/components/Modals.js +1 -1
  11. package/dist/editor/components/NewComposition/RemInput.d.ts +1 -1
  12. package/dist/editor/components/NewComposition/RemInputTypeColor.d.ts +1 -1
  13. package/dist/editor/components/NewComposition/RemTextarea.d.ts +1 -1
  14. package/dist/editor/components/RenderButton.js +1 -0
  15. package/dist/editor/components/RenderModal/RenderModal.d.ts +2 -1
  16. package/dist/editor/components/RenderModal/RenderModal.js +11 -2
  17. package/dist/editor/components/RenderModal/RenderModalAdvanced.d.ts +4 -0
  18. package/dist/editor/components/RenderModal/RenderModalAdvanced.js +21 -2
  19. package/dist/editor/components/RenderModal/RenderModalBasic.js +1 -1
  20. package/dist/editor/components/RenderModal/SchemaEditor/ZodDiscriminatedUnionEditor.js +1 -1
  21. package/dist/editor/components/RenderModal/human-readable-codec.d.ts +1 -1
  22. package/dist/editor/components/RenderQueue/actions.d.ts +3 -2
  23. package/dist/editor/components/RenderQueue/actions.js +2 -1
  24. package/dist/editor/components/RightPanel.d.ts +8 -0
  25. package/dist/editor/components/RightPanel.js +112 -0
  26. package/dist/editor/components/SidebarRenderButton.js +1 -0
  27. package/dist/editor/helpers/document-title.js +1 -0
  28. package/dist/editor/helpers/presets-labels.d.ts +2 -0
  29. package/dist/editor/helpers/presets-labels.js +37 -0
  30. package/dist/editor/state/modals.d.ts +2 -1
  31. package/dist/get-cli-options.d.ts +2 -1
  32. package/dist/get-cli-options.js +6 -0
  33. package/dist/index.d.ts +7 -5
  34. package/dist/parse-command-line.d.ts +2 -1
  35. package/dist/parse-command-line.js +3 -0
  36. package/dist/preview-server/dev-middleware/range-parser.d.ts +1 -1
  37. package/dist/preview-server/error-overlay/react-overlay/listen-to-runtime-errors.js +1 -0
  38. package/dist/preview-server/hot-middleware/process-update.d.ts +0 -5
  39. package/dist/preview-server/hot-middleware/process-update.js +21 -2
  40. package/dist/preview-server/render-queue/job.d.ts +3 -1
  41. package/dist/preview-server/render-queue/make-retry-payload.js +3 -1
  42. package/dist/preview-server/render-queue/process-video.js +2 -1
  43. package/dist/preview-server/routes/add-render.js +1 -0
  44. package/dist/preview-server/routes.js +4 -2
  45. package/dist/render-flows/render.d.ts +3 -2
  46. package/dist/render-flows/render.js +2 -1
  47. package/dist/render.js +2 -1
  48. package/package.json +8 -8
package/dist/benchmark.js CHANGED
@@ -95,7 +95,7 @@ const benchmarkCommand = async (remotionRoot, args) => {
95
95
  process.exit(1);
96
96
  }
97
97
  const fullEntryPoint = (0, convert_entry_point_to_serve_url_1.convertEntryPointToServeUrl)(file);
98
- const { inputProps, envVariables, browserExecutable, chromiumOptions, port, puppeteerTimeout, browser, scale, publicDir, proResProfile, frameRange: defaultFrameRange, overwrite, jpegQuality, crf: configFileCrf, pixelFormat, scale: configFileScale, numberOfGifLoops, everyNthFrame, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, height, width, concurrency: unparsedConcurrency, logLevel, } = await (0, get_cli_options_1.getCliOptions)({
98
+ const { inputProps, envVariables, browserExecutable, chromiumOptions, port, puppeteerTimeout, browser, scale, publicDir, proResProfile, x264Preset, frameRange: defaultFrameRange, overwrite, jpegQuality, crf: configFileCrf, pixelFormat, scale: configFileScale, numberOfGifLoops, everyNthFrame, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, height, width, concurrency: unparsedConcurrency, logLevel, } = await (0, get_cli_options_1.getCliOptions)({
99
99
  isLambda: false,
100
100
  type: 'series',
101
101
  remotionRoot,
@@ -201,6 +201,7 @@ const benchmarkCommand = async (remotionRoot, args) => {
201
201
  overwrite,
202
202
  pixelFormat,
203
203
  proResProfile,
204
+ x264Preset,
204
205
  jpegQuality,
205
206
  chromiumOptions,
206
207
  timeoutInMilliseconds: config_1.ConfigInternals.getCurrentPuppeteerTimeout(),
@@ -2,4 +2,4 @@ import type { StillImageFormat, VideoImageFormat } from '@remotion/renderer';
2
2
  export declare const setStillImageFormat: (format: StillImageFormat) => void;
3
3
  export declare const setVideoImageFormat: (format: VideoImageFormat) => void;
4
4
  export declare const getUserPreferredStillImageFormat: () => "png" | "jpeg" | "pdf" | "webp" | undefined;
5
- export declare const getUserPreferredVideoImageFormat: () => "png" | "jpeg" | "none" | undefined;
5
+ export declare const getUserPreferredVideoImageFormat: () => "none" | "png" | "jpeg" | undefined;
@@ -220,6 +220,7 @@ declare global {
220
220
  * See https://avpres.net/FFmpeg/im_ProRes.html for meaning of possible values.
221
221
  */
222
222
  readonly setProResProfile: (profile: '4444-xq' | '4444' | 'hq' | 'standard' | 'light' | 'proxy' | undefined) => void;
223
+ readonly setX264Preset: (profile: 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow' | 'slower' | 'veryslow' | 'placebo' | undefined) => void;
223
224
  /**
224
225
  * Override the arguments that Remotion passes to FFMPEG.
225
226
  * Consult https://remotion.dev/docs/renderer/render-media#ffmpegoverride before using this feature.
@@ -278,6 +279,7 @@ export declare const ConfigInternals: {
278
279
  getBrowser: () => null;
279
280
  getPixelFormat: () => "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
280
281
  getProResProfile: () => "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined;
282
+ getPresetProfile: () => "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | undefined;
281
283
  getShouldOverwrite: ({ defaultValue, }: {
282
284
  defaultValue: boolean;
283
285
  }) => boolean;
@@ -297,7 +299,7 @@ export declare const ConfigInternals: {
297
299
  getShouldOutputImageSequence: (frameRange: FrameRange | null) => boolean;
298
300
  getDotEnvLocation: () => string | null;
299
301
  getUserPreferredStillImageFormat: () => "png" | "jpeg" | "pdf" | "webp" | undefined;
300
- getUserPreferredVideoImageFormat: () => "png" | "jpeg" | "none" | undefined;
302
+ getUserPreferredVideoImageFormat: () => "none" | "png" | "jpeg" | undefined;
301
303
  getWebpackOverrideFn: () => WebpackOverrideFn;
302
304
  getWebpackCaching: () => boolean;
303
305
  getOutputLocation: () => string | null;
@@ -46,6 +46,7 @@ const scale_1 = require("./scale");
46
46
  const still_frame_1 = require("./still-frame");
47
47
  const timeout_1 = require("./timeout");
48
48
  const webpack_caching_1 = require("./webpack-caching");
49
+ const x264_preset_1 = require("./x264-preset");
49
50
  const audio_codec_1 = require("./audio-codec");
50
51
  const bitrate_1 = require("./bitrate");
51
52
  const browser_executable_2 = require("./browser-executable");
@@ -82,6 +83,7 @@ const user_agent_1 = require("./user-agent");
82
83
  const webpack_caching_2 = require("./webpack-caching");
83
84
  const webpack_poll_1 = require("./webpack-poll");
84
85
  const width_1 = require("./width");
86
+ const x264_preset_2 = require("./x264-preset");
85
87
  exports.Config = {
86
88
  get Bundling() {
87
89
  throw new Error('The config format has changed. Change `Config.Bundling.*()` calls to `Config.*()` in your config file.');
@@ -144,6 +146,7 @@ exports.Config = {
144
146
  setCrf: crf_1.setCrf,
145
147
  setImageSequence: image_sequence_2.setImageSequence,
146
148
  setProResProfile: prores_profile_2.setProResProfile,
149
+ setX264Preset: x264_preset_2.setX264Preset,
147
150
  setAudioBitrate: bitrate_1.setAudioBitrate,
148
151
  setVideoBitrate: bitrate_1.setVideoBitrate,
149
152
  overrideHeight: height_1.overrideHeight,
@@ -157,6 +160,7 @@ exports.ConfigInternals = {
157
160
  getBrowser: browser_1.getBrowser,
158
161
  getPixelFormat: pixel_format_1.getPixelFormat,
159
162
  getProResProfile: prores_profile_1.getProResProfile,
163
+ getPresetProfile: x264_preset_1.getX264Preset,
160
164
  getShouldOverwrite: overwrite_1.getShouldOverwrite,
161
165
  getBrowserExecutable: browser_executable_1.getBrowserExecutable,
162
166
  getScale: scale_1.getScale,
@@ -0,0 +1,3 @@
1
+ import type { PresetsProfile } from '@remotion/renderer';
2
+ export declare const getPresetProfile: () => PresetsProfile | undefined;
3
+ export declare const setPresetProfile: (profile: PresetsProfile | undefined) => void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setPresetProfile = exports.getPresetProfile = void 0;
4
+ let preset;
5
+ const getPresetProfile = () => {
6
+ return preset;
7
+ };
8
+ exports.getPresetProfile = getPresetProfile;
9
+ const setPresetProfile = (profile) => {
10
+ preset = profile;
11
+ };
12
+ exports.setPresetProfile = setPresetProfile;
@@ -0,0 +1,3 @@
1
+ import type { X264Preset } from '@remotion/renderer';
2
+ export declare const getX264Preset: () => X264Preset | undefined;
3
+ export declare const setX264Preset: (profile: X264Preset | undefined) => void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setX264Preset = exports.getX264Preset = void 0;
4
+ let preset;
5
+ const getX264Preset = () => {
6
+ return preset;
7
+ };
8
+ exports.getX264Preset = getX264Preset;
9
+ const setX264Preset = (profile) => {
10
+ preset = profile;
11
+ };
12
+ exports.setX264Preset = setX264Preset;
@@ -29,6 +29,17 @@ const Editor = () => {
29
29
  }
30
30
  return (0, remotion_1.delayRender)('Waiting for registerRoot()');
31
31
  });
32
+ (0, react_1.useEffect)(() => {
33
+ const listenToChanges = (e) => {
34
+ if (window.remotion_unsavedProps) {
35
+ e.returnValue = 'Are you sure you want to leave?';
36
+ }
37
+ };
38
+ window.addEventListener('beforeunload', listenToChanges);
39
+ return () => {
40
+ window.removeEventListener('beforeunload', listenToChanges);
41
+ };
42
+ }, []);
32
43
  (0, react_1.useEffect)(() => {
33
44
  if (Root) {
34
45
  return;
@@ -37,7 +48,9 @@ const Editor = () => {
37
48
  setRoot(() => NewRoot);
38
49
  (0, remotion_1.continueRender)(waitForRoot);
39
50
  });
40
- return () => cleanup();
51
+ return () => {
52
+ cleanup();
53
+ };
41
54
  }, [Root, waitForRoot]);
42
55
  return ((0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onEscape: noop_1.noop, onOutsideClick: noop_1.noop, children: (0, jsx_runtime_1.jsxs)(timeline_zoom_1.TimelineZoomContext, { children: [(0, jsx_runtime_1.jsxs)("div", { style: background, children: [Root === null ? null : (0, jsx_runtime_1.jsx)(Root, {}), (0, jsx_runtime_1.jsxs)(remotion_1.Internals.CanUseRemotionHooksProvider, { children: [Root === null ? (0, jsx_runtime_1.jsx)(NoRegisterRoot_1.NoRegisterRoot, {}) : (0, jsx_runtime_1.jsx)(EditorContent_1.EditorContent, {}), (0, jsx_runtime_1.jsx)(GlobalKeybindings_1.GlobalKeybindings, {})] }), (0, jsx_runtime_1.jsx)(NotificationCenter_1.NotificationCenter, {})] }), (0, jsx_runtime_1.jsx)(Modals_1.Modals, {})] }) }));
43
56
  };
@@ -16,7 +16,7 @@ const UpdateModal_1 = require("./UpdateModal/UpdateModal");
16
16
  const Modals = () => {
17
17
  const { selectedModal: modalContextType } = (0, react_1.useContext)(modals_1.ModalsContext);
18
18
  const canRender = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx).type === 'connected';
19
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [modalContextType && modalContextType.type === 'new-comp' && ((0, jsx_runtime_1.jsx)(NewComposition_1.default, { initialCompType: modalContextType.compType })), modalContextType && canRender && modalContextType.type === 'render' && ((0, jsx_runtime_1.jsx)(RenderModal_1.RenderModalWithLoader, { initialFrame: modalContextType.initialFrame, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialOutName: modalContextType.initialOutName, initialScale: modalContextType.initialScale, initialVerbose: modalContextType.initialVerbose, initialRenderType: modalContextType.initialRenderType, initialVideoCodecForAudioTab: modalContextType.initialVideoCodecForAudioTab, initialVideoCodecForVideoTab: modalContextType.initialVideoCodecForVideoTab, initialConcurrency: modalContextType.initialConcurrency, maxConcurrency: modalContextType.maxConcurrency, minConcurrency: modalContextType.minConcurrency, initialStillImageFormat: modalContextType.initialStillImageFormat, initialMuted: modalContextType.initialMuted, initialEnforceAudioTrack: modalContextType.initialEnforceAudioTrack, initialProResProfile: modalContextType.initialProResProfile, initialPixelFormat: modalContextType.initialPixelFormat, initialAudioBitrate: modalContextType.initialAudioBitrate, initialVideoBitrate: modalContextType.initialVideoBitrate, initialEveryNthFrame: modalContextType.initialEveryNthFrame, initialNumberOfGifLoops: modalContextType.initialNumberOfGifLoops, initialDelayRenderTimeout: modalContextType.initialDelayRenderTimeout, initialAudioCodec: modalContextType.initialAudioCodec, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark })), modalContextType &&
19
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [modalContextType && modalContextType.type === 'new-comp' && ((0, jsx_runtime_1.jsx)(NewComposition_1.default, { initialCompType: modalContextType.compType })), modalContextType && canRender && modalContextType.type === 'render' && ((0, jsx_runtime_1.jsx)(RenderModal_1.RenderModalWithLoader, { initialFrame: modalContextType.initialFrame, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialOutName: modalContextType.initialOutName, initialScale: modalContextType.initialScale, initialVerbose: modalContextType.initialVerbose, initialRenderType: modalContextType.initialRenderType, initialVideoCodecForAudioTab: modalContextType.initialVideoCodecForAudioTab, initialVideoCodecForVideoTab: modalContextType.initialVideoCodecForVideoTab, 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, initialAudioCodec: modalContextType.initialAudioCodec, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark })), modalContextType &&
20
20
  canRender &&
21
21
  modalContextType.type === 'render-progress' && ((0, jsx_runtime_1.jsx)(RenderStatusModal_1.RenderStatusModal, { jobId: modalContextType.jobId })), modalContextType && modalContextType.type === 'update' && ((0, jsx_runtime_1.jsx)(UpdateModal_1.UpdateModal, { info: modalContextType.info })), modalContextType && modalContextType.type === 'quick-switcher' && ((0, jsx_runtime_1.jsx)(QuickSwitcher_1.default, { invocationTimestamp: modalContextType.invocationTimestamp, initialMode: modalContextType.mode }))] }));
22
22
  };
@@ -13,5 +13,5 @@ export declare const getInputBorderColor: ({ status, isFocused, isHovered, }: {
13
13
  isFocused: boolean;
14
14
  isHovered: boolean;
15
15
  }) => "hsla(0, 0%, 100%, 0.15)" | "rgba(0, 0, 0, 0.6)" | "rgba(255, 255, 255, 0.05)" | "#ff3232" | "#f1c40f";
16
- export declare const RemotionInput: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | "rightAlign" | keyof React.InputHTMLAttributes<HTMLInputElement>> & React.RefAttributes<HTMLInputElement>>;
16
+ export declare const RemotionInput: React.ForwardRefExoticComponent<Pick<Props, "key" | keyof React.InputHTMLAttributes<HTMLInputElement> | "status" | "rightAlign"> & React.RefAttributes<HTMLInputElement>>;
17
17
  export {};
@@ -4,5 +4,5 @@ type Props = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>
4
4
  status: RemInputStatus;
5
5
  name: string;
6
6
  };
7
- export declare const RemInputTypeColor: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>> & React.RefAttributes<HTMLInputElement>>;
7
+ export declare const RemInputTypeColor: React.ForwardRefExoticComponent<Pick<Props, "key" | keyof React.InputHTMLAttributes<HTMLInputElement> | "status"> & React.RefAttributes<HTMLInputElement>>;
8
8
  export {};
@@ -3,5 +3,5 @@ type Props = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLTextAreaEleme
3
3
  status: 'error' | 'warning' | 'ok';
4
4
  };
5
5
  export declare const inputBaseStyle: React.CSSProperties;
6
- export declare const RemTextarea: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | keyof React.InputHTMLAttributes<HTMLTextAreaElement>> & React.RefAttributes<HTMLTextAreaElement>>;
6
+ export declare const RemTextarea: React.ForwardRefExoticComponent<Pick<Props, "key" | "status" | keyof React.InputHTMLAttributes<HTMLTextAreaElement>> & React.RefAttributes<HTMLTextAreaElement>>;
7
7
  export {};
@@ -82,6 +82,7 @@ const RenderButton = () => {
82
82
  initialMuted: defaults.muted,
83
83
  initialEnforceAudioTrack: defaults.enforceAudioTrack,
84
84
  initialProResProfile: defaults.proResProfile,
85
+ initialx264Preset: defaults.x264Preset,
85
86
  initialPixelFormat: defaults.pixelFormat,
86
87
  initialAudioBitrate: defaults.audioBitrate,
87
88
  initialVideoBitrate: defaults.videoBitrate,
@@ -1,4 +1,4 @@
1
- import type { AudioCodec, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import React from 'react';
3
3
  import type { RenderType } from './RenderModalAdvanced';
4
4
  type RenderModalProps = {
@@ -20,6 +20,7 @@ type RenderModalProps = {
20
20
  initialMuted: boolean;
21
21
  initialEnforceAudioTrack: boolean;
22
22
  initialProResProfile: ProResProfile;
23
+ initialx264Preset: X264Preset;
23
24
  initialPixelFormat: PixelFormat;
24
25
  initialVideoBitrate: string | null;
25
26
  initialAudioBitrate: string | null;
@@ -114,7 +114,7 @@ const outer = {
114
114
  display: 'flex',
115
115
  flexDirection: 'column',
116
116
  };
117
- const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageFormat, initialJpegQuality, initialScale, initialVerbose, initialOutName, initialRenderType, initialVideoCodecForAudioTab, initialVideoCodecForVideoTab, initialConcurrency, maxConcurrency, minConcurrency, initialMuted, initialEnforceAudioTrack, initialProResProfile, initialPixelFormat, initialVideoBitrate, initialAudioBitrate, initialEveryNthFrame, initialNumberOfGifLoops, initialDelayRenderTimeout, initialAudioCodec, initialEnvVariables, initialDisableWebSecurity, initialGl, initialHeadless, initialIgnoreCertificateErrors, defaultProps, inFrameMark, outFrameMark, onClose, resolvedComposition, unresolvedComposition, }) => {
117
+ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageFormat, initialJpegQuality, initialScale, initialVerbose, initialOutName, initialRenderType, initialVideoCodecForAudioTab, initialVideoCodecForVideoTab, initialConcurrency, maxConcurrency, minConcurrency, initialMuted, initialEnforceAudioTrack, initialProResProfile, initialx264Preset, initialPixelFormat, initialVideoBitrate, initialAudioBitrate, initialEveryNthFrame, initialNumberOfGifLoops, initialDelayRenderTimeout, initialAudioCodec, initialEnvVariables, initialDisableWebSecurity, initialGl, initialHeadless, initialIgnoreCertificateErrors, defaultProps, inFrameMark, outFrameMark, onClose, resolvedComposition, unresolvedComposition, }) => {
118
118
  const isMounted = (0, react_1.useRef)(true);
119
119
  const [state, dispatch] = (0, react_1.useReducer)(reducer, initialState);
120
120
  const [unclampedFrame, setFrame] = (0, react_1.useState)(() => initialFrame);
@@ -151,6 +151,7 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
151
151
  const [endFrameOrNull, setEndFrame] = (0, react_1.useState)(() => outFrameMark !== null && outFrameMark !== void 0 ? outFrameMark : null);
152
152
  const [startFrameOrNull, setStartFrame] = (0, react_1.useState)(() => inFrameMark !== null && inFrameMark !== void 0 ? inFrameMark : null);
153
153
  const [proResProfileSetting, setProResProfile] = (0, react_1.useState)(() => initialProResProfile);
154
+ const [x264PresetSetting, setx264Preset] = (0, react_1.useState)(() => initialx264Preset);
154
155
  const [pixelFormat, setPixelFormat] = (0, react_1.useState)(() => initialPixelFormat);
155
156
  const [preferredQualityControlType, setQualityControl] = (0, react_1.useState)(() => initialVideoBitrate === null ? 'crf' : 'bitrate');
156
157
  const [shouldHaveCustomTargetAudioBitrate, setShouldHaveCustomTargetAudioBitrate,] = (0, react_1.useState)(() => initialAudioBitrate !== null);
@@ -232,6 +233,12 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
232
233
  }
233
234
  return null;
234
235
  }, [codec, proResProfileSetting, renderMode]);
236
+ const x264Preset = (0, react_1.useMemo)(() => {
237
+ if (renderMode === 'video' && codec === 'h264') {
238
+ return x264PresetSetting;
239
+ }
240
+ return null;
241
+ }, [codec, x264PresetSetting, renderMode]);
235
242
  const [inputProps, setInputProps] = (0, react_1.useState)(() => defaultProps);
236
243
  const endFrame = (0, react_1.useMemo)(() => {
237
244
  if (endFrameOrNull === null) {
@@ -379,6 +386,7 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
379
386
  muted,
380
387
  enforceAudioTrack,
381
388
  proResProfile,
389
+ x264Preset,
382
390
  pixelFormat,
383
391
  audioBitrate,
384
392
  videoBitrate,
@@ -417,6 +425,7 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
417
425
  muted,
418
426
  enforceAudioTrack,
419
427
  proResProfile,
428
+ x264Preset,
420
429
  pixelFormat,
421
430
  audioBitrate,
422
431
  videoBitrate,
@@ -585,7 +594,7 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
585
594
  return ((0, jsx_runtime_1.jsxs)("div", { style: outer, children: [(0, jsx_runtime_1.jsx)(ModalHeader_1.NewCompHeader, { title: `Render ${resolvedComposition.id}` }), (0, jsx_runtime_1.jsxs)("div", { style: container, children: [(0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: renderTabOptions, needsWrapping: false }), (0, jsx_runtime_1.jsx)("div", { style: flexer }), (0, jsx_runtime_1.jsxs)(Button_1.Button, { autoFocus: true, onClick: trigger, disabled: renderDisabled, style: {
586
595
  ...buttonStyle,
587
596
  backgroundColor: outnameValidation.valid ? colors_1.BLUE : colors_1.BLUE_DISABLED,
588
- }, children: [state.type === 'idle' ? `Render ${renderMode}` : 'Rendering...', (0, jsx_runtime_1.jsx)(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: horizontalLayout, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftSidebar, children: [shownTabs.includes('general') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'general', onClick: () => setTab('general'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(file_1.FileIcon, { style: icon }) }), "General"] })) : null, shownTabs.includes('data') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(data_1.DataIcon, { style: icon }) }), "Input Props"] })) : null, shownTabs.includes('picture') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(frame_1.PicIcon, { style: icon }) }), "Picture"] })) : null, shownTabs.includes('audio') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(audio_1.AudioIcon, { style: icon }) }), "Audio"] })) : null, shownTabs.includes('gif') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'gif', onClick: () => setTab('gif'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gif_1.GifIcon, { style: icon }) }), "GIF"] })) : null, shownTabs.includes('advanced') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gear_1.GearIcon, { style: icon }) }), "Other"] })) : null] }), (0, jsx_runtime_1.jsx)("div", { style: optionsPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? ((0, jsx_runtime_1.jsx)(RenderModalBasic_1.RenderModalBasic, { codec: codec, resolvedComposition: resolvedComposition, frame: frame, imageFormatOptions: imageFormatOptions, outName: outName, proResProfile: proResProfile, renderMode: renderMode, setVideoCodec: setCodec, setFrame: setFrame, setOutName: setOutName, setProResProfile: setProResProfile, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message })) : tab === 'picture' ? ((0, jsx_runtime_1.jsx)(RenderModalPicture_1.RenderModalPicture, { renderMode: renderMode, scale: scale, setScale: setScale, pixelFormat: pixelFormat, setPixelFormat: setPixelFormat, imageFormatOptions: imageFormatOptions, crf: crf, setCrf: setCrf, customTargetVideoBitrate: customTargetVideoBitrate, maxCrf: maxCrf, minCrf: minCrf, jpegQuality: jpegQuality, qualityControlType: qualityControlType, setJpegQuality: setJpegQuality, setCustomTargetVideoBitrateValue: setCustomTargetVideoBitrateValue, setQualityControl: setQualityControl, videoImageFormat: videoImageFormat, stillImageFormat: stillImageFormat, shouldDisplayQualityControlPicker: supportsBothQualityControls })) : tab === 'audio' ? ((0, jsx_runtime_1.jsx)(RenderModalAudio_1.RenderModalAudio, { muted: muted, renderMode: renderMode, setMuted: setMuted, codec: codec, audioCodec: audioCodec, setAudioCodec: setAudioCodec, enforceAudioTrack: enforceAudioTrack, setEnforceAudioTrackState: setEnforceAudioTrackState, customTargetAudioBitrate: customTargetAudioBitrate, setCustomTargetAudioBitrateValue: setCustomTargetAudioBitrateValue, setShouldHaveCustomTargetAudioBitrate: setShouldHaveCustomTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate: shouldHaveCustomTargetAudioBitrate })) : tab === 'gif' ? ((0, jsx_runtime_1.jsx)(RenderModalGif_1.RenderModalGif, { everyNthFrame: everyNthFrame, limitNumberOfGifLoops: limitNumberOfGifLoops, numberOfGifLoopsSetting: numberOfGifLoopsSetting, setEveryNthFrameSetting: setEveryNthFrameSetting, setLimitNumberOfGifLoops: setLimitNumberOfGifLoops, setNumberOfGifLoopsSetting: setNumberOfGifLoopsSetting })) : tab === 'data' ? ((0, jsx_runtime_1.jsx)(DataEditor_1.DataEditor, { inputProps: inputProps, setInputProps: setInputProps, unresolvedComposition: unresolvedComposition, mayShowSaveButton: false, propsEditType: "input-props", saving: saving, setSaving: setSaving })) : ((0, jsx_runtime_1.jsx)(RenderModalAdvanced_1.RenderModalAdvanced, { concurrency: concurrency, maxConcurrency: maxConcurrency, minConcurrency: minConcurrency, renderMode: renderMode, setConcurrency: setConcurrency, setVerboseLogging: setVerboseLogging, verbose: verbose, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, disallowParallelEncoding: disallowParallelEncoding, setDisallowParallelEncoding: setDisallowParallelEncoding, setDisableWebSecurity: setDisableWebSecurity, setIgnoreCertificateErrors: setIgnoreCertificateErrors, setHeadless: setHeadless, headless: headless, ignoreCertificateErrors: ignoreCertificateErrors, disableWebSecurity: disableWebSecurity, openGlOption: openGlOption, setOpenGlOption: setOpenGlOption, setEnvVariables: setEnvVariables, envVariables: envVariables })) })] })] }));
597
+ }, children: [state.type === 'idle' ? `Render ${renderMode}` : 'Rendering...', (0, jsx_runtime_1.jsx)(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: horizontalLayout, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftSidebar, children: [shownTabs.includes('general') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'general', onClick: () => setTab('general'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(file_1.FileIcon, { style: icon }) }), "General"] })) : null, shownTabs.includes('data') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(data_1.DataIcon, { style: icon }) }), "Input Props"] })) : null, shownTabs.includes('picture') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(frame_1.PicIcon, { style: icon }) }), "Picture"] })) : null, shownTabs.includes('audio') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(audio_1.AudioIcon, { style: icon }) }), "Audio"] })) : null, shownTabs.includes('gif') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'gif', onClick: () => setTab('gif'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gif_1.GifIcon, { style: icon }) }), "GIF"] })) : null, shownTabs.includes('advanced') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gear_1.GearIcon, { style: icon }) }), "Other"] })) : null] }), (0, jsx_runtime_1.jsx)("div", { style: optionsPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? ((0, jsx_runtime_1.jsx)(RenderModalBasic_1.RenderModalBasic, { codec: codec, resolvedComposition: resolvedComposition, frame: frame, imageFormatOptions: imageFormatOptions, outName: outName, proResProfile: proResProfile, renderMode: renderMode, setVideoCodec: setCodec, setFrame: setFrame, setOutName: setOutName, setProResProfile: setProResProfile, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message })) : tab === 'picture' ? ((0, jsx_runtime_1.jsx)(RenderModalPicture_1.RenderModalPicture, { renderMode: renderMode, scale: scale, setScale: setScale, pixelFormat: pixelFormat, setPixelFormat: setPixelFormat, imageFormatOptions: imageFormatOptions, crf: crf, setCrf: setCrf, customTargetVideoBitrate: customTargetVideoBitrate, maxCrf: maxCrf, minCrf: minCrf, jpegQuality: jpegQuality, qualityControlType: qualityControlType, setJpegQuality: setJpegQuality, setCustomTargetVideoBitrateValue: setCustomTargetVideoBitrateValue, setQualityControl: setQualityControl, videoImageFormat: videoImageFormat, stillImageFormat: stillImageFormat, shouldDisplayQualityControlPicker: supportsBothQualityControls })) : tab === 'audio' ? ((0, jsx_runtime_1.jsx)(RenderModalAudio_1.RenderModalAudio, { muted: muted, renderMode: renderMode, setMuted: setMuted, codec: codec, audioCodec: audioCodec, setAudioCodec: setAudioCodec, enforceAudioTrack: enforceAudioTrack, setEnforceAudioTrackState: setEnforceAudioTrackState, customTargetAudioBitrate: customTargetAudioBitrate, setCustomTargetAudioBitrateValue: setCustomTargetAudioBitrateValue, setShouldHaveCustomTargetAudioBitrate: setShouldHaveCustomTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate: shouldHaveCustomTargetAudioBitrate })) : tab === 'gif' ? ((0, jsx_runtime_1.jsx)(RenderModalGif_1.RenderModalGif, { everyNthFrame: everyNthFrame, limitNumberOfGifLoops: limitNumberOfGifLoops, numberOfGifLoopsSetting: numberOfGifLoopsSetting, setEveryNthFrameSetting: setEveryNthFrameSetting, setLimitNumberOfGifLoops: setLimitNumberOfGifLoops, setNumberOfGifLoopsSetting: setNumberOfGifLoopsSetting })) : tab === 'data' ? ((0, jsx_runtime_1.jsx)(DataEditor_1.DataEditor, { inputProps: inputProps, setInputProps: setInputProps, unresolvedComposition: unresolvedComposition, mayShowSaveButton: false, propsEditType: "input-props", saving: saving, setSaving: setSaving })) : ((0, jsx_runtime_1.jsx)(RenderModalAdvanced_1.RenderModalAdvanced, { x264Preset: x264Preset, setx264Preset: setx264Preset, concurrency: concurrency, maxConcurrency: maxConcurrency, minConcurrency: minConcurrency, renderMode: renderMode, setConcurrency: setConcurrency, setVerboseLogging: setVerboseLogging, verbose: verbose, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, disallowParallelEncoding: disallowParallelEncoding, setDisallowParallelEncoding: setDisallowParallelEncoding, setDisableWebSecurity: setDisableWebSecurity, setIgnoreCertificateErrors: setIgnoreCertificateErrors, setHeadless: setHeadless, headless: headless, ignoreCertificateErrors: ignoreCertificateErrors, disableWebSecurity: disableWebSecurity, openGlOption: openGlOption, setOpenGlOption: setOpenGlOption, setEnvVariables: setEnvVariables, envVariables: envVariables, codec: codec })) })] })] }));
589
598
  };
590
599
  const RenderModalWithLoader = (props) => {
591
600
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
@@ -1,3 +1,4 @@
1
+ import type { Codec, X264Preset } from '@remotion/renderer';
1
2
  import React from 'react';
2
3
  import type { UiOpenGlOptions } from '../../../required-chromium-options';
3
4
  export type RenderType = 'still' | 'video' | 'audio';
@@ -23,4 +24,7 @@ export declare const RenderModalAdvanced: React.FC<{
23
24
  setOpenGlOption: React.Dispatch<React.SetStateAction<UiOpenGlOptions>>;
24
25
  envVariables: [string, string][];
25
26
  setEnvVariables: React.Dispatch<React.SetStateAction<[string, string][]>>;
27
+ x264Preset: X264Preset | null;
28
+ setx264Preset: React.Dispatch<React.SetStateAction<X264Preset>>;
29
+ codec: Codec;
26
30
  }>;
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RenderModalAdvanced = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const client_1 = require("@remotion/renderer/client");
5
6
  const react_1 = require("react");
7
+ const presets_labels_1 = require("../../helpers/presets-labels");
6
8
  const Checkmark_1 = require("../../icons/Checkmark");
7
9
  const Checkbox_1 = require("../Checkbox");
8
10
  const is_menu_item_1 = require("../Menu/is-menu-item");
@@ -15,7 +17,7 @@ const container = {
15
17
  flex: 1,
16
18
  overflowY: 'auto',
17
19
  };
18
- const RenderModalAdvanced = ({ renderMode, maxConcurrency, minConcurrency, setConcurrency, concurrency, setVerboseLogging, verbose, delayRenderTimeout, setDelayRenderTimeout, disallowParallelEncoding, setDisallowParallelEncoding, setDisableWebSecurity, setIgnoreCertificateErrors, setHeadless, headless, ignoreCertificateErrors, disableWebSecurity, openGlOption, setOpenGlOption, setEnvVariables, envVariables, }) => {
20
+ const RenderModalAdvanced = ({ renderMode, maxConcurrency, minConcurrency, setConcurrency, concurrency, setVerboseLogging, verbose, delayRenderTimeout, setDelayRenderTimeout, disallowParallelEncoding, setDisallowParallelEncoding, setDisableWebSecurity, setIgnoreCertificateErrors, setHeadless, headless, ignoreCertificateErrors, disableWebSecurity, openGlOption, setOpenGlOption, setEnvVariables, envVariables, setx264Preset, x264Preset, codec, }) => {
19
21
  const extendedOpenGlOptions = (0, react_1.useMemo)(() => {
20
22
  return ['angle', 'egl', 'swangle', 'swiftshader', 'default'];
21
23
  }, []);
@@ -50,7 +52,24 @@ const RenderModalAdvanced = ({ renderMode, maxConcurrency, minConcurrency, setCo
50
52
  };
51
53
  });
52
54
  }, [extendedOpenGlOptions, openGlOption, setOpenGlOption]);
53
- return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [renderMode === 'still' ? null : ((0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting, { min: minConcurrency, max: maxConcurrency, step: 1, name: "Concurrency", formatter: (w) => `${w}x`, onValueChanged: setConcurrency, value: concurrency })), (0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting
55
+ const x264PresetOptions = (0, react_1.useMemo)(() => {
56
+ return client_1.BrowserSafeApis.x264PresetOptions.map((option) => {
57
+ return {
58
+ label: (0, presets_labels_1.labelx264Preset)(option),
59
+ onClick: () => setx264Preset(option),
60
+ key: option,
61
+ selected: x264Preset === option,
62
+ type: 'item',
63
+ id: option,
64
+ keyHint: null,
65
+ leftItem: null,
66
+ quickSwitcherLabel: null,
67
+ subMenu: null,
68
+ value: option,
69
+ };
70
+ });
71
+ }, [setx264Preset, x264Preset]);
72
+ return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [renderMode === 'video' && codec === 'h264' ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "x264 Preset" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: x264Preset, selectedId: x264Preset, values: x264PresetOptions }) })] })) : null, renderMode === 'still' ? null : ((0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting, { min: minConcurrency, max: maxConcurrency, step: 1, name: "Concurrency", formatter: (w) => `${w}x`, onValueChanged: setConcurrency, value: concurrency })), (0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting
54
73
  // Also appears in packages/renderer/src/validate-puppeteer-timeout.ts
55
74
  , {
56
75
  // Also appears in packages/renderer/src/validate-puppeteer-timeout.ts
@@ -75,6 +75,6 @@ const RenderModalBasic = ({ renderMode, imageFormatOptions, outName, codec, setV
75
75
  const onValueChange = (0, react_1.useCallback)((e) => {
76
76
  setOutName(e.target.value);
77
77
  }, [setOutName]);
78
- return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [renderMode === 'still' ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Format" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: imageFormatOptions, needsWrapping: true }) })] })) : ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.label, children: ["Codec", (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(InfoBubble_1.InfoBubble, { title: "Learn more about this option", children: (0, jsx_runtime_1.jsx)(OptionExplainer_1.OptionExplainer, { option: client_1.BrowserSafeApis.options.videoCodecOption }) })] }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: videoCodecOptions, selectedId: codec, title: "Codec" }) })] })), renderMode === 'still' && resolvedComposition.durationInFrames > 1 ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Frame" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(RemInput_1.RightAlignInput, { children: (0, 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 }) }) })] })) : null, renderMode === 'video' && codec === 'prores' ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "ProRes profile" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: proResProfile, selectedId: proResProfile, values: proResProfileOptions }) })] })) : null, renderMode === 'still' ? null : ((0, jsx_runtime_1.jsx)(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame })), (0, jsx_runtime_1.jsx)(RenderModalInput_1.RenderModalInput, { existence: existence, inputStyle: layout_2.input, outName: outName, onValueChange: onValueChange, validationMessage: validationMessage })] }));
78
+ return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [renderMode === 'still' ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Format" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: imageFormatOptions, needsWrapping: true }) })] })) : ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.label, children: ["Codec", (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(InfoBubble_1.InfoBubble, { title: "Learn more about this option", children: (0, jsx_runtime_1.jsx)(OptionExplainer_1.OptionExplainer, { option: client_1.BrowserSafeApis.options.videoCodecOption }) })] }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: videoCodecOptions, selectedId: codec, title: "Codec" }) })] })), renderMode === 'still' && resolvedComposition.durationInFrames > 1 ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Frame" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(RemInput_1.RightAlignInput, { children: (0, 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 }) }) })] })) : null, renderMode === 'video' && codec === 'prores' ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "ProRes profile" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: 'proResProfile', selectedId: proResProfile, values: proResProfileOptions }) })] })) : null, renderMode === 'still' ? null : ((0, jsx_runtime_1.jsx)(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame })), (0, jsx_runtime_1.jsx)(RenderModalInput_1.RenderModalInput, { existence: existence, inputStyle: layout_2.input, outName: outName, onValueChange: onValueChange, validationMessage: validationMessage })] }));
79
79
  };
80
80
  exports.RenderModalBasic = RenderModalBasic;
@@ -58,7 +58,7 @@ const ZodDiscriminatedUnionEditor = ({ schema, setValue, showSaveButton, saving,
58
58
  return {
59
59
  discriminator: typedSchema.discriminator,
60
60
  markup: ((0, jsx_runtime_1.jsxs)(Fieldset_1.Fieldset, { shouldPad: mayPad, success: true, children: [(0, jsx_runtime_1.jsx)(SchemaLabel_1.SchemaLabel, { isDefaultValue: localValue.value[typedSchema.discriminator] ===
61
- defaultValue[typedSchema.discriminator], jsonPath: [...jsonPath, typedSchema.discriminator], onRemove: onRemove, onReset: reset, onSave: save, saveDisabledByParent: saveDisabledByParent, saving: saving, showSaveButton: showSaveButton, suffix: null, valid: localValue.zodValidation.success }), (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: "Select type", values: comboBoxValues, selectedId: value[typedSchema.discriminator] })] })),
61
+ defaultValue[typedSchema.discriminator], jsonPath: [...jsonPath, typedSchema.discriminator], onRemove: onRemove, onReset: reset, onSave: save, saveDisabledByParent: saveDisabledByParent, saving: saving, showSaveButton: showSaveButton, suffix: null, valid: localValue.zodValidation.success }), (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: "Select type", values: comboBoxValues, selectedId: value[typedSchema.discriminator] })] }, 'replacement')),
62
62
  };
63
63
  }, [
64
64
  comboBoxValues,
@@ -1,2 +1,2 @@
1
1
  import type { Codec } from '@remotion/renderer';
2
- export declare const humanReadableCodec: (codec: Codec) => "GIF" | "AAC" | "MP3" | "H.264" | "H.264 Matroska" | "H.265" | "ProRes" | "WebM VP8" | "WebM VP9" | "Waveform" | undefined;
2
+ export declare const humanReadableCodec: (codec: Codec) => "AAC" | "MP3" | "GIF" | "H.264" | "H.264 Matroska" | "H.265" | "ProRes" | "WebM VP8" | "WebM VP9" | "Waveform" | undefined;
@@ -1,4 +1,4 @@
1
- import type { AudioCodec, Codec, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, Codec, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import type { RenderJob } from '../../../preview-server/render-queue/job';
3
3
  import type { RequiredChromiumOptions } from '../../../required-chromium-options';
4
4
  import type { EnumPath } from '../RenderModal/SchemaEditor/extract-enum-json-paths';
@@ -15,7 +15,7 @@ export declare const addStillRenderJob: ({ compositionId, outName, imageFormat,
15
15
  envVariables: Record<string, string>;
16
16
  inputProps: Record<string, unknown>;
17
17
  }) => Promise<undefined>;
18
- export declare const addVideoRenderJob: ({ compositionId, outName, imageFormat, jpegQuality, scale, verbose, codec, concurrency, crf, startFrame, endFrame, muted, enforceAudioTrack, proResProfile, pixelFormat, audioBitrate, videoBitrate, everyNthFrame, numberOfGifLoops, delayRenderTimeout, audioCodec, disallowParallelEncoding, chromiumOptions, envVariables, inputProps, }: {
18
+ export declare const addVideoRenderJob: ({ compositionId, outName, imageFormat, jpegQuality, scale, verbose, codec, concurrency, crf, startFrame, endFrame, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, audioBitrate, videoBitrate, everyNthFrame, numberOfGifLoops, delayRenderTimeout, audioCodec, disallowParallelEncoding, chromiumOptions, envVariables, inputProps, }: {
19
19
  compositionId: string;
20
20
  outName: string;
21
21
  imageFormat: VideoImageFormat;
@@ -30,6 +30,7 @@ export declare const addVideoRenderJob: ({ compositionId, outName, imageFormat,
30
30
  muted: boolean;
31
31
  enforceAudioTrack: boolean;
32
32
  proResProfile: ProResProfile | null;
33
+ x264Preset: X264Preset | null;
33
34
  pixelFormat: PixelFormat;
34
35
  audioBitrate: string | null;
35
36
  videoBitrate: string | null;
@@ -47,7 +47,7 @@ const addStillRenderJob = ({ compositionId, outName, imageFormat, jpegQuality, f
47
47
  });
48
48
  };
49
49
  exports.addStillRenderJob = addStillRenderJob;
50
- const addVideoRenderJob = ({ compositionId, outName, imageFormat, jpegQuality, scale, verbose, codec, concurrency, crf, startFrame, endFrame, muted, enforceAudioTrack, proResProfile, pixelFormat, audioBitrate, videoBitrate, everyNthFrame, numberOfGifLoops, delayRenderTimeout, audioCodec, disallowParallelEncoding, chromiumOptions, envVariables, inputProps, }) => {
50
+ const addVideoRenderJob = ({ compositionId, outName, imageFormat, jpegQuality, scale, verbose, codec, concurrency, crf, startFrame, endFrame, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, audioBitrate, videoBitrate, everyNthFrame, numberOfGifLoops, delayRenderTimeout, audioCodec, disallowParallelEncoding, chromiumOptions, envVariables, inputProps, }) => {
51
51
  return callApi('/api/render', {
52
52
  compositionId,
53
53
  type: 'video',
@@ -64,6 +64,7 @@ const addVideoRenderJob = ({ compositionId, outName, imageFormat, jpegQuality, s
64
64
  muted,
65
65
  enforceAudioTrack,
66
66
  proResProfile,
67
+ x264Preset,
67
68
  pixelFormat,
68
69
  audioBitrate,
69
70
  videoBitrate,
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ type SidebarPanel = 'input-props' | 'renders';
3
+ export declare const persistSelectedPanel: (panel: SidebarPanel) => void;
4
+ export declare const rightSidebarTabs: React.RefObject<{
5
+ selectRendersPanel: () => void;
6
+ }>;
7
+ export declare const RightPanel: React.FC<{}>;
8
+ export {};
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RightPanel = exports.rightSidebarTabs = exports.persistSelectedPanel = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const remotion_1 = require("remotion");
7
+ const ShortcutHint_1 = require("../../preview-server/error-overlay/remotion-overlay/ShortcutHint");
8
+ const colors_1 = require("../helpers/colors");
9
+ const DataEditor_1 = require("./RenderModal/DataEditor");
10
+ const deep_equal_1 = require("./RenderModal/SchemaEditor/deep-equal");
11
+ const RenderQueue_1 = require("./RenderQueue");
12
+ const RendersTab_1 = require("./RendersTab");
13
+ const Tabs_1 = require("./Tabs");
14
+ const container = {
15
+ height: '100%',
16
+ width: '100%',
17
+ position: 'absolute',
18
+ display: 'flex',
19
+ flexDirection: 'column',
20
+ };
21
+ const circle = {
22
+ width: 8,
23
+ height: 8,
24
+ borderRadius: 4,
25
+ };
26
+ const localStorageKey = 'remotion.sidebarPanel';
27
+ const getSelectedPanel = () => {
28
+ const panel = localStorage.getItem(localStorageKey);
29
+ if (panel === 'renders') {
30
+ return 'renders';
31
+ }
32
+ return 'input-props';
33
+ };
34
+ const tabsContainer = {
35
+ backgroundColor: colors_1.BACKGROUND,
36
+ };
37
+ const persistSelectedPanel = (panel) => {
38
+ localStorage.setItem(localStorageKey, panel);
39
+ };
40
+ exports.persistSelectedPanel = persistSelectedPanel;
41
+ exports.rightSidebarTabs = (0, react_1.createRef)();
42
+ const RightPanel = () => {
43
+ const { props, updateProps } = (0, react_1.useContext)(remotion_1.Internals.EditorPropsContext);
44
+ const [saving, setSaving] = (0, react_1.useState)(false);
45
+ const [panel, setPanel] = (0, react_1.useState)(() => getSelectedPanel());
46
+ const onCompositionsSelected = (0, react_1.useCallback)(() => {
47
+ setPanel('input-props');
48
+ (0, exports.persistSelectedPanel)('input-props');
49
+ }, []);
50
+ const onRendersSelected = (0, react_1.useCallback)(() => {
51
+ setPanel('renders');
52
+ (0, exports.persistSelectedPanel)('renders');
53
+ }, []);
54
+ (0, react_1.useImperativeHandle)(exports.rightSidebarTabs, () => {
55
+ return {
56
+ selectRendersPanel: () => {
57
+ setPanel('renders');
58
+ (0, exports.persistSelectedPanel)('renders');
59
+ },
60
+ };
61
+ }, []);
62
+ const { compositions, currentComposition } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
63
+ const circleStyle = (0, react_1.useMemo)(() => {
64
+ const onTabColor = saving ? colors_1.LIGHT_TEXT : 'white';
65
+ return {
66
+ ...circle,
67
+ backgroundColor: panel === 'input-props' ? onTabColor : colors_1.LIGHT_TEXT,
68
+ cursor: 'help',
69
+ };
70
+ }, [panel, saving]);
71
+ const composition = (0, react_1.useMemo)(() => {
72
+ for (const comp of compositions) {
73
+ if (comp.id === currentComposition) {
74
+ return comp;
75
+ }
76
+ }
77
+ return null;
78
+ }, [compositions, currentComposition]);
79
+ const saveToolTip = (0, react_1.useMemo)(() => {
80
+ return process.env.KEYBOARD_SHORTCUTS_ENABLED
81
+ ? `Save using ${ShortcutHint_1.cmdOrCtrlCharacter}+S`
82
+ : 'There are unsaved changes';
83
+ }, []);
84
+ const setInputProps = (0, react_1.useCallback)((newProps) => {
85
+ if (composition === null) {
86
+ return;
87
+ }
88
+ updateProps({
89
+ id: composition.id,
90
+ defaultProps: composition.defaultProps,
91
+ newProps,
92
+ });
93
+ }, [composition, updateProps]);
94
+ const actualProps = (0, react_1.useMemo)(() => {
95
+ var _a, _b;
96
+ if (composition === null) {
97
+ return {};
98
+ }
99
+ return (_b = (_a = props[composition.id]) !== null && _a !== void 0 ? _a : composition.defaultProps) !== null && _b !== void 0 ? _b : {};
100
+ }, [composition, props]);
101
+ const unsavedChangesExist = (0, react_1.useMemo)(() => {
102
+ if (composition === null || composition.defaultProps === undefined) {
103
+ return false;
104
+ }
105
+ return !(0, deep_equal_1.deepEqual)(composition.defaultProps, actualProps);
106
+ }, [actualProps, composition]);
107
+ if (composition === null) {
108
+ return null;
109
+ }
110
+ return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsx)("div", { style: tabsContainer, children: (0, jsx_runtime_1.jsxs)(Tabs_1.Tabs, { children: [(0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { selected: panel === 'input-props', onClick: onCompositionsSelected, style: { justifyContent: 'space-between' }, children: ["Props", unsavedChangesExist ? ((0, jsx_runtime_1.jsx)("div", { title: saveToolTip, style: circleStyle })) : null] }), (0, jsx_runtime_1.jsx)(RendersTab_1.RendersTab, { onClick: onRendersSelected, selected: panel === 'renders' })] }) }), panel === 'renders' ? ((0, jsx_runtime_1.jsx)(RenderQueue_1.RenderQueue, {})) : ((0, jsx_runtime_1.jsx)(DataEditor_1.DataEditor, { unresolvedComposition: composition, inputProps: actualProps, setInputProps: setInputProps, mayShowSaveButton: true, propsEditType: "default-props", saving: saving, setSaving: setSaving }, composition.id))] }));
111
+ };
112
+ exports.RightPanel = RightPanel;
@@ -61,6 +61,7 @@ const SidebarRenderButton = ({ composition, visible }) => {
61
61
  initialMuted: defaults.muted,
62
62
  initialEnforceAudioTrack: defaults.enforceAudioTrack,
63
63
  initialProResProfile: defaults.proResProfile,
64
+ initialx264Preset: defaults.x264Preset,
64
65
  initialPixelFormat: defaults.pixelFormat,
65
66
  initialAudioBitrate: defaults.audioBitrate,
66
67
  initialVideoBitrate: defaults.videoBitrate,
@@ -12,6 +12,7 @@ const setCurrentVideoId = (id) => {
12
12
  };
13
13
  exports.setCurrentVideoId = setCurrentVideoId;
14
14
  const setUnsavedProps = (unsaved) => {
15
+ window.remotion_unsavedProps = unsaved;
15
16
  unsavedProps = unsaved;
16
17
  };
17
18
  exports.setUnsavedProps = setUnsavedProps;
@@ -0,0 +1,2 @@
1
+ import type { X264Preset } from '@remotion/renderer';
2
+ export declare const labelx264Preset: (profile: X264Preset) => "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.labelx264Preset = void 0;
4
+ const labelx264Preset = (profile) => {
5
+ if (profile === 'ultrafast') {
6
+ return 'ultrafast';
7
+ }
8
+ if (profile === 'superfast') {
9
+ return 'superfast';
10
+ }
11
+ if (profile === 'veryfast') {
12
+ return 'veryfast';
13
+ }
14
+ if (profile === 'faster') {
15
+ return 'faster';
16
+ }
17
+ if (profile === 'fast') {
18
+ return 'fast';
19
+ }
20
+ if (profile === 'medium') {
21
+ return 'medium';
22
+ }
23
+ if (profile === 'slow') {
24
+ return 'slow';
25
+ }
26
+ if (profile === 'slower') {
27
+ return 'slower';
28
+ }
29
+ if (profile === 'veryslow') {
30
+ return 'veryslow';
31
+ }
32
+ if (profile === 'placebo') {
33
+ return 'placebo';
34
+ }
35
+ throw new TypeError(`Unknown x264 preset: ${profile}`);
36
+ };
37
+ exports.labelx264Preset = labelx264Preset;
@@ -1,4 +1,4 @@
1
- import type { AudioCodec, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import type React from 'react';
3
3
  import type { QuickSwitcherMode } from '../components/QuickSwitcher/NoResults';
4
4
  import type { RenderType } from '../components/RenderModal/RenderModalAdvanced';
@@ -22,6 +22,7 @@ export type RenderModalState = {
22
22
  initialMuted: boolean;
23
23
  initialEnforceAudioTrack: boolean;
24
24
  initialProResProfile: ProResProfile;
25
+ initialx264Preset: X264Preset;
25
26
  initialPixelFormat: PixelFormat;
26
27
  initialVideoBitrate: string | null;
27
28
  initialAudioBitrate: string | null;
@@ -16,6 +16,7 @@ export declare const getCliOptions: (options: {
16
16
  crf: import("@remotion/renderer").Crf | null;
17
17
  pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
18
18
  proResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined;
19
+ x264Preset: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | undefined;
19
20
  everyNthFrame: number;
20
21
  numberOfGifLoops: import("./config/number-of-gif-loops").Loop;
21
22
  stillFrame: number;
@@ -33,5 +34,5 @@ export declare const getCliOptions: (options: {
33
34
  videoBitrate: string | null;
34
35
  height: number | null;
35
36
  width: number | null;
36
- configFileImageFormat: "png" | "jpeg" | "none" | undefined;
37
+ configFileImageFormat: "none" | "png" | "jpeg" | undefined;
37
38
  }>;
@@ -44,6 +44,10 @@ const getProResProfile = () => {
44
44
  const proResProfile = config_1.ConfigInternals.getProResProfile();
45
45
  return proResProfile;
46
46
  };
47
+ const getx264Preset = () => {
48
+ const x264Preset = config_1.ConfigInternals.getPresetProfile();
49
+ return x264Preset;
50
+ };
47
51
  const getAndValidateBrowser = async (browserExecutable) => {
48
52
  const browser = getBrowser();
49
53
  try {
@@ -71,6 +75,7 @@ const getCliOptions = async (options) => {
71
75
  const videoBitrate = config_1.ConfigInternals.getVideoBitrate();
72
76
  const pixelFormat = config_1.ConfigInternals.getPixelFormat();
73
77
  const proResProfile = getProResProfile();
78
+ const x264Preset = getx264Preset();
74
79
  const browserExecutable = config_1.ConfigInternals.getBrowserExecutable();
75
80
  const scale = config_1.ConfigInternals.getScale();
76
81
  const port = config_1.ConfigInternals.getServerPort();
@@ -99,6 +104,7 @@ const getCliOptions = async (options) => {
99
104
  crf,
100
105
  pixelFormat,
101
106
  proResProfile,
107
+ x264Preset,
102
108
  everyNthFrame,
103
109
  numberOfGifLoops,
104
110
  stillFrame: config_1.ConfigInternals.getStillFrame(),
package/dist/index.d.ts CHANGED
@@ -101,6 +101,7 @@ export declare const CliInternals: {
101
101
  crf: import("@remotion/renderer").Crf | null;
102
102
  pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
103
103
  proResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined;
104
+ x264Preset: "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo" | undefined;
104
105
  everyNthFrame: number;
105
106
  numberOfGifLoops: import("./config/number-of-gif-loops").Loop;
106
107
  stillFrame: number;
@@ -118,7 +119,7 @@ export declare const CliInternals: {
118
119
  videoBitrate: string | null;
119
120
  height: number | null;
120
121
  width: number | null;
121
- configFileImageFormat: "png" | "jpeg" | "none" | undefined;
122
+ configFileImageFormat: "none" | "png" | "jpeg" | undefined;
122
123
  }>;
123
124
  loadConfig: (remotionRoot: string) => Promise<string | null>;
124
125
  initializeCli: (remotionRoot: string) => Promise<void>;
@@ -127,8 +128,9 @@ export declare const CliInternals: {
127
128
  parsedCli: {
128
129
  "browser-executable": import("@remotion/renderer").BrowserExecutable;
129
130
  "pixel-format": "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
130
- "image-format": "png" | "jpeg" | "pdf" | "webp" | "none";
131
+ "image-format": "none" | "png" | "jpeg" | "pdf" | "webp";
131
132
  "prores-profile": "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy";
133
+ "x264-preset": "medium" | "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "slow" | "slower" | "veryslow" | "placebo";
132
134
  "bundle-cache": string;
133
135
  "env-file": string;
134
136
  "ignore-certificate-errors": string;
@@ -192,7 +194,7 @@ export declare const CliInternals: {
192
194
  downloadName: string | null;
193
195
  outName: string | null;
194
196
  configImageFormat: "png" | "jpeg" | "pdf" | "webp" | null;
195
- cliFlag: "png" | "jpeg" | "pdf" | "webp" | "none" | null;
197
+ cliFlag: "none" | "png" | "jpeg" | "pdf" | "webp" | null;
196
198
  isLambda: boolean;
197
199
  fromUi: "png" | "jpeg" | "pdf" | "webp" | null;
198
200
  }) => {
@@ -207,8 +209,8 @@ export declare const CliInternals: {
207
209
  };
208
210
  getVideoImageFormat: ({ codec, uiImageFormat, }: {
209
211
  codec: import("@remotion/renderer").CodecOrUndefined;
210
- uiImageFormat: "png" | "jpeg" | "none" | null;
211
- }) => "png" | "jpeg" | "none";
212
+ uiImageFormat: "none" | "png" | "jpeg" | null;
213
+ }) => "none" | "png" | "jpeg";
212
214
  printCompositions: (compositions: import("remotion").VideoConfig[]) => void;
213
215
  getFinalOutputCodec: ({ cliFlag, configFile, downloadName, outName, uiCodec, }: {
214
216
  cliFlag: import("@remotion/renderer").CodecOrUndefined;
@@ -1,9 +1,10 @@
1
- import type { AudioCodec, BrowserExecutable, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, BrowserExecutable, Codec, OpenGlRenderer, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  type CommandLineOptions = {
3
3
  ['browser-executable']: BrowserExecutable;
4
4
  ['pixel-format']: PixelFormat;
5
5
  ['image-format']: VideoImageFormat | StillImageFormat;
6
6
  ['prores-profile']: ProResProfile;
7
+ ['x264-preset']: X264Preset;
7
8
  ['bundle-cache']: string;
8
9
  ['env-file']: string;
9
10
  ['ignore-certificate-errors']: string;
@@ -105,6 +105,9 @@ const parseCommandLine = () => {
105
105
  if (exports.parsedCli['prores-profile']) {
106
106
  config_1.Config.setProResProfile(String(exports.parsedCli['prores-profile']));
107
107
  }
108
+ if (exports.parsedCli['x264-preset']) {
109
+ config_1.Config.setX264Preset(String(exports.parsedCli['x264-preset']));
110
+ }
108
111
  if (exports.parsedCli.overwrite) {
109
112
  config_1.Config.setOverwriteOutput(exports.parsedCli.overwrite);
110
113
  }
@@ -11,5 +11,5 @@ type Range = {
11
11
  type Ranges = Range[] & {
12
12
  type?: string;
13
13
  };
14
- export declare function parseRange(size: number, str: string | string[]): -1 | Ranges | -2;
14
+ export declare function parseRange(size: number, str: string | string[]): -1 | -2 | Ranges;
15
15
  export {};
@@ -42,6 +42,7 @@ const crashWithFrames = (crash) => (error) => {
42
42
  if (didHookOrderChange && !justRefreshedBecauseOfHooks) {
43
43
  // eslint-disable-next-line no-console
44
44
  console.log('Hook order changed. Reloading app...');
45
+ window.remotion_unsavedProps = false;
45
46
  window.location.reload();
46
47
  }
47
48
  else {
@@ -3,10 +3,5 @@
3
3
  * https://github.com/webpack-contrib/webpack-hot-middleware#readme
4
4
  * and rewritten in TypeScript. This file is MIT licensed
5
5
  */
6
- /**
7
- * Based heavily on https://github.com/webpack/webpack/blob/
8
- * c0afdf9c6abc1dd70707c594e473802a566f7b6e/hot/only-dev-server.js
9
- * Original copyright Tobias Koppers @sokra (MIT license)
10
- */
11
6
  import type { HotMiddlewareOptions, ModuleMap } from './types';
12
7
  export declare const processUpdate: (hash: string | undefined, moduleMap: ModuleMap, options: HotMiddlewareOptions) => void;
@@ -7,6 +7,12 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.processUpdate = void 0;
10
+ /**
11
+ * Based heavily on https://github.com/webpack/webpack/blob/
12
+ * c0afdf9c6abc1dd70707c594e473802a566f7b6e/hot/only-dev-server.js
13
+ * Original copyright Tobias Koppers @sokra (MIT license)
14
+ */
15
+ const NotificationCenter_1 = require("../../editor/components/Notifications/NotificationCenter");
10
16
  if (!__webpack_module__.hot) {
11
17
  throw new Error('[Fast refresh] Hot Module Replacement is disabled.');
12
18
  }
@@ -128,16 +134,29 @@ const processUpdate = function (hash, moduleMap, options) {
128
134
  }
129
135
  if (options.warn) {
130
136
  console.warn('[Fast refresh] Update check failed: ' + (err.stack || err.message));
131
- window.location.reload();
137
+ if (!window.remotion_unsavedProps) {
138
+ window.location.reload();
139
+ }
132
140
  }
133
141
  }
134
142
  function performReload() {
143
+ var _a;
135
144
  if (!reload) {
136
145
  return;
137
146
  }
138
147
  if (options.warn)
139
148
  console.warn('[Fast refresh] Reloading page');
140
- window.location.reload();
149
+ if (window.remotion_unsavedProps) {
150
+ (_a = NotificationCenter_1.notificationCenter.current) === null || _a === void 0 ? void 0 : _a.addNotification({
151
+ id: 'random',
152
+ content: 'Fast refresh needs to reload the page, but you have unsaved props. Save then reload the page to apply changes.',
153
+ created: new Date().getMilliseconds(),
154
+ duration: 1,
155
+ });
156
+ }
157
+ else {
158
+ window.location.reload();
159
+ }
141
160
  }
142
161
  };
143
162
  exports.processUpdate = processUpdate;
@@ -1,4 +1,4 @@
1
- import type { AudioCodec, Codec, makeCancelSignal, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, Codec, makeCancelSignal, PixelFormat, ProResProfile, StillImageFormat, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import type { EnumPath } from '../../editor/components/RenderModal/SchemaEditor/extract-enum-json-paths';
3
3
  import type { AggregateRenderProgress } from '../../progress-types';
4
4
  import type { RequiredChromiumOptions } from '../../required-chromium-options';
@@ -43,6 +43,7 @@ type RenderJobDynamicFields = ({
43
43
  muted: boolean;
44
44
  enforceAudioTrack: boolean;
45
45
  proResProfile: ProResProfile | null;
46
+ x264Preset: X264Preset | null;
46
47
  pixelFormat: PixelFormat;
47
48
  audioBitrate: string | null;
48
49
  videoBitrate: string | null;
@@ -88,6 +89,7 @@ type AddRenderRequestDynamicFields = {
88
89
  muted: boolean;
89
90
  enforceAudioTrack: boolean;
90
91
  proResProfile: ProResProfile | null;
92
+ x264Preset: X264Preset | null;
91
93
  pixelFormat: PixelFormat;
92
94
  audioBitrate: string | null;
93
95
  videoBitrate: string | null;
@@ -4,7 +4,7 @@ exports.makeRetryPayload = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const get_default_video_contexts_1 = require("./get-default-video-contexts");
6
6
  const makeRetryPayload = (job) => {
7
- var _a, _b, _c;
7
+ var _a, _b, _c, _d;
8
8
  const defaults = window.remotion_renderDefaults;
9
9
  if (!defaults) {
10
10
  throw new Error('defaults not set');
@@ -33,6 +33,7 @@ const makeRetryPayload = (job) => {
33
33
  initialMuted: defaults.muted,
34
34
  initialEnforceAudioTrack: defaults.enforceAudioTrack,
35
35
  initialProResProfile: defaults.proResProfile,
36
+ initialx264Preset: defaults.x264Preset,
36
37
  initialPixelFormat: defaults.pixelFormat,
37
38
  initialAudioBitrate: defaults.audioBitrate,
38
39
  initialVideoBitrate: defaults.videoBitrate,
@@ -74,6 +75,7 @@ const makeRetryPayload = (job) => {
74
75
  initialRenderType,
75
76
  initialVideoCodecForVideoTab: initialVideoCodec,
76
77
  initialProResProfile: (_c = job.proResProfile) !== null && _c !== void 0 ? _c : defaults.proResProfile,
78
+ initialx264Preset: (_d = job.x264Preset) !== null && _d !== void 0 ? _d : defaults.x264Preset,
77
79
  initialPixelFormat: job.pixelFormat,
78
80
  initialAudioBitrate: job.audioBitrate,
79
81
  initialVideoBitrate: job.videoBitrate,
@@ -5,7 +5,7 @@ const convert_entry_point_to_serve_url_1 = require("../../convert-entry-point-to
5
5
  const get_cli_options_1 = require("../../get-cli-options");
6
6
  const render_1 = require("../../render-flows/render");
7
7
  const processVideoJob = async ({ job, remotionRoot, entryPoint, onProgress, addCleanupCallback, }) => {
8
- var _a, _b;
8
+ var _a, _b, _c;
9
9
  if (job.type !== 'video') {
10
10
  throw new Error('Expected video job');
11
11
  }
@@ -53,6 +53,7 @@ const processVideoJob = async ({ job, remotionRoot, entryPoint, onProgress, addC
53
53
  muted: job.muted,
54
54
  enforceAudioTrack: job.enforceAudioTrack,
55
55
  proResProfile: (_b = job.proResProfile) !== null && _b !== void 0 ? _b : undefined,
56
+ x264Preset: (_c = job.x264Preset) !== null && _c !== void 0 ? _c : undefined,
56
57
  pixelFormat: job.pixelFormat,
57
58
  videoBitrate: job.videoBitrate,
58
59
  numberOfGifLoops: job.numberOfGifLoops,
@@ -32,6 +32,7 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, }) => {
32
32
  muted: input.muted,
33
33
  enforceAudioTrack: input.enforceAudioTrack,
34
34
  proResProfile: input.proResProfile,
35
+ x264Preset: input.x264Preset,
35
36
  pixelFormat: input.pixelFormat,
36
37
  audioBitrate: input.audioBitrate,
37
38
  videoBitrate: input.videoBitrate,
@@ -28,7 +28,7 @@ const static404 = (response) => {
28
28
  response.end('The static/ prefix has been changed, this URL is no longer valid.');
29
29
  };
30
30
  const handleFallback = async ({ remotionRoot, hash, response, getCurrentInputProps, getEnvVariables, publicDir, }) => {
31
- var _a, _b;
31
+ var _a, _b, _c;
32
32
  const [edit] = await editorGuess;
33
33
  const displayName = (0, open_in_editor_1.getDisplayNameForEditor)(edit ? edit.command : null);
34
34
  const defaultJpegQuality = config_1.ConfigInternals.getJpegQuality();
@@ -40,6 +40,7 @@ const handleFallback = async ({ remotionRoot, hash, response, getCurrentInputPro
40
40
  const enforceAudioTrack = config_1.ConfigInternals.getEnforceAudioTrack();
41
41
  const pixelFormat = config_1.ConfigInternals.getPixelFormat();
42
42
  const proResProfile = (_a = config_1.ConfigInternals.getProResProfile()) !== null && _a !== void 0 ? _a : 'hq';
43
+ const x264Preset = (_b = config_1.ConfigInternals.getPresetProfile()) !== null && _b !== void 0 ? _b : 'medium';
43
44
  const audioBitrate = config_1.ConfigInternals.getAudioBitrate();
44
45
  const videoBitrate = config_1.ConfigInternals.getVideoBitrate();
45
46
  const everyNthFrame = config_1.ConfigInternals.getEveryNthFrame();
@@ -67,7 +68,7 @@ const handleFallback = async ({ remotionRoot, hash, response, getCurrentInputPro
67
68
  remotionRoot,
68
69
  studioServerCommand: packageManager === 'unknown' ? null : packageManager.startCommand,
69
70
  renderQueue: (0, queue_1.getRenderQueue)(),
70
- numberOfAudioTags: (_b = parse_command_line_1.parsedCli['number-of-shared-audio-tags']) !== null && _b !== void 0 ? _b : (0, number_of_shared_audio_tags_1.getNumberOfSharedAudioTags)(),
71
+ numberOfAudioTags: (_c = parse_command_line_1.parsedCli['number-of-shared-audio-tags']) !== null && _c !== void 0 ? _c : (0, number_of_shared_audio_tags_1.getNumberOfSharedAudioTags)(),
71
72
  publicFiles: (0, public_folder_1.getFiles)(),
72
73
  includeFavicon: true,
73
74
  title: 'Remotion Studio',
@@ -84,6 +85,7 @@ const handleFallback = async ({ remotionRoot, hash, response, getCurrentInputPro
84
85
  muted,
85
86
  enforceAudioTrack,
86
87
  proResProfile,
88
+ x264Preset,
87
89
  pixelFormat,
88
90
  audioBitrate,
89
91
  videoBitrate,
@@ -1,7 +1,7 @@
1
- import type { AudioCodec, Browser, BrowserExecutable, CancelSignal, ChromiumOptions, Codec, Crf, FfmpegOverrideFn, FrameRange, LogLevel, PixelFormat, ProResProfile, VideoImageFormat } from '@remotion/renderer';
1
+ import type { AudioCodec, Browser, BrowserExecutable, CancelSignal, ChromiumOptions, Codec, Crf, FfmpegOverrideFn, FrameRange, LogLevel, PixelFormat, ProResProfile, VideoImageFormat, X264Preset } from '@remotion/renderer';
2
2
  import type { Loop } from '../config/number-of-gif-loops';
3
3
  import type { JobProgressCallback } from '../preview-server/render-queue/job';
4
- export declare const renderVideoFlow: ({ remotionRoot, fullEntryPoint, indent, logLevel, browserExecutable, browser, chromiumOptions, scale, shouldOutputImageSequence, publicDir, envVariables, puppeteerTimeout, port, height, width, remainingArgs, compositionIdFromUi, entryPointReason, overwrite, quiet, concurrency, frameRange, everyNthFrame, outputLocationFromUI, jpegQuality, onProgress, addCleanupCallback, cancelSignal, crf, uiCodec, uiImageFormat, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, pixelFormat, videoBitrate, numberOfGifLoops, audioCodec, serializedInputPropsWithCustomSchema, disallowParallelEncoding, }: {
4
+ export declare const renderVideoFlow: ({ remotionRoot, fullEntryPoint, indent, logLevel, browserExecutable, browser, chromiumOptions, scale, shouldOutputImageSequence, publicDir, envVariables, puppeteerTimeout, port, height, width, remainingArgs, compositionIdFromUi, entryPointReason, overwrite, quiet, concurrency, frameRange, everyNthFrame, outputLocationFromUI, jpegQuality, onProgress, addCleanupCallback, cancelSignal, crf, uiCodec, uiImageFormat, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, videoBitrate, numberOfGifLoops, audioCodec, serializedInputPropsWithCustomSchema, disallowParallelEncoding, }: {
5
5
  remotionRoot: string;
6
6
  fullEntryPoint: string;
7
7
  entryPointReason: string;
@@ -40,6 +40,7 @@ export declare const renderVideoFlow: ({ remotionRoot, fullEntryPoint, indent, l
40
40
  muted: boolean;
41
41
  enforceAudioTrack: boolean;
42
42
  proResProfile: ProResProfile | undefined;
43
+ x264Preset: X264Preset | undefined;
43
44
  pixelFormat: PixelFormat;
44
45
  numberOfGifLoops: Loop;
45
46
  audioCodec: AudioCodec | null;
@@ -47,7 +47,7 @@ const setup_cache_1 = require("../setup-cache");
47
47
  const should_use_non_overlaying_logger_1 = require("../should-use-non-overlaying-logger");
48
48
  const truthy_1 = require("../truthy");
49
49
  const user_passed_output_location_1 = require("../user-passed-output-location");
50
- const renderVideoFlow = async ({ remotionRoot, fullEntryPoint, indent, logLevel, browserExecutable, browser, chromiumOptions, scale, shouldOutputImageSequence, publicDir, envVariables, puppeteerTimeout, port, height, width, remainingArgs, compositionIdFromUi, entryPointReason, overwrite, quiet, concurrency, frameRange, everyNthFrame, outputLocationFromUI, jpegQuality, onProgress, addCleanupCallback, cancelSignal, crf, uiCodec, uiImageFormat, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, pixelFormat, videoBitrate, numberOfGifLoops, audioCodec, serializedInputPropsWithCustomSchema, disallowParallelEncoding, }) => {
50
+ const renderVideoFlow = async ({ remotionRoot, fullEntryPoint, indent, logLevel, browserExecutable, browser, chromiumOptions, scale, shouldOutputImageSequence, publicDir, envVariables, puppeteerTimeout, port, height, width, remainingArgs, compositionIdFromUi, entryPointReason, overwrite, quiet, concurrency, frameRange, everyNthFrame, outputLocationFromUI, jpegQuality, onProgress, addCleanupCallback, cancelSignal, crf, uiCodec, uiImageFormat, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, videoBitrate, numberOfGifLoops, audioCodec, serializedInputPropsWithCustomSchema, disallowParallelEncoding, }) => {
51
51
  var _a;
52
52
  const downloads = [];
53
53
  if (browserExecutable) {
@@ -268,6 +268,7 @@ const renderVideoFlow = async ({ remotionRoot, fullEntryPoint, indent, logLevel,
268
268
  overwrite,
269
269
  pixelFormat,
270
270
  proResProfile,
271
+ x264Preset,
271
272
  jpegQuality: jpegQuality !== null && jpegQuality !== void 0 ? jpegQuality : renderer_1.RenderInternals.DEFAULT_JPEG_QUALITY,
272
273
  chromiumOptions,
273
274
  timeoutInMilliseconds: puppeteerTimeout,
package/dist/render.js CHANGED
@@ -25,7 +25,7 @@ const render = async (remotionRoot, args) => {
25
25
  log_1.Log.error('--frame flag was passed to the `render` command. This flag only works with the `still` command. Did you mean `--frames`? See reference: https://www.remotion.dev/docs/cli/');
26
26
  process.exit(1);
27
27
  }
28
- const { concurrency, frameRange, shouldOutputImageSequence, overwrite, inputProps, envVariables, jpegQuality, browser, browserExecutable, scale, chromiumOptions, port, everyNthFrame, puppeteerTimeout, publicDir, height, width, crf, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, pixelFormat, videoBitrate, numberOfGifLoops, } = await (0, get_cli_options_1.getCliOptions)({
28
+ const { concurrency, frameRange, shouldOutputImageSequence, overwrite, inputProps, envVariables, jpegQuality, browser, browserExecutable, scale, chromiumOptions, port, everyNthFrame, puppeteerTimeout, publicDir, height, width, crf, ffmpegOverride, audioBitrate, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, videoBitrate, numberOfGifLoops, } = await (0, get_cli_options_1.getCliOptions)({
29
29
  isLambda: false,
30
30
  type: 'series',
31
31
  remotionRoot,
@@ -75,6 +75,7 @@ const render = async (remotionRoot, args) => {
75
75
  muted,
76
76
  enforceAudioTrack,
77
77
  proResProfile,
78
+ x264Preset,
78
79
  pixelFormat,
79
80
  videoBitrate,
80
81
  numberOfGifLoops,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/cli",
3
- "version": "4.0.21",
3
+ "version": "4.0.22",
4
4
  "description": "CLI for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "sideEffects": false,
@@ -35,11 +35,11 @@
35
35
  "prompts": "2.4.1",
36
36
  "semver": "7.5.3",
37
37
  "source-map": "0.6.1",
38
- "@remotion/media-utils": "4.0.21",
39
- "@remotion/player": "4.0.21",
40
- "@remotion/bundler": "4.0.21",
41
- "@remotion/renderer": "4.0.21",
42
- "remotion": "4.0.21"
38
+ "@remotion/bundler": "4.0.22",
39
+ "@remotion/media-utils": "4.0.22",
40
+ "@remotion/renderer": "4.0.22",
41
+ "@remotion/player": "4.0.22",
42
+ "remotion": "4.0.22"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": ">=16.8.0",
@@ -64,8 +64,8 @@
64
64
  "react-dom": "^18.0.0",
65
65
  "vitest": "0.31.1",
66
66
  "zod": "^3.21.4",
67
- "@remotion/zod-types": "4.0.21",
68
- "@remotion/tailwind": "4.0.21"
67
+ "@remotion/zod-types": "4.0.22",
68
+ "@remotion/tailwind": "4.0.22"
69
69
  },
70
70
  "keywords": [
71
71
  "remotion",