@vibeframe/cli 0.115.1 → 0.115.2
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/dist/commands/_shared/build-cache-model.test.d.ts +1 -0
- package/dist/commands/_shared/build-cache.d.ts +6 -0
- package/dist/commands/_shared/build-plan.d.ts +2 -0
- package/dist/commands/_shared/footage-assemble.d.ts +166 -0
- package/dist/commands/_shared/footage-assemble.test.d.ts +1 -0
- package/dist/commands/_shared/scene-build.d.ts +26 -1
- package/dist/commands/_shared/storyboard-parse.d.ts +7 -1
- package/dist/index.js +1065 -455
- package/dist/tools/manifest/index.js +1317 -794
- package/dist/tools/manifest/scene.d.ts +3 -0
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -19,6 +19,8 @@ export declare function backdropCacheDescriptor(opts: {
|
|
|
19
19
|
quality: "standard" | "hd";
|
|
20
20
|
size: string;
|
|
21
21
|
ratio?: string;
|
|
22
|
+
/** Provider-specific image model override — switching models re-keys the asset. */
|
|
23
|
+
model?: string;
|
|
22
24
|
}): CacheAssetDescriptor;
|
|
23
25
|
export declare function characterCacheDescriptor(opts: {
|
|
24
26
|
name: string;
|
|
@@ -26,6 +28,8 @@ export declare function characterCacheDescriptor(opts: {
|
|
|
26
28
|
provider: string;
|
|
27
29
|
quality: "standard" | "hd";
|
|
28
30
|
size: string;
|
|
31
|
+
/** Provider-specific image model override — switching models re-keys the asset. */
|
|
32
|
+
model?: string;
|
|
29
33
|
}): CacheAssetDescriptor;
|
|
30
34
|
export declare function keyframeCacheDescriptor(opts: {
|
|
31
35
|
beatId: string;
|
|
@@ -36,6 +40,8 @@ export declare function keyframeCacheDescriptor(opts: {
|
|
|
36
40
|
ratio?: string;
|
|
37
41
|
/** Character sheet paths used as edit references — changing them re-keys the keyframe. */
|
|
38
42
|
characters?: string[];
|
|
43
|
+
/** Provider-specific image model override — switching models re-keys the asset. */
|
|
44
|
+
model?: string;
|
|
39
45
|
}): CacheAssetDescriptor;
|
|
40
46
|
export declare function imageRatioForSize(size: string | undefined): string;
|
|
41
47
|
export declare function videoCacheDescriptor(opts: {
|
|
@@ -109,6 +109,8 @@ export interface CreateBuildPlanOptions {
|
|
|
109
109
|
imageProvider?: string;
|
|
110
110
|
imageQuality?: "standard" | "hd";
|
|
111
111
|
imageSize?: string;
|
|
112
|
+
/** Provider-specific image model override — must match executeSceneBuild for cache parity. */
|
|
113
|
+
imageModel?: string;
|
|
112
114
|
videoProvider?: string;
|
|
113
115
|
musicProvider?: string;
|
|
114
116
|
composer?: string;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { ReviewAction } from "./review-report.js";
|
|
2
|
+
export interface FootageClipInput {
|
|
3
|
+
id: string;
|
|
4
|
+
clipDurationSec: number;
|
|
5
|
+
narrationDurationSec?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FootagePlanOptions {
|
|
8
|
+
/** Crossfade length between segments (seconds). */
|
|
9
|
+
transitionSec?: number;
|
|
10
|
+
/** Fade-from/to-black length at the head and tail of the cut (seconds). */
|
|
11
|
+
fadeSec?: number;
|
|
12
|
+
/** Gap between a segment becoming dominant and its narration starting. */
|
|
13
|
+
narrationLeadSec?: number;
|
|
14
|
+
/** Silence required after narration ends before the segment may end. */
|
|
15
|
+
narrationTailSec?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface FootageBeatPlan {
|
|
18
|
+
id: string;
|
|
19
|
+
clipDurationSec: number;
|
|
20
|
+
narrationDurationSec?: number;
|
|
21
|
+
/** Segment length on the timeline (clip, possibly tpad-extended). */
|
|
22
|
+
segmentDurationSec: number;
|
|
23
|
+
/** Seconds of last-frame clone added so narration + tail fit. 0 = untouched. */
|
|
24
|
+
extendedSec: number;
|
|
25
|
+
/** Timeline position where this segment (and its incoming crossfade) starts. */
|
|
26
|
+
startSec: number;
|
|
27
|
+
/** Timeline position where this segment's narration starts (when present). */
|
|
28
|
+
narrationStartSec?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface FootageTimelinePlan {
|
|
31
|
+
beats: FootageBeatPlan[];
|
|
32
|
+
transitionSec: number;
|
|
33
|
+
fadeSec: number;
|
|
34
|
+
totalDurationSec: number;
|
|
35
|
+
warnings: string[];
|
|
36
|
+
}
|
|
37
|
+
export declare const FOOTAGE_DEFAULTS: {
|
|
38
|
+
readonly transitionSec: 0.5;
|
|
39
|
+
readonly fadeSec: 0.6;
|
|
40
|
+
readonly narrationLeadSec: 0.35;
|
|
41
|
+
readonly narrationTailSec: 0.4;
|
|
42
|
+
readonly width: 1920;
|
|
43
|
+
readonly height: 1080;
|
|
44
|
+
readonly fps: 30;
|
|
45
|
+
readonly crf: 18;
|
|
46
|
+
readonly finishCrf: 23;
|
|
47
|
+
readonly musicVolume: 0.35;
|
|
48
|
+
readonly duck: {
|
|
49
|
+
readonly thresholdDb: -30;
|
|
50
|
+
readonly ratio: 3;
|
|
51
|
+
readonly attackMs: 20;
|
|
52
|
+
readonly releaseMs: 200;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The cinematic finish pass: subtle vignette + temporal film grain, applied
|
|
56
|
+
* before the head/tail fades. These are the field-tested values that pull
|
|
57
|
+
* provider clips away from the too-clean "AI look"; the fades multiply over
|
|
58
|
+
* them so blacks stay black.
|
|
59
|
+
*/
|
|
60
|
+
readonly finish: readonly ["vignette=angle=PI/5", "noise=alls=7:allf=t"];
|
|
61
|
+
/** Base segment length for a ken-burns keyframe fallback (no clip to probe). */
|
|
62
|
+
readonly kenburnsSec: 4;
|
|
63
|
+
/** Slow-push ceiling for the ken-burns zoom. */
|
|
64
|
+
readonly kenburnsMaxZoom: 1.1;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Compute segment lengths and timeline offsets from real clip/narration
|
|
68
|
+
* durations. Deterministic and side-effect free so agents can reason about the
|
|
69
|
+
* cut from the report alone.
|
|
70
|
+
*
|
|
71
|
+
* Timeline model: segment i starts at `start_i = start_{i-1} + seg_{i-1} - T`
|
|
72
|
+
* (each crossfade overlaps T seconds), so the xfade filter offset for join i
|
|
73
|
+
* is exactly `start_i`. When clips are too short to host the requested
|
|
74
|
+
* transition, T is clamped (with a warning) instead of failing the run.
|
|
75
|
+
*/
|
|
76
|
+
export declare function planFootageTimeline(inputs: FootageClipInput[], opts?: FootagePlanOptions): FootageTimelinePlan;
|
|
77
|
+
/** One visual source per beat: a generated clip, or a keyframe still to ken-burns. */
|
|
78
|
+
export interface FootageSource {
|
|
79
|
+
/** Absolute path to the clip (video) or keyframe still (image). */
|
|
80
|
+
path: string;
|
|
81
|
+
kind: "video" | "image";
|
|
82
|
+
}
|
|
83
|
+
export interface FootageAssembleArgsOptions {
|
|
84
|
+
/** Visual sources in beat order (parallel to `plan.beats`). */
|
|
85
|
+
sources: FootageSource[];
|
|
86
|
+
plan: FootageTimelinePlan;
|
|
87
|
+
/** Absolute narration paths keyed by beat index (sparse — not every beat narrates). */
|
|
88
|
+
narrationPaths: ReadonlyMap<number, string>;
|
|
89
|
+
/** Absolute music-bed path; looped and ducked under narration when present. */
|
|
90
|
+
musicPath?: string;
|
|
91
|
+
outputPath: string;
|
|
92
|
+
width?: number;
|
|
93
|
+
height?: number;
|
|
94
|
+
fps?: number;
|
|
95
|
+
crf?: number;
|
|
96
|
+
musicVolume?: number;
|
|
97
|
+
/** Apply the cinematic finish pass (vignette + film grain) before the fades. */
|
|
98
|
+
finish?: boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build the single-pass FFmpeg invocation: normalize every clip to one
|
|
102
|
+
* geometry/fps, xfade-chain them at the planned offsets, fade the head and
|
|
103
|
+
* tail, and mix narration (adelay per beat) over an optional looped,
|
|
104
|
+
* sidechain-ducked music bed.
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildFootageAssembleArgs(opts: FootageAssembleArgsOptions): string[];
|
|
107
|
+
export interface FootageAssembleOptions {
|
|
108
|
+
projectDir: string;
|
|
109
|
+
/** Output path (relative paths resolve against projectDir). Default: renders/footage.mp4. */
|
|
110
|
+
output?: string;
|
|
111
|
+
transitionSec?: number;
|
|
112
|
+
fadeSec?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Music bed: an explicit path, `"none"` to disable, or undefined to
|
|
115
|
+
* auto-detect `assets/music.mp3|wav` then `assets/music-<firstBeat>.mp3|wav`.
|
|
116
|
+
*/
|
|
117
|
+
music?: string;
|
|
118
|
+
musicVolume?: number;
|
|
119
|
+
/** Apply the cinematic finish pass (vignette + film grain). */
|
|
120
|
+
finish?: boolean;
|
|
121
|
+
dryRun?: boolean;
|
|
122
|
+
}
|
|
123
|
+
export interface FootageAssembleReport {
|
|
124
|
+
schemaVersion: "1";
|
|
125
|
+
kind: "footage-assemble";
|
|
126
|
+
project: string;
|
|
127
|
+
output: string;
|
|
128
|
+
totalDurationSec: number;
|
|
129
|
+
transitionSec: number;
|
|
130
|
+
fadeSec: number;
|
|
131
|
+
beats: Array<FootageBeatPlan & {
|
|
132
|
+
/** The visual source file (generated clip, or keyframe still on fallback). */
|
|
133
|
+
clip: string;
|
|
134
|
+
/** How the segment was produced. */
|
|
135
|
+
source: "clip" | "keyframe-kenburns";
|
|
136
|
+
narration?: string;
|
|
137
|
+
}>;
|
|
138
|
+
music: {
|
|
139
|
+
path: string;
|
|
140
|
+
source: "flag" | "auto";
|
|
141
|
+
volume: number;
|
|
142
|
+
ducked: boolean;
|
|
143
|
+
} | null;
|
|
144
|
+
/** The finish filters applied before the fades, or null when skipped. */
|
|
145
|
+
finish: {
|
|
146
|
+
filters: string[];
|
|
147
|
+
} | null;
|
|
148
|
+
warnings: string[];
|
|
149
|
+
nextActions: ReviewAction[];
|
|
150
|
+
}
|
|
151
|
+
export interface FootageAssembleResult {
|
|
152
|
+
success: boolean;
|
|
153
|
+
dryRun: boolean;
|
|
154
|
+
outputPath: string;
|
|
155
|
+
reportPath?: string;
|
|
156
|
+
report?: FootageAssembleReport;
|
|
157
|
+
error?: string;
|
|
158
|
+
suggestion?: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Assemble a scene project's generated clips into the footage cut. Probes real
|
|
162
|
+
* durations, plans the timeline, runs one FFmpeg pass, and writes
|
|
163
|
+
* `assemble-report.json` so the driving agent can read the cut's anatomy
|
|
164
|
+
* (offsets, extensions, clamps) without watching the video.
|
|
165
|
+
*/
|
|
166
|
+
export declare function executeFootageAssemble(opts: FootageAssembleOptions): Promise<FootageAssembleResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* already have one with sub-composition references.
|
|
20
20
|
*/
|
|
21
21
|
import { type ImageOptions } from "@vibeframe/ai-providers";
|
|
22
|
+
import { type FootageAssembleReport } from "./footage-assemble.js";
|
|
22
23
|
import type { ComposerProvider } from "./composer-resolve.js";
|
|
23
24
|
import { type ComposePromptsBeat } from "./compose-prompts.js";
|
|
24
25
|
import { type SceneRenderResult } from "./scene-render.js";
|
|
@@ -128,6 +129,12 @@ export type SceneBuildProgressEvent = {
|
|
|
128
129
|
type: "video-failed";
|
|
129
130
|
beatId: string;
|
|
130
131
|
error: string;
|
|
132
|
+
} | {
|
|
133
|
+
type: "video-fallback";
|
|
134
|
+
beatId: string;
|
|
135
|
+
from: string;
|
|
136
|
+
to: string;
|
|
137
|
+
reason: string;
|
|
131
138
|
} | {
|
|
132
139
|
type: "video-skipped";
|
|
133
140
|
beatId: string;
|
|
@@ -244,7 +251,7 @@ export interface SceneBuildOptions {
|
|
|
244
251
|
* based on env keys (claude > gemini > openai). Pass an explicit value
|
|
245
252
|
* to require that provider's key.
|
|
246
253
|
*/
|
|
247
|
-
composer?: ComposerProvider | "template";
|
|
254
|
+
composer?: ComposerProvider | "template" | "footage";
|
|
248
255
|
skipNarration?: boolean;
|
|
249
256
|
skipBackdrop?: boolean;
|
|
250
257
|
skipRender?: boolean;
|
|
@@ -271,6 +278,12 @@ export interface SceneBuildOptions {
|
|
|
271
278
|
* kinetic-type reveals to speech. Pass true to opt out (no transcribe cost).
|
|
272
279
|
*/
|
|
273
280
|
skipTranscript?: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Provider-specific image model for backdrops/keyframes/character sheets
|
|
283
|
+
* (e.g. gemini `flash` | `pro`, openai `gpt-image-2`). Provider default when
|
|
284
|
+
* omitted; grok has a single model and ignores it.
|
|
285
|
+
*/
|
|
286
|
+
imageModel?: string;
|
|
274
287
|
/** OpenAI image quality — see `vibe generate image --quality`. */
|
|
275
288
|
imageQuality?: "standard" | "hd";
|
|
276
289
|
/** OpenAI image size. Default 1536x1024 for cinematic 16:9-ish framing. */
|
|
@@ -341,6 +354,12 @@ export interface SceneBuildResult {
|
|
|
341
354
|
/** MP4 path when `skipRender` is false and render succeeded. */
|
|
342
355
|
outputPath?: string;
|
|
343
356
|
renderResult?: SceneRenderResult;
|
|
357
|
+
/**
|
|
358
|
+
* The footage composer's cut anatomy (offsets, extensions, clamps) — also
|
|
359
|
+
* persisted as `assemble-report.json`. Present only when
|
|
360
|
+
* `composer === "footage"` reached the render phase.
|
|
361
|
+
*/
|
|
362
|
+
footageReport?: FootageAssembleReport;
|
|
344
363
|
/**
|
|
345
364
|
* Populated only in agent mode when {@link phase} === `"needs-author"`.
|
|
346
365
|
* The host agent should consume this to write each beat's HTML, then
|
|
@@ -372,6 +391,12 @@ export interface SceneBuildResult {
|
|
|
372
391
|
totalLatencyMs: number;
|
|
373
392
|
}
|
|
374
393
|
export declare function executeSceneBuild(opts: SceneBuildOptions): Promise<SceneBuildResult>;
|
|
394
|
+
/**
|
|
395
|
+
* ByteDance's platform-wide moderation rejects i2v inputs showing a
|
|
396
|
+
* recognizable face with a deterministic 422 ("likenesses of real people") —
|
|
397
|
+
* it applies to AI-generated photoreal faces too, and retrying never helps.
|
|
398
|
+
*/
|
|
399
|
+
export declare function isLikenessRejection(error: string | undefined): boolean;
|
|
375
400
|
export type BuildReport = ReturnType<typeof toBuildReport>;
|
|
376
401
|
declare function toBuildReport(projectDir: string, result: SceneBuildResult): {
|
|
377
402
|
schemaVersion: string;
|
|
@@ -104,7 +104,7 @@ export declare function resolveCharacters(frontmatter: ProjectFrontmatter | unde
|
|
|
104
104
|
* rather than restating it - four surfaces had drifted to four different
|
|
105
105
|
* sub-lists before this became the one list.
|
|
106
106
|
*/
|
|
107
|
-
export declare const STORYBOARD_CUE_KEYS: readonly ["duration", "narration", "backdrop", "video", "keyframe", "motion", "voice", "music", "asset", "characters", "eyebrow", "title", "caption", "kicker", "sub"];
|
|
107
|
+
export declare const STORYBOARD_CUE_KEYS: readonly ["duration", "narration", "backdrop", "video", "keyframe", "provider", "motion", "voice", "music", "asset", "characters", "eyebrow", "title", "caption", "kicker", "sub"];
|
|
108
108
|
export type StoryboardCueKey = (typeof STORYBOARD_CUE_KEYS)[number];
|
|
109
109
|
/**
|
|
110
110
|
* Per-beat cues extracted from the first ```yaml fenced block inside a beat
|
|
@@ -138,6 +138,12 @@ export interface BeatCues {
|
|
|
138
138
|
* and shapes the HTML that agent writes.
|
|
139
139
|
*/
|
|
140
140
|
motion?: string;
|
|
141
|
+
/**
|
|
142
|
+
* Video-provider override for this beat (seedance|runway|kling|veo|grok).
|
|
143
|
+
* Use to pin a face-visible keyframe to a provider that accepts it (e.g.
|
|
144
|
+
* `provider: runway` — Seedance's likeness filter rejects face i2v inputs).
|
|
145
|
+
*/
|
|
146
|
+
provider?: string;
|
|
141
147
|
/** Voice override for this beat (overrides project frontmatter `voice`). */
|
|
142
148
|
voice?: string;
|
|
143
149
|
/** Music prompt or a project-relative path to an existing track. */
|