@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.
@@ -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. */