Skip to content

Commit c878919

Browse files
vanceingallsclaude
andcommitted
feat(engine): default-on page-side compositing for SDR shader transitions
Page-side compositing is now enabled by default for SDR shader-transition renders without video content. The 6.6× speedup applies automatically — no flag needed. Auto-disables when: - HDR content detected - Alpha output (WebM/MOV/PNG-sequence) - Composition contains <video> elements (cloneNode loses playback state) - beginFrame capture mode (Linux headless) Use --no-page-side-compositing to force the Node-side layered path. Changes: - Engine config: enablePageSideCompositing defaults to true - CLI: flag default flipped to true; --no-page-side-compositing disables - Orchestrator: added composition.videos.length === 0 gate - Docker: forwards --no-page-side-compositing when explicitly disabled - Config tests updated for new default Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 08da30a commit c878919

6 files changed

Lines changed: 22 additions & 34 deletions

File tree

packages/cli/src/commands/render.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,11 @@ export default defineCommand({
225225
"page-side-compositing": {
226226
type: "boolean",
227227
description:
228-
"EXPERIMENTAL. Run shader transitions on a page-side WebGL canvas " +
229-
"inside Chrome instead of the Node-side layered blend. ~6× faster " +
230-
"for SDR shader-transition renders on Mac. HDR/alpha content forces " +
231-
"the existing path. Scenes with <video> or live <canvas> elements " +
232-
"may render those elements as black during transition windows.",
233-
default: false,
228+
"Run shader transitions on a page-side WebGL canvas inside Chrome " +
229+
"instead of the Node-side layered blend. ~6× faster for SDR " +
230+
"shader-transition renders. HDR/alpha/video content auto-disables. " +
231+
"Use --no-page-side-compositing to force the layered path.",
232+
default: true,
234233
},
235234
},
236235
async run({ args }) {
@@ -304,13 +303,8 @@ export default defineCommand({
304303
}
305304

306305
// ── Wire opt-in: page-side compositing ───────────────────────────────
307-
// EXPERIMENTAL — the engine reads HF_PAGE_SIDE_COMPOSITING via
308-
// `resolveConfig()` (engine `EngineConfig.enablePageSideCompositing`).
309-
// Set the env var BEFORE `loadProducer()` runs so producer's first call
310-
// to `resolveConfig()` picks it up. Same pattern as
311-
// PRODUCER_HEADLESS_SHELL_PATH below.
312-
if (args["page-side-compositing"]) {
313-
process.env.HF_PAGE_SIDE_COMPOSITING = "true";
306+
if (args["page-side-compositing"] === false) {
307+
process.env.HF_PAGE_SIDE_COMPOSITING = "false";
314308
}
315309

316310
// ── Validate max-concurrent-renders ─────────────────────────────────
@@ -558,7 +552,7 @@ export default defineCommand({
558552
variables,
559553
entryFile,
560554
outputResolution,
561-
pageSideCompositing: !!args["page-side-compositing"],
555+
pageSideCompositing: args["page-side-compositing"] !== false,
562556
exitAfterComplete: true,
563557
});
564558
} else {

packages/cli/src/utils/dockerRunArgs.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,16 +278,16 @@ describe("buildDockerRunArgs", () => {
278278
expect(args).not.toContain("--resolution");
279279
});
280280

281-
it("forwards --page-side-compositing when pageSideCompositing is true", () => {
281+
it("forwards --no-page-side-compositing when pageSideCompositing is false", () => {
282282
const args = buildDockerRunArgs({
283283
...FIXED_INPUT,
284-
options: { ...BASE, pageSideCompositing: true },
284+
options: { ...BASE, pageSideCompositing: false },
285285
});
286-
expect(args).toContain("--page-side-compositing");
286+
expect(args).toContain("--no-page-side-compositing");
287287
});
288288

289-
it("omits --page-side-compositing when pageSideCompositing is not set", () => {
289+
it("omits --no-page-side-compositing when pageSideCompositing is not explicitly false", () => {
290290
const args = buildDockerRunArgs({ ...FIXED_INPUT, options: BASE });
291-
expect(args).not.toContain("--page-side-compositing");
291+
expect(args).not.toContain("--no-page-side-compositing");
292292
});
293293
});

packages/cli/src/utils/dockerRunArgs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,6 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
8181
: []),
8282
...(options.entryFile ? ["--composition", options.entryFile] : []),
8383
...(options.outputResolution ? ["--resolution", options.outputResolution] : []),
84-
...(options.pageSideCompositing ? ["--page-side-compositing"] : []),
84+
...(options.pageSideCompositing === false ? ["--no-page-side-compositing"] : []),
8585
];
8686
}

packages/engine/src/config.test.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,15 @@ describe("resolveConfig", () => {
140140
});
141141

142142
describe("enablePageSideCompositing (HF_PAGE_SIDE_COMPOSITING)", () => {
143-
it("defaults to false", () => {
144-
const config = resolveConfig();
145-
expect(config.enablePageSideCompositing).toBe(false);
146-
});
147-
148-
it("flips to true when HF_PAGE_SIDE_COMPOSITING=true", () => {
149-
setEnv("HF_PAGE_SIDE_COMPOSITING", "true");
143+
it("defaults to true", () => {
150144
const config = resolveConfig();
151145
expect(config.enablePageSideCompositing).toBe(true);
152146
});
153147

154-
it("ignores any non-'true' value", () => {
155-
setEnv("HF_PAGE_SIDE_COMPOSITING", "1");
156-
expect(resolveConfig().enablePageSideCompositing).toBe(false);
157-
setEnv("HF_PAGE_SIDE_COMPOSITING", "yes");
158-
expect(resolveConfig().enablePageSideCompositing).toBe(false);
148+
it("disabled when HF_PAGE_SIDE_COMPOSITING=false", () => {
149+
setEnv("HF_PAGE_SIDE_COMPOSITING", "false");
150+
const config = resolveConfig();
151+
expect(config.enablePageSideCompositing).toBe(false);
159152
});
160153

161154
it("explicit override wins over the env var", () => {

packages/engine/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export const DEFAULT_CONFIG: EngineConfig = {
177177
browserTimeout: 120_000,
178178
protocolTimeout: 300_000,
179179
forceScreenshot: false,
180-
enablePageSideCompositing: false,
180+
enablePageSideCompositing: true,
181181

182182
enableChunkedEncode: false,
183183
chunkSizeFrames: 360,

packages/producer/src/services/renderOrchestrator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,8 @@ export async function executeRenderJob(
17621762
compiled.hasShaderTransitions &&
17631763
!hasHdrContent &&
17641764
!isPngSequence &&
1765-
!needsAlpha;
1765+
!needsAlpha &&
1766+
composition.videos.length === 0;
17661767
if (usePageSideCompositingForTransitions) {
17671768
fileServer.addPreHeadScript(HF_PAGE_SIDE_COMPOSITING_STUB);
17681769
log.info(

0 commit comments

Comments
 (0)