feat(producer): support entryFile for rendering individual compositions

Add optional `entryFile` parameter to the render API. When provided,
the producer renders the specified HTML file instead of defaulting to
index.html. This enables rendering individual sub-compositions
(e.g. `compositions/intro.html`) without wrapping them in a full
project.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Miguel Ángel
2026-03-26 18:47:31 -04:00
co-authored by Claude Opus 4.6
parent 09fdc31e33
commit fea504a41f
2 changed files with 18 additions and 4 deletions
+11 -3
View File
@@ -69,6 +69,7 @@ interface RenderInput {
workers?: number;
useGpu: boolean;
debug: boolean;
entryFile?: string;
}
interface PreparedRenderInput {
@@ -91,7 +92,12 @@ function parseRenderOptions(body: Record<string, unknown>): Omit<RenderInput, "p
? body.output
: null;
return { outputPath, fps, quality, workers, useGpu, debug };
const entryFile =
typeof body.entryFile === "string" && body.entryFile.trim().length > 0
? body.entryFile.trim()
: undefined;
return { outputPath, fps, quality, workers, useGpu, debug, entryFile };
}
async function prepareRenderBody(
@@ -104,8 +110,9 @@ async function prepareRenderBody(
if (!existsSync(absProjectDir) || !statSync(absProjectDir).isDirectory()) {
return { error: `Project directory not found: ${absProjectDir}` };
}
if (!existsSync(resolve(absProjectDir, "index.html"))) {
return { error: `No index.html in project directory: ${absProjectDir}` };
const entry = options.entryFile || "index.html";
if (!existsSync(resolve(absProjectDir, entry))) {
return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
}
return { prepared: { input: { projectDir: absProjectDir, ...options } } };
}
@@ -317,6 +324,7 @@ export function createRenderHandlers(options: HandlerOptions = {}): RenderHandle
workers: input.workers,
useGpu: input.useGpu,
debug: input.debug,
entryFile: input.entryFile,
logger: log,
});
@@ -93,6 +93,8 @@ export interface RenderConfig {
workers?: number;
useGpu?: boolean;
debug?: boolean;
/** Entry HTML file relative to projectDir. Defaults to "index.html". */
entryFile?: string;
/** Full producer config. When provided, env vars are not read. */
producerConfig?: EngineConfig;
/** Custom logger. Defaults to console-based defaultLogger. */
@@ -319,7 +321,11 @@ export async function executeRenderJob(
restoreLogger = installDebugLogger(logPath, log);
}
const htmlPath = join(projectDir, "index.html");
const entryFile = job.config.entryFile || "index.html";
const htmlPath = join(projectDir, entryFile);
if (!existsSync(htmlPath)) {
throw new Error(`Entry file not found: ${htmlPath}`);
}
assertNotAborted();
// ── Stage 1: Compile ─────────────────────────────────────────────────