From 6b3d8370a78993330d2d4a88816b5734d17bce2e Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Tue, 17 Feb 2026 18:33:13 +0100 Subject: [PATCH 1/6] Migrate `--every-nth-frame` and `--prores-profile` to options system - Create `everyNthFrameOption` and `proResProfileOption` as proper `AnyRemotionOption` definitions - Register both in the options index and export `ProResProfile` type from renderer client - Remove both from `parseCommandLine()` and `getCliOptions()` return value - Update all call sites in cli, lambda, and cloudrun to import options directly - Update docs to use `` Co-authored-by: Cursor --- packages/cli/src/benchmark.ts | 10 ++- packages/cli/src/config/browser-executable.ts | 13 ---- packages/cli/src/config/every-nth-frame.ts | 9 --- packages/cli/src/config/index.ts | 11 ++-- packages/cli/src/config/pixel-format.ts | 16 ----- packages/cli/src/config/prores-profile.ts | 15 ----- packages/cli/src/get-cli-options.ts | 12 ---- packages/cli/src/get-render-defaults.ts | 9 ++- packages/cli/src/parse-command-line.ts | 39 ++--------- packages/cli/src/render.tsx | 10 ++- .../cloudrun/src/cli/commands/render/index.ts | 10 ++- packages/docs/docs/cli/render.mdx | 4 +- packages/docs/docs/cloudrun/cli/render.mdx | 4 +- packages/docs/docs/config.mdx | 9 +-- packages/docs/docs/lambda/cli/render.mdx | 4 +- packages/example/remotion.config.ts | 2 - .../lambda/src/cli/commands/render/render.ts | 10 ++- packages/renderer/src/client.ts | 1 + .../renderer/src/options/every-nth-frame.tsx | 47 ++++++++++++++ packages/renderer/src/options/index.tsx | 4 ++ .../renderer/src/options/prores-profile.tsx | 64 +++++++++++++++++++ 21 files changed, 171 insertions(+), 132 deletions(-) delete mode 100644 packages/cli/src/config/browser-executable.ts delete mode 100644 packages/cli/src/config/every-nth-frame.ts delete mode 100644 packages/cli/src/config/pixel-format.ts delete mode 100644 packages/cli/src/config/prores-profile.ts create mode 100644 packages/renderer/src/options/every-nth-frame.tsx create mode 100644 packages/renderer/src/options/prores-profile.tsx diff --git a/packages/cli/src/benchmark.ts b/packages/cli/src/benchmark.ts index 5f27032ff2c..044962d0c33 100644 --- a/packages/cli/src/benchmark.ts +++ b/packages/cli/src/benchmark.ts @@ -62,6 +62,8 @@ const { keyboardShortcutsOption, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, } = BrowserSafeApis.options; const getValidConcurrency = (cliConcurrency: number | string | null) => { @@ -202,9 +204,7 @@ export const benchmarkCommand = async ( const { inputProps, envVariables, - proResProfile, frameRange: defaultFrameRange, - everyNthFrame, ffmpegOverride, height, width, @@ -224,6 +224,12 @@ export const benchmarkCommand = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const everyNthFrame = everyNthFrameOption.getValue({ + commandLine: parsedCli, + }).value; + const proResProfile = proResProfileOption.getValue({ + commandLine: parsedCli, + }).value; Log.verbose( {indent: false, logLevel}, diff --git a/packages/cli/src/config/browser-executable.ts b/packages/cli/src/config/browser-executable.ts deleted file mode 100644 index f5a3c796022..00000000000 --- a/packages/cli/src/config/browser-executable.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type {BrowserExecutable} from '@remotion/renderer'; - -let currentBrowserExecutablePath: BrowserExecutable = null; - -export const setBrowserExecutable = ( - newBrowserExecutablePath: BrowserExecutable, -) => { - currentBrowserExecutablePath = newBrowserExecutablePath; -}; - -export const getBrowserExecutable = () => { - return currentBrowserExecutablePath; -}; diff --git a/packages/cli/src/config/every-nth-frame.ts b/packages/cli/src/config/every-nth-frame.ts deleted file mode 100644 index 8002d50a5e8..00000000000 --- a/packages/cli/src/config/every-nth-frame.ts +++ /dev/null @@ -1,9 +0,0 @@ -let everyNthFrame = 1; - -export const setEveryNthFrame = (frame: number) => { - everyNthFrame = frame; -}; - -export const getEveryNthFrame = () => { - return everyNthFrame; -}; diff --git a/packages/cli/src/config/index.ts b/packages/cli/src/config/index.ts index 4bd93e47209..1b269b7810d 100644 --- a/packages/cli/src/config/index.ts +++ b/packages/cli/src/config/index.ts @@ -17,7 +17,6 @@ import { getRendererPortFromConfigFileAndCliFlag, getStudioPort, } from './preview-server'; -import {getProResProfile} from './prores-profile'; import {getStillFrame, setStillFrame} from './still-frame'; import {getWebpackCaching} from './webpack-caching'; @@ -49,7 +48,6 @@ import type {Concurrency} from './concurrency'; import {setConcurrency} from './concurrency'; import {getEntryPoint, setEntryPoint} from './entry-point'; import {setDotEnvLocation} from './env-file'; -import {getEveryNthFrame, setEveryNthFrame} from './every-nth-frame'; import { getFfmpegOverrideFunction, setFfmpegOverrideFunction, @@ -63,7 +61,6 @@ import {setOutputLocation} from './output-location'; import type {WebpackOverrideFn} from './override-webpack'; import {overrideWebpackConfig} from './override-webpack'; import {setPort, setRendererPort, setStudioPort} from './preview-server'; -import {setProResProfile} from './prores-profile'; import {getChromiumUserAgent, setChromiumUserAgent} from './user-agent'; import {setWebpackCaching} from './webpack-caching'; import { @@ -122,6 +119,8 @@ const { ipv4Option, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, stillImageFormatOption, videoImageFormatOption, } = BrowserSafeApis.options; @@ -692,7 +691,7 @@ export const Config: FlatConfig = { setEncodingBufferSize: encodingBufferSizeOption.setConfig, setFrameRange, setScale: scaleOption.setConfig, - setEveryNthFrame, + setEveryNthFrame: everyNthFrameOption.setConfig, setNumberOfGifLoops: numberOfGifLoopsOption.setConfig, setMuted: mutedOption.setConfig, setEnforceAudioTrack: enforceAudioOption.setConfig, @@ -703,7 +702,7 @@ export const Config: FlatConfig = { setCodec: videoCodecOption.setConfig, setCrf: crfOption.setConfig, setImageSequence, - setProResProfile, + setProResProfile: proResProfileOption.setConfig, setX264Preset: x264Option.setConfig, setAudioBitrate: audioBitrateOption.setConfig, setVideoBitrate: videoBitrateOption.setConfig, @@ -738,13 +737,11 @@ export const Config: FlatConfig = { export const ConfigInternals = { getRange, getBrowser, - getProResProfile, getStudioPort, getRendererPortFromConfigFile, getRendererPortFromConfigFileAndCliFlag, getChromiumDisableWebSecurity, getIgnoreCertificateErrors, - getEveryNthFrame, getConcurrency, getStillFrame, getShouldOutputImageSequence, diff --git a/packages/cli/src/config/pixel-format.ts b/packages/cli/src/config/pixel-format.ts deleted file mode 100644 index 8587bf12d5d..00000000000 --- a/packages/cli/src/config/pixel-format.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type {PixelFormat} from '@remotion/renderer'; -import {RenderInternals} from '@remotion/renderer'; - -let currentPixelFormat: PixelFormat = RenderInternals.DEFAULT_PIXEL_FORMAT; - -export const setPixelFormat = (format: PixelFormat) => { - if (!RenderInternals.validPixelFormats.includes(format)) { - throw new TypeError(`Value ${format} is not valid as a pixel format.`); - } - - currentPixelFormat = format; -}; - -export const getPixelFormat = () => { - return currentPixelFormat; -}; diff --git a/packages/cli/src/config/prores-profile.ts b/packages/cli/src/config/prores-profile.ts deleted file mode 100644 index 63dfdc817d9..00000000000 --- a/packages/cli/src/config/prores-profile.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type {_InternalTypes} from 'remotion'; - -let proResProfile: _InternalTypes['ProResProfile'] | undefined; - -export const getProResProfile = (): - | _InternalTypes['ProResProfile'] - | undefined => { - return proResProfile; -}; - -export const setProResProfile = ( - profile: _InternalTypes['ProResProfile'] | undefined, -) => { - proResProfile = profile; -}; diff --git a/packages/cli/src/get-cli-options.ts b/packages/cli/src/get-cli-options.ts index 6e54d4e276e..30049fa1a24 100644 --- a/packages/cli/src/get-cli-options.ts +++ b/packages/cli/src/get-cli-options.ts @@ -47,12 +47,6 @@ export const getAndValidateAbsoluteOutputFile = ( return absoluteOutputFile; }; -const getProResProfile = () => { - const proResProfile = ConfigInternals.getProResProfile(); - - return proResProfile; -}; - export const getCliOptions = (options: { isStill: boolean; logLevel: LogLevel; @@ -64,14 +58,10 @@ export const getCliOptions = (options: { ? true : ConfigInternals.getShouldOutputImageSequence(frameRange); - const proResProfile = getProResProfile(); - const disableWebSecurity = ConfigInternals.getChromiumDisableWebSecurity(); const ignoreCertificateErrors = ConfigInternals.getIgnoreCertificateErrors(); const userAgent = ConfigInternals.getChromiumUserAgent(); - const everyNthFrame = ConfigInternals.getEveryNthFrame(); - const concurrency = ConfigInternals.getConcurrency(); const height = ConfigInternals.getHeight(); @@ -93,8 +83,6 @@ export const getCliOptions = (options: { options.logLevel, options.indent, ), - proResProfile, - everyNthFrame, stillFrame: ConfigInternals.getStillFrame(), userAgent, disableWebSecurity, diff --git a/packages/cli/src/get-render-defaults.ts b/packages/cli/src/get-render-defaults.ts index 1283dae671a..992c2401080 100644 --- a/packages/cli/src/get-render-defaults.ts +++ b/packages/cli/src/get-render-defaults.ts @@ -32,6 +32,8 @@ const { mediaCacheSizeInBytesOption, darkModeOption, pixelFormatOption, + everyNthFrameOption, + proResProfileOption, publicLicenseKeyOption, stillImageFormatOption, videoImageFormatOption, @@ -49,7 +51,8 @@ export const getRenderDefaults = (): RenderDefaults => { const pixelFormat = pixelFormatOption.getValue({ commandLine: parsedCli, }).value; - const proResProfile = ConfigInternals.getProResProfile() ?? null; + const proResProfile = + proResProfileOption.getValue({commandLine: parsedCli}).value ?? null; const x264Preset = x264Option.getValue({ commandLine: parsedCli, @@ -126,7 +129,9 @@ export const getRenderDefaults = (): RenderDefaults => { commandLine: parsedCli, }).value; - const everyNthFrame = ConfigInternals.getEveryNthFrame(); + const everyNthFrame = everyNthFrameOption.getValue({ + commandLine: parsedCli, + }).value; const stillImageFormat = stillImageFormatOption.getValue({ commandLine: parsedCli, }).value; diff --git a/packages/cli/src/parse-command-line.ts b/packages/cli/src/parse-command-line.ts index 9223bbd8159..5edeb55f58b 100644 --- a/packages/cli/src/parse-command-line.ts +++ b/packages/cli/src/parse-command-line.ts @@ -7,9 +7,7 @@ import type { } from '@remotion/renderer'; import type {TypeOfOption} from '@remotion/renderer/client'; import {BrowserSafeApis} from '@remotion/renderer/client'; -import type {_InternalTypes} from 'remotion'; import {Config, ConfigInternals} from './config'; -import {Log} from './log'; import {parsedCli} from './parsed-cli'; const { @@ -38,6 +36,8 @@ const { ipv4Option, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, } = BrowserSafeApis.options; export type CommandLineOptions = { @@ -46,14 +46,14 @@ export type CommandLineOptions = { >; [pixelFormatOption.cliFlag]: TypeOfOption; ['image-format']: VideoImageFormat | StillImageFormat; - ['prores-profile']: _InternalTypes['ProResProfile']; + [proResProfileOption.cliFlag]: TypeOfOption; [x264Option.cliFlag]: TypeOfOption; ['bundle-cache']: string; ['env-file']: string; ['ignore-certificate-errors']: string; [darkModeOption.cliFlag]: TypeOfOption; ['disable-web-security']: string; - ['every-nth-frame']: number; + [everyNthFrameOption.cliFlag]: TypeOfOption; [numberOfGifLoopsOption.cliFlag]: TypeOfOption; [numberOfSharedAudioTagsOption.cliFlag]: TypeOfOption< typeof numberOfSharedAudioTagsOption @@ -179,16 +179,6 @@ export const parseCommandLine = () => { Config.setImageSequence(true); } - if (parsedCli['every-nth-frame']) { - Config.setEveryNthFrame(parsedCli['every-nth-frame']); - } - - if (parsedCli['prores-profile']) { - Config.setProResProfile( - String(parsedCli['prores-profile']) as _InternalTypes['ProResProfile'], - ); - } - if ( parsedCli['license-key'] && parsedCli['license-key'].startsWith('rm_pub_') @@ -200,27 +190,6 @@ export const parseCommandLine = () => { Config.setPublicLicenseKey(parsedCli['public-license-key']); } - if (typeof parsedCli.quality !== 'undefined') { - Log.warn( - {indent: false, logLevel: 'info'}, - 'The --quality flag has been renamed to --jpeg-quality instead.', - ); - Config.setJpegQuality(parsedCli.quality); - } - - if (typeof parsedCli.scale !== 'undefined') { - Config.setScale(parsedCli.scale); - } - - if ( - typeof parsedCli['enable-experimental-client-side-rendering'] !== - 'undefined' - ) { - Config.setExperimentalClientSideRenderingEnabled( - parsedCli['enable-experimental-client-side-rendering'], - ); - } - if (typeof parsedCli['webpack-poll'] !== 'undefined') { Config.setWebpackPollingInMilliseconds(parsedCli['webpack-poll']); } diff --git a/packages/cli/src/render.tsx b/packages/cli/src/render.tsx index a76148e5264..d2842eb3ab3 100644 --- a/packages/cli/src/render.tsx +++ b/packages/cli/src/render.tsx @@ -50,6 +50,8 @@ const { keyboardShortcutsOption, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, } = BrowserSafeApis.options; export const render = async ( @@ -95,14 +97,12 @@ export const render = async ( shouldOutputImageSequence, inputProps, envVariables, - everyNthFrame, userAgent, disableWebSecurity, ignoreCertificateErrors, height, width, ffmpegOverride, - proResProfile, } = getCliOptions({ isStill: false, logLevel, @@ -115,6 +115,12 @@ export const render = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const everyNthFrame = everyNthFrameOption.getValue({ + commandLine: parsedCli, + }).value; + const proResProfile = proResProfileOption.getValue({ + commandLine: parsedCli, + }).value; const x264Preset = x264Option.getValue({commandLine: parsedCli}).value; const audioBitrate = audioBitrateOption.getValue({ commandLine: parsedCli, diff --git a/packages/cloudrun/src/cli/commands/render/index.ts b/packages/cloudrun/src/cli/commands/render/index.ts index 395d9d2fb5f..83439871eac 100644 --- a/packages/cloudrun/src/cli/commands/render/index.ts +++ b/packages/cloudrun/src/cli/commands/render/index.ts @@ -40,6 +40,8 @@ const { darkModeOption, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, } = BrowserSafeApis.options; export const renderCommand = async ( @@ -83,8 +85,6 @@ export const renderCommand = async ( envVariables, frameRange, inputProps, - proResProfile, - everyNthFrame, height, width, disableWebSecurity, @@ -102,6 +102,12 @@ export const renderCommand = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: CliInternals.parsedCli, }).value; + const everyNthFrame = everyNthFrameOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const proResProfile = proResProfileOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; const offthreadVideoCacheSizeInBytes = offthreadVideoCacheSizeInBytesOption.getValue({ commandLine: CliInternals.parsedCli, diff --git a/packages/docs/docs/cli/render.mdx b/packages/docs/docs/cli/render.mdx index 77a4cc4d364..8d1b1c4aa07 100644 --- a/packages/docs/docs/cli/render.mdx +++ b/packages/docs/docs/cli/render.mdx @@ -116,7 +116,7 @@ Sets the output file path, as an alternative to the `output-location` positional ### `--prores-profile` -[Set the ProRes profile](/docs/config#setproresprofile). This option is only valid if the [`codec`](#--codec) has been set to `prores`. Possible values: `4444-xq`, `4444`, `hq`, `standard`, `light`, `proxy`. See [here](https://video.stackexchange.com/a/14715) for explanation of possible values. Default: `hq`. + ### `--x264-preset` @@ -148,7 +148,7 @@ If you enable [hardware acceleration](/docs/hardware-acceleration), you cannot s ### `--every-nth-frame` -[Render only every nth frame.](/docs/config#seteverynthframe) This option may only be set when rendering GIFs. This allows you to lower the FPS of the GIF. + For example only every second frame, every third frame and so on. Only works for rendering GIFs. [See here for more details.](/docs/render-as-gif#reducing-frame-rate) diff --git a/packages/docs/docs/cloudrun/cli/render.mdx b/packages/docs/docs/cloudrun/cli/render.mdx index ad6a27ecc13..9965b9561d2 100644 --- a/packages/docs/docs/cloudrun/cli/render.mdx +++ b/packages/docs/docs/cloudrun/cli/render.mdx @@ -163,7 +163,7 @@ You will be responsible for ensuring that the render ID is unique, otherwise it ### `--prores-profile` -[Set the ProRes profile](/docs/config#setproresprofile). This option is only valid if the [`codec`](#--codec) has been set to `prores`. Possible values: `4444-xq`, `4444`, `hq`, `standard`, `light`, `proxy`. See [here](https://video.stackexchange.com/a/14715) for explanation of possible values. Default: `hq`. + ### `--x264-preset` @@ -179,7 +179,7 @@ You will be responsible for ensuring that the render ID is unique, otherwise it ### `--every-nth-frame` -[Render only every nth frame.](/docs/config#seteverynthframe) This option may only be set when rendering GIFs. This allows you to lower the FPS of the GIF. + For example only every second frame, every third frame and so on. Only works for rendering GIFs. [See here for more details.](/docs/render-as-gif) diff --git a/packages/docs/docs/config.mdx b/packages/docs/docs/config.mdx index f36e664acf8..c1816de003f 100644 --- a/packages/docs/docs/config.mdx +++ b/packages/docs/docs/config.mdx @@ -467,9 +467,7 @@ The [command line flag](/docs/cli/render#--env-file) `--env-file` will take prec ## `setEveryNthFrame()` -This option may only be set when rendering GIFs. [It determines how many frames are rendered, while the other ones gets skipped in order to lower the FPS of the GIF.](/docs/render-as-gif) - -For example, if the `fps` is 30, and `everyNthFrame` is 2, the FPS of the GIF is `15`. + ```ts twoslash title="remotion.config.ts" import {Config} from '@remotion/cli/config'; @@ -573,10 +571,7 @@ Refer to the [Encoding guide](/docs/encoding) to see defaults and supported comb ## `setProResProfile()` -Set the ProRes profile. This option is only valid if the codec has been set to `prores`. -Possible values: `4444-xq`, `4444`, `hq`, `standard`, `light`, `proxy`. -See [here](https://video.stackexchange.com/a/14715) for explanation of possible values. -Default: `hq` + ```ts twoslash title="remotion.config.ts" import {Config} from '@remotion/cli/config'; diff --git a/packages/docs/docs/lambda/cli/render.mdx b/packages/docs/docs/lambda/cli/render.mdx index 9b41b953d9a..eddc8ed12f4 100644 --- a/packages/docs/docs/lambda/cli/render.mdx +++ b/packages/docs/docs/lambda/cli/render.mdx @@ -162,7 +162,7 @@ Renamed to `jpegQuality` in `v4.0.0`. ### `--prores-profile` -[Set the ProRes profile](/docs/config#setproresprofile). This option is only valid if the [`codec`](#--codec) has been set to `prores`. Possible values: `4444-xq`, `4444`, `hq`, `standard`, `light`, `proxy`. See [here](https://video.stackexchange.com/a/14715) for explanation of possible values. Default: `hq`. + ### `--x264-preset` @@ -194,7 +194,7 @@ Specify a location for a dotenv file - Default `.env`. [Read about how environme ### `--every-nth-frame` -[Render only every nth frame.](/docs/config#seteverynthframe) This option may only be set when rendering GIFs. This allows you to lower the FPS of the GIF. + For example only every second frame, every third frame and so on. Only works for rendering GIFs. [See here for more details.](/docs/render-as-gif) diff --git a/packages/example/remotion.config.ts b/packages/example/remotion.config.ts index 912bffef8bb..56b0ff09068 100644 --- a/packages/example/remotion.config.ts +++ b/packages/example/remotion.config.ts @@ -8,5 +8,3 @@ Config.overrideWebpackConfig(async (config) => { }); return webpackOverride(config); }); - -Config.setExperimentalClientSideRenderingEnabled(true); diff --git a/packages/lambda/src/cli/commands/render/render.ts b/packages/lambda/src/cli/commands/render/render.ts index 2922e30398e..a7d7153e0ed 100644 --- a/packages/lambda/src/cli/commands/render/render.ts +++ b/packages/lambda/src/cli/commands/render/render.ts @@ -58,6 +58,8 @@ const { darkModeOption, pixelFormatOption, browserExecutableOption, + everyNthFrameOption, + proResProfileOption, } = BrowserSafeApis.options; export const renderCommand = async ({ @@ -92,8 +94,6 @@ export const renderCommand = async ({ envVariables, frameRange, inputProps, - proResProfile, - everyNthFrame, height, width, ignoreCertificateErrors, @@ -111,6 +111,12 @@ export const renderCommand = async ({ const browserExecutable = browserExecutableOption.getValue({ commandLine: CliInternals.parsedCli, }).value; + const everyNthFrame = everyNthFrameOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const proResProfile = proResProfileOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; const x264Preset = x264Option.getValue({ commandLine: CliInternals.parsedCli, }).value; diff --git a/packages/renderer/src/client.ts b/packages/renderer/src/client.ts index 7379e625515..3737bd2754e 100644 --- a/packages/renderer/src/client.ts +++ b/packages/renderer/src/client.ts @@ -36,6 +36,7 @@ import { import {validateOutputFilename} from './validate-output-filename'; export {AvailableOptions, TypeOfOption} from './options'; export {HardwareAccelerationOption} from './options/hardware-acceleration'; +export {ProResProfile} from './options/prores-profile'; export const BrowserSafeApis = { getFileExtensionFromCodec, diff --git a/packages/renderer/src/options/every-nth-frame.tsx b/packages/renderer/src/options/every-nth-frame.tsx new file mode 100644 index 00000000000..9670e433631 --- /dev/null +++ b/packages/renderer/src/options/every-nth-frame.tsx @@ -0,0 +1,47 @@ +import type {AnyRemotionOption} from './option'; + +const DEFAULT_EVERY_NTH_FRAME = 1; + +let everyNthFrame = DEFAULT_EVERY_NTH_FRAME; + +const cliFlag = 'every-nth-frame' as const; + +export const everyNthFrameOption = { + name: 'Every nth frame', + cliFlag, + description: () => ( + <> + This option may only be set when rendering GIFs. It determines how many + frames are rendered, while the other ones get skipped in order to lower + the FPS of the GIF. For example, if the fps is 30, and{' '} + everyNthFrame is 2, the FPS of the GIF is 15. + + ), + ssrName: 'everyNthFrame' as const, + docLink: 'https://www.remotion.dev/docs/config#seteverynthframe', + type: DEFAULT_EVERY_NTH_FRAME as number, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: commandLine[cliFlag] as number, + }; + } + + if (everyNthFrame !== DEFAULT_EVERY_NTH_FRAME) { + return { + source: 'config', + value: everyNthFrame, + }; + } + + return { + source: 'default', + value: DEFAULT_EVERY_NTH_FRAME, + }; + }, + setConfig: (value) => { + everyNthFrame = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; diff --git a/packages/renderer/src/options/index.tsx b/packages/renderer/src/options/index.tsx index cae1339aa93..cc0d038d373 100644 --- a/packages/renderer/src/options/index.tsx +++ b/packages/renderer/src/options/index.tsx @@ -18,6 +18,7 @@ import {enableMultiprocessOnLinuxOption} from './enable-multiprocess-on-linux'; import {encodingBufferSizeOption} from './encoding-buffer-size'; import {encodingMaxRateOption} from './encoding-max-rate'; import {enforceAudioOption} from './enforce-audio'; +import {everyNthFrameOption} from './every-nth-frame'; import {experimentalClientSideRenderingOption} from './experimental-client-side-rendering'; import {folderExpiryOption} from './folder-expiry'; import {forSeamlessAacConcatenationOption} from './for-seamless-aac-concatenation'; @@ -44,6 +45,7 @@ import type {AnyRemotionOption} from './option'; import {overwriteOption} from './overwrite'; import {pixelFormatOption} from './pixel-format'; import {preferLosslessAudioOption} from './prefer-lossless'; +import {proResProfileOption} from './prores-profile'; import {publicDirOption} from './public-dir'; import {publicLicenseKeyOption} from './public-license-key'; import {publicPathOption} from './public-path'; @@ -69,6 +71,7 @@ export const allOptions = { videoBitrateOption, audioBitrateOption, enforceAudioOption, + everyNthFrameOption, mutedOption, videoCodecOption, offthreadVideoCacheSizeInBytesOption, @@ -88,6 +91,7 @@ export const allOptions = { reproOption, pixelFormatOption, preferLosslessOption: preferLosslessAudioOption, + proResProfileOption, x264Option, logLevelOption, delayRenderTimeoutInMillisecondsOption, diff --git a/packages/renderer/src/options/prores-profile.tsx b/packages/renderer/src/options/prores-profile.tsx new file mode 100644 index 00000000000..0a57be5a274 --- /dev/null +++ b/packages/renderer/src/options/prores-profile.tsx @@ -0,0 +1,64 @@ +import type {AnyRemotionOption} from './option'; + +export type ProResProfile = + | '4444-xq' + | '4444' + | 'hq' + | 'standard' + | 'light' + | 'proxy'; + +const validProResProfiles: ProResProfile[] = [ + '4444-xq', + '4444', + 'hq', + 'standard', + 'light', + 'proxy', +]; + +let proResProfile: ProResProfile | undefined; + +const cliFlag = 'prores-profile' as const; + +export const proResProfileOption = { + name: 'ProRes profile', + cliFlag, + description: () => ( + <> + Set the ProRes profile. This option is only valid if the codec has been + set to prores. Possible values:{' '} + {validProResProfiles.map((p) => `"${p}"`).join(', ')}. Default:{' '} + "hq". See{' '} + here for an + explanation of possible values. + + ), + ssrName: 'proResProfile' as const, + docLink: 'https://www.remotion.dev/docs/config#setproresprofile', + type: undefined as ProResProfile | undefined, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: String(commandLine[cliFlag]) as ProResProfile, + }; + } + + if (proResProfile !== undefined) { + return { + source: 'config', + value: proResProfile, + }; + } + + return { + source: 'default', + value: undefined, + }; + }, + setConfig: (value) => { + proResProfile = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; From 742000b844a5fd7d55298a61f761d6002f0451b8 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Tue, 17 Feb 2026 18:54:19 +0100 Subject: [PATCH 2/6] `@remotion/renderer`, `@remotion/cli`: Migrate `--user-agent`, `--disable-web-security`, `--ignore-certificate-errors` to options system - Create `userAgentOption`, `disableWebSecurityOption`, and `ignoreCertificateErrorsOption` as proper `AnyRemotionOption` definitions - Register all three in the options index - Remove from `parseCommandLine()` and `getCliOptions()` return value - Update all call sites in cli, lambda, and cloudrun packages to import options directly - Update docs to use `` - Clean up old config files (chromium-flags.ts, user-agent.ts) Co-authored-by: Cursor --- packages/cli/src/benchmark.ts | 13 ++++-- packages/cli/src/compositions.ts | 18 +++++--- packages/cli/src/config/index.ts | 21 +++------ packages/cli/src/get-cli-options.ts | 7 --- packages/cli/src/get-render-defaults.ts | 13 ++++-- packages/cli/src/gpu.ts | 18 ++++---- packages/cli/src/parse-command-line.ts | 29 +++++------- packages/cli/src/parsed-cli.ts | 4 +- packages/cli/src/render.tsx | 13 ++++-- packages/cli/src/still.ts | 21 ++++----- .../cloudrun/src/cli/commands/render/index.ts | 15 +++++-- packages/cloudrun/src/cli/commands/still.ts | 15 +++++-- packages/docs/docs/cli/compositions.mdx | 8 ++-- packages/docs/docs/cli/render.mdx | 6 +-- packages/docs/docs/cli/still.mdx | 6 +-- packages/docs/docs/config.mdx | 4 +- .../src/cli/commands/compositions/index.ts | 20 ++++++--- .../lambda/src/cli/commands/render/render.ts | 32 ++++++++------ packages/lambda/src/cli/commands/still.ts | 21 ++++----- .../src/options/disable-web-security.tsx | 44 +++++++++++++++++++ .../src/options/ignore-certificate-errors.tsx | 44 +++++++++++++++++++ packages/renderer/src/options/index.tsx | 6 +++ packages/renderer/src/options/user-agent.tsx | 42 ++++++++++++++++++ 23 files changed, 293 insertions(+), 127 deletions(-) create mode 100644 packages/renderer/src/options/disable-web-security.tsx create mode 100644 packages/renderer/src/options/ignore-certificate-errors.tsx create mode 100644 packages/renderer/src/options/user-agent.tsx diff --git a/packages/cli/src/benchmark.ts b/packages/cli/src/benchmark.ts index 044962d0c33..db7c313f29a 100644 --- a/packages/cli/src/benchmark.ts +++ b/packages/cli/src/benchmark.ts @@ -64,6 +64,9 @@ const { browserExecutableOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; const getValidConcurrency = (cliConcurrency: number | string | null) => { @@ -209,9 +212,6 @@ export const benchmarkCommand = async ( height, width, concurrency: unparsedConcurrency, - disableWebSecurity, - userAgent, - ignoreCertificateErrors, } = getCliOptions({ isStill: false, logLevel, @@ -230,6 +230,13 @@ export const benchmarkCommand = async ( const proResProfile = proResProfileOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; Log.verbose( {indent: false, logLevel}, diff --git a/packages/cli/src/compositions.ts b/packages/cli/src/compositions.ts index 1ead340f8d9..0f0deb39d8b 100644 --- a/packages/cli/src/compositions.ts +++ b/packages/cli/src/compositions.ts @@ -30,6 +30,9 @@ const { experimentalClientSideRenderingOption, keyboardShortcutsOption, browserExecutableOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const listCompositionsCommand = async ( @@ -68,13 +71,7 @@ export const listCompositionsCommand = async ( reason, ); - const { - envVariables, - inputProps, - ignoreCertificateErrors, - userAgent, - disableWebSecurity, - } = getCliOptions({ + const {envVariables, inputProps} = getCliOptions({ isStill: false, logLevel, indent: false, @@ -83,6 +80,13 @@ export const listCompositionsCommand = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const publicPath = publicPathOption.getValue({commandLine: parsedCli}).value; const timeoutInMilliseconds = delayRenderTimeoutInMillisecondsOption.getValue( { diff --git a/packages/cli/src/config/index.ts b/packages/cli/src/config/index.ts index 1b269b7810d..567c32a727b 100644 --- a/packages/cli/src/config/index.ts +++ b/packages/cli/src/config/index.ts @@ -1,8 +1,4 @@ import {getBrowser} from './browser'; -import { - getChromiumDisableWebSecurity, - getIgnoreCertificateErrors, -} from './chromium-flags'; import {getConcurrency} from './concurrency'; import {getDotEnvLocation} from './env-file'; import {getRange, setFrameRangeFromCli} from './frame-range'; @@ -40,10 +36,6 @@ import { getBufferStateDelayInMilliseconds, setBufferStateDelayInMilliseconds, } from './buffer-state-delay-in-milliseconds'; -import { - setChromiumDisableWebSecurity, - setChromiumIgnoreCertificateErrors, -} from './chromium-flags'; import type {Concurrency} from './concurrency'; import {setConcurrency} from './concurrency'; import {getEntryPoint, setEntryPoint} from './entry-point'; @@ -61,7 +53,6 @@ import {setOutputLocation} from './output-location'; import type {WebpackOverrideFn} from './override-webpack'; import {overrideWebpackConfig} from './override-webpack'; import {setPort, setRendererPort, setStudioPort} from './preview-server'; -import {getChromiumUserAgent, setChromiumUserAgent} from './user-agent'; import {setWebpackCaching} from './webpack-caching'; import { getWebpackPolling, @@ -123,6 +114,9 @@ const { proResProfileOption, stillImageFormatOption, videoImageFormatOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; declare global { @@ -664,11 +658,11 @@ export const Config: FlatConfig = { setTimeoutInMilliseconds: delayRenderTimeoutInMillisecondsOption.setConfig, setDelayRenderTimeoutInMilliseconds: delayRenderTimeoutInMillisecondsOption.setConfig, - setChromiumDisableWebSecurity, - setChromiumIgnoreCertificateErrors, + setChromiumDisableWebSecurity: disableWebSecurityOption.setConfig, + setChromiumIgnoreCertificateErrors: ignoreCertificateErrorsOption.setConfig, setChromiumHeadlessMode: headlessOption.setConfig, setChromiumOpenGlRenderer: glOption.setConfig, - setChromiumUserAgent, + setChromiumUserAgent: userAgentOption.setConfig, setDotEnvLocation, setConcurrency, setChromiumMultiProcessOnLinux: enableMultiprocessOnLinuxOption.setConfig, @@ -740,8 +734,6 @@ export const ConfigInternals = { getStudioPort, getRendererPortFromConfigFile, getRendererPortFromConfigFileAndCliFlag, - getChromiumDisableWebSecurity, - getIgnoreCertificateErrors, getConcurrency, getStillFrame, getShouldOutputImageSequence, @@ -760,7 +752,6 @@ export const ConfigInternals = { getEntryPoint, getWebpackPolling, getShouldOpenBrowser, - getChromiumUserAgent, getBufferStateDelayInMilliseconds, getOutputCodecOrUndefined: BrowserSafeApis.getOutputCodecOrUndefined, }; diff --git a/packages/cli/src/get-cli-options.ts b/packages/cli/src/get-cli-options.ts index 30049fa1a24..d37a614d58e 100644 --- a/packages/cli/src/get-cli-options.ts +++ b/packages/cli/src/get-cli-options.ts @@ -58,10 +58,6 @@ export const getCliOptions = (options: { ? true : ConfigInternals.getShouldOutputImageSequence(frameRange); - const disableWebSecurity = ConfigInternals.getChromiumDisableWebSecurity(); - const ignoreCertificateErrors = ConfigInternals.getIgnoreCertificateErrors(); - const userAgent = ConfigInternals.getChromiumUserAgent(); - const concurrency = ConfigInternals.getConcurrency(); const height = ConfigInternals.getHeight(); @@ -84,9 +80,6 @@ export const getCliOptions = (options: { options.indent, ), stillFrame: ConfigInternals.getStillFrame(), - userAgent, - disableWebSecurity, - ignoreCertificateErrors, ffmpegOverride: ConfigInternals.getFfmpegOverrideFunction(), height, width, diff --git a/packages/cli/src/get-render-defaults.ts b/packages/cli/src/get-render-defaults.ts index 992c2401080..af0964ec6ee 100644 --- a/packages/cli/src/get-render-defaults.ts +++ b/packages/cli/src/get-render-defaults.ts @@ -34,6 +34,9 @@ const { pixelFormatOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, publicLicenseKeyOption, stillImageFormatOption, videoImageFormatOption, @@ -138,12 +141,16 @@ export const getRenderDefaults = (): RenderDefaults => { const videoImageFormat = videoImageFormatOption.getValue({ commandLine: parsedCli, }).value; - const disableWebSecurity = ConfigInternals.getChromiumDisableWebSecurity(); - const ignoreCertificateErrors = ConfigInternals.getIgnoreCertificateErrors(); + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const darkMode = darkModeOption.getValue({ commandLine: parsedCli, }).value; - const userAgent = ConfigInternals.getChromiumUserAgent(); + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; const metadata = ConfigInternals.getMetadata(); const outputLocation = ConfigInternals.getOutputLocation(); diff --git a/packages/cli/src/gpu.ts b/packages/cli/src/gpu.ts index b62ad0668be..1774a3c6247 100644 --- a/packages/cli/src/gpu.ts +++ b/packages/cli/src/gpu.ts @@ -3,7 +3,6 @@ import {RenderInternals} from '@remotion/renderer'; import {BrowserSafeApis} from '@remotion/renderer/client'; import {defaultBrowserDownloadProgress} from './browser-download-bar'; import {chalk} from './chalk'; -import {getCliOptions} from './get-cli-options'; import {Log} from './log'; import {parsedCli, quietFlagProvided} from './parsed-cli'; @@ -17,19 +16,22 @@ const { chromeModeOption, darkModeOption, browserExecutableOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const gpuCommand = async (logLevel: LogLevel) => { - const {disableWebSecurity, ignoreCertificateErrors, userAgent} = - getCliOptions({ - isStill: false, - logLevel, - indent: false, - }); - const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const enableMultiProcessOnLinux = enableMultiprocessOnLinuxOption.getValue({ commandLine: parsedCli, }).value; diff --git a/packages/cli/src/parse-command-line.ts b/packages/cli/src/parse-command-line.ts index 5edeb55f58b..1d0c8e8bdf0 100644 --- a/packages/cli/src/parse-command-line.ts +++ b/packages/cli/src/parse-command-line.ts @@ -38,6 +38,9 @@ const { browserExecutableOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export type CommandLineOptions = { @@ -50,9 +53,13 @@ export type CommandLineOptions = { [x264Option.cliFlag]: TypeOfOption; ['bundle-cache']: string; ['env-file']: string; - ['ignore-certificate-errors']: string; + [ignoreCertificateErrorsOption.cliFlag]: TypeOfOption< + typeof ignoreCertificateErrorsOption + >; [darkModeOption.cliFlag]: TypeOfOption; - ['disable-web-security']: string; + [disableWebSecurityOption.cliFlag]: TypeOfOption< + typeof disableWebSecurityOption + >; [everyNthFrameOption.cliFlag]: TypeOfOption; [numberOfGifLoopsOption.cliFlag]: TypeOfOption; [numberOfSharedAudioTagsOption.cliFlag]: TypeOfOption< @@ -112,7 +119,7 @@ export type CommandLineOptions = { ['no-open']: boolean; ['browser']: string; ['browser-args']: string; - ['user-agent']: string; + [userAgentOption.cliFlag]: TypeOfOption; ['out-dir']: string; [audioLatencyHintOption.cliFlag]: AudioContextLatencyCategory; [ipv4Option.cliFlag]: TypeOfOption; @@ -133,22 +140,6 @@ export const parseCommandLine = () => { Config.setCachingEnabled(parsedCli['bundle-cache'] !== 'false'); } - if (parsedCli['disable-web-security']) { - Config.setChromiumDisableWebSecurity(true); - } - - if (parsedCli['ignore-certificate-errors']) { - Config.setChromiumIgnoreCertificateErrors(true); - } - - if (parsedCli[darkModeOption.cliFlag]) { - Config.setChromiumDarkMode(parsedCli[darkModeOption.cliFlag]); - } - - if (parsedCli['user-agent']) { - Config.setChromiumUserAgent(parsedCli['user-agent']); - } - if (parsedCli.concurrency) { Config.setConcurrency(parsedCli.concurrency); } diff --git a/packages/cli/src/parsed-cli.ts b/packages/cli/src/parsed-cli.ts index 6f6761baa53..76a1675fcff 100644 --- a/packages/cli/src/parsed-cli.ts +++ b/packages/cli/src/parsed-cli.ts @@ -19,9 +19,9 @@ export const BooleanFlags = [ 'enable-lambda-insights', 'yes', 'y', - 'disable-web-security', + BrowserSafeApis.options.disableWebSecurityOption.cliFlag, BrowserSafeApis.options.darkModeOption.cliFlag, - 'ignore-certificate-errors', + BrowserSafeApis.options.ignoreCertificateErrorsOption.cliFlag, 'disable-headless', 'disable-keyboard-shortcuts', 'default-only', diff --git a/packages/cli/src/render.tsx b/packages/cli/src/render.tsx index d2842eb3ab3..7bb02756631 100644 --- a/packages/cli/src/render.tsx +++ b/packages/cli/src/render.tsx @@ -52,6 +52,9 @@ const { browserExecutableOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const render = async ( @@ -97,9 +100,6 @@ export const render = async ( shouldOutputImageSequence, inputProps, envVariables, - userAgent, - disableWebSecurity, - ignoreCertificateErrors, height, width, ffmpegOverride, @@ -121,6 +121,13 @@ export const render = async ( const proResProfile = proResProfileOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const x264Preset = x264Option.getValue({commandLine: parsedCli}).value; const audioBitrate = audioBitrateOption.getValue({ commandLine: parsedCli, diff --git a/packages/cli/src/still.ts b/packages/cli/src/still.ts index 7bc43cc3389..da126daefaa 100644 --- a/packages/cli/src/still.ts +++ b/packages/cli/src/still.ts @@ -31,6 +31,9 @@ const { experimentalClientSideRenderingOption, keyboardShortcutsOption, browserExecutableOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const still = async ( @@ -70,16 +73,7 @@ export const still = async ( process.exit(1); } - const { - envVariables, - height, - inputProps, - stillFrame, - width, - disableWebSecurity, - ignoreCertificateErrors, - userAgent, - } = getCliOptions({ + const {envVariables, height, inputProps, stillFrame, width} = getCliOptions({ isStill: true, logLevel, indent: false, @@ -88,6 +82,13 @@ export const still = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const jpegQuality = jpegQualityOption.getValue({ commandLine: parsedCli, }).value; diff --git a/packages/cloudrun/src/cli/commands/render/index.ts b/packages/cloudrun/src/cli/commands/render/index.ts index 83439871eac..76290749993 100644 --- a/packages/cloudrun/src/cli/commands/render/index.ts +++ b/packages/cloudrun/src/cli/commands/render/index.ts @@ -42,6 +42,9 @@ const { browserExecutableOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const renderCommand = async ( @@ -87,9 +90,6 @@ export const renderCommand = async ( inputProps, height, width, - disableWebSecurity, - ignoreCertificateErrors, - userAgent, } = CliInternals.getCliOptions({ isStill: false, logLevel, @@ -108,6 +108,15 @@ export const renderCommand = async ( const proResProfile = proResProfileOption.getValue({ commandLine: CliInternals.parsedCli, }).value; + const userAgent = userAgentOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; const offthreadVideoCacheSizeInBytes = offthreadVideoCacheSizeInBytesOption.getValue({ commandLine: CliInternals.parsedCli, diff --git a/packages/cloudrun/src/cli/commands/still.ts b/packages/cloudrun/src/cli/commands/still.ts index 4a7015b819c..cc152904e4b 100644 --- a/packages/cloudrun/src/cli/commands/still.ts +++ b/packages/cloudrun/src/cli/commands/still.ts @@ -25,6 +25,9 @@ const { mediaCacheSizeInBytesOption, darkModeOption, browserExecutableOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const stillCommand = async ( @@ -48,9 +51,6 @@ export const stillCommand = async ( stillFrame, height, width, - userAgent, - disableWebSecurity, - ignoreCertificateErrors, } = CliInternals.getCliOptions({ isStill: false, logLevel, @@ -60,6 +60,15 @@ export const stillCommand = async ( const browserExecutable = browserExecutableOption.getValue({ commandLine: CliInternals.parsedCli, }).value; + const userAgent = userAgentOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; let composition = args[1]; diff --git a/packages/docs/docs/cli/compositions.mdx b/packages/docs/docs/cli/compositions.mdx index 8b7d42ad3f5..44d97d94e12 100644 --- a/packages/docs/docs/cli/compositions.mdx +++ b/packages/docs/docs/cli/compositions.mdx @@ -66,13 +66,11 @@ Not to be confused with the [`--timeout` flag when deploying a Lambda function]( ### `--ignore-certificate-errors` -Results in invalid SSL certificates in Chrome, such as self-signed ones, being ignored. + ### `--disable-web-security` -_available since v2.6.5_ - -This will most notably disable CORS in Chrome among other security features. + ### ~`--disable-headless`~ @@ -88,7 +86,7 @@ This will most notably disable CORS in Chrome among other security features. ### `--user-agent` -Lets you set a custom user agent that the headless Chrome browser assumes. + ### `--media-cache-size-in-bytes` diff --git a/packages/docs/docs/cli/render.mdx b/packages/docs/docs/cli/render.mdx index 8d1b1c4aa07..b1aea02c872 100644 --- a/packages/docs/docs/cli/render.mdx +++ b/packages/docs/docs/cli/render.mdx @@ -202,11 +202,11 @@ Not to be confused with the [`--timeout` flag when deploying a Lambda function]( ### `--ignore-certificate-errors` -Results in invalid SSL certificates in Chrome, such as self-signed ones, being ignored. + ### `--disable-web-security` -This will most notably disable CORS in Chrome among other security features. + ### ~`--disable-headless`~ @@ -222,7 +222,7 @@ This will most notably disable CORS in Chrome among other security features. ### `--user-agent` -Lets you set a custom user agent that the headless Chrome browser assumes. + ### `--media-cache-size-in-bytes` diff --git a/packages/docs/docs/cli/still.mdx b/packages/docs/docs/cli/still.mdx index dce0c253754..7d8504149d3 100644 --- a/packages/docs/docs/cli/still.mdx +++ b/packages/docs/docs/cli/still.mdx @@ -98,11 +98,11 @@ Not to be confused with the [`--timeout` flag when deploying a Lambda function]( ### `--ignore-certificate-errors` -Results in invalid SSL certificates in Chrome, such as self-signed ones, being ignored. + ### `--disable-web-security` -This will most notably disable CORS in Chrome among other security features. + ### ~`--disable-headless`~ @@ -122,7 +122,7 @@ This will most notably disable CORS in Chrome among other security features. ### `--user-agent` -Lets you set a custom user agent that the headless Chrome browser assumes. + ### `--media-cache-size-in-bytes` diff --git a/packages/docs/docs/config.mdx b/packages/docs/docs/config.mdx index c1816de003f..a4d42848ed6 100644 --- a/packages/docs/docs/config.mdx +++ b/packages/docs/docs/config.mdx @@ -216,7 +216,7 @@ The [command line flag](/docs/cli/render#--timeout) `--timeout` will take preced ## `setChromiumDisableWebSecurity()` -This will most notably disable CORS among other security features during rendering. + ```tsx twoslash title="remotion.config.ts" import {Config} from '@remotion/cli/config'; @@ -241,7 +241,7 @@ Config.setChromiumDarkMode(true); ## `setChromiumIgnoreCertificateErrors()` -Results in invalid SSL certificates, such as self-signed ones, being ignored during rendering. + ```tsx twoslash title="remotion.config.ts" import {Config} from '@remotion/cli/config'; diff --git a/packages/lambda/src/cli/commands/compositions/index.ts b/packages/lambda/src/cli/commands/compositions/index.ts index 246afb30cc8..37ae33c364f 100644 --- a/packages/lambda/src/cli/commands/compositions/index.ts +++ b/packages/lambda/src/cli/commands/compositions/index.ts @@ -22,6 +22,9 @@ const { delayRenderTimeoutInMillisecondsOption, headlessOption, darkModeOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const compositionsCommand = async ({ @@ -49,18 +52,21 @@ export const compositionsCommand = async ({ quit(1); } - const { - envVariables, - inputProps, - ignoreCertificateErrors, - userAgent, - disableWebSecurity, - } = CliInternals.getCliOptions({ + const {envVariables, inputProps} = CliInternals.getCliOptions({ isStill: false, logLevel, indent: false, }); + const userAgent = userAgentOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; const enableMultiProcessOnLinux = enableMultiprocessOnLinuxOption.getValue({ commandLine: CliInternals.parsedCli, }).value; diff --git a/packages/lambda/src/cli/commands/render/render.ts b/packages/lambda/src/cli/commands/render/render.ts index a7d7153e0ed..f0f5e583736 100644 --- a/packages/lambda/src/cli/commands/render/render.ts +++ b/packages/lambda/src/cli/commands/render/render.ts @@ -60,6 +60,9 @@ const { browserExecutableOption, everyNthFrameOption, proResProfileOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; export const renderCommand = async ({ @@ -90,20 +93,12 @@ export const renderCommand = async ({ const region = getAwsRegion(); - const { - envVariables, - frameRange, - inputProps, - height, - width, - ignoreCertificateErrors, - userAgent, - disableWebSecurity, - } = CliInternals.getCliOptions({ - isStill: false, - logLevel, - indent: false, - }); + const {envVariables, frameRange, inputProps, height, width} = + CliInternals.getCliOptions({ + isStill: false, + logLevel, + indent: false, + }); const pixelFormat = pixelFormatOption.getValue({ commandLine: CliInternals.parsedCli, @@ -117,6 +112,15 @@ export const renderCommand = async ({ const proResProfile = proResProfileOption.getValue({ commandLine: CliInternals.parsedCli, }).value; + const userAgent = userAgentOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: CliInternals.parsedCli, + }).value; const x264Preset = x264Option.getValue({ commandLine: CliInternals.parsedCli, }).value; diff --git a/packages/lambda/src/cli/commands/still.ts b/packages/lambda/src/cli/commands/still.ts index bffe16f3cb6..103d45670d7 100644 --- a/packages/lambda/src/cli/commands/still.ts +++ b/packages/lambda/src/cli/commands/still.ts @@ -36,6 +36,9 @@ const { mediaCacheSizeInBytesOption, darkModeOption, browserExecutableOption, + userAgentOption, + disableWebSecurityOption, + ignoreCertificateErrorsOption, } = BrowserSafeApis.options; const { @@ -76,16 +79,7 @@ export const stillCommand = async ({ quit(1); } - const { - envVariables, - inputProps, - stillFrame, - height, - width, - userAgent, - disableWebSecurity, - ignoreCertificateErrors, - } = getCliOptions({ + const {envVariables, inputProps, stillFrame, height, width} = getCliOptions({ isStill: true, logLevel, indent: false, @@ -94,6 +88,13 @@ export const stillCommand = async ({ const browserExecutable = browserExecutableOption.getValue({ commandLine: parsedCli, }).value; + const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value; + const disableWebSecurity = disableWebSecurityOption.getValue({ + commandLine: parsedCli, + }).value; + const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({ + commandLine: parsedCli, + }).value; const region = getAwsRegion(); let composition = args[1]; diff --git a/packages/renderer/src/options/disable-web-security.tsx b/packages/renderer/src/options/disable-web-security.tsx new file mode 100644 index 00000000000..bb7a1342eb1 --- /dev/null +++ b/packages/renderer/src/options/disable-web-security.tsx @@ -0,0 +1,44 @@ +import type {AnyRemotionOption} from './option'; + +let disableWebSecurity = false; + +const cliFlag = 'disable-web-security' as const; + +export const disableWebSecurityOption = { + name: 'Disable web security', + cliFlag, + description: () => ( + <> + This will most notably disable CORS in Chrome among other security + features. + + ), + ssrName: 'disableWebSecurity' as const, + docLink: + 'https://www.remotion.dev/docs/chromium-flags#--disable-web-security', + type: false as boolean, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: Boolean(commandLine[cliFlag]), + }; + } + + if (disableWebSecurity) { + return { + source: 'config', + value: disableWebSecurity, + }; + } + + return { + source: 'default', + value: false, + }; + }, + setConfig: (value) => { + disableWebSecurity = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; diff --git a/packages/renderer/src/options/ignore-certificate-errors.tsx b/packages/renderer/src/options/ignore-certificate-errors.tsx new file mode 100644 index 00000000000..e5756c88b50 --- /dev/null +++ b/packages/renderer/src/options/ignore-certificate-errors.tsx @@ -0,0 +1,44 @@ +import type {AnyRemotionOption} from './option'; + +let ignoreCertificateErrors = false; + +const cliFlag = 'ignore-certificate-errors' as const; + +export const ignoreCertificateErrorsOption = { + name: 'Ignore certificate errors', + cliFlag, + description: () => ( + <> + Results in invalid SSL certificates in Chrome, such as self-signed ones, + being ignored. + + ), + ssrName: 'ignoreCertificateErrors' as const, + docLink: + 'https://www.remotion.dev/docs/chromium-flags#--ignore-certificate-errors', + type: false as boolean, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: Boolean(commandLine[cliFlag]), + }; + } + + if (ignoreCertificateErrors) { + return { + source: 'config', + value: ignoreCertificateErrors, + }; + } + + return { + source: 'default', + value: false, + }; + }, + setConfig: (value) => { + ignoreCertificateErrors = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; diff --git a/packages/renderer/src/options/index.tsx b/packages/renderer/src/options/index.tsx index cc0d038d373..563a2b4c847 100644 --- a/packages/renderer/src/options/index.tsx +++ b/packages/renderer/src/options/index.tsx @@ -12,6 +12,7 @@ import {enableCrossSiteIsolationOption} from './cross-site-isolation'; import {darkModeOption} from './dark-mode'; import {deleteAfterOption} from './delete-after'; import {disableGitSourceOption} from './disable-git-source'; +import {disableWebSecurityOption} from './disable-web-security'; import {disallowParallelEncodingOption} from './disallow-parallel-encoding'; import {enableLambdaInsights} from './enable-lambda-insights'; import {enableMultiprocessOnLinuxOption} from './enable-multiprocess-on-linux'; @@ -26,6 +27,7 @@ import {forceNewStudioOption} from './force-new-studio'; import {glOption} from './gl'; import {hardwareAccelerationOption} from './hardware-acceleration'; import {headlessOption} from './headless'; +import {ignoreCertificateErrorsOption} from './ignore-certificate-errors'; import {imageSequencePatternOption} from './image-sequence-pattern'; import {ipv4Option} from './ipv4'; import {isProductionOption} from './is-production'; @@ -55,6 +57,7 @@ import {separateAudioOption} from './separate-audio'; import {stillImageFormatOption} from './still-image-format'; import {throwIfSiteExistsOption} from './throw-if-site-exists'; import {delayRenderTimeoutInMillisecondsOption} from './timeout'; +import {userAgentOption} from './user-agent'; import {videoBitrateOption} from './video-bitrate'; import {mediaCacheSizeInBytesOption} from './video-cache-size'; import {videoCodecOption} from './video-codec'; @@ -79,6 +82,7 @@ export const allOptions = { webhookCustomDataOption, colorSpaceOption, deleteAfterOption, + disableWebSecurityOption, disallowParallelEncodingOption, folderExpiryOption, enableMultiprocessOnLinuxOption, @@ -112,6 +116,7 @@ export const allOptions = { licenseKeyOption, audioLatencyHintOption, enableCrossSiteIsolationOption, + ignoreCertificateErrorsOption, imageSequencePatternOption, mediaCacheSizeInBytesOption, darkModeOption, @@ -124,6 +129,7 @@ export const allOptions = { numberOfSharedAudioTagsOption, ipv4Option, stillImageFormatOption, + userAgentOption, videoImageFormatOption, }; diff --git a/packages/renderer/src/options/user-agent.tsx b/packages/renderer/src/options/user-agent.tsx new file mode 100644 index 00000000000..f0dd2542de3 --- /dev/null +++ b/packages/renderer/src/options/user-agent.tsx @@ -0,0 +1,42 @@ +import type {AnyRemotionOption} from './option'; + +let userAgent: string | null = null; + +const cliFlag = 'user-agent' as const; + +export const userAgentOption = { + name: 'User agent', + cliFlag, + description: () => ( + <> + Lets you set a custom user agent that the headless Chrome browser assumes. + + ), + ssrName: 'userAgent' as const, + docLink: 'https://www.remotion.dev/docs/chromium-flags#--user-agent', + type: null as string | null, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: commandLine[cliFlag] as string, + }; + } + + if (userAgent !== null) { + return { + source: 'config', + value: userAgent, + }; + } + + return { + source: 'default', + value: null, + }; + }, + setConfig: (value) => { + userAgent = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; From b5eb646ffa50076bae6e4aa411748b70392d7327 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Tue, 17 Feb 2026 18:54:38 +0100 Subject: [PATCH 3/6] Update Balloons.tsx --- packages/example/src/Lottie/Halloween/Balloons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/example/src/Lottie/Halloween/Balloons.tsx b/packages/example/src/Lottie/Halloween/Balloons.tsx index b9aabd4de0e..bf86da7f02c 100644 --- a/packages/example/src/Lottie/Halloween/Balloons.tsx +++ b/packages/example/src/Lottie/Halloween/Balloons.tsx @@ -43,7 +43,7 @@ const Balloons = () => { setError(err); console.log('Animation failed to load', err); }); - }, [handle]); + }, [handle, continueRender]); if (!animationData) { return null; From 12e9d975e0fbf4b078da02d77dea3c2f5e67c4ad Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Tue, 17 Feb 2026 18:57:14 +0100 Subject: [PATCH 4/6] `@remotion/it-tests`: Increase frame accuracy test timeout and limit concurrency Co-Authored-By: Claude Opus 4.6 --- packages/it-tests/src/rendering/frame-accuracy.test.ts | 8 ++++---- packages/it-tests/src/rendering/test-utils.ts | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/it-tests/src/rendering/frame-accuracy.test.ts b/packages/it-tests/src/rendering/frame-accuracy.test.ts index aa2fa12870a..4f1675e6e57 100644 --- a/packages/it-tests/src/rendering/frame-accuracy.test.ts +++ b/packages/it-tests/src/rendering/frame-accuracy.test.ts @@ -8,7 +8,7 @@ test( expect(missedFrames).toBeLessThanOrEqual(8); }, { - timeout: 30000, + timeout: 60000, }, ); @@ -19,7 +19,7 @@ test( expect(missedFrames).toBe(0); }, { - timeout: 30000, + timeout: 60000, }, ); @@ -30,7 +30,7 @@ test( expect(missedFrames).toBeLessThanOrEqual(8); }, { - timeout: 30000, + timeout: 60000, }, ); @@ -41,6 +41,6 @@ test( expect(missedFrames).toBe(0); }, { - timeout: 30000, + timeout: 60000, }, ); diff --git a/packages/it-tests/src/rendering/test-utils.ts b/packages/it-tests/src/rendering/test-utils.ts index da4b04a12fb..b18f4730bc3 100644 --- a/packages/it-tests/src/rendering/test-utils.ts +++ b/packages/it-tests/src/rendering/test-utils.ts @@ -152,6 +152,8 @@ async function saveSequenceInTempDir(id: string) { '--image-format', 'png', '--sequence', + '--concurrency', + '2', ], { cwd: path.join(process.cwd(), '..', 'example'), From 713722912c19e20561a0b3a7a03b63c17573bf5c Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Tue, 17 Feb 2026 18:58:40 +0100 Subject: [PATCH 5/6] Update remotion.config.ts --- packages/example/remotion.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/example/remotion.config.ts b/packages/example/remotion.config.ts index 56b0ff09068..912bffef8bb 100644 --- a/packages/example/remotion.config.ts +++ b/packages/example/remotion.config.ts @@ -8,3 +8,5 @@ Config.overrideWebpackConfig(async (config) => { }); return webpackOverride(config); }); + +Config.setExperimentalClientSideRenderingEnabled(true); From bff3ef1ed761c8ef02b93dcd2dc6e5ce91a3967e Mon Sep 17 00:00:00 2001 From: JonnyBurger Date: Tue, 17 Feb 2026 20:41:35 +0100 Subject: [PATCH 6/6] Convert concurrency to a proper AnyRemotionOption Move the concurrency CLI flag from manual parsing in parse-command-line.ts to the standard AnyRemotionOption system, consistent with other options like scale, every-nth-frame, etc. Co-Authored-By: Claude Opus 4.6 --- packages/cli/src/config/index.ts | 4 +- packages/cli/src/get-cli-options.ts | 6 ++- packages/cli/src/get-render-defaults.ts | 3 +- packages/cli/src/parse-command-line.ts | 11 +---- packages/docs/docs/cli/render.mdx | 2 +- packages/docs/docs/cloudrun/cli/render.mdx | 2 +- packages/docs/docs/config.mdx | 3 +- packages/renderer/src/index.ts | 1 + packages/renderer/src/options/concurrency.tsx | 46 +++++++++++++++++++ packages/renderer/src/options/index.tsx | 2 + 10 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 packages/renderer/src/options/concurrency.tsx diff --git a/packages/cli/src/config/index.ts b/packages/cli/src/config/index.ts index 567c32a727b..3f9463fb34a 100644 --- a/packages/cli/src/config/index.ts +++ b/packages/cli/src/config/index.ts @@ -37,7 +37,6 @@ import { setBufferStateDelayInMilliseconds, } from './buffer-state-delay-in-milliseconds'; import type {Concurrency} from './concurrency'; -import {setConcurrency} from './concurrency'; import {getEntryPoint, setEntryPoint} from './entry-point'; import {setDotEnvLocation} from './env-file'; import { @@ -63,6 +62,7 @@ import {getWidth, overrideWidth} from './width'; export type {Concurrency, WebpackConfiguration, WebpackOverrideFn}; const { + concurrencyOption, offthreadVideoCacheSizeInBytesOption, x264Option, audioBitrateOption, @@ -664,7 +664,7 @@ export const Config: FlatConfig = { setChromiumOpenGlRenderer: glOption.setConfig, setChromiumUserAgent: userAgentOption.setConfig, setDotEnvLocation, - setConcurrency, + setConcurrency: concurrencyOption.setConfig, setChromiumMultiProcessOnLinux: enableMultiprocessOnLinuxOption.setConfig, setChromiumDarkMode: darkModeOption.setConfig, setQuality: () => { diff --git a/packages/cli/src/get-cli-options.ts b/packages/cli/src/get-cli-options.ts index d37a614d58e..3a57a0ca11c 100644 --- a/packages/cli/src/get-cli-options.ts +++ b/packages/cli/src/get-cli-options.ts @@ -1,11 +1,13 @@ import type {LogLevel} from '@remotion/renderer'; import {RenderInternals} from '@remotion/renderer'; +import {BrowserSafeApis} from '@remotion/renderer/client'; import fs from 'node:fs'; import path from 'node:path'; import {ConfigInternals} from './config'; import {getEnvironmentVariables} from './get-env'; import {getInputProps} from './get-input-props'; import {Log} from './log'; +import {parsedCli} from './parsed-cli'; const getAndValidateFrameRange = (logLevel: LogLevel, indent: boolean) => { const frameRange = ConfigInternals.getRange(); @@ -58,7 +60,9 @@ export const getCliOptions = (options: { ? true : ConfigInternals.getShouldOutputImageSequence(frameRange); - const concurrency = ConfigInternals.getConcurrency(); + const concurrency = BrowserSafeApis.options.concurrencyOption.getValue({ + commandLine: parsedCli, + }).value; const height = ConfigInternals.getHeight(); const width = ConfigInternals.getWidth(); diff --git a/packages/cli/src/get-render-defaults.ts b/packages/cli/src/get-render-defaults.ts index af0964ec6ee..a00f1993331 100644 --- a/packages/cli/src/get-render-defaults.ts +++ b/packages/cli/src/get-render-defaults.ts @@ -8,6 +8,7 @@ const { x264Option, audioBitrateOption, offthreadVideoCacheSizeInBytesOption, + concurrencyOption, offthreadVideoThreadsOption, scaleOption, jpegQualityOption, @@ -49,7 +50,7 @@ export const getRenderDefaults = (): RenderDefaults => { const logLevel = logLevelOption.getValue({commandLine: parsedCli}).value; const defaultCodec = ConfigInternals.getOutputCodecOrUndefined(); const concurrency = RenderInternals.resolveConcurrency( - ConfigInternals.getConcurrency(), + concurrencyOption.getValue({commandLine: parsedCli}).value, ); const pixelFormat = pixelFormatOption.getValue({ commandLine: parsedCli, diff --git a/packages/cli/src/parse-command-line.ts b/packages/cli/src/parse-command-line.ts index 1d0c8e8bdf0..9d8e5e62ce9 100644 --- a/packages/cli/src/parse-command-line.ts +++ b/packages/cli/src/parse-command-line.ts @@ -13,6 +13,7 @@ import {parsedCli} from './parsed-cli'; const { beepOnFinishOption, colorSpaceOption, + concurrencyOption, disallowParallelEncodingOption, offthreadVideoCacheSizeInBytesOption, encodingBufferSizeOption, @@ -75,7 +76,7 @@ export type CommandLineOptions = { [beepOnFinishOption.cliFlag]: TypeOfOption; version: string; codec: Codec; - concurrency: number; + [concurrencyOption.cliFlag]: TypeOfOption; timeout: number; config: string; ['public-dir']: string; @@ -140,10 +141,6 @@ export const parseCommandLine = () => { Config.setCachingEnabled(parsedCli['bundle-cache'] !== 'false'); } - if (parsedCli.concurrency) { - Config.setConcurrency(parsedCli.concurrency); - } - if (parsedCli.height) { Config.overrideHeight(parsedCli.height); } @@ -177,10 +174,6 @@ export const parseCommandLine = () => { Config.setPublicLicenseKey(parsedCli['license-key']); } - if (parsedCli['public-license-key']) { - Config.setPublicLicenseKey(parsedCli['public-license-key']); - } - if (typeof parsedCli['webpack-poll'] !== 'undefined') { Config.setWebpackPollingInMilliseconds(parsedCli['webpack-poll']); } diff --git a/packages/docs/docs/cli/render.mdx b/packages/docs/docs/cli/render.mdx index b1aea02c872..2b3a9141682 100644 --- a/packages/docs/docs/cli/render.mdx +++ b/packages/docs/docs/cli/render.mdx @@ -41,7 +41,7 @@ Inline JSON string isn't supported on Windows shells because it removes the `"` ### `--concurrency` -[How many CPU threads to use.](/docs/config#setconcurrency) Minimum 1. The maximum is the amount of threads you have (In Node.JS `os.cpus().length`). You can also provide a percentage value (e.g. `50%`). + ### `--pixel-format` diff --git a/packages/docs/docs/cloudrun/cli/render.mdx b/packages/docs/docs/cloudrun/cli/render.mdx index 9965b9561d2..9265804c6a8 100644 --- a/packages/docs/docs/cloudrun/cli/render.mdx +++ b/packages/docs/docs/cloudrun/cli/render.mdx @@ -75,7 +75,7 @@ Specify a specific bucket name to be used for the output. The resulting Google C ### `--concurrency` -A number or a string describing how many browser tabs should be opened. Default "50%". + :::note Before v4.0.76, this was "100%" by default. It is now aligned to the other server-side rendering APIs. diff --git a/packages/docs/docs/config.mdx b/packages/docs/docs/config.mdx index a4d42848ed6..348ddfa60c8 100644 --- a/packages/docs/docs/config.mdx +++ b/packages/docs/docs/config.mdx @@ -307,8 +307,7 @@ The [command line flag](/docs/cli/render#--gl) `--gl` will take precedence over ## `setConcurrency()` -Sets how many Puppeteer instances will work on rendering your video in parallel. -Default: `null`, meaning **half of the threads** available on your CPU. + ```ts twoslash title="remotion.config.ts" import {Config} from '@remotion/cli/config'; diff --git a/packages/renderer/src/index.ts b/packages/renderer/src/index.ts index 90457f574ef..e2c96e88bf1 100644 --- a/packages/renderer/src/index.ts +++ b/packages/renderer/src/index.ts @@ -103,6 +103,7 @@ export {openBrowser} from './open-browser'; export type {ChromiumOptions} from './open-browser'; export {ChromeMode} from './options/chrome-mode'; export {ColorSpace} from './options/color-space'; +export type {Concurrency} from './options/concurrency'; export type {DeleteAfter} from './options/delete-after'; export {OpenGlRenderer} from './options/gl'; export {NumberOfGifLoops} from './options/number-of-gif-loops'; diff --git a/packages/renderer/src/options/concurrency.tsx b/packages/renderer/src/options/concurrency.tsx new file mode 100644 index 00000000000..81314bd273d --- /dev/null +++ b/packages/renderer/src/options/concurrency.tsx @@ -0,0 +1,46 @@ +import type {AnyRemotionOption} from './option'; + +export type Concurrency = number | string | null; + +let currentConcurrency: Concurrency = null; + +const cliFlag = 'concurrency' as const; + +export const concurrencyOption = { + name: 'Concurrency', + cliFlag, + description: () => ( + <> + How many CPU threads to use. Minimum 1. The maximum is the amount of + threads you have (In Node.JS os.cpus().length). You can also + provide a percentage value (e.g. 50%). + + ), + ssrName: 'concurrency' as const, + docLink: 'https://www.remotion.dev/docs/config#setconcurrency', + type: null as Concurrency, + getValue: ({commandLine}) => { + if (commandLine[cliFlag] !== undefined) { + return { + source: 'cli', + value: commandLine[cliFlag] as Concurrency, + }; + } + + if (currentConcurrency !== null) { + return { + source: 'config', + value: currentConcurrency, + }; + } + + return { + source: 'default', + value: null, + }; + }, + setConfig: (value) => { + currentConcurrency = value; + }, + id: cliFlag, +} satisfies AnyRemotionOption; diff --git a/packages/renderer/src/options/index.tsx b/packages/renderer/src/options/index.tsx index 563a2b4c847..bb1e7dcb3f6 100644 --- a/packages/renderer/src/options/index.tsx +++ b/packages/renderer/src/options/index.tsx @@ -7,6 +7,7 @@ import {binariesDirectoryOption} from './binaries-directory'; import {browserExecutableOption} from './browser-executable'; import {chromeModeOption} from './chrome-mode'; import {colorSpaceOption} from './color-space'; +import {concurrencyOption} from './concurrency'; import {crfOption} from './crf'; import {enableCrossSiteIsolationOption} from './cross-site-isolation'; import {darkModeOption} from './dark-mode'; @@ -68,6 +69,7 @@ import {x264Option} from './x264-preset'; export const allOptions = { audioCodecOption, browserExecutableOption, + concurrencyOption, scaleOption, crfOption, jpegQualityOption,