Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/guides/rendering.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ browser already supports the source or you are diagnosing the proxy itself.
## Choose quality and frame rate

The default `standard` quality is the right choice for most finished work.
MOV is an alpha-preserving editing intermediate and always uses the fixed
ProRes 4444 profile. `--crf` and `--video-bitrate` do not map to that profile
and are rejected for MOV; choose MP4 or WebM when you need those controls.

```bash
# Faster review version
Expand Down
6 changes: 3 additions & 3 deletions docs/packages/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ The flags that come up most:
| `--composition, -c` | `index.html` | Render a different composition file. Sub-compositions using `<template>` wrappers must be referenced from `index.html` via `data-composition-src`. |
| `--format` | `mp4` | `mp4`, `webm`, `mov`, `gif`, or `png-sequence`. WebM and MOV carry transparency; `png-sequence` writes RGBA frames to a directory. |
| `--fps, -f` | root `data-fps`, otherwise 30 | 1–240, or an ffmpeg rational like `30000/1001` for 29.97 |
| `--quality, -q` | `standard` | `draft`, `standard`, or `high`. Drives CRF and bitrate. |
| `--quality, -q` | `standard` | `draft`, `standard`, or `high`. Drives MP4/WebM encoder settings; MOV always uses the fixed alpha-preserving ProRes 4444 profile. |
| `--resolution` | the composition's size | Supersample to a preset via Chrome's `deviceScaleFactor`. Aspect ratio must match and the scale must be a whole multiple. Not with `--hdr`. See [4K rendering](/guides/4k-rendering). |
| `--docker` | off | Render inside Docker for [deterministic output](/concepts/determinism) |
| `--variables` | — | JSON object merged over the composition's `data-composition-variables` defaults |
Expand All @@ -869,8 +869,8 @@ Quality and file size:

| Flag | Default | Description |
| ---------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| `--crf` | from `--quality`| Override encoder CRF, 0–51. Lower is better quality. Not with `--video-bitrate`. |
| `--video-bitrate` | from `--quality`| Target bitrate, e.g. `10M` or `5000k`. Not with `--crf`. |
| `--crf` | from `--quality`| Override MP4/WebM encoder CRF, 0–51. Lower is better quality. Not with `--video-bitrate`; rejected for MOV. |
| `--video-bitrate` | from `--quality`| Target MP4/WebM bitrate, e.g. `10M` or `5000k`. Not with `--crf`; rejected for MOV. |
| `--vp9-cpu-used` | encoder default | libvpx-vp9 speed/quality trade-off for WebM, -8 to 8. Env: `PRODUCER_VP9_CPU_USED`. |
| `--gif-loop` | `0` | GIF loop count, `0` for forever. Range 0–65535, `--format gif` only. |
| `--video-frame-format` | `auto` | How source video frames are extracted: `auto`, `jpg`, `png`. Use `png` for UI recordings, screen captures, and other colour-sensitive footage. |
Expand Down
9 changes: 6 additions & 3 deletions packages/cli/src/commands/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ export default defineCommand({
quality: {
type: "string",
alias: "q",
description: "Quality: draft, standard, high",
description:
"Quality: draft, standard, high. MOV always uses the fixed alpha-preserving ProRes 4444 profile.",
default: "standard",
},
skill: {
Expand Down Expand Up @@ -191,11 +192,13 @@ export default defineCommand({
},
crf: {
type: "string",
description: "Override encoder CRF. Mutually exclusive with --video-bitrate.",
description:
"Override MP4/WebM encoder CRF. Mutually exclusive with --video-bitrate; unsupported for MOV.",
},
"video-bitrate": {
type: "string",
description: "Target video bitrate such as 10M. Mutually exclusive with --crf.",
description:
"Target MP4/WebM video bitrate such as 10M. Mutually exclusive with --crf; unsupported for MOV.",
},
"vp9-cpu-used": {
type: "string",
Expand Down
28 changes: 28 additions & 0 deletions packages/cli/src/commands/render/plan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,34 @@ describe("createRenderPlan", () => {
expect(() => createRenderPlan({ dir: projectDir, quality: "maximum" })).toThrow(CliUsageError);
});

it.each([
["--crf", { crf: "18" }],
["--video-bitrate", { "video-bitrate": "78M" }],
])("rejects unsupported %s rate control for ProRes MOV", (flag, encoderArgs) => {
expect(() => createRenderPlan({ dir: projectDir, format: "mov", ...encoderArgs })).toThrow(
CliUsageError,
);
expect(vi.mocked(console.error).mock.calls.flat().join("\n")).toContain(flag);
expect(vi.mocked(console.error).mock.calls.flat().join("\n")).toContain(
"fixed alpha-preserving ProRes 4444",
);
});

it("keeps MOV quality tiers on the fixed alpha-preserving profile", () => {
const plan = createRenderPlan({ dir: projectDir, format: "mov", quality: "high" });

expect(plan).toMatchObject({ format: "mov", quality: "high" });
expect(plan.crf).toBeUndefined();
expect(plan.videoBitrate).toBeUndefined();
});

it("keeps MP4 and WebM rate controls available", () => {
expect(createRenderPlan({ dir: projectDir, format: "mp4", crf: "18" }).crf).toBe(18);
expect(
createRenderPlan({ dir: projectDir, format: "webm", "video-bitrate": "10M" }).videoBitrate,
).toBe("10M");
});

it("rejects batch and single-render variables before execution", () => {
expect(() =>
createRenderPlan({ dir: projectDir, batch: "rows.json", variables: '{"name":"Ada"}' }),
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/commands/render/plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,15 @@ export function createRenderPlan(args: RenderCommandArgs, now = new Date()): Ren
);
failUsage();
}
if (format === "mov" && (crf !== undefined || videoBitrate !== undefined)) {
const flag = crf !== undefined ? "--crf" : "--video-bitrate";
errorBox(
"Unsupported ProRes rate control",
`${flag} does not apply to MOV. MOV uses a fixed alpha-preserving ProRes 4444 profile.`,
`Remove ${flag}, or choose MP4/WebM when you need CRF or target-bitrate control.`,
);
failUsage();
}

const quiet = args.quiet ?? false;
const batchJson = args.json ?? false;
Expand Down
Loading