Skip to content

Commit a0d7295

Browse files
refactor(producer): simplify — extract HDR compositor, delete dead code, consolidate patterns (#1414)
* refactor(producer): extract HDR compositor from renderOrchestrator Move ~700 LOC of HDR compositing primitives (countNonZeroAlpha, countNonZeroRgb48, cropRgb48le, HdrVideoFrameSource, closeHdrVideoFrameSource, blitHdrVideoLayer, HdrImageBuffer, blitHdrImageLayer, CompositeTransfer, shouldUseLayeredComposite, resolveCompositeTransfer, HdrCompositeContext, compositeHdrFrame, HdrTransitionMeta, TransitionRange) into a dedicated hdrCompositor.ts module. Remove backward-compat re-exports from renderOrchestrator (hdrPerf, captureCost, shared) and rewire all import sites to the authoritative source modules. * refactor(producer): delete 4 re-export shim files screenshotService.ts, videoFrameExtractor.ts, videoFrameInjector.ts, and streamingEncoder.ts existed solely to re-export symbols from @hyperframes/engine. No internal consumer imported from them except index.ts → videoFrameInjector, which now imports directly from engine. * refactor(producer): delete unused PNG decode/blit worker pool The pool (455 LOC) and worker (127 LOC) were built speculatively for pipelining Chrome screenshots with PNG decode/blit but were never wired into any capture path. Zero non-test source files imported them. Also removed the esbuild entry point from producer/build.mjs, the tsup entry point + alpha-blit alias from cli/tsup.config.ts, and the PNG worker bootstrap from cli/src/cli.ts. * refactor(producer): centralize frame filename construction Replace 4 inline padStart(6) template literals with shared helpers: - formatCaptureFrameName(index, ext): zero-based, for internal capture - formatExportFrameName(index, ext): zero-based input, one-based output for user-facing png-sequence export * perf(producer): hoist allElementIds out of compositing loop Move fullStacking.map() from inside the per-layer iteration to before the loop, computing the element ID list once per frame instead of once per DOM layer per frame. * refactor(producer): consolidate HDR timing instrumentation * refactor(producer): remove typecasts and deduplicate HDR capture patterns - Extract seekInjectAndQueryStacking() and seekAndInject() helpers to deduplicate the seek+inject+query pattern across sequential loop, hybrid loop, and per-scene transition capture (3 call sites → 1 helper) - Fix sceneBuf as Buffer casts by properly typing the scene-capture arrays as [Buffer, Set<string>][] instead of using as const + cast - Replace as NonNullable<> cast on outputFormat with as const fallback - Add explanatory comments on inherent linkedom DOM casts * refactor(producer): name constants, type matrix, extract opacity helper - Replace magic 0.001/0.999 with TRANSFORM_IDENTITY_EPSILON and OPAQUE_ALPHA_THRESHOLD; replace BPP=6 with RGB48_BYTES_PER_PIXEL - Add AffineMatrix tuple type + isAffineMatrix guard, eliminating all 4 non-null assertions on matrix indices - Extract resolveBlitOpacity() to replace 5 identical ternaries - Narrow fallow-ignore-file to line-level complexity suppressions
1 parent 7bff49e commit a0d7295

26 files changed

Lines changed: 937 additions & 1894 deletions

packages/cli/src/cli.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,24 @@ for (const stream of [process.stdout, process.stderr]) {
2222
}
2323

2424
// ── Worker entry path bootstrap (must run before any producer/engine load) ──
25-
// The hf#677 worker_threads pools (`pngDecodeBlitWorkerPool`,
26-
// `shaderTransitionWorkerPool`) live in the producer package and try to
27-
// resolve their worker entry by probing for sibling `.js` files next to
25+
// The shaderTransitionWorkerPool lives in the producer package and resolves
26+
// its worker entry by probing for a sibling `.js` file next to
2827
// `import.meta.url`. When this CLI is bundled by tsup, the producer code is
2928
// inlined into `cli.js`, but `import.meta.url` resolves to the producer's
3029
// own dist path (NOT cli.js) on some module-graph layouts — so the sibling
31-
// probe lands in a directory that does not contain the bundled workers.
32-
// We emit the worker entries next to cli.js (see tsup.config.ts) and tell
33-
// the pools where to find them via the published env-var overrides. The
34-
// pools have an explicit `workerEntryPath` factory option as the canonical
35-
// API, but setting the env vars here covers every call site without having
36-
// to thread the path through the renderOrchestrator → captureHdrStage →
37-
// captureHdrHybridLoop chain.
30+
// probe lands in a directory that does not contain the bundled worker.
31+
// We emit the worker entry next to cli.js (see tsup.config.ts) and tell
32+
// the pool where to find it via the published env-var override.
3833
import { dirname, join } from "node:path";
3934
import { fileURLToPath } from "node:url";
4035
import { existsSync } from "node:fs";
4136

42-
// fallow-ignore-next-line complexity
4337
(() => {
4438
const here = dirname(fileURLToPath(import.meta.url));
4539
const shader = join(here, "shaderTransitionWorker.js");
46-
const png = join(here, "pngDecodeBlitWorker.js");
4740
if (!process.env.HF_SHADER_WORKER_ENTRY && existsSync(shader)) {
4841
process.env.HF_SHADER_WORKER_ENTRY = shader;
4942
}
50-
if (!process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY && existsSync(png)) {
51-
process.env.HF_PNG_DECODE_BLIT_WORKER_ENTRY = png;
52-
}
5343
})();
5444

5545
// ── Fast-path exits ─────────────────────────────────────────────────────────

packages/cli/tsup.config.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,8 @@ const pkg = JSON.parse(readFileSync(new URL("./package.json", import.meta.url),
77
};
88

99
export default defineConfig({
10-
// hf#732 lever-4: emit BOTH the CLI bundle and the PNG decode + alpha-blit
11-
// worker entry. The producer's `pngDecodeBlitWorkerPool` instantiates a
12-
// Node `worker_threads` Worker via `new Worker(<path>)`, which is a
13-
// filesystem load — it cannot share the parent module graph. The pool's
14-
// path resolver probes for `pngDecodeBlitWorker.js` next to its own loaded
15-
// module (which lives inside `dist/cli.js` after the producer is
16-
// `noExternal`'d and bundled in). Without this entry the file would not
17-
// exist at runtime and the pool would either crash or silently fall back
18-
// to inline decode/blit, killing the perf gain.
1910
entry: {
2011
cli: "src/cli.ts",
21-
pngDecodeBlitWorker: "../producer/src/services/pngDecodeBlitWorker.ts",
22-
// hf#677/#732: shader-blend worker. Same `new Worker(<path>)`
23-
// bundling rationale as `pngDecodeBlitWorker` above.
2412
shaderTransitionWorker: "../producer/src/services/shaderTransitionWorker.ts",
2513
},
2614
format: ["esm"],
@@ -96,10 +84,6 @@ var __dirname = __hf_dirname(__filename);`,
9684
"@hyperframes/aws-lambda/sdk": resolve(__dirname, "../aws-lambda/src/sdk/index.ts"),
9785
// Same for the GCP adapter's SDK subpath barrel.
9886
"@hyperframes/gcp-cloud-run/sdk": resolve(__dirname, "../gcp-cloud-run/src/sdk/index.ts"),
99-
// hf#732 lever-4: alias for the PNG decode+blit worker's import.
100-
// `alphaBlit.ts` is import-free (only zlib) so the worker survives
101-
// the worker_thread loader boundary directly via this TS source.
102-
"@hyperframes/engine/alpha-blit": resolve(__dirname, "../engine/src/utils/alphaBlit.ts"),
10387
// hf#677 follow-up: the shader-blend worker imports from
10488
// `@hyperframes/engine/shader-transitions` (subpath export) — a
10589
// standalone TS file with zero internal imports that survives the

packages/producer/build.mjs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ const sharedOpts = {
5959
await Promise.all([
6060
build({ ...sharedOpts, entryPoints: ["src/index.ts"], outfile: "dist/index.js" }),
6161
build({ ...sharedOpts, entryPoints: ["src/server.ts"], outfile: "dist/public-server.js" }),
62-
build({
63-
...sharedOpts,
64-
entryPoints: ["src/services/pngDecodeBlitWorker.ts"],
65-
outfile: "dist/services/pngDecodeBlitWorker.js",
66-
}),
6762
build({
6863
...sharedOpts,
6964
entryPoints: ["src/services/shaderTransitionWorker.ts"],

packages/producer/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export {
5252
} from "./services/fileServer.js";
5353

5454
// ── Video frame injection (Hyperframes-specific hook) ───────────────────────
55-
export { createVideoFrameInjector } from "./services/videoFrameInjector.js";
55+
export { createVideoFrameInjector } from "@hyperframes/engine";
5656

5757
// ── Configuration ───────────────────────────────────────────────────────────
5858
export { resolveConfig, DEFAULT_CONFIG, type ProducerConfig } from "./config.js";

packages/producer/src/services/distributed/assemble.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { dirname, join } from "node:path";
3737
import { applyFaststart, muxVideoWithAudio, runFfmpeg } from "@hyperframes/engine";
3838
import { fpsToFfmpegArg } from "@hyperframes/core";
3939
import { defaultLogger, type ProducerLogger } from "../../logger.js";
40+
import { formatExportFrameName } from "../../utils/paths.js";
4041
import { padOrTrimAudioToVideoFrameCount } from "../render/audioPadTrim.js";
4142
import type { ChunkSliceJson } from "../render/stages/freezePlan.js";
4243
import type { DistributedFormat } from "./shared.js";
@@ -397,7 +398,7 @@ function mergePngFrameDirs(
397398
throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
398399
}
399400
for (const frame of frames) {
400-
const dst = join(outputPath, `frame_${String(globalIdx + 1).padStart(6, "0")}.png`);
401+
const dst = join(outputPath, formatExportFrameName(globalIdx, "png"));
401402
cpSync(join(chunkDir, frame), dst);
402403
globalIdx += 1;
403404
}

0 commit comments

Comments
 (0)