From 69446e77265a420c4f24a0395682212793eb323f Mon Sep 17 00:00:00 2001 From: Xuanru Li <157947275+xuanruli@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:39:03 -0700 Subject: [PATCH] Revert "feat(producer): renderStretch to re-time short compositions across longer scenes (#2676)" (#2730) This reverts commit e786b78b3311d697e95269ec8fc21a4159af909d. --- packages/core/src/core.types.ts | 12 -------- packages/core/src/index.ts | 1 - .../src/outputFrameToTimelineSeconds.test.ts | 30 ------------------- packages/engine/src/services/frameCapture.ts | 11 ++----- .../src/services/parallelCoordinator.ts | 9 ++---- packages/engine/src/types.ts | 2 -- packages/producer/src/renderRequest.ts | 12 -------- packages/producer/src/server.ts | 7 ----- .../producer/src/services/distributed/plan.ts | 5 ---- .../src/services/distributed/renderChunk.ts | 3 -- .../distributed/renderConfigValidation.ts | 12 -------- .../src/services/distributed/shared.ts | 2 -- .../render/stages/captureHdrHybridLoop.ts | 3 +- .../render/stages/captureHdrSequentialLoop.ts | 3 +- .../services/render/stages/captureStage.ts | 13 ++------ .../render/stages/captureStreamingStage.ts | 13 ++------ .../services/render/stages/planHash.test.ts | 20 ------------- .../src/services/render/stages/planHash.ts | 7 +---- .../src/services/render/stages/probeStage.ts | 7 ++--- .../src/services/renderOrchestrator.ts | 2 -- 20 files changed, 15 insertions(+), 159 deletions(-) delete mode 100644 packages/core/src/outputFrameToTimelineSeconds.test.ts diff --git a/packages/core/src/core.types.ts b/packages/core/src/core.types.ts index 402f43170..99d356b55 100644 --- a/packages/core/src/core.types.ts +++ b/packages/core/src/core.types.ts @@ -38,18 +38,6 @@ export function fpsToNumber(fps: Fps): number { return fps.num / fps.den; } -/** - * Timeline seek time for an output frame. `renderStretch` (=intrinsic/target, - * default 1 = no-op) scales the mapping so a short comp spans a longer output. - */ -export function outputFrameToTimelineSeconds( - frameIndex: number, - fps: Fps, - renderStretch = 1, -): number { - return ((frameIndex * fps.den) / fps.num) * renderStretch; -} - /** * FFmpeg-style fps argument. Returns `"30"` for integer fps and `"30000/1001"` * for rationals — both forms are accepted verbatim by FFmpeg's `-r` and diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2ce7d2587..d99e932a7 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -63,7 +63,6 @@ export { parseFpsWithDefault, toFps, fpsToNumber, - outputFrameToTimelineSeconds, fpsToFfmpegArg, TIMELINE_COLORS, DEFAULT_DURATIONS, diff --git a/packages/core/src/outputFrameToTimelineSeconds.test.ts b/packages/core/src/outputFrameToTimelineSeconds.test.ts deleted file mode 100644 index de18361be..000000000 --- a/packages/core/src/outputFrameToTimelineSeconds.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { outputFrameToTimelineSeconds } from "./core.types.js"; - -describe("outputFrameToTimelineSeconds", () => { - const fps = { num: 30, den: 1 }; - - it("no-op when renderStretch is omitted (defaults to 1)", () => { - for (const i of [0, 1, 29, 143]) { - expect(outputFrameToTimelineSeconds(i, fps)).toBe((i * fps.den) / fps.num); - } - }); - - it("renderStretch=1 is byte-identical to the raw frame time", () => { - expect(outputFrameToTimelineSeconds(143, fps, 1)).toBe(143 / 30); - }); - - it("stretches a 1s comp across a 4.8s output (renderStretch = intrinsic/target)", () => { - const rs = 1 / 4.8; - expect(outputFrameToTimelineSeconds(0, fps, rs)).toBe(0); - // last of 144 output frames lands just under intrinsic 1.0s — never past it - const last = outputFrameToTimelineSeconds(143, fps, rs); - expect(last).toBeGreaterThan(0.98); - expect(last).toBeLessThan(1.0); - }); - - it("honors an exact rational fps (NTSC 30000/1001)", () => { - const ntsc = { num: 30000, den: 1001 }; - expect(outputFrameToTimelineSeconds(30, ntsc, 1)).toBe((30 * 1001) / 30000); - }); -}); diff --git a/packages/engine/src/services/frameCapture.ts b/packages/engine/src/services/frameCapture.ts index 576a07c99..0c7346dc7 100644 --- a/packages/engine/src/services/frameCapture.ts +++ b/packages/engine/src/services/frameCapture.ts @@ -2709,9 +2709,8 @@ export async function verifyStaticFramesSafe( if (last && f === last.b + 1) last.b = f; else runs.push({ a: f, b: f }); } - const renderStretch = session.options.renderStretch ?? 1; const seekToFrame = async (frameIdx: number): Promise => { - const t = quantizeTimeToFrame((frameIdx / fps) * renderStretch, fps); + const t = quantizeTimeToFrame(frameIdx / fps, fps); await page.evaluate((tt: number) => { const hf = ( window as unknown as { @@ -3649,14 +3648,11 @@ async function captureDeVerificationFrames( // their data-duration, and infinite-repeat GSAP reports a huge sentinel — // and indices derived from it would never be drained, silently disarming // verification for exactly the comps that need it. - // compositionDurationSeconds is already the output (drained) duration; the raw - // page fallback is intrinsic — divide it by renderStretch to match (1 = no-op). - const renderStretch = session.options.renderStretch ?? 1; const duration = session.options.compositionDurationSeconds ?? (await page.evaluate( () => (window as unknown as { __hf?: { duration?: number } }).__hf?.duration ?? 0, - )) / renderStretch; + )); const totalFrames = Math.floor(duration * fps); if (totalFrames < 10) return; if (duration > 3600) { @@ -3706,8 +3702,7 @@ async function captureDeVerificationFrames( while (boundary.has(idx) && guard++ < 6) idx = Math.min(totalFrames - 1, idx + 2); if (boundary.has(idx)) continue; if (frames.has(idx)) continue; - // Seek truth with the same ×renderStretch mapping the real capture uses for output frame idx. - const t = quantizeTimeToFrame((idx / fps) * renderStretch, fps); + const t = quantizeTimeToFrame(idx / fps, fps); await seekTo(t); // Video frame injection (same hook the real capture paths run) — without // it,