@vibeframe/cli 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/agent/tools/index.d.ts +1 -0
- package/dist/agent/tools/index.d.ts.map +1 -1
- package/dist/agent/tools/index.js +3 -0
- package/dist/agent/tools/index.js.map +1 -1
- package/dist/agent/tools/scene.d.ts +17 -0
- package/dist/agent/tools/scene.d.ts.map +1 -0
- package/dist/agent/tools/scene.js +263 -0
- package/dist/agent/tools/scene.js.map +1 -0
- package/dist/agent/tools/scene.test.d.ts +2 -0
- package/dist/agent/tools/scene.test.d.ts.map +1 -0
- package/dist/agent/tools/scene.test.js +139 -0
- package/dist/agent/tools/scene.test.js.map +1 -0
- package/dist/commands/_shared/scene-html-emit.d.ts +85 -0
- package/dist/commands/_shared/scene-html-emit.d.ts.map +1 -0
- package/dist/commands/_shared/scene-html-emit.js +353 -0
- package/dist/commands/_shared/scene-html-emit.js.map +1 -0
- package/dist/commands/_shared/scene-html-emit.test.d.ts +2 -0
- package/dist/commands/_shared/scene-html-emit.test.d.ts.map +1 -0
- package/dist/commands/_shared/scene-html-emit.test.js +203 -0
- package/dist/commands/_shared/scene-html-emit.test.js.map +1 -0
- package/dist/commands/_shared/scene-lint.d.ts +110 -0
- package/dist/commands/_shared/scene-lint.d.ts.map +1 -0
- package/dist/commands/_shared/scene-lint.js +207 -0
- package/dist/commands/_shared/scene-lint.js.map +1 -0
- package/dist/commands/_shared/scene-lint.test.d.ts +2 -0
- package/dist/commands/_shared/scene-lint.test.d.ts.map +1 -0
- package/dist/commands/_shared/scene-lint.test.js +208 -0
- package/dist/commands/_shared/scene-lint.test.js.map +1 -0
- package/dist/commands/_shared/scene-project.d.ts +101 -0
- package/dist/commands/_shared/scene-project.d.ts.map +1 -0
- package/dist/commands/_shared/scene-project.js +281 -0
- package/dist/commands/_shared/scene-project.js.map +1 -0
- package/dist/commands/_shared/scene-project.test.d.ts +2 -0
- package/dist/commands/_shared/scene-project.test.d.ts.map +1 -0
- package/dist/commands/_shared/scene-project.test.js +203 -0
- package/dist/commands/_shared/scene-project.test.js.map +1 -0
- package/dist/commands/_shared/scene-render.d.ts +79 -0
- package/dist/commands/_shared/scene-render.d.ts.map +1 -0
- package/dist/commands/_shared/scene-render.js +138 -0
- package/dist/commands/_shared/scene-render.js.map +1 -0
- package/dist/commands/_shared/scene-render.test.d.ts +2 -0
- package/dist/commands/_shared/scene-render.test.d.ts.map +1 -0
- package/dist/commands/_shared/scene-render.test.js +145 -0
- package/dist/commands/_shared/scene-render.test.js.map +1 -0
- package/dist/commands/_shared/segments-to-scenes.d.ts +85 -0
- package/dist/commands/_shared/segments-to-scenes.d.ts.map +1 -0
- package/dist/commands/_shared/segments-to-scenes.js +202 -0
- package/dist/commands/_shared/segments-to-scenes.js.map +1 -0
- package/dist/commands/_shared/segments-to-scenes.test.d.ts +2 -0
- package/dist/commands/_shared/segments-to-scenes.test.d.ts.map +1 -0
- package/dist/commands/_shared/segments-to-scenes.test.js +219 -0
- package/dist/commands/_shared/segments-to-scenes.test.js.map +1 -0
- package/dist/commands/ai-script-pipeline-cli.d.ts.map +1 -1
- package/dist/commands/ai-script-pipeline-cli.js +49 -0
- package/dist/commands/ai-script-pipeline-cli.js.map +1 -1
- package/dist/commands/ai-script-pipeline.d.ts +16 -0
- package/dist/commands/ai-script-pipeline.d.ts.map +1 -1
- package/dist/commands/ai-script-pipeline.js +28 -0
- package/dist/commands/ai-script-pipeline.js.map +1 -1
- package/dist/commands/ai.test.js +4 -1
- package/dist/commands/ai.test.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +8 -2
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/scene.d.ts +60 -0
- package/dist/commands/scene.d.ts.map +1 -0
- package/dist/commands/scene.js +621 -0
- package/dist/commands/scene.js.map +1 -0
- package/dist/commands/scene.test.d.ts +2 -0
- package/dist/commands/scene.test.d.ts.map +1 -0
- package/dist/commands/scene.test.js +133 -0
- package/dist/commands/scene.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/renderers/chrome.d.ts +26 -0
- package/dist/pipeline/renderers/chrome.d.ts.map +1 -0
- package/dist/pipeline/renderers/chrome.js +48 -0
- package/dist/pipeline/renderers/chrome.js.map +1 -0
- package/dist/pipeline/renderers/hyperframes.d.ts.map +1 -1
- package/dist/pipeline/renderers/hyperframes.js +2 -32
- package/dist/pipeline/renderers/hyperframes.js.map +1 -1
- package/package.json +32 -13
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module _shared/scene-render
|
|
3
|
+
*
|
|
4
|
+
* Render a VibeFrame scene project to MP4/WebM/MOV using the Hyperframes
|
|
5
|
+
* producer directly. Unlike the FFmpeg-bridge backend in
|
|
6
|
+
* `pipeline/renderers/hyperframes.ts` which has to convert a `TimelineState`
|
|
7
|
+
* into a temp Hyperframes project, scene projects already ARE Hyperframes
|
|
8
|
+
* projects — so we hand the producer the user's project dir and entry file
|
|
9
|
+
* verbatim.
|
|
10
|
+
*
|
|
11
|
+
* `executeSceneRender()` is decoupled from CLI flags so that the C6 agent
|
|
12
|
+
* tool and the C5 `--format scenes` pipeline can call it the same way. It
|
|
13
|
+
* returns a structured result instead of throwing or exiting.
|
|
14
|
+
*/
|
|
15
|
+
import { type RenderConfig } from "@hyperframes/producer";
|
|
16
|
+
export type RenderFps = 24 | 30 | 60;
|
|
17
|
+
export type RenderQuality = "draft" | "standard" | "high";
|
|
18
|
+
export type RenderFormat = "mp4" | "webm" | "mov";
|
|
19
|
+
export interface SceneRenderOptions {
|
|
20
|
+
/** Project directory (defaults to cwd). */
|
|
21
|
+
projectDir?: string;
|
|
22
|
+
/** Root composition file relative to projectDir (default: "index.html"). */
|
|
23
|
+
root?: string;
|
|
24
|
+
/** Output file. When relative, resolved against projectDir. Default:
|
|
25
|
+
* `renders/<projectName>-<isoStamp>.<format>`. */
|
|
26
|
+
output?: string;
|
|
27
|
+
fps?: RenderFps;
|
|
28
|
+
quality?: RenderQuality;
|
|
29
|
+
format?: RenderFormat;
|
|
30
|
+
/** Hyperframes capture worker count. Default 1 (the existing backend's
|
|
31
|
+
* default — auto-worker mode times out on small comps). */
|
|
32
|
+
workers?: number;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
onProgress?: (pct: number, stage: string) => void;
|
|
35
|
+
}
|
|
36
|
+
export interface SceneRenderResult {
|
|
37
|
+
success: boolean;
|
|
38
|
+
outputPath?: string;
|
|
39
|
+
durationMs?: number;
|
|
40
|
+
framesRendered?: number;
|
|
41
|
+
totalFrames?: number;
|
|
42
|
+
fps?: RenderFps;
|
|
43
|
+
quality?: RenderQuality;
|
|
44
|
+
format?: RenderFormat;
|
|
45
|
+
error?: string;
|
|
46
|
+
}
|
|
47
|
+
/** Map a quality preset to an x264 CRF (lower = higher quality). */
|
|
48
|
+
export declare function qualityToCrf(quality?: RenderQuality): number;
|
|
49
|
+
/**
|
|
50
|
+
* Compute the default output path for a render. Pure — does no I/O. Returns
|
|
51
|
+
* an absolute path under `<projectDir>/renders/`.
|
|
52
|
+
*
|
|
53
|
+
* `now` is injectable so tests get deterministic output.
|
|
54
|
+
*/
|
|
55
|
+
export declare function defaultOutputPath(opts: {
|
|
56
|
+
projectDir: string;
|
|
57
|
+
projectName?: string;
|
|
58
|
+
format?: RenderFormat;
|
|
59
|
+
now?: Date;
|
|
60
|
+
}): string;
|
|
61
|
+
/**
|
|
62
|
+
* Build the producer's `RenderConfig` from caller options. Pure — useful for
|
|
63
|
+
* unit tests that want to assert defaults without touching Chrome.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildRenderConfig(opts: {
|
|
66
|
+
fps?: RenderFps;
|
|
67
|
+
quality?: RenderQuality;
|
|
68
|
+
format?: RenderFormat;
|
|
69
|
+
workers?: number;
|
|
70
|
+
entryFile?: string;
|
|
71
|
+
}): RenderConfig;
|
|
72
|
+
/**
|
|
73
|
+
* Render a scene project. Mirrors the contract of the existing Hyperframes
|
|
74
|
+
* backend (preflight → execute → structured result), but skips the
|
|
75
|
+
* `TimelineState` → temp project conversion because the user's project is
|
|
76
|
+
* already a valid Hyperframes project.
|
|
77
|
+
*/
|
|
78
|
+
export declare function executeSceneRender(opts?: SceneRenderOptions): Promise<SceneRenderResult>;
|
|
79
|
+
//# sourceMappingURL=scene-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-render.d.ts","sourceRoot":"","sources":["../../../src/commands/_shared/scene-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAI/B,MAAM,MAAM,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACrC,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;uDACmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;gEAC4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,OAAO,GAAE,aAA0B,GAAG,MAAM,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,MAAM,CAST;AAmBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,YAAY,CAUf;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA+DlG"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module _shared/scene-render
|
|
3
|
+
*
|
|
4
|
+
* Render a VibeFrame scene project to MP4/WebM/MOV using the Hyperframes
|
|
5
|
+
* producer directly. Unlike the FFmpeg-bridge backend in
|
|
6
|
+
* `pipeline/renderers/hyperframes.ts` which has to convert a `TimelineState`
|
|
7
|
+
* into a temp Hyperframes project, scene projects already ARE Hyperframes
|
|
8
|
+
* projects — so we hand the producer the user's project dir and entry file
|
|
9
|
+
* verbatim.
|
|
10
|
+
*
|
|
11
|
+
* `executeSceneRender()` is decoupled from CLI flags so that the C6 agent
|
|
12
|
+
* tool and the C5 `--format scenes` pipeline can call it the same way. It
|
|
13
|
+
* returns a structured result instead of throwing or exiting.
|
|
14
|
+
*/
|
|
15
|
+
import { mkdir, stat } from "node:fs/promises";
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
|
+
import { resolve, relative, dirname, basename } from "node:path";
|
|
18
|
+
import { parse as yamlParse } from "yaml";
|
|
19
|
+
import { createRenderJob, executeRenderJob, } from "@hyperframes/producer";
|
|
20
|
+
import { preflightChrome } from "../../pipeline/renderers/chrome.js";
|
|
21
|
+
import { rootExists } from "./scene-lint.js";
|
|
22
|
+
/** Map a quality preset to an x264 CRF (lower = higher quality). */
|
|
23
|
+
export function qualityToCrf(quality = "standard") {
|
|
24
|
+
return quality === "draft" ? 28 : quality === "high" ? 18 : 23;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Compute the default output path for a render. Pure — does no I/O. Returns
|
|
28
|
+
* an absolute path under `<projectDir>/renders/`.
|
|
29
|
+
*
|
|
30
|
+
* `now` is injectable so tests get deterministic output.
|
|
31
|
+
*/
|
|
32
|
+
export function defaultOutputPath(opts) {
|
|
33
|
+
const fmt = opts.format ?? "mp4";
|
|
34
|
+
const now = opts.now ?? new Date();
|
|
35
|
+
const stamp = now
|
|
36
|
+
.toISOString()
|
|
37
|
+
.replace(/[:T]/g, "-")
|
|
38
|
+
.replace(/\..+$/, "");
|
|
39
|
+
const name = (opts.projectName ?? basename(resolve(opts.projectDir))) || "scene";
|
|
40
|
+
return resolve(opts.projectDir, "renders", `${name}-${stamp}.${fmt}`);
|
|
41
|
+
}
|
|
42
|
+
async function readProjectName(projectDir) {
|
|
43
|
+
const cfgPath = resolve(projectDir, "vibe.project.yaml");
|
|
44
|
+
if (!existsSync(cfgPath))
|
|
45
|
+
return undefined;
|
|
46
|
+
try {
|
|
47
|
+
const raw = await (await import("node:fs/promises")).readFile(cfgPath, "utf-8");
|
|
48
|
+
const parsed = yamlParse(raw);
|
|
49
|
+
return parsed?.name ?? undefined;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the producer's `RenderConfig` from caller options. Pure — useful for
|
|
57
|
+
* unit tests that want to assert defaults without touching Chrome.
|
|
58
|
+
*/
|
|
59
|
+
export function buildRenderConfig(opts) {
|
|
60
|
+
const quality = opts.quality ?? "standard";
|
|
61
|
+
return {
|
|
62
|
+
fps: opts.fps ?? 30,
|
|
63
|
+
quality,
|
|
64
|
+
format: opts.format ?? "mp4",
|
|
65
|
+
entryFile: opts.entryFile ?? "index.html",
|
|
66
|
+
crf: qualityToCrf(quality),
|
|
67
|
+
workers: opts.workers ?? 1,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Render a scene project. Mirrors the contract of the existing Hyperframes
|
|
72
|
+
* backend (preflight → execute → structured result), but skips the
|
|
73
|
+
* `TimelineState` → temp project conversion because the user's project is
|
|
74
|
+
* already a valid Hyperframes project.
|
|
75
|
+
*/
|
|
76
|
+
export async function executeSceneRender(opts = {}) {
|
|
77
|
+
const projectDir = resolve(opts.projectDir ?? ".");
|
|
78
|
+
const root = opts.root ?? "index.html";
|
|
79
|
+
// -- Preflight: project + Chrome ---------------------------------------
|
|
80
|
+
const projectStat = await safeStat(projectDir);
|
|
81
|
+
if (!projectStat || !projectStat.isDirectory()) {
|
|
82
|
+
return { success: false, error: `Project directory not found: ${projectDir}` };
|
|
83
|
+
}
|
|
84
|
+
if (!(await rootExists(projectDir, root))) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
error: `Root composition not found: ${resolve(projectDir, root)}. Run \`vibe scene init\` first.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const chrome = await preflightChrome();
|
|
91
|
+
if (!chrome.ok) {
|
|
92
|
+
return { success: false, error: chrome.reason };
|
|
93
|
+
}
|
|
94
|
+
// -- Resolve output path -----------------------------------------------
|
|
95
|
+
const projectName = await readProjectName(projectDir);
|
|
96
|
+
const outputPath = opts.output
|
|
97
|
+
? resolve(projectDir, opts.output)
|
|
98
|
+
: defaultOutputPath({ projectDir, projectName, format: opts.format });
|
|
99
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
100
|
+
// -- Execute render ----------------------------------------------------
|
|
101
|
+
const config = buildRenderConfig({
|
|
102
|
+
fps: opts.fps,
|
|
103
|
+
quality: opts.quality,
|
|
104
|
+
format: opts.format,
|
|
105
|
+
workers: opts.workers,
|
|
106
|
+
entryFile: root,
|
|
107
|
+
});
|
|
108
|
+
const job = createRenderJob(config);
|
|
109
|
+
const start = Date.now();
|
|
110
|
+
try {
|
|
111
|
+
await executeRenderJob(job, projectDir, outputPath, (j, msg) => opts.onProgress?.(j.progress, j.currentStage ?? msg), opts.signal);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return {
|
|
115
|
+
success: false,
|
|
116
|
+
error: err instanceof Error ? err.message : String(err),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
success: true,
|
|
121
|
+
outputPath: relative(process.cwd(), outputPath) || outputPath,
|
|
122
|
+
durationMs: Date.now() - start,
|
|
123
|
+
framesRendered: job.framesRendered,
|
|
124
|
+
totalFrames: job.totalFrames,
|
|
125
|
+
fps: config.fps,
|
|
126
|
+
quality: config.quality,
|
|
127
|
+
format: config.format,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function safeStat(p) {
|
|
131
|
+
try {
|
|
132
|
+
return await stat(p);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=scene-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-render.js","sourceRoot":"","sources":["../../../src/commands/_shared/scene-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-render.test.d.ts","sourceRoot":"","sources":["../../../src/commands/_shared/scene-render.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, expect, it, beforeAll } from "vitest";
|
|
2
|
+
import { mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
import { buildRenderConfig, defaultOutputPath, executeSceneRender, qualityToCrf, } from "./scene-render.js";
|
|
7
|
+
import { scaffoldSceneProject } from "./scene-project.js";
|
|
8
|
+
import { emitSceneHtml, insertClipIntoRoot } from "./scene-html-emit.js";
|
|
9
|
+
import { preflightChrome } from "../../pipeline/renderers/chrome.js";
|
|
10
|
+
async function makeTmp(label = "vibe-scene-render-") {
|
|
11
|
+
return mkdtemp(join(tmpdir(), label));
|
|
12
|
+
}
|
|
13
|
+
// ── qualityToCrf ────────────────────────────────────────────────────────────
|
|
14
|
+
describe("qualityToCrf", () => {
|
|
15
|
+
it.each([
|
|
16
|
+
["draft", 28],
|
|
17
|
+
["standard", 23],
|
|
18
|
+
["high", 18],
|
|
19
|
+
])("%s → %d", (q, expected) => {
|
|
20
|
+
expect(qualityToCrf(q)).toBe(expected);
|
|
21
|
+
});
|
|
22
|
+
it("defaults to standard when no preset is given", () => {
|
|
23
|
+
expect(qualityToCrf()).toBe(23);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
// ── buildRenderConfig ───────────────────────────────────────────────────────
|
|
27
|
+
describe("buildRenderConfig", () => {
|
|
28
|
+
it("supplies producer-compatible defaults", () => {
|
|
29
|
+
const cfg = buildRenderConfig({});
|
|
30
|
+
expect(cfg).toEqual({
|
|
31
|
+
fps: 30,
|
|
32
|
+
quality: "standard",
|
|
33
|
+
format: "mp4",
|
|
34
|
+
entryFile: "index.html",
|
|
35
|
+
crf: 23,
|
|
36
|
+
workers: 1,
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
it("propagates overrides and recomputes crf from quality", () => {
|
|
40
|
+
const cfg = buildRenderConfig({ fps: 60, quality: "high", format: "webm", workers: 4, entryFile: "alt.html" });
|
|
41
|
+
expect(cfg).toEqual({
|
|
42
|
+
fps: 60,
|
|
43
|
+
quality: "high",
|
|
44
|
+
format: "webm",
|
|
45
|
+
entryFile: "alt.html",
|
|
46
|
+
crf: 18,
|
|
47
|
+
workers: 4,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
// ── defaultOutputPath ───────────────────────────────────────────────────────
|
|
52
|
+
describe("defaultOutputPath", () => {
|
|
53
|
+
it("places output under <projectDir>/renders with project name + iso stamp", () => {
|
|
54
|
+
const out = defaultOutputPath({
|
|
55
|
+
projectDir: "/tmp/proj",
|
|
56
|
+
projectName: "promo",
|
|
57
|
+
format: "mp4",
|
|
58
|
+
now: new Date("2026-04-25T12:34:56Z"),
|
|
59
|
+
});
|
|
60
|
+
expect(out).toBe("/tmp/proj/renders/promo-2026-04-25-12-34-56.mp4");
|
|
61
|
+
});
|
|
62
|
+
it("falls back to projectDir basename when no name is given", () => {
|
|
63
|
+
const out = defaultOutputPath({
|
|
64
|
+
projectDir: "/tmp/my-video",
|
|
65
|
+
format: "webm",
|
|
66
|
+
now: new Date("2026-04-25T00:00:00Z"),
|
|
67
|
+
});
|
|
68
|
+
expect(out).toBe("/tmp/my-video/renders/my-video-2026-04-25-00-00-00.webm");
|
|
69
|
+
});
|
|
70
|
+
it("defaults to mp4 when no format is given", () => {
|
|
71
|
+
const out = defaultOutputPath({
|
|
72
|
+
projectDir: "/tmp/p",
|
|
73
|
+
projectName: "n",
|
|
74
|
+
now: new Date("2026-04-25T00:00:00Z"),
|
|
75
|
+
});
|
|
76
|
+
expect(out.endsWith(".mp4")).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
// ── executeSceneRender — pre-Chrome failure paths ───────────────────────────
|
|
80
|
+
//
|
|
81
|
+
// These tests exercise the validation surface (project dir, root file, Chrome
|
|
82
|
+
// preflight) WITHOUT requiring Chrome to be installed.
|
|
83
|
+
describe("executeSceneRender — validation", () => {
|
|
84
|
+
it("returns a structured error when the project directory doesn't exist", async () => {
|
|
85
|
+
const r = await executeSceneRender({ projectDir: "/tmp/__vibe_does_not_exist__" });
|
|
86
|
+
expect(r.success).toBe(false);
|
|
87
|
+
expect(r.error).toMatch(/Project directory not found/);
|
|
88
|
+
});
|
|
89
|
+
it("returns a structured error when index.html is missing", async () => {
|
|
90
|
+
const dir = await makeTmp();
|
|
91
|
+
const r = await executeSceneRender({ projectDir: dir });
|
|
92
|
+
expect(r.success).toBe(false);
|
|
93
|
+
expect(r.error).toMatch(/Root composition not found/);
|
|
94
|
+
});
|
|
95
|
+
it("(without Chrome) returns the Chrome preflight reason", async () => {
|
|
96
|
+
const pre = await preflightChrome();
|
|
97
|
+
if (pre.ok)
|
|
98
|
+
return; // Chrome present — Chrome-gated integration test covers the success path.
|
|
99
|
+
const dir = await makeTmp();
|
|
100
|
+
await scaffoldSceneProject({ dir, name: "fixture", aspect: "16:9", duration: 4 });
|
|
101
|
+
const r = await executeSceneRender({ projectDir: dir });
|
|
102
|
+
expect(r.success).toBe(false);
|
|
103
|
+
expect(r.error).toMatch(/Chrome not found/);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
// ── executeSceneRender — Chrome-gated integration ───────────────────────────
|
|
107
|
+
describe("executeSceneRender — Chrome-gated render", () => {
|
|
108
|
+
let chromeAvailable = false;
|
|
109
|
+
beforeAll(async () => {
|
|
110
|
+
chromeAvailable = (await preflightChrome()).ok;
|
|
111
|
+
if (!chromeAvailable) {
|
|
112
|
+
console.warn("[scene-render] Chrome not found — skipping render integration test");
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
it("renders a 1-scene project to MP4 (requires Chrome, skipped in CI)", async () => {
|
|
116
|
+
if (!chromeAvailable || process.env.CI)
|
|
117
|
+
return;
|
|
118
|
+
// Build a minimal scene project: root + one announcement scene.
|
|
119
|
+
const dir = await makeTmp("vibe-scene-render-int-");
|
|
120
|
+
await scaffoldSceneProject({ dir, name: "fixture", aspect: "16:9", duration: 2 });
|
|
121
|
+
let root = await readFile(resolve(dir, "index.html"), "utf-8");
|
|
122
|
+
const intro = emitSceneHtml({
|
|
123
|
+
id: "intro", preset: "announcement", width: 1920, height: 1080,
|
|
124
|
+
duration: 1.5, headline: "Render OK",
|
|
125
|
+
});
|
|
126
|
+
await writeFile(resolve(dir, "compositions/scene-intro.html"), intro, "utf-8");
|
|
127
|
+
root = insertClipIntoRoot(root, { id: "intro", start: 0, duration: 1.5 });
|
|
128
|
+
await writeFile(resolve(dir, "index.html"), root, "utf-8");
|
|
129
|
+
const out = resolve(dir, "renders", "out.mp4");
|
|
130
|
+
const result = await executeSceneRender({
|
|
131
|
+
projectDir: dir,
|
|
132
|
+
output: "renders/out.mp4",
|
|
133
|
+
fps: 30,
|
|
134
|
+
quality: "draft",
|
|
135
|
+
format: "mp4",
|
|
136
|
+
});
|
|
137
|
+
expect(result.success).toBe(true);
|
|
138
|
+
expect(existsSync(out)).toBe(true);
|
|
139
|
+
expect(result.fps).toBe(30);
|
|
140
|
+
expect(result.quality).toBe("draft");
|
|
141
|
+
expect(result.format).toBe("mp4");
|
|
142
|
+
expect((result.framesRendered ?? 0)).toBeGreaterThan(0);
|
|
143
|
+
}, 90_000);
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=scene-render.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-render.test.js","sourceRoot":"","sources":["../../../src/commands/_shared/scene-render.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module _shared/segments-to-scenes
|
|
3
|
+
*
|
|
4
|
+
* Branch of the script-to-video pipeline that materialises a Hyperframes-style
|
|
5
|
+
* scene project (HTML compositions + GSAP timelines) instead of an opaque MP4.
|
|
6
|
+
* Triggered by `vibe pipeline script-to-video --format scenes`.
|
|
7
|
+
*
|
|
8
|
+
* **Scope (MVP 1 c5):** template-based scene HTML using the C2 emitters.
|
|
9
|
+
* Claude-authored per-scene HTML with a lint-feedback retry loop is
|
|
10
|
+
* intentionally deferred — the bet that matters ("expensive opaque MP4 → cheap
|
|
11
|
+
* editable HTML") is delivered with templates alone, and the user can hand-
|
|
12
|
+
* edit any scene afterwards via `vibe scene add --force` or by editing the
|
|
13
|
+
* file directly.
|
|
14
|
+
*
|
|
15
|
+
* Inputs: storyboard segments, narration audio paths, image paths (any of
|
|
16
|
+
* which may be missing). Outputs: a fully scaffolded scene project at
|
|
17
|
+
* `outputDir`, ready for `vibe scene lint` / `vibe scene render`.
|
|
18
|
+
*/
|
|
19
|
+
import { type SceneAspect } from "./scene-project.js";
|
|
20
|
+
import { type ScenePreset } from "./scene-html-emit.js";
|
|
21
|
+
import { type ProjectLintResult } from "./scene-lint.js";
|
|
22
|
+
import type { StoryboardSegment, NarrationEntry } from "../ai-script-pipeline.js";
|
|
23
|
+
export interface SegmentsToScenesOptions {
|
|
24
|
+
segments: StoryboardSegment[];
|
|
25
|
+
/** Index-aligned with `segments`. Missing/failed entries → no narration audio. */
|
|
26
|
+
narrationEntries?: NarrationEntry[];
|
|
27
|
+
/** Index-aligned with `segments`. Empty string → image generation failed. */
|
|
28
|
+
imagePaths?: string[];
|
|
29
|
+
/** Absolute output directory (will be scaffolded as a scene project). */
|
|
30
|
+
outputDir: string;
|
|
31
|
+
/** Aspect ratio (drives canvas dims for both root + sub-comps). */
|
|
32
|
+
aspectRatio?: SceneAspect;
|
|
33
|
+
/** Project name (defaults to dir basename). */
|
|
34
|
+
projectName?: string;
|
|
35
|
+
/** Style preset applied to every scene (default `explainer`). */
|
|
36
|
+
scenePreset?: ScenePreset;
|
|
37
|
+
/** Optional progress sink — wired to `executeScriptToVideo`'s onProgress. */
|
|
38
|
+
onProgress?: (msg: string) => void;
|
|
39
|
+
/** When true (default), runs lint after emit and returns the result for
|
|
40
|
+
* visibility. Lint warnings/errors do NOT cause this function to fail. */
|
|
41
|
+
lintAfter?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface SegmentsToScenesResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
outputDir: string;
|
|
46
|
+
scenesEmitted: number;
|
|
47
|
+
/** Project-relative paths of every scene HTML written. */
|
|
48
|
+
scenePaths: string[];
|
|
49
|
+
/** Project-relative path of the root composition. */
|
|
50
|
+
rootPath: string;
|
|
51
|
+
/** Lint result when `lintAfter` is set. Surfaces warnings/errors but does
|
|
52
|
+
* not change `success`. */
|
|
53
|
+
lintResult?: ProjectLintResult;
|
|
54
|
+
/** 1-indexed scene numbers whose narration audio was missing. */
|
|
55
|
+
missingNarration: number[];
|
|
56
|
+
/** 1-indexed scene numbers whose image was missing. */
|
|
57
|
+
missingImage: number[];
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Pad an integer with leading zeros to a fixed width. `zeroPad(3, 2)` → "03".
|
|
62
|
+
* Pure helper exposed for tests so the scene-id convention is locked in.
|
|
63
|
+
*/
|
|
64
|
+
export declare function zeroPad(n: number, width?: number): string;
|
|
65
|
+
/**
|
|
66
|
+
* Build the canonical scene id for the i-th storyboard segment (1-indexed).
|
|
67
|
+
* Used in both `compositions/scene-NN.html` and `data-composition-id`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function sceneIdFromIndex(oneIndexedIndex: number): string;
|
|
70
|
+
/**
|
|
71
|
+
* Materialise a scene project from script-to-video pipeline outputs.
|
|
72
|
+
*
|
|
73
|
+
* Steps:
|
|
74
|
+
* 1. Scaffold the bilingual scene project (vibe.project.yaml + index.html
|
|
75
|
+
* + hyperframes.json + compositions/ + assets/ + CLAUDE.md + .gitignore).
|
|
76
|
+
* 2. Move narration `.mp3` and image `.png` files from the pipeline's flat
|
|
77
|
+
* output layout into `assets/`.
|
|
78
|
+
* 3. For each segment, emit `compositions/scene-NN.html` via the C2
|
|
79
|
+
* `emitSceneHtml` template (default preset: `explainer`).
|
|
80
|
+
* 4. Splice each scene into the root via `insertClipIntoRoot` so root
|
|
81
|
+
* `data-duration` grows to fit and clip start times stack correctly.
|
|
82
|
+
* 5. Run `runProjectLint` (info only — does not fail the call).
|
|
83
|
+
*/
|
|
84
|
+
export declare function executeSegmentsToScenes(opts: SegmentsToScenesOptions): Promise<SegmentsToScenesResult>;
|
|
85
|
+
//# sourceMappingURL=segments-to-scenes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments-to-scenes.d.ts","sourceRoot":"","sources":["../../../src/commands/_shared/segments-to-scenes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAElF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;IACpC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;+EAC2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB;gCAC4B;IAC5B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,uDAAuD;IACvD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAEhE;AA0BD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,sBAAsB,CAAC,CA6HjC"}
|