From 09466652840c6fff683d154ee4a9d638e4887006 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 13:20:47 +0100 Subject: [PATCH 1/7] `@remotion/renderer`: Surface signal when FFmpeg process is killed Co-Authored-By: Claude Opus 4.6 --- packages/renderer/src/prespawn-ffmpeg.ts | 8 +++++--- packages/renderer/src/render-media.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/renderer/src/prespawn-ffmpeg.ts b/packages/renderer/src/prespawn-ffmpeg.ts index 9706d2db43d..5382f938742 100644 --- a/packages/renderer/src/prespawn-ffmpeg.ts +++ b/packages/renderer/src/prespawn-ffmpeg.ts @@ -32,6 +32,7 @@ type RunningStatus = | { type: 'quit-with-error'; exitCode: number; + signal: NodeJS.Signals | null; stderr: string; }; @@ -164,11 +165,12 @@ export const prespawnFfmpeg = (options: PreStitcherOptions) => { type: 'running', }; - task.on('exit', (code) => { - if (typeof code === 'number' && code > 0) { + task.on('exit', (code, signal) => { + if ((typeof code === 'number' && code > 0) || signal) { exitCode = { type: 'quit-with-error', - exitCode: code, + exitCode: code ?? 1, + signal: signal ?? null, stderr: ffmpegOutput, }; } else { diff --git a/packages/renderer/src/render-media.ts b/packages/renderer/src/render-media.ts index 960a54131cf..56eff13e4b6 100644 --- a/packages/renderer/src/render-media.ts +++ b/packages/renderer/src/render-media.ts @@ -702,7 +702,7 @@ const internalRenderMediaRaw = ({ if (exitStatus?.type === 'quit-with-error') { throw new Error( - `FFmpeg quit with code ${exitStatus.exitCode} while piping frame ${frame}. Stderr: ${exitStatus.stderr}}`, + `FFmpeg quit with code ${exitStatus.exitCode}${exitStatus.signal ? ` (signal ${exitStatus.signal})` : ''} while piping frame ${frame}. Stderr: ${exitStatus.stderr}}`, ); } From a1fbd8c0962e663e786249e6d4e58782ca232858 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 13:37:57 +0100 Subject: [PATCH 2/7] `@remotion/discord-poster`: Split changelog into chunks to avoid Discord 2000 char limit Co-Authored-By: Claude Opus 4.6 --- packages/discord-poster/post.ts | 87 +++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/packages/discord-poster/post.ts b/packages/discord-poster/post.ts index c5f6bec681a..1d8ba2346fe 100644 --- a/packages/discord-poster/post.ts +++ b/packages/discord-poster/post.ts @@ -1,41 +1,68 @@ +const DISCORD_MAX_LENGTH = 2000; + const latestRelease = await fetch( - "https://api.github.com/repos/remotion-dev/remotion/releases?per_page=1" + 'https://api.github.com/repos/remotion-dev/remotion/releases?per_page=1', ); const json = await latestRelease.json(); const markdown = [ - `${json[0].tag_name} has been released!`, - `<:merge:909914451447259177> ${json[0].html_url}`, - ...json[0].body.split("\n").map((s) => { - if (s.startsWith("## ")) { - return s.replace("## ", "**<:love:989990489824559104> ") + "**"; - } - return s; - }), + `${json[0].tag_name} has been released!`, + `<:merge:909914451447259177> ${json[0].html_url}`, + ...json[0].body.split('\n').map((s: string) => { + if (s.startsWith('## ')) { + return s.replace('## ', '**<:love:989990489824559104> ') + '**'; + } + return s; + }), ] - .filter(Boolean) - .join("\n"); - -const res = await fetch( - `https://discord.com/api/channels/994527481598070815/messages`, - { - method: "post", - body: JSON.stringify({ - content: markdown, - allowed_mentions: {}, - flags: 1 << 2, - }), - headers: { - "Content-Type": "application/json", - Authorization: `Bot ${process.env.DISCORD_TOKEN}`, - }, - } -); + .filter(Boolean) + .join('\n'); + +const splitIntoChunks = (text: string): string[] => { + const chunks: string[] = []; + let remaining = text; + + while (remaining.length > 0) { + if (remaining.length <= DISCORD_MAX_LENGTH) { + chunks.push(remaining); + break; + } + + const slice = remaining.slice(0, DISCORD_MAX_LENGTH); + const lastNewline = slice.lastIndexOf('\n'); + const splitAt = lastNewline > 0 ? lastNewline : DISCORD_MAX_LENGTH; + + chunks.push(remaining.slice(0, splitAt)); + remaining = remaining.slice(splitAt).replace(/^\n/, ''); + } + + return chunks; +}; + +const chunks = splitIntoChunks(markdown); + +for (const chunk of chunks) { + const res = await fetch( + `https://discord.com/api/channels/994527481598070815/messages`, + { + method: 'post', + body: JSON.stringify({ + content: chunk, + allowed_mentions: {}, + flags: 1 << 2, + }), + headers: { + 'Content-Type': 'application/json', + Authorization: `Bot ${process.env.DISCORD_TOKEN}`, + }, + }, + ); -if (res.status !== 200) { - console.log(await res.text()); - process.exit(1); + if (res.status !== 200) { + console.log(await res.text()); + process.exit(1); + } } export {}; From 0ea92729cf5de9056afda35d7e609223e5a55d45 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 13:43:09 +0100 Subject: [PATCH 3/7] Fix extra closing brace in FFmpeg error messages Co-Authored-By: Claude Opus 4.6 --- packages/renderer/src/render-media.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/renderer/src/render-media.ts b/packages/renderer/src/render-media.ts index 56eff13e4b6..e43b8f2152f 100644 --- a/packages/renderer/src/render-media.ts +++ b/packages/renderer/src/render-media.ts @@ -696,13 +696,13 @@ const internalRenderMediaRaw = ({ const exitStatus = preStitcher?.getExitStatus(); if (exitStatus?.type === 'quit-successfully') { throw new Error( - `FFmpeg already quit while trying to pipe frame ${frame} to it. Stderr: ${exitStatus.stderr}}`, + `FFmpeg already quit while trying to pipe frame ${frame} to it. Stderr: ${exitStatus.stderr}`, ); } if (exitStatus?.type === 'quit-with-error') { throw new Error( - `FFmpeg quit with code ${exitStatus.exitCode}${exitStatus.signal ? ` (signal ${exitStatus.signal})` : ''} while piping frame ${frame}. Stderr: ${exitStatus.stderr}}`, + `FFmpeg quit with code ${exitStatus.exitCode}${exitStatus.signal ? ` (signal ${exitStatus.signal})` : ''} while piping frame ${frame}. Stderr: ${exitStatus.stderr}`, ); } From cc3644b46aa93593c0fa10739cd0a997ce333013 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 13:55:32 +0100 Subject: [PATCH 4/7] Add TypeScript types reference page for @remotion/renderer Create a dedicated types.mdx page documenting all public TypeScript types exported from @remotion/renderer, following the same pattern as the @remotion/web-renderer types page. Update render-media.mdx to use references linking to the exported types instead of inline type literals. Co-Authored-By: Claude Opus 4.6 --- packages/docs/docs/renderer/render-media.mdx | 38 +-- packages/docs/docs/renderer/types.mdx | 250 ++++++++++++++++++ packages/docs/sidebars.ts | 1 + packages/docs/src/data/articles.ts | 9 + .../articles-docs-renderer-types.png | Bin 0 -> 51943 bytes 5 files changed, 280 insertions(+), 18 deletions(-) create mode 100644 packages/docs/docs/renderer/types.mdx create mode 100644 packages/docs/static/generated/articles-docs-renderer-types.png diff --git a/packages/docs/docs/renderer/render-media.mdx b/packages/docs/docs/renderer/render-media.mdx index a9ed26d6726..b8b1b1318fb 100644 --- a/packages/docs/docs/renderer/render-media.mdx +++ b/packages/docs/docs/renderer/render-media.mdx @@ -71,7 +71,7 @@ Call [`selectComposition()`](/docs/renderer/select-composition) or [`getComposit ### `codec` -_"h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif"_ +_string_ Choose a suitable codec for your output media. Refer to the [Encoding guide](/docs/encoding) to find the best codec for your use case. @@ -88,12 +88,14 @@ Make sure to also pass the same `inputProps` to [`selectComposition()`](/docs/re ### `frameRange?` -_number | [number, number] | [number, null]_ +_number | [number, number] | [number, null]_ Specify a single frame (passing a `number`) or a range of frames (passing a tuple `[number, number]`) to be rendered. By passing `null` (default) all frames of a composition get rendered. Pass `[number, null]` to render from a frame to the end of the composition. ### `concurrency?` +_number | string | null_ + A `number` specifying how many render processes should be started in parallel, a `string` specifying the percentage of the CPU threads to use (e.g. `50%`), or `null` to let Remotion decide based on the CPU of the host machine. Default is half of the CPU threads available. ### `metadata?` @@ -108,11 +110,13 @@ _object_ ### `onArtifact?` +_function_ + [Handle an artifact](/docs/artifacts#using-rendermedia-renderstill-or-renderframes) that was emitted by the [``](/docs/artifact) component. ### `audioCodec?` -_"pcm-16" | "aac" | "mp3" | "opus", available from v3.3.41_ +_string_ Choose the encoding of your audio. @@ -133,7 +137,7 @@ Refer to the [Encoding guide](/docs/encoding/#audio-codec) to see defaults and s ### `crf?` -_number | null_ +_number | null_ The constant rate factor, controlling the quality. See: [Controlling quality using the CRF setting.](/docs/encoding/#controlling-quality-using-the-crf-setting) @@ -151,7 +155,7 @@ If you enable [hardware acceleration](/docs/hardware-acceleration), you cannot s ### `imageFormat?` -_"jpeg" (default) | "png" | "none", since v3.2.27_ +_string_ In which image format the frames should be rendered. @@ -173,7 +177,7 @@ Renders only every nth frame. For example only every second frame, every third f ### `pixelFormat?` -_string_ +_string_ [A custom pixel format to use.](/docs/transparent-videos/) Usually used for special use cases like transparent videos. @@ -231,12 +235,12 @@ If set to false, the output file will not be written if a file already exists. ### `onStart?` -_function_ +_function_ Callback function that gets called once the renderer has prepared to start rendering and has calculated the amount of frames that are going to be rendered: ```tsx twoslash -import {OnStartData} from '@remotion/renderer'; +import type {OnStartData} from '@remotion/renderer'; const onStart = ({ frameCount, @@ -255,12 +259,12 @@ const onStart = ({ ### `onProgress?` -_function_ +_function_ React to render progress. The following callback function is similar to how Remotion displays render progress on it's CLI: ```tsx twoslash title="Simple example - Log overall progress" -import {RenderMediaOnProgress} from '@remotion/renderer'; +import type {RenderMediaOnProgress} from '@remotion/renderer'; const onProgress: RenderMediaOnProgress = ({progress}) => { console.log(`Rendering is ${progress * 100}% complete`); @@ -268,7 +272,7 @@ const onProgress: RenderMediaOnProgress = ({progress}) => { ``` ```tsx twoslash title="Advanced example - Fine-grained progress values" -import {RenderMediaOnProgress} from '@remotion/renderer'; +import type {RenderMediaOnProgress} from '@remotion/renderer'; const onProgress: RenderMediaOnProgress = ({renderedFrames, encodedFrames, encodedDoneIn, renderedDoneIn, stitchStage}) => { if (stitchStage === 'encoding') { @@ -300,12 +304,12 @@ The `progress` attribute is available from v3.2.17. ### `onDownload?` -_function_ +_function_ If an audio (or a video with sound) is included in your project, Remotion needs to download it in order to use it's audio in the output file. You can use this callback to react to a download happening and progressing. ```tsx twoslash -import {RenderMediaOnDownload} from '@remotion/renderer'; +import type {RenderMediaOnDownload} from '@remotion/renderer'; const onDownload: RenderMediaOnDownload = (src) => { console.log(`Downloading ${src}...`); @@ -323,8 +327,6 @@ const onDownload: RenderMediaOnDownload = (src) => { ### `proResProfile?` -_string_ - Sets a ProRes profile. Only applies to videos rendered with `prores` codec. See [Encoding guide](/docs/encoding/#controlling-quality-using-prores-profile) for possible options. ### `x264Preset?` @@ -335,12 +337,12 @@ _string_ ### `onBrowserLog?` -_function_ +_function_ Catch a console message being printed. Example: ```tsx twoslash -import {BrowserLog} from '@remotion/renderer'; +import type {BrowserLog} from '@remotion/renderer'; const onBrowserLog = (log: BrowserLog) => { // `type` is the console.* method: `log`, `warn`, `error`, etc. @@ -406,7 +408,7 @@ Lets you set a custom user agent that the headless Chrome browser assumes. ### `ffmpegOverride?` -_function_ +_function_ Modifies the FFMPEG command that Remotion uses under the hood. It works reducer-style, meaning that you pass a function that takes a command as an argument and returns a new command. diff --git a/packages/docs/docs/renderer/types.mdx b/packages/docs/docs/renderer/types.mdx new file mode 100644 index 00000000000..ceac26de23e --- /dev/null +++ b/packages/docs/docs/renderer/types.mdx @@ -0,0 +1,250 @@ +--- +image: /generated/articles-docs-renderer-types.png +id: renderer-types +sidebar_label: Types +title: TypeScript Types Reference +slug: /renderer/types +crumb: '@remotion/renderer' +--- + +The following types are part of the API of `@remotion/renderer`: + +## `Codec` + +```tsx twoslash +import type {Codec} from '@remotion/renderer'; +// ^? +``` + +Refer to the [Encoding guide](/docs/encoding) for more information. + +## `AudioCodec` + +```tsx twoslash +import type {AudioCodec} from '@remotion/renderer'; +// ^? +``` + +Refer to the [Encoding guide](/docs/encoding/#audio-codec) to see defaults and supported combinations. + +## `VideoImageFormat` + +```tsx twoslash +import type {VideoImageFormat} from '@remotion/renderer'; +// ^? +``` + +## `StillImageFormat` + +```tsx twoslash +import type {StillImageFormat} from '@remotion/renderer'; +// ^? +``` + +## `PixelFormat` + +```tsx twoslash +import type {PixelFormat} from '@remotion/renderer'; +// ^? +``` + +## `FrameRange` + +```tsx twoslash +import type {FrameRange} from '@remotion/renderer'; +// ^? +``` + +- A single number renders only that frame +- A tuple `[start, end]` renders frames from `start` to `end` (inclusive) +- A tuple `[start, null]` renders frames from `start` to the end of the composition + +## `Concurrency` + +```tsx twoslash +import type {Concurrency} from '@remotion/renderer'; +// ^? +``` + +## `LogLevel` + +```tsx twoslash +import type {LogLevel} from '@remotion/renderer'; +// ^? +``` + +## `OpenGlRenderer` + +```tsx twoslash +import type {OpenGlRenderer} from '@remotion/renderer'; +// ^? +``` + +## `ChromeMode` + +```tsx twoslash +import type {ChromeMode} from '@remotion/renderer'; +// ^? +``` + +## `ColorSpace` + +```tsx twoslash +import type {ColorSpace} from '@remotion/renderer'; +// ^? +``` + +## `X264Preset` + +```tsx twoslash +import type {X264Preset} from '@remotion/renderer'; +// ^? +``` + +## `Crf` + +```tsx twoslash +import type {Crf} from '@remotion/renderer'; +// ^? +``` + +## `Bitrate` + +```tsx twoslash +import type {Bitrate} from '@remotion/renderer'; +// ^? +``` + +## `ChromiumOptions` + +```tsx twoslash +import type {ChromiumOptions} from '@remotion/renderer'; +// ^? +``` + +## `OnStartData` + +```tsx twoslash +import type {OnStartData} from '@remotion/renderer'; +// ^? +``` + +- `frameCount`: The number of frames that will be rendered +- `parallelEncoding`: Whether parallel encoding is enabled +- `resolvedConcurrency`: The concurrency that will be used + +## `RenderMediaOnProgress` + +```tsx twoslash +import type {RenderMediaOnProgress} from '@remotion/renderer'; +// ^? +``` + +## `StitchingState` + +```tsx twoslash +import type {StitchingState} from '@remotion/renderer'; +// ^? +``` + +- `encoding`: Rendering frames and encoding into video +- `muxing`: Encoding audio and combining it with video (only when parallel encoding is used) + +## `SlowFrame` + +```tsx twoslash +import type {SlowFrame} from '@remotion/renderer'; +// ^? +``` + +## `RenderMediaOnDownload` + +```tsx twoslash +import type {RenderMediaOnDownload} from '@remotion/renderer'; +// ^? +``` + +## `BrowserLog` + +```tsx twoslash +import type {BrowserLog} from '@remotion/renderer'; +// ^? +``` + +- `type`: The `console.*` method (`log`, `warn`, `error`, etc.) +- `text`: The logged message +- `stackTrace`: The stack trace of the log + +## `FfmpegOverrideFn` + +```tsx twoslash +import type {FfmpegOverrideFn} from '@remotion/renderer'; +// ^? +``` + +## `OnArtifact` + +```tsx twoslash +import type {OnArtifact} from '@remotion/renderer'; +// ^? +``` + +## `EmittedArtifact` + +```tsx twoslash +import type {EmittedArtifact} from '@remotion/renderer'; +// ^? +``` + +- `filename`: The name of the artifact file +- `content`: The content of the artifact as a `string` or `Uint8Array` +- `frame`: The frame number at which the artifact was emitted + +## `OnBrowserDownload` + +```tsx twoslash +import type {OnBrowserDownload} from '@remotion/renderer'; +// ^? +``` + +## `DownloadBrowserProgressFn` + +```tsx twoslash +import type {DownloadBrowserProgressFn} from '@remotion/renderer'; +// ^? +``` + +## `NumberOfGifLoops` + +```tsx twoslash +import type {NumberOfGifLoops} from '@remotion/renderer'; +// ^? +``` + +## `RenderMediaOptions` + +```tsx twoslash +import type {RenderMediaOptions} from '@remotion/renderer'; +// ^? +``` + +## `RenderStillOptions` + +```tsx twoslash +import type {RenderStillOptions} from '@remotion/renderer'; +// ^? +``` + +## `RenderFramesOptions` + +```tsx twoslash +import type {RenderFramesOptions} from '@remotion/renderer'; +// ^? +``` + +## `SelectCompositionOptions` + +```tsx twoslash +import type {SelectCompositionOptions} from '@remotion/renderer'; +// ^? +``` diff --git a/packages/docs/sidebars.ts b/packages/docs/sidebars.ts index 3b924af0a16..5a67a2c9d56 100644 --- a/packages/docs/sidebars.ts +++ b/packages/docs/sidebars.ts @@ -555,6 +555,7 @@ const sidebars: SidebarsConfig = { 'renderer/get-silent-parts', 'renderer/combine-chunks', 'renderer/extract-audio', + 'renderer/renderer-types', ], }, { diff --git a/packages/docs/src/data/articles.ts b/packages/docs/src/data/articles.ts index 4c017c8e851..f13fae7bcda 100644 --- a/packages/docs/src/data/articles.ts +++ b/packages/docs/src/data/articles.ts @@ -5115,6 +5115,15 @@ export const articles = [ noAi: false, slug: 'renderer/stitch-frames-to-video', }, + { + id: 'renderer-types', + title: 'TypeScript Types Reference', + relativePath: 'docs/renderer/types.mdx', + compId: 'articles-docs-renderer-types', + crumb: '@remotion/renderer', + noAi: false, + slug: 'renderer/types', + }, { id: 'resources', title: 'List of resources', diff --git a/packages/docs/static/generated/articles-docs-renderer-types.png b/packages/docs/static/generated/articles-docs-renderer-types.png new file mode 100644 index 0000000000000000000000000000000000000000..658e4644208385b1e93c8368f031c68ee259d09e GIT binary patch literal 51943 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

K)bR_%TTyng|wf>EnuY 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 Date: Thu, 19 Feb 2026 14:15:01 +0100 Subject: [PATCH 5/7] Mark getVideoMetadata() as deprecated in renderer table of contents Co-Authored-By: Claude Opus 4.6 --- packages/docs/docs/renderer/TableOfContents.tsx | 4 +++- packages/docs/docs/renderer/types.mdx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/docs/docs/renderer/TableOfContents.tsx b/packages/docs/docs/renderer/TableOfContents.tsx index 71551f8ac42..6708e3dcb92 100644 --- a/packages/docs/docs/renderer/TableOfContents.tsx +++ b/packages/docs/docs/renderer/TableOfContents.tsx @@ -44,7 +44,9 @@ export const TableOfContents: React.FC = () => {

Create token to later cancel a render
- getVideoMetadata() + + getVideoMetadata() +
Get metadata from a video file in Node.js
diff --git a/packages/docs/docs/renderer/types.mdx b/packages/docs/docs/renderer/types.mdx index ceac26de23e..e0082a44fd1 100644 --- a/packages/docs/docs/renderer/types.mdx +++ b/packages/docs/docs/renderer/types.mdx @@ -105,7 +105,7 @@ import type {X264Preset} from '@remotion/renderer'; ```tsx twoslash import type {Crf} from '@remotion/renderer'; -// ^? +// ^? ``` ## `Bitrate` From 27b84d37c16837c89200e495b916ef001d298b55 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 14:43:42 +0100 Subject: [PATCH 6/7] with card --- packages/docs/docs/renderer/render-frames.mdx | 4 - packages/docs/docs/renderer/render-media.mdx | 59 +++++++------ packages/docs/docs/renderer/render-still.mdx | 46 ++++++---- .../theme/CodeBlock/styles.css | 1 + packages/docs/src/components/TsType.tsx | 48 +++++++--- packages/docs/src/css/custom.css | 9 ++ packages/renderer/src/render-frames.ts | 88 ++++++++++--------- packages/renderer/src/select-composition.ts | 34 ++++--- 8 files changed, 173 insertions(+), 116 deletions(-) diff --git a/packages/docs/docs/renderer/render-frames.mdx b/packages/docs/docs/renderer/render-frames.mdx index dccf4323ddc..aa540513aba 100644 --- a/packages/docs/docs/renderer/render-frames.mdx +++ b/packages/docs/docs/renderer/render-frames.mdx @@ -15,10 +15,6 @@ If you want to render only a still image, use [renderStill()](/docs/renderer/ren In Remotion 3.0, we added the [`renderMedia()`](/docs/renderer/render-media) API which combines `renderFrames()` and `stitchFramesToVideo()` into one simplified step and performs the render faster. Prefer `renderMedia()` if you can. ::: -:::info -Configuration in `remotion.config.ts` and CLI flags do not apply to this function. You must pass all options explicitly. -::: - ## Arguments Takes an object with the following keys: diff --git a/packages/docs/docs/renderer/render-media.mdx b/packages/docs/docs/renderer/render-media.mdx index b8b1b1318fb..30269d41bee 100644 --- a/packages/docs/docs/renderer/render-media.mdx +++ b/packages/docs/docs/renderer/render-media.mdx @@ -5,9 +5,9 @@ title: renderMedia() crumb: '@remotion/renderer' --- -_Part of the `@remotion/renderer` package._ +# renderMedia() - +_Part of the `@remotion/renderer` package._ Render a video or an audio programmatically. @@ -28,7 +28,6 @@ const composition = await selectComposition({ }); // ---cut--- - await renderMedia({ composition, serveUrl, @@ -50,31 +49,27 @@ _string_ Either a local path pointing to a Remotion Webpack bundle generated by [`bundle()`](/docs/bundle) or a URL where the bundle is hosted. -### `port?` - -Prefer a specific port that will be used to serve the Remotion project. If not specified, a random port will be used. - -### `outputLocation?` - -_string, since v3.0.26_ - -Where to save the output artifact to. Either an absolute path or a relative path that will be resolved relative to the current working directory. Must be a file path (not a folder). - -If not specified or set to `null`, the file will be returned in-memory as a buffer. - ### `composition` _VideoConfig_ -An object describing a composition using `id`, `width`, `height`, `fps` and `durationInFrames`, `defaultProps` and `props`. +An object describing a composition using `id`, `width`, `height`, `fps` and `durationInFrames`, `defaultProps` and `props`. Call [`selectComposition()`](/docs/renderer/select-composition) or [`getCompositions()`](/docs/renderer/get-compositions) to get an array of possible configs. ### `codec` -_string_ +_string_ Choose a suitable codec for your output media. Refer to the [Encoding guide](/docs/encoding) to find the best codec for your use case. +### `outputLocation?` + +_string_ + +Where to save the output artifact to. Either an absolute path or a relative path that will be resolved relative to the current working directory. Must be a file path (not a folder). + +If not specified or set to `null`, the file will be returned in-memory as a buffer. + ### `inputProps?` _object_ @@ -86,15 +81,21 @@ You may transform input props using [`calculateMetadata()`](/docs/calculate-meta Make sure to also pass the same `inputProps` to [`selectComposition()`](/docs/renderer/select-composition) for this to work correctly. +### `port?` + +_number_ + +Prefer a specific port that will be used to serve the Remotion project. If not specified, a random port will be used. + ### `frameRange?` -_number | [number, number] | [number, null]_ +_number | [number, number] | [number, null]_ Specify a single frame (passing a `number`) or a range of frames (passing a tuple `[number, number]`) to be rendered. By passing `null` (default) all frames of a composition get rendered. Pass `[number, null]` to render from a frame to the end of the composition. ### `concurrency?` -_number | string | null_ +_number | string | null_ A `number` specifying how many render processes should be started in parallel, a `string` specifying the percentage of the CPU threads to use (e.g. `50%`), or `null` to let Remotion decide based on the CPU of the host machine. Default is half of the CPU threads available. @@ -110,13 +111,13 @@ _object_ ### `onArtifact?` -_function_ +_function_ [Handle an artifact](/docs/artifacts#using-rendermedia-renderstill-or-renderframes) that was emitted by the [``](/docs/artifact) component. ### `audioCodec?` -_string_ +_string_ Choose the encoding of your audio. @@ -137,7 +138,7 @@ Refer to the [Encoding guide](/docs/encoding/#audio-codec) to see defaults and s ### `crf?` -_number | null_ +_number | null_ The constant rate factor, controlling the quality. See: [Controlling quality using the CRF setting.](/docs/encoding/#controlling-quality-using-the-crf-setting) @@ -155,7 +156,7 @@ If you enable [hardware acceleration](/docs/hardware-acceleration), you cannot s ### `imageFormat?` -_string_ +_string_ In which image format the frames should be rendered. @@ -177,7 +178,7 @@ Renders only every nth frame. For example only every second frame, every third f ### `pixelFormat?` -_string_ +_string_ [A custom pixel format to use.](/docs/transparent-videos/) Usually used for special use cases like transparent videos. @@ -235,7 +236,7 @@ If set to false, the output file will not be written if a file already exists. ### `onStart?` -_function_ +_function_ Callback function that gets called once the renderer has prepared to start rendering and has calculated the amount of frames that are going to be rendered: @@ -259,7 +260,7 @@ const onStart = ({ ### `onProgress?` -_function_ +_function_ React to render progress. The following callback function is similar to how Remotion displays render progress on it's CLI: @@ -304,7 +305,7 @@ The `progress` attribute is available from v3.2.17. ### `onDownload?` -_function_ +_function_ If an audio (or a video with sound) is included in your project, Remotion needs to download it in order to use it's audio in the output file. You can use this callback to react to a download happening and progressing. @@ -337,7 +338,7 @@ _string_ ### `onBrowserLog?` -_function_ +_function_ Catch a console message being printed. Example: @@ -408,7 +409,7 @@ Lets you set a custom user agent that the headless Chrome browser assumes. ### `ffmpegOverride?` -_function_ +_function_ Modifies the FFMPEG command that Remotion uses under the hood. It works reducer-style, meaning that you pass a function that takes a command as an argument and returns a new command. diff --git a/packages/docs/docs/renderer/render-still.mdx b/packages/docs/docs/renderer/render-still.mdx index f1027aed41f..523e9b90f17 100644 --- a/packages/docs/docs/renderer/render-still.mdx +++ b/packages/docs/docs/renderer/render-still.mdx @@ -5,17 +5,18 @@ title: renderStill() crumb: '@remotion/renderer' --- -_Part of the `@remotion/renderer` package._ +# renderStill() - +_Part of the `@remotion/renderer` package._ Renders a single frame to an image and writes it to the specified output location. -If you want to render a video, use [renderMedia()](/docs/renderer/render-media) instead. +If you want to render a video, use [`renderMedia()`](/docs/renderer/render-media) instead. ## Example usage -You first need to bundle the project and fetch the compositions. Read [the code snippet on the site for server-side rendering](/docs/ssr) for an example how to come up with the `bundleLocation` and `composition` variables. +You first need to bundle the project and fetch the compositions. +Read [the code snippet on the site for server-side rendering](/docs/ssr) for an example how to come up with the `serveUrl` and `composition` variables. ```ts twoslash import {bundle} from '@remotion/bundler'; @@ -24,11 +25,11 @@ import {getCompositions, renderStill} from '@remotion/renderer'; // The composition you want to render const compositionId = 'HelloWorld'; -const bundleLocation = await bundle({ +const serveUrl = await bundle({ entryPoint: require.resolve('./src/index.ts'), }); -const comps = await getCompositions(bundleLocation, { +const comps = await getCompositions(serveUrl, { inputProps: { custom: 'data', }, @@ -40,10 +41,9 @@ if (!composition) { } // ---cut--- - await renderStill({ composition, - serveUrl: bundleLocation, + serveUrl, output: '/tmp/still.png', inputProps: { custom: 'data', @@ -59,28 +59,36 @@ Takes an object with the following properties: _VideoConfig_ -An object describing a composition using `id`, `width`, `height`, `fps` and `durationInFrames`, `defaultProps` and `props`. +An object describing a composition using `id`, `width`, `height`, `fps` and `durationInFrames`, `defaultProps` and `props`. Call [`selectComposition()`](/docs/renderer/select-composition) or [`getCompositions()`](/docs/renderer/get-compositions) to get an array of possible configs. ### `serveUrl` -Either a local path pointing to a Remotion Webpack bundle generated by [`bundle()`](/docs/bundle) or a URL where the bundle is hosted. +_string_ -### `port?` - -Prefer a specific port that will be used to serve the Remotion project. If not specified, a random port will be used. +Either a local path pointing to a Remotion Webpack bundle generated by [`bundle()`](/docs/bundle) or a URL where the bundle is hosted. ### `output` +_string_ + An absolute path to where the frame should be rendered to. ### `inputProps?` -[Input Props to pass to the selected composition of your video.](/docs/passing-props#passing-input-props-in-the-cli). -Must be a JSON object. -From the root component the props can be read using [`getInputProps()`](/docs/get-input-props). +_object_ + +[Input Props to pass to the selected composition of your video.](/docs/passing-props#passing-input-props-in-the-cli). +Must be a JSON object. +From the root component the props can be read using [`getInputProps()`](/docs/get-input-props). You may transform input props using [`calculateMetadata()`](/docs/calculate-metadata). +### `port?` + +_number_ + +Prefer a specific port that will be used to serve the Remotion project. If not specified, a random port will be used. + ### `frame?` Which frame should be rendered based on its number. Default: `0`. Frames are zero-indexed. @@ -89,6 +97,8 @@ From v3.2.27, negative values are allowed, with `-1` being the last frame. ### `imageFormat?` +_string_ + Which output format the image should have, either `png`, `jpeg`, `webp` or `pdf`. Default: `"png"`. ### `scale?` @@ -117,6 +127,8 @@ An object containing key-value pairs of environment variables which will be inje ### `onArtifact?` +_function_ + [Handle an artifact](/docs/artifacts#using-rendermedia-renderstill-or-renderframes) that was emitted by the [``](/docs/artifact) component. ### `overwrite?` @@ -129,6 +141,8 @@ A string defining the absolute path on disk of the browser executable that shoul ### `onBrowserLog?` +_function_ + Gets called when your project calls `console.log` or another method from console. See the documentation for [`renderFrames`](/docs/renderer/render-frames#onbrowserlog) for more information. ### `timeoutInMilliseconds?` diff --git a/packages/docs/docusaurus-theme-shiki-twoslash/theme/CodeBlock/styles.css b/packages/docs/docusaurus-theme-shiki-twoslash/theme/CodeBlock/styles.css index a05bd93a495..199c93a8a78 100644 --- a/packages/docs/docusaurus-theme-shiki-twoslash/theme/CodeBlock/styles.css +++ b/packages/docs/docusaurus-theme-shiki-twoslash/theme/CodeBlock/styles.css @@ -79,6 +79,7 @@ pre.shiki .meta-line { pre.shiki > code { padding: var(--ifm-pre-padding) 0; display: block; + overflow: auto; } /* Also support old .code-container wrapper if rendererClassic produces it */ diff --git a/packages/docs/src/components/TsType.tsx b/packages/docs/src/components/TsType.tsx index 24f247caf00..6a0bb11561c 100644 --- a/packages/docs/src/components/TsType.tsx +++ b/packages/docs/src/components/TsType.tsx @@ -3,27 +3,51 @@ import React from 'react'; export const TsType: React.FC<{ readonly type: string; readonly source: string; -}> = ({type, source}) => { + readonly href?: string; +}> = ({type, source, href}) => { if (!type || !source) { throw new Error('type and source are required'); } + const icon = ( + + + + ); + + const content = ( + <> + {icon} + {type} + + ); + + if (href) { + return ( + + {content} + + ); + } + return ( - - - - {type} + {content} ); }; diff --git a/packages/docs/src/css/custom.css b/packages/docs/src/css/custom.css index f42f2f91ce7..1b0e0d391f5 100644 --- a/packages/docs/src/css/custom.css +++ b/packages/docs/src/css/custom.css @@ -148,6 +148,15 @@ code { text-decoration: underline; } +.ts-type-link { + text-decoration: none !important; + text-underline-position: under; +} + +.ts-type-link:hover { + text-decoration: underline !important; +} + .no-scroll-bar::-webkit-scrollbar { display: none; } diff --git a/packages/renderer/src/render-frames.ts b/packages/renderer/src/render-frames.ts index c0f6b648197..ff84670a0c4 100644 --- a/packages/renderer/src/render-frames.ts +++ b/packages/renderer/src/render-frames.ts @@ -157,47 +157,53 @@ export type FrameAndAssets = { inlineAudioAssets: InlineAudioAsset[]; }; -export type RenderFramesOptions = { - onStart: (data: OnStartData) => void; - onFrameUpdate: ( - framesRendered: number, - frameIndex: number, - timeToRenderInMilliseconds: number, - ) => void; - outputDir: string | null; - inputProps: Record; - envVariables?: Record; - imageFormat?: VideoImageFormat; - /** - * @deprecated Renamed to "jpegQuality" - */ - quality?: never; - frameRange?: FrameRange | null; - everyNthFrame?: number; - /** - * @deprecated Use "logLevel": "verbose" instead - */ - dumpBrowserLogs?: boolean; - /** - * @deprecated Use "logLevel" instead - */ - verbose?: boolean; - puppeteerInstance?: HeadlessBrowser; - browserExecutable?: BrowserExecutable; - onBrowserLog?: (log: BrowserLog) => void; - onFrameBuffer?: (buffer: Buffer, frame: number) => void; - onDownload?: RenderMediaOnDownload; - timeoutInMilliseconds?: number; - chromiumOptions?: ChromiumOptions; - scale?: number; - port?: number | null; - cancelSignal?: CancelSignal; - composition: VideoConfig; - muted?: boolean; - concurrency?: number | string | null; - onArtifact?: OnArtifact | null; - serveUrl: string; -} & Partial>; +type Prettify = { + [K in keyof T]: T[K]; +} & {}; + +export type RenderFramesOptions = Prettify< + { + onStart: (data: OnStartData) => void; + onFrameUpdate: ( + framesRendered: number, + frameIndex: number, + timeToRenderInMilliseconds: number, + ) => void; + outputDir: string | null; + inputProps: Record; + envVariables?: Record; + imageFormat?: VideoImageFormat; + /** + * @deprecated Renamed to "jpegQuality" + */ + quality?: never; + frameRange?: FrameRange | null; + everyNthFrame?: number; + /** + * @deprecated Use "logLevel": "verbose" instead + */ + dumpBrowserLogs?: boolean; + /** + * @deprecated Use "logLevel" instead + */ + verbose?: boolean; + puppeteerInstance?: HeadlessBrowser; + browserExecutable?: BrowserExecutable; + onBrowserLog?: (log: BrowserLog) => void; + onFrameBuffer?: (buffer: Buffer, frame: number) => void; + onDownload?: RenderMediaOnDownload; + timeoutInMilliseconds?: number; + chromiumOptions?: ChromiumOptions; + scale?: number; + port?: number | null; + cancelSignal?: CancelSignal; + composition: VideoConfig; + muted?: boolean; + concurrency?: number | string | null; + onArtifact?: OnArtifact | null; + serveUrl: string; + } & Partial> +>; const innerRenderFrames = async ({ onFrameUpdate, diff --git a/packages/renderer/src/select-composition.ts b/packages/renderer/src/select-composition.ts index 1726708b59d..d6906fcad4f 100644 --- a/packages/renderer/src/select-composition.ts +++ b/packages/renderer/src/select-composition.ts @@ -39,20 +39,26 @@ type InternalSelectCompositionsConfig = { onServeUrlVisited: () => void; } & ToOptions; -export type SelectCompositionOptions = RequiredInputPropsInV5 & { - envVariables?: Record; - puppeteerInstance?: HeadlessBrowser; - onBrowserLog?: (log: BrowserLog) => void; - browserExecutable?: BrowserExecutable; - chromiumOptions?: ChromiumOptions; - port?: number | null; - /** - * @deprecated Use `logLevel` instead. - */ - verbose?: boolean; - serveUrl: string; - id: string; -} & Partial>; +type Prettify = { + [K in keyof T]: T[K]; +} & {}; + +export type SelectCompositionOptions = Prettify< + RequiredInputPropsInV5 & { + envVariables?: Record; + puppeteerInstance?: HeadlessBrowser; + onBrowserLog?: (log: BrowserLog) => void; + browserExecutable?: BrowserExecutable; + chromiumOptions?: ChromiumOptions; + port?: number | null; + /** + * @deprecated Use `logLevel` instead. + */ + verbose?: boolean; + serveUrl: string; + id: string; + } & Partial> +>; type CleanupFn = () => Promise; From 6b1c3a61616c276f1c2470bc23d4994a9fa2132c Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 19 Feb 2026 15:03:59 +0100 Subject: [PATCH 7/7] renderer-types -> types --- packages/docs/docs/renderer/types.mdx | 2 +- packages/docs/sidebars.ts | 2 +- packages/docs/src/data/articles.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/docs/docs/renderer/types.mdx b/packages/docs/docs/renderer/types.mdx index e0082a44fd1..4615693efdd 100644 --- a/packages/docs/docs/renderer/types.mdx +++ b/packages/docs/docs/renderer/types.mdx @@ -1,6 +1,6 @@ --- image: /generated/articles-docs-renderer-types.png -id: renderer-types +id: types sidebar_label: Types title: TypeScript Types Reference slug: /renderer/types diff --git a/packages/docs/sidebars.ts b/packages/docs/sidebars.ts index 5a67a2c9d56..c3c363c4404 100644 --- a/packages/docs/sidebars.ts +++ b/packages/docs/sidebars.ts @@ -555,7 +555,7 @@ const sidebars: SidebarsConfig = { 'renderer/get-silent-parts', 'renderer/combine-chunks', 'renderer/extract-audio', - 'renderer/renderer-types', + 'renderer/types', ], }, { diff --git a/packages/docs/src/data/articles.ts b/packages/docs/src/data/articles.ts index f13fae7bcda..920d0806133 100644 --- a/packages/docs/src/data/articles.ts +++ b/packages/docs/src/data/articles.ts @@ -5116,7 +5116,7 @@ export const articles = [ slug: 'renderer/stitch-frames-to-video', }, { - id: 'renderer-types', + id: 'types', title: 'TypeScript Types Reference', relativePath: 'docs/renderer/types.mdx', compId: 'articles-docs-renderer-types',