@vibeframe/cli 0.105.2 → 0.106.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/dist/commands/_shared/edit/silence-cut.d.ts +1 -1
- package/dist/commands/_shared/render-inspect.d.ts +1 -1
- package/dist/commands/_shared/scene-html-emit.d.ts +24 -0
- package/dist/commands/ai-analyze.d.ts +2 -2
- package/dist/commands/ai-motion.d.ts +1 -1
- package/dist/commands/ai-review.d.ts +1 -1
- package/dist/commands/scene.d.ts +4 -1
- package/dist/index.js +267 -73
- package/dist/tools/manifest/edit.d.ts +11 -11
- package/dist/tools/manifest/generate.d.ts +6 -3
- package/dist/tools/manifest/index.js +249 -65
- package/dist/tools/manifest/inspect.d.ts +12 -12
- package/package.json +3 -3
|
@@ -14543,6 +14543,39 @@ var init_whisper = __esm({
|
|
|
14543
14543
|
}
|
|
14544
14544
|
});
|
|
14545
14545
|
|
|
14546
|
+
// ../ai-providers/dist/gemini/gemini-models.js
|
|
14547
|
+
function isGeminiTextModelAlias(model) {
|
|
14548
|
+
return Object.prototype.hasOwnProperty.call(GEMINI_TEXT_MODEL_ALIASES, model);
|
|
14549
|
+
}
|
|
14550
|
+
function resolveGeminiTextModel(model) {
|
|
14551
|
+
const trimmed = model?.trim();
|
|
14552
|
+
if (!trimmed)
|
|
14553
|
+
return GEMINI_DEFAULT_TEXT_MODEL;
|
|
14554
|
+
if (isGeminiTextModelAlias(trimmed))
|
|
14555
|
+
return GEMINI_TEXT_MODEL_ALIASES[trimmed];
|
|
14556
|
+
if (trimmed.startsWith("gemini-"))
|
|
14557
|
+
return trimmed;
|
|
14558
|
+
return GEMINI_DEFAULT_TEXT_MODEL;
|
|
14559
|
+
}
|
|
14560
|
+
var GEMINI_DEFAULT_TEXT_MODEL, GEMINI_AGENT_DEFAULT_TEXT_MODEL, GEMINI_TEXT_MODEL_ALIASES, GEMINI_TEXT_MODEL_HELP;
|
|
14561
|
+
var init_gemini_models = __esm({
|
|
14562
|
+
"../ai-providers/dist/gemini/gemini-models.js"() {
|
|
14563
|
+
"use strict";
|
|
14564
|
+
GEMINI_DEFAULT_TEXT_MODEL = "gemini-3.5-flash";
|
|
14565
|
+
GEMINI_AGENT_DEFAULT_TEXT_MODEL = "gemini-2.5-flash";
|
|
14566
|
+
GEMINI_TEXT_MODEL_ALIASES = {
|
|
14567
|
+
flash: GEMINI_DEFAULT_TEXT_MODEL,
|
|
14568
|
+
latest: GEMINI_DEFAULT_TEXT_MODEL,
|
|
14569
|
+
"flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
|
|
14570
|
+
"flash-3": "gemini-3-flash-preview",
|
|
14571
|
+
"flash-2.5": "gemini-2.5-flash",
|
|
14572
|
+
pro: "gemini-2.5-pro",
|
|
14573
|
+
"pro-3.1": "gemini-3.1-pro-preview"
|
|
14574
|
+
};
|
|
14575
|
+
GEMINI_TEXT_MODEL_HELP = "flash/latest (Gemini 3.5 Flash), flash-3.5, flash-3, flash-2.5, pro, pro-3.1, or a full gemini-* model ID";
|
|
14576
|
+
}
|
|
14577
|
+
});
|
|
14578
|
+
|
|
14546
14579
|
// ../ai-providers/dist/gemini/gemini-motion.js
|
|
14547
14580
|
function buildMotionSystemPrompt(width, height, fps, duration, durationInFrames, stylePreset) {
|
|
14548
14581
|
return `You are a world-class broadcast motion graphics designer (like Apple Keynote, Netflix intros, ESPN graphics). Create STUNNING, jaw-dropping overlays that make viewers go "wow".
|
|
@@ -14696,7 +14729,7 @@ async function generateMotion(api, description, options = {}) {
|
|
|
14696
14729
|
const duration = options.duration || 5;
|
|
14697
14730
|
const durationInFrames = Math.round(duration * fps);
|
|
14698
14731
|
const stylePreset = options.style || "modern and clean";
|
|
14699
|
-
const modelId = options.model
|
|
14732
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
14700
14733
|
let systemPrompt = buildMotionSystemPrompt(width, height, fps, duration, durationInFrames, stylePreset);
|
|
14701
14734
|
if (options.videoContext) {
|
|
14702
14735
|
const sourceLabel = options.sourceType === "image" ? "IMAGE" : "VIDEO";
|
|
@@ -14777,7 +14810,7 @@ async function refineMotion(api, existingCode, instructions, options = {}) {
|
|
|
14777
14810
|
const fps = options.fps || 30;
|
|
14778
14811
|
const duration = options.duration || 5;
|
|
14779
14812
|
const durationInFrames = Math.round(duration * fps);
|
|
14780
|
-
const modelId = options.model
|
|
14813
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
14781
14814
|
const systemPrompt = `You are a world-class broadcast motion graphics designer. Modify the provided Remotion component based on instructions.
|
|
14782
14815
|
|
|
14783
14816
|
CANVAS: ${width}\xD7${height}px | ${fps}fps | ${durationInFrames} frames (${duration}s)
|
|
@@ -14872,9 +14905,18 @@ var GEMINI_MOTION_MODELS, STYLE_USER_INSTRUCTIONS;
|
|
|
14872
14905
|
var init_gemini_motion = __esm({
|
|
14873
14906
|
"../ai-providers/dist/gemini/gemini-motion.js"() {
|
|
14874
14907
|
"use strict";
|
|
14908
|
+
init_gemini_models();
|
|
14875
14909
|
GEMINI_MOTION_MODELS = {
|
|
14910
|
+
gemini: GEMINI_DEFAULT_TEXT_MODEL,
|
|
14911
|
+
flash: GEMINI_DEFAULT_TEXT_MODEL,
|
|
14912
|
+
latest: GEMINI_DEFAULT_TEXT_MODEL,
|
|
14913
|
+
"flash-3.5": GEMINI_DEFAULT_TEXT_MODEL,
|
|
14914
|
+
"flash-3": "gemini-3-flash-preview",
|
|
14915
|
+
"flash-2.5": "gemini-2.5-flash",
|
|
14876
14916
|
pro: "gemini-2.5-pro",
|
|
14877
|
-
"
|
|
14917
|
+
"2.5-pro": "gemini-2.5-pro",
|
|
14918
|
+
"3.1-pro": "gemini-3.1-pro-preview",
|
|
14919
|
+
"pro-3.1": "gemini-3.1-pro-preview"
|
|
14878
14920
|
};
|
|
14879
14921
|
STYLE_USER_INSTRUCTIONS = {
|
|
14880
14922
|
minimal: "CENTER-ALIGNED pure typography. Thin lines + large title + subtitle. NO glass panels, NO bokeh, NO dark bars. Breathing pulse during hold.",
|
|
@@ -14997,7 +15039,7 @@ async function analyzeContent(api, content, targetDuration, options) {
|
|
|
14997
15039
|
maxOutputTokens: 4096
|
|
14998
15040
|
}
|
|
14999
15041
|
};
|
|
15000
|
-
const response = await fetch(`${api.baseUrl}/models
|
|
15042
|
+
const response = await fetch(`${api.baseUrl}/models/${GEMINI_DEFAULT_TEXT_MODEL}:generateContent?key=${api.apiKey}`, {
|
|
15001
15043
|
method: "POST",
|
|
15002
15044
|
headers: { "Content-Type": "application/json" },
|
|
15003
15045
|
body: JSON.stringify(payload)
|
|
@@ -15030,6 +15072,7 @@ var init_gemini_storyboard = __esm({
|
|
|
15030
15072
|
"../ai-providers/dist/gemini/gemini-storyboard.js"() {
|
|
15031
15073
|
"use strict";
|
|
15032
15074
|
init_storyboard_prompt();
|
|
15075
|
+
init_gemini_models();
|
|
15033
15076
|
}
|
|
15034
15077
|
});
|
|
15035
15078
|
|
|
@@ -15068,6 +15111,7 @@ var init_GeminiProvider = __esm({
|
|
|
15068
15111
|
"../ai-providers/dist/gemini/GeminiProvider.js"() {
|
|
15069
15112
|
"use strict";
|
|
15070
15113
|
init_gemini_motion();
|
|
15114
|
+
init_gemini_models();
|
|
15071
15115
|
init_gemini_storyboard();
|
|
15072
15116
|
init_http();
|
|
15073
15117
|
MODEL_MAP = {
|
|
@@ -15576,7 +15620,7 @@ var init_GeminiProvider = __esm({
|
|
|
15576
15620
|
error: "Google API key not configured"
|
|
15577
15621
|
};
|
|
15578
15622
|
}
|
|
15579
|
-
const modelId = options.model
|
|
15623
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
15580
15624
|
try {
|
|
15581
15625
|
let videoPart;
|
|
15582
15626
|
if (typeof videoData === "string") {
|
|
@@ -15683,7 +15727,7 @@ var init_GeminiProvider = __esm({
|
|
|
15683
15727
|
error: "Google API key not configured"
|
|
15684
15728
|
};
|
|
15685
15729
|
}
|
|
15686
|
-
const modelId = options.model
|
|
15730
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
15687
15731
|
try {
|
|
15688
15732
|
const buffers = Array.isArray(imageData) ? imageData : [imageData];
|
|
15689
15733
|
const imageParts = buffers.map((buf) => ({
|
|
@@ -15785,7 +15829,7 @@ Example response:
|
|
|
15785
15829
|
[{"type":"trim","description":"Trim intro to 3 seconds","clipIds":["clip-1"],"params":{"newDuration":3},"confidence":0.9}]
|
|
15786
15830
|
|
|
15787
15831
|
Respond with ONLY the JSON array, no other text.`;
|
|
15788
|
-
const response = await fetch(`${this.baseUrl}/models
|
|
15832
|
+
const response = await fetch(`${this.baseUrl}/models/${GEMINI_DEFAULT_TEXT_MODEL}:generateContent?key=${this.apiKey}`, {
|
|
15789
15833
|
method: "POST",
|
|
15790
15834
|
headers: {
|
|
15791
15835
|
"Content-Type": "application/json"
|
|
@@ -15907,6 +15951,7 @@ var init_gemini = __esm({
|
|
|
15907
15951
|
"use strict";
|
|
15908
15952
|
init_GeminiProvider();
|
|
15909
15953
|
init_gemini_motion();
|
|
15954
|
+
init_gemini_models();
|
|
15910
15955
|
init_define_provider();
|
|
15911
15956
|
defineProvider({
|
|
15912
15957
|
id: "gemini",
|
|
@@ -25270,6 +25315,10 @@ __export(dist_exports2, {
|
|
|
25270
25315
|
ClaudeProvider: () => ClaudeProvider,
|
|
25271
25316
|
ElevenLabsProvider: () => ElevenLabsProvider,
|
|
25272
25317
|
FalProvider: () => FalProvider,
|
|
25318
|
+
GEMINI_AGENT_DEFAULT_TEXT_MODEL: () => GEMINI_AGENT_DEFAULT_TEXT_MODEL,
|
|
25319
|
+
GEMINI_DEFAULT_TEXT_MODEL: () => GEMINI_DEFAULT_TEXT_MODEL,
|
|
25320
|
+
GEMINI_TEXT_MODEL_ALIASES: () => GEMINI_TEXT_MODEL_ALIASES,
|
|
25321
|
+
GEMINI_TEXT_MODEL_HELP: () => GEMINI_TEXT_MODEL_HELP,
|
|
25273
25322
|
GeminiProvider: () => GeminiProvider,
|
|
25274
25323
|
GrokProvider: () => GrokProvider,
|
|
25275
25324
|
KNOWN_VOICES: () => KNOWN_VOICES,
|
|
@@ -25300,6 +25349,7 @@ __export(dist_exports2, {
|
|
|
25300
25349
|
getProvidersFor: () => getProvidersFor,
|
|
25301
25350
|
getSetupProviders: () => getSetupProviders,
|
|
25302
25351
|
grokProvider: () => grokProvider,
|
|
25352
|
+
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
25303
25353
|
klingProvider: () => klingProvider,
|
|
25304
25354
|
kokoroProvider: () => kokoroProvider,
|
|
25305
25355
|
ollamaProvider: () => ollamaProvider,
|
|
@@ -25307,6 +25357,7 @@ __export(dist_exports2, {
|
|
|
25307
25357
|
openaiProvider: () => openaiProvider,
|
|
25308
25358
|
providerRegistry: () => providerRegistry,
|
|
25309
25359
|
replicateProvider: () => replicateProvider,
|
|
25360
|
+
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
25310
25361
|
resolveVoiceId: () => resolveVoiceId,
|
|
25311
25362
|
runwayProvider: () => runwayProvider,
|
|
25312
25363
|
whisperProvider: () => whisperProvider
|
|
@@ -28479,6 +28530,7 @@ var MODEL_SETTINGS_BY_PROVIDER, ComposeBeatError, defaultCallLLM, CONFIG_PROVIDE
|
|
|
28479
28530
|
var init_compose_scenes_skills = __esm({
|
|
28480
28531
|
"src/commands/_shared/compose-scenes-skills.ts"() {
|
|
28481
28532
|
"use strict";
|
|
28533
|
+
init_dist2();
|
|
28482
28534
|
init_config();
|
|
28483
28535
|
init_bundle();
|
|
28484
28536
|
init_scene_lint();
|
|
@@ -28500,12 +28552,12 @@ var init_compose_scenes_skills = __esm({
|
|
|
28500
28552
|
medium: { model: "gpt-5", maxTokens: 6e3, costPerMTokIn: 1.25, costPerMTokOut: 10 },
|
|
28501
28553
|
high: { model: "gpt-5", maxTokens: 8e3, costPerMTokIn: 1.25, costPerMTokOut: 10 }
|
|
28502
28554
|
},
|
|
28503
|
-
// Google Gemini
|
|
28504
|
-
//
|
|
28555
|
+
// Google Gemini 3.5 Flash — current one-shot Gemini default for
|
|
28556
|
+
// analysis/composition. Keep agent loops on their explicit 2.5 Flash default.
|
|
28505
28557
|
gemini: {
|
|
28506
|
-
low: { model:
|
|
28507
|
-
medium: { model:
|
|
28508
|
-
high: { model:
|
|
28558
|
+
low: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 4e3, costPerMTokIn: 1.5, costPerMTokOut: 9 },
|
|
28559
|
+
medium: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 6e3, costPerMTokIn: 1.5, costPerMTokOut: 9 },
|
|
28560
|
+
high: { model: GEMINI_DEFAULT_TEXT_MODEL, maxTokens: 8e3, costPerMTokIn: 1.5, costPerMTokOut: 9 }
|
|
28509
28561
|
}
|
|
28510
28562
|
};
|
|
28511
28563
|
ComposeBeatError = class extends Error {
|
|
@@ -35178,12 +35230,7 @@ async function detectSilencePeriodsWithGemini(videoPath, minDuration, options) {
|
|
|
35178
35230
|
const gemini = new GeminiProvider();
|
|
35179
35231
|
await gemini.initialize({ apiKey: geminiApiKey });
|
|
35180
35232
|
const videoBuffer = await readFile18(videoPath);
|
|
35181
|
-
const
|
|
35182
|
-
flash: "gemini-3-flash-preview",
|
|
35183
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
35184
|
-
pro: "gemini-2.5-pro"
|
|
35185
|
-
};
|
|
35186
|
-
const modelId = options.model ? modelMap[options.model] || modelMap.flash : void 0;
|
|
35233
|
+
const modelId = options.model ? resolveGeminiTextModel(options.model) : void 0;
|
|
35187
35234
|
const prompt3 = `Analyze this video and identify all silent or dead segments where there is NO meaningful content.
|
|
35188
35235
|
|
|
35189
35236
|
Detect these as silent/dead segments:
|
|
@@ -38635,7 +38682,7 @@ Use this image analysis to inform the color palette, typography placement, and o
|
|
|
38635
38682
|
6. Recommended animation timing and entrance/exit style
|
|
38636
38683
|
7. Any moments where overlays should pause, fade, or stay minimal`;
|
|
38637
38684
|
const analysisResult = await gemini.analyzeVideo(videoBuffer, analysisPrompt, {
|
|
38638
|
-
model:
|
|
38685
|
+
model: GEMINI_DEFAULT_TEXT_MODEL,
|
|
38639
38686
|
fps: 1,
|
|
38640
38687
|
lowResolution: true
|
|
38641
38688
|
});
|
|
@@ -38804,7 +38851,7 @@ function registerMotionCommand(aiCommand) {
|
|
|
38804
38851
|
"auto"
|
|
38805
38852
|
).option("--understanding-prompt <text>", "Custom prompt for --video understanding").option("--from-tsx <path>", "Refine an existing TSX file instead of generating from scratch").option(
|
|
38806
38853
|
"-m, --model <alias>",
|
|
38807
|
-
"LLM model: sonnet (default), opus, gemini, gemini-3.1-pro",
|
|
38854
|
+
"LLM model: sonnet (default), opus, gemini, gemini-2.5-pro, gemini-3.1-pro",
|
|
38808
38855
|
"sonnet"
|
|
38809
38856
|
).option("--dry-run", "Preview parameters without executing").action(async (description, options) => {
|
|
38810
38857
|
const startedAt = Date.now();
|
|
@@ -38948,7 +38995,8 @@ var init_ai_motion = __esm({
|
|
|
38948
38995
|
sonnet: { provider: "claude", modelId: "claude-sonnet-4-6" },
|
|
38949
38996
|
opus: { provider: "claude", modelId: "claude-opus-4-7" },
|
|
38950
38997
|
"opus-4-6": { provider: "claude", modelId: "claude-opus-4-6" },
|
|
38951
|
-
gemini: { provider: "gemini", modelId:
|
|
38998
|
+
gemini: { provider: "gemini", modelId: GEMINI_DEFAULT_TEXT_MODEL },
|
|
38999
|
+
"gemini-2.5-pro": { provider: "gemini", modelId: "gemini-2.5-pro" },
|
|
38952
39000
|
"gemini-3.1-pro": { provider: "gemini", modelId: "gemini-3.1-pro-preview" }
|
|
38953
39001
|
};
|
|
38954
39002
|
}
|
|
@@ -39529,7 +39577,7 @@ async function executeMotionOverlay(options) {
|
|
|
39529
39577
|
};
|
|
39530
39578
|
}
|
|
39531
39579
|
function registerMotionOverlayCommand(parent) {
|
|
39532
|
-
parent.command("motion-overlay").description("Apply designed motion graphics overlays to an existing video").argument("<video>", "Video file path").argument("[description]", "Motion overlay description (omit when using --asset)").option("--asset <path>", "User-provided .json/.lottie animation to overlay").option("-o, --output <path>", "Output video file path").option("-d, --duration <sec>", "Overlay/render duration in seconds").option("--start <sec>", "Overlay start time in seconds", "0").option("--style <style>", "Style preset for generated overlays: minimal, corporate, playful, cinematic").option("-m, --model <alias>", "LLM model for generated overlays: sonnet, opus, gemini, gemini-3.1-pro", "sonnet").option("--understand <mode>", "Analyze video before generated overlay: auto, off, required", "auto").option("--understanding-prompt <text>", "Custom prompt for video understanding").option("--position <position>", "Lottie position: full, center, top-left, top-right, bottom-left, bottom-right", "full").option("--scale <number>", "Lottie overlay scale (0.01-2)").option("--opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--loop", "Loop Lottie overlay", true).option("--no-loop", "Do not loop Lottie overlay").option("--dry-run", "Preview parameters without executing").action(async (videoPath, description, options) => {
|
|
39580
|
+
parent.command("motion-overlay").description("Apply designed motion graphics overlays to an existing video").argument("<video>", "Video file path").argument("[description]", "Motion overlay description (omit when using --asset)").option("--asset <path>", "User-provided .json/.lottie animation to overlay").option("-o, --output <path>", "Output video file path").option("-d, --duration <sec>", "Overlay/render duration in seconds").option("--start <sec>", "Overlay start time in seconds", "0").option("--style <style>", "Style preset for generated overlays: minimal, corporate, playful, cinematic").option("-m, --model <alias>", "LLM model for generated overlays: sonnet, opus, gemini, gemini-2.5-pro, gemini-3.1-pro", "sonnet").option("--understand <mode>", "Analyze video before generated overlay: auto, off, required", "auto").option("--understanding-prompt <text>", "Custom prompt for video understanding").option("--position <position>", "Lottie position: full, center, top-left, top-right, bottom-left, bottom-right", "full").option("--scale <number>", "Lottie overlay scale (0.01-2)").option("--opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--loop", "Loop Lottie overlay", true).option("--no-loop", "Do not loop Lottie overlay").option("--dry-run", "Preview parameters without executing").action(async (videoPath, description, options) => {
|
|
39533
39581
|
const startedAt = Date.now();
|
|
39534
39582
|
try {
|
|
39535
39583
|
if (options.output) validateOutputPath(options.output);
|
|
@@ -40818,13 +40866,7 @@ async function executeThumbnailBestFrame(options) {
|
|
|
40818
40866
|
await gemini.initialize({ apiKey: googleKey });
|
|
40819
40867
|
const videoData = await readFile25(videoPath);
|
|
40820
40868
|
const analysisPrompt = prompt3 || 'Analyze this video and find the single best frame for a thumbnail. Look for frames that are visually striking, well-composed, emotionally engaging, and representative of the video content. Avoid blurry frames, transitions, or dark scenes. Return ONLY a JSON object: {"timestamp": <seconds as number>, "reason": "<brief explanation>"}';
|
|
40821
|
-
const
|
|
40822
|
-
flash: "gemini-3-flash-preview",
|
|
40823
|
-
latest: "gemini-2.5-flash",
|
|
40824
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
40825
|
-
pro: "gemini-2.5-pro"
|
|
40826
|
-
};
|
|
40827
|
-
const modelId = modelMap[model] || "gemini-3-flash-preview";
|
|
40869
|
+
const modelId = resolveGeminiTextModel(model);
|
|
40828
40870
|
const result = await gemini.analyzeVideo(videoData, analysisPrompt, {
|
|
40829
40871
|
model: modelId,
|
|
40830
40872
|
fps: 1
|
|
@@ -40884,12 +40926,7 @@ async function executeGeminiVideo(options) {
|
|
|
40884
40926
|
return { success: false, error: "Google API key required. Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
|
|
40885
40927
|
}
|
|
40886
40928
|
const isYouTube = options.source.includes("youtube.com") || options.source.includes("youtu.be");
|
|
40887
|
-
const
|
|
40888
|
-
flash: "gemini-3-flash-preview",
|
|
40889
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
40890
|
-
pro: "gemini-2.5-pro"
|
|
40891
|
-
};
|
|
40892
|
-
const modelId = modelMap[options.model || "flash"] || modelMap.flash;
|
|
40929
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
40893
40930
|
let videoData;
|
|
40894
40931
|
if (isYouTube) {
|
|
40895
40932
|
videoData = options.source;
|
|
@@ -40950,12 +40987,7 @@ async function executeAnalyze(options) {
|
|
|
40950
40987
|
error: "Cannot detect source type. Supported: images (.png/.jpg/.webp/.gif), videos (.mp4/.mov/.webm), YouTube URLs, image URLs."
|
|
40951
40988
|
};
|
|
40952
40989
|
}
|
|
40953
|
-
const
|
|
40954
|
-
flash: "gemini-3-flash-preview",
|
|
40955
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
40956
|
-
pro: "gemini-2.5-pro"
|
|
40957
|
-
};
|
|
40958
|
-
const modelId = modelMap[options.model || "flash"] || modelMap.flash;
|
|
40990
|
+
const modelId = resolveGeminiTextModel(options.model);
|
|
40959
40991
|
const gemini = new GeminiProvider();
|
|
40960
40992
|
await gemini.initialize({ apiKey });
|
|
40961
40993
|
if (isImage) {
|
|
@@ -41035,7 +41067,7 @@ async function executeAnalyze(options) {
|
|
|
41035
41067
|
}
|
|
41036
41068
|
}
|
|
41037
41069
|
function registerAnalyzeCommands(aiCommand) {
|
|
41038
|
-
aiCommand.command("gemini-video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>",
|
|
41070
|
+
aiCommand.command("gemini-video").description("Analyze video using Gemini (summarize, Q&A, extract info)").argument("<source>", "Video file path or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second (default: 1, higher for action)").option("--start <seconds>", "Start offset in seconds (for clipping)").option("--end <seconds>", "End offset in seconds (for clipping)").option("--low-res", "Use low resolution mode (fewer tokens, longer videos)").option("-v, --verbose", "Show token usage").action(async (source, prompt3, options) => {
|
|
41039
41071
|
try {
|
|
41040
41072
|
if (options.apiKey) {
|
|
41041
41073
|
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
@@ -41078,7 +41110,7 @@ function registerAnalyzeCommands(aiCommand) {
|
|
|
41078
41110
|
exitWithError(apiError(`Video analysis failed: ${error instanceof Error ? error.message : String(error)}`, true));
|
|
41079
41111
|
}
|
|
41080
41112
|
});
|
|
41081
|
-
aiCommand.command("analyze").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>",
|
|
41113
|
+
aiCommand.command("analyze").description("Analyze any media: images, videos, or YouTube URLs using Gemini").argument("<source>", "Image/video file path, image URL, or YouTube URL").argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')").option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)").option("-m, --model <model>", `Model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("--fps <number>", "Frames per second for video (default: 1)").option("--start <seconds>", "Start offset in seconds (video only)").option("--end <seconds>", "End offset in seconds (video only)").option("--low-res", "Use low resolution mode (fewer tokens)").option("-v, --verbose", "Show token usage").action(async (source, prompt3, options) => {
|
|
41082
41114
|
try {
|
|
41083
41115
|
if (options.apiKey) {
|
|
41084
41116
|
process.env.GOOGLE_API_KEY = options.apiKey;
|
|
@@ -41199,12 +41231,7 @@ ${content}`;
|
|
|
41199
41231
|
|
|
41200
41232
|
Project context for beat-aware review:
|
|
41201
41233
|
${projectContext}` : "";
|
|
41202
|
-
const
|
|
41203
|
-
flash: "gemini-3-flash-preview",
|
|
41204
|
-
"flash-2.5": "gemini-2.5-flash",
|
|
41205
|
-
pro: "gemini-2.5-pro"
|
|
41206
|
-
};
|
|
41207
|
-
const modelId = modelMap[model] || modelMap.flash;
|
|
41234
|
+
const modelId = resolveGeminiTextModel(model);
|
|
41208
41235
|
const reviewPrompt = `You are a professional video editor reviewing this video for quality. Analyze the video and return a JSON review with the following structure. Return ONLY valid JSON, no extra text.
|
|
41209
41236
|
|
|
41210
41237
|
{
|
|
@@ -41311,7 +41338,7 @@ Score each category 1-10. Prefer beatIssues when you can map a problem to a stor
|
|
|
41311
41338
|
return result;
|
|
41312
41339
|
}
|
|
41313
41340
|
function registerReviewCommand(aiCommand) {
|
|
41314
|
-
aiCommand.command("review", { hidden: true }).description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<source>", "Video file path").option("--storyboard <path>", "Storyboard JSON file for context").option("--auto-apply", "Automatically apply fixable corrections").option("--verify", "Run verification pass after applying fixes").option("-m, --model <model>",
|
|
41341
|
+
aiCommand.command("review", { hidden: true }).description("Review video quality using Gemini AI and optionally auto-fix issues").argument("<source>", "Video file path").option("--storyboard <path>", "Storyboard JSON file for context").option("--auto-apply", "Automatically apply fixable corrections").option("--verify", "Run verification pass after applying fixes").option("-m, --model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").option("-o, --output <path>", "Output video file path (for auto-apply)").option("--dry-run", "Preview parameters without executing").action(async (videoPath, options) => {
|
|
41315
41342
|
const startedAt = Date.now();
|
|
41316
41343
|
try {
|
|
41317
41344
|
if (options.output) {
|
|
@@ -42198,7 +42225,7 @@ import { resolve as resolve46, dirname as dirname19, basename as basename13, ext
|
|
|
42198
42225
|
import { existsSync as existsSync38 } from "node:fs";
|
|
42199
42226
|
import { writeFile as writeFile34, mkdir as mkdir20 } from "node:fs/promises";
|
|
42200
42227
|
function registerThumbnailCommand(parent) {
|
|
42201
|
-
parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>",
|
|
42228
|
+
parent.command("thumbnail").description("Generate video thumbnail (DALL-E) or extract best frame from video (Gemini)").argument("[description]", "Thumbnail description (for DALL-E generation)").option("-k, --api-key <key>", "API key (OpenAI for generation, Google for best-frame)").option("-o, --output <path>", "Output file path").option("--style <style>", "Platform style: youtube, instagram, tiktok, twitter").option("--best-frame <video>", "Extract best thumbnail frame from video using Gemini AI").option("--prompt <prompt>", "Custom prompt for best-frame analysis").option("--model <model>", `Gemini model: ${GEMINI_TEXT_MODEL_HELP}`, "flash").action(async (description, options) => {
|
|
42202
42229
|
const startedAt = Date.now();
|
|
42203
42230
|
try {
|
|
42204
42231
|
if (description) rejectControlChars(description);
|
|
@@ -44353,7 +44380,7 @@ function registerVideoCommand(parent) {
|
|
|
44353
44380
|
"--seedance-model <model>",
|
|
44354
44381
|
"Seedance variant: quality or fast (fal.ai only)",
|
|
44355
44382
|
"quality"
|
|
44356
|
-
).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 720p, 1080p, 4k
|
|
44383
|
+
).option("--negative <prompt>", "Negative prompt - what to avoid (Kling/Veo)").option("--resolution <res>", "Video resolution: 480p, 720p, 1080p, or 4k depending on provider").option("--last-frame <path>", "Last frame image for frame interpolation (Veo) or Seedance end frame").option("--end-image <path>", "Ending frame image for Seedance image-to-video").option(
|
|
44357
44384
|
"--ref-images <paths...>",
|
|
44358
44385
|
"Reference images for Seedance reference-to-video or Veo character consistency"
|
|
44359
44386
|
).option("--ref-videos <paths...>", "Reference videos for Seedance reference-to-video").option("--ref-audio <paths...>", "Reference audio for Seedance reference-to-video").option("--no-generate-audio", "Disable native audio when the provider supports it").option("--person <mode>", "Person generation: allow_all, allow_adult (Veo only)").option("--veo-model <model>", "Veo model: 3.0, 3.1, 3.1-fast (default: 3.1-fast)", "3.1-fast").option(
|
|
@@ -44814,6 +44841,30 @@ Examples:
|
|
|
44814
44841
|
exitWithError(apiError(message, true));
|
|
44815
44842
|
}
|
|
44816
44843
|
}
|
|
44844
|
+
let seedanceEndImage;
|
|
44845
|
+
const seedanceEndImagePath = options.endImage ?? options.lastFrame;
|
|
44846
|
+
if (seedanceEndImagePath && seedanceReferences.length === 0) {
|
|
44847
|
+
try {
|
|
44848
|
+
const absEndImagePath = resolve50(process.cwd(), seedanceEndImagePath);
|
|
44849
|
+
const endImageBuffer = await readFile32(absEndImagePath);
|
|
44850
|
+
const ext = seedanceEndImagePath.toLowerCase().split(".").pop();
|
|
44851
|
+
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext || "png"}`;
|
|
44852
|
+
const uploadHost = await resolveUploadHost();
|
|
44853
|
+
spinner2.text = `Uploading end image via ${uploadHost.provider} for Seedance...`;
|
|
44854
|
+
const upload = await uploadHost.uploadImage(endImageBuffer, {
|
|
44855
|
+
filename: seedanceEndImagePath,
|
|
44856
|
+
mimeType
|
|
44857
|
+
});
|
|
44858
|
+
seedanceEndImage = upload.url;
|
|
44859
|
+
} catch (err) {
|
|
44860
|
+
spinner2.fail("End image upload failed");
|
|
44861
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
44862
|
+
if (message.includes("IMGBB_API_KEY")) {
|
|
44863
|
+
exitWithError(authError("IMGBB_API_KEY", "ImgBB"));
|
|
44864
|
+
}
|
|
44865
|
+
exitWithError(apiError(message, true));
|
|
44866
|
+
}
|
|
44867
|
+
}
|
|
44817
44868
|
spinner2.text = "Generating video with fal.ai Seedance 2.0 (this may take 1-3 minutes)...";
|
|
44818
44869
|
const seedanceModel = String(options.seedanceModel ?? "quality").toLowerCase();
|
|
44819
44870
|
const falModel = seedanceModel === "fast" || seedanceModel === "seedance-2.0-fast" ? "seedance-2.0-fast" : "seedance-2.0";
|
|
@@ -44826,7 +44877,8 @@ Examples:
|
|
|
44826
44877
|
negativePrompt: options.negative,
|
|
44827
44878
|
model: falModel,
|
|
44828
44879
|
resolution: options.resolution,
|
|
44829
|
-
generateAudio: options.generateAudio
|
|
44880
|
+
generateAudio: options.generateAudio,
|
|
44881
|
+
lastFrame: seedanceEndImage
|
|
44830
44882
|
});
|
|
44831
44883
|
finalResult = result;
|
|
44832
44884
|
}
|
|
@@ -50718,6 +50770,14 @@ var SCENE_PRESETS = [
|
|
|
50718
50770
|
"kinetic-type",
|
|
50719
50771
|
"product-shot"
|
|
50720
50772
|
];
|
|
50773
|
+
var LOTTIE_POSITIONS = [
|
|
50774
|
+
"full",
|
|
50775
|
+
"center",
|
|
50776
|
+
"top-left",
|
|
50777
|
+
"top-right",
|
|
50778
|
+
"bottom-left",
|
|
50779
|
+
"bottom-right"
|
|
50780
|
+
];
|
|
50721
50781
|
var GSAP_CDN = "https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js";
|
|
50722
50782
|
function esc(text) {
|
|
50723
50783
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -50998,6 +51058,56 @@ function buildPreset(input) {
|
|
|
50998
51058
|
}
|
|
50999
51059
|
}
|
|
51000
51060
|
}
|
|
51061
|
+
var DOTLOTTIE_WC_VERSION = "0.9.12";
|
|
51062
|
+
var DOTLOTTIE_WEB_VERSION = "0.71.0";
|
|
51063
|
+
var DOTLOTTIE_WC_CDN = `https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-wc@${DOTLOTTIE_WC_VERSION}/dist/index.js`;
|
|
51064
|
+
var DOTLOTTIE_WASM_CDN = `https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web@${DOTLOTTIE_WEB_VERSION}/dist/dotlottie-player.wasm`;
|
|
51065
|
+
function lottieOverlayStyle(input) {
|
|
51066
|
+
const pos = input.position ?? "full";
|
|
51067
|
+
const rawScale = input.scale ?? (pos === "full" ? 1 : 0.25);
|
|
51068
|
+
const scale = Math.max(0.01, Math.min(2, rawScale));
|
|
51069
|
+
const opacity = Math.max(0, Math.min(1, input.opacity ?? 1));
|
|
51070
|
+
const base = [
|
|
51071
|
+
"position:absolute",
|
|
51072
|
+
"pointer-events:none",
|
|
51073
|
+
`opacity:${opacity}`
|
|
51074
|
+
];
|
|
51075
|
+
if (pos === "full") {
|
|
51076
|
+
base.push("inset:0", "width:100%", "height:100%");
|
|
51077
|
+
} else {
|
|
51078
|
+
const pct = scale * 100;
|
|
51079
|
+
base.push(`width:${pct}%`, `height:${pct}%`);
|
|
51080
|
+
switch (pos) {
|
|
51081
|
+
case "center":
|
|
51082
|
+
base.push("top:50%", "left:50%", "transform:translate(-50%,-50%)");
|
|
51083
|
+
break;
|
|
51084
|
+
case "top-left":
|
|
51085
|
+
base.push("top:4%", "left:4%");
|
|
51086
|
+
break;
|
|
51087
|
+
case "top-right":
|
|
51088
|
+
base.push("top:4%", "right:4%");
|
|
51089
|
+
break;
|
|
51090
|
+
case "bottom-left":
|
|
51091
|
+
base.push("bottom:4%", "left:4%");
|
|
51092
|
+
break;
|
|
51093
|
+
case "bottom-right":
|
|
51094
|
+
base.push("bottom:4%", "right:4%");
|
|
51095
|
+
break;
|
|
51096
|
+
}
|
|
51097
|
+
}
|
|
51098
|
+
return base.join(";");
|
|
51099
|
+
}
|
|
51100
|
+
function buildLottieOverlay(input, sceneId) {
|
|
51101
|
+
const loop = input.loop ?? true ? " loop" : "";
|
|
51102
|
+
const style = lottieOverlayStyle(input);
|
|
51103
|
+
const overlayId = `lottie-overlay-${sceneId}`;
|
|
51104
|
+
const markup = `<dotlottie-wc id="${overlayId}" src="${esc(input.src)}" autoplay${loop} style="${style}"></dotlottie-wc>`;
|
|
51105
|
+
const script = `<script type="module">
|
|
51106
|
+
import { setWasmUrl } from "${DOTLOTTIE_WC_CDN}";
|
|
51107
|
+
setWasmUrl("${DOTLOTTIE_WASM_CDN}");
|
|
51108
|
+
</script>`;
|
|
51109
|
+
return { markup, script };
|
|
51110
|
+
}
|
|
51001
51111
|
function emitSceneHtml(input) {
|
|
51002
51112
|
if (input.duration <= 0) {
|
|
51003
51113
|
throw new Error(`Scene duration must be > 0, got ${input.duration}`);
|
|
@@ -51018,15 +51128,20 @@ function emitSceneHtml(input) {
|
|
|
51018
51128
|
data-volume="1"
|
|
51019
51129
|
></audio>
|
|
51020
51130
|
` : "";
|
|
51131
|
+
const lottieLayer = input.lottie ? buildLottieOverlay(input.lottie, id) : null;
|
|
51132
|
+
const lottieMarkup = lottieLayer ? `
|
|
51133
|
+
${lottieLayer.markup}` : "";
|
|
51134
|
+
const lottieScript = lottieLayer ? `
|
|
51135
|
+
${lottieLayer.script}` : "";
|
|
51021
51136
|
return `<template id="scene-${id}-template">
|
|
51022
51137
|
<div data-composition-id="${id}" data-start="0" data-duration="${dur}" data-width="${input.width}" data-height="${input.height}">
|
|
51023
51138
|
<style>
|
|
51024
51139
|
${parts.css}
|
|
51025
51140
|
</style>
|
|
51026
51141
|
|
|
51027
|
-
${parts.body}
|
|
51142
|
+
${parts.body}${lottieMarkup}
|
|
51028
51143
|
${audioBlock}
|
|
51029
|
-
<script src="${GSAP_CDN}"></script
|
|
51144
|
+
<script src="${GSAP_CDN}"></script>${lottieScript}
|
|
51030
51145
|
<script>
|
|
51031
51146
|
window.__timelines = window.__timelines || {};
|
|
51032
51147
|
const tl = gsap.timeline({ paused: true });
|
|
@@ -51450,9 +51565,40 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
51450
51565
|
).option("--no-image", "Skip image generation even when --visuals is provided").option(
|
|
51451
51566
|
"--no-transcribe",
|
|
51452
51567
|
"Skip Whisper word-level transcribe step (no transcript-<id>.json emitted)"
|
|
51453
|
-
).option("--transcribe-language <code>", "BCP-47 language code passed to Whisper (e.g. en, ko)").option("--force", "Overwrite an existing compositions/scene-<id>.html").option("--
|
|
51568
|
+
).option("--transcribe-language <code>", "BCP-47 language code passed to Whisper (e.g. en, ko)").option("--force", "Overwrite an existing compositions/scene-<id>.html").option("--lottie <path>", "Lottie animation file (.json/.lottie) to overlay on the scene").option(
|
|
51569
|
+
"--lottie-position <position>",
|
|
51570
|
+
`Lottie position: ${LOTTIE_POSITIONS.join(", ")}`,
|
|
51571
|
+
"full"
|
|
51572
|
+
).option("--lottie-scale <number>", "Lottie overlay scale (0.01-2)").option("--lottie-opacity <number>", "Lottie overlay opacity (0-1)", "1").option("--lottie-no-loop", "Do not loop the Lottie animation").option("--dry-run", "Preview parameters without writing files or calling APIs").action(async (name, options) => {
|
|
51454
51573
|
const startedAt = Date.now();
|
|
51455
51574
|
if (options.style) options.style = validatePreset(options.style);
|
|
51575
|
+
if (options.lottiePosition) {
|
|
51576
|
+
if (!LOTTIE_POSITIONS.includes(options.lottiePosition)) {
|
|
51577
|
+
exitWithError(
|
|
51578
|
+
usageError(
|
|
51579
|
+
`Invalid --lottie-position "${options.lottiePosition}". Valid: ${LOTTIE_POSITIONS.join(", ")}`
|
|
51580
|
+
)
|
|
51581
|
+
);
|
|
51582
|
+
}
|
|
51583
|
+
}
|
|
51584
|
+
let lottieScale;
|
|
51585
|
+
if (options.lottieScale !== void 0) {
|
|
51586
|
+
lottieScale = Number(options.lottieScale);
|
|
51587
|
+
if (!Number.isFinite(lottieScale) || lottieScale < 0.01 || lottieScale > 2) {
|
|
51588
|
+
exitWithError(
|
|
51589
|
+
usageError(`Invalid --lottie-scale "${options.lottieScale}". Must be between 0.01 and 2.`)
|
|
51590
|
+
);
|
|
51591
|
+
}
|
|
51592
|
+
}
|
|
51593
|
+
let lottieOpacity = 1;
|
|
51594
|
+
if (options.lottieOpacity !== void 0) {
|
|
51595
|
+
lottieOpacity = Number(options.lottieOpacity);
|
|
51596
|
+
if (!Number.isFinite(lottieOpacity) || lottieOpacity < 0 || lottieOpacity > 1) {
|
|
51597
|
+
exitWithError(
|
|
51598
|
+
usageError(`Invalid --lottie-opacity "${options.lottieOpacity}". Must be between 0 and 1.`)
|
|
51599
|
+
);
|
|
51600
|
+
}
|
|
51601
|
+
}
|
|
51456
51602
|
if (options.duration !== void 0) options.duration = validateDuration(options.duration);
|
|
51457
51603
|
let tts;
|
|
51458
51604
|
try {
|
|
@@ -51481,7 +51627,11 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
51481
51627
|
imageProvider: options.imageProvider,
|
|
51482
51628
|
tts,
|
|
51483
51629
|
audio: options.audio,
|
|
51484
|
-
|
|
51630
|
+
lottie: options.lottie ?? null,
|
|
51631
|
+
lottiePosition: options.lottiePosition,
|
|
51632
|
+
lottieScale: lottieScale ?? null,
|
|
51633
|
+
lottieOpacity: options.lottieOpacity !== void 0 ? lottieOpacity : null,
|
|
51634
|
+
lottieLoop: !options.lottieNoLoop,
|
|
51485
51635
|
image: options.image
|
|
51486
51636
|
}
|
|
51487
51637
|
}
|
|
@@ -51509,6 +51659,13 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
51509
51659
|
skipTranscribe: options.transcribe === false,
|
|
51510
51660
|
transcribeLanguage: options.transcribeLanguage,
|
|
51511
51661
|
force: !!options.force,
|
|
51662
|
+
lottie: options.lottie ? {
|
|
51663
|
+
src: options.lottie,
|
|
51664
|
+
position: options.lottiePosition ?? "full",
|
|
51665
|
+
scale: lottieScale,
|
|
51666
|
+
opacity: options.lottieOpacity !== void 0 ? lottieOpacity : 1,
|
|
51667
|
+
loop: !options.lottieNoLoop
|
|
51668
|
+
} : void 0,
|
|
51512
51669
|
onProgress: (msg) => {
|
|
51513
51670
|
if (spinner2) spinner2.text = msg;
|
|
51514
51671
|
}
|
|
@@ -51784,6 +51941,30 @@ async function executeSceneAdd(opts) {
|
|
|
51784
51941
|
await writeFile10(imageAbsPath, buffer);
|
|
51785
51942
|
}
|
|
51786
51943
|
}
|
|
51944
|
+
let lottieRelPath;
|
|
51945
|
+
let lottieAbsPath;
|
|
51946
|
+
let lottieInput;
|
|
51947
|
+
if (opts.lottie) {
|
|
51948
|
+
const sourceAbs = resolve12(opts.lottie.src);
|
|
51949
|
+
if (!await pathExists2(sourceAbs)) {
|
|
51950
|
+
return errResult(`Lottie file not found: ${sourceAbs}`);
|
|
51951
|
+
}
|
|
51952
|
+
const ext = (sourceAbs.match(/\.([a-z0-9]+)$/i)?.[1] ?? "json").toLowerCase();
|
|
51953
|
+
if (ext !== "json" && ext !== "lottie") {
|
|
51954
|
+
return errResult(`Unsupported Lottie file extension: .${ext}. Use .json or .lottie.`);
|
|
51955
|
+
}
|
|
51956
|
+
lottieRelPath = `assets/lottie-${id}.${ext}`;
|
|
51957
|
+
lottieAbsPath = resolve12(projectDir, lottieRelPath);
|
|
51958
|
+
await mkdir5(dirname3(lottieAbsPath), { recursive: true });
|
|
51959
|
+
await copyFile(sourceAbs, lottieAbsPath);
|
|
51960
|
+
lottieInput = {
|
|
51961
|
+
src: lottieRelPath,
|
|
51962
|
+
position: opts.lottie.position,
|
|
51963
|
+
scale: opts.lottie.scale,
|
|
51964
|
+
opacity: opts.lottie.opacity,
|
|
51965
|
+
loop: opts.lottie.loop
|
|
51966
|
+
};
|
|
51967
|
+
}
|
|
51787
51968
|
const cfg = await loadVibeProjectConfig(projectDir);
|
|
51788
51969
|
const fallback2 = cfg?.defaultSceneDuration ?? 5;
|
|
51789
51970
|
const NARRATION_TAIL_BUFFER = 0.5;
|
|
@@ -51812,7 +51993,8 @@ async function executeSceneAdd(opts) {
|
|
|
51812
51993
|
kicker: opts.kicker,
|
|
51813
51994
|
imagePath: imageRelPath,
|
|
51814
51995
|
audioPath: audioRelPath,
|
|
51815
|
-
transcript: transcriptWords
|
|
51996
|
+
transcript: transcriptWords,
|
|
51997
|
+
lottie: lottieInput
|
|
51816
51998
|
});
|
|
51817
51999
|
await mkdir5(dirname3(scenePath), { recursive: true });
|
|
51818
52000
|
await writeFile10(scenePath, sceneHtml, "utf-8");
|
|
@@ -51833,6 +52015,7 @@ async function executeSceneAdd(opts) {
|
|
|
51833
52015
|
rootPath: relative5(process.cwd(), rootPath) || rootPath,
|
|
51834
52016
|
audioPath: audioAbsPath ? relative5(process.cwd(), audioAbsPath) || audioAbsPath : void 0,
|
|
51835
52017
|
imagePath: imageAbsPath ? relative5(process.cwd(), imageAbsPath) || imageAbsPath : void 0,
|
|
52018
|
+
lottiePath: lottieAbsPath ? relative5(process.cwd(), lottieAbsPath) || lottieAbsPath : void 0,
|
|
51836
52019
|
transcriptPath: transcriptAbsPath ? relative5(process.cwd(), transcriptAbsPath) || transcriptAbsPath : void 0,
|
|
51837
52020
|
transcriptWordCount
|
|
51838
52021
|
};
|
|
@@ -53099,7 +53282,7 @@ var editMotionOverlayTool = defineTool({
|
|
|
53099
53282
|
duration: external_exports.number().optional().describe("Overlay/render duration in seconds"),
|
|
53100
53283
|
start: external_exports.number().optional().describe("Overlay start time in seconds"),
|
|
53101
53284
|
style: external_exports.string().optional().describe("Style preset for generated overlays"),
|
|
53102
|
-
model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-3.1-pro"]).optional().describe("LLM model for generated overlays"),
|
|
53285
|
+
model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-2.5-pro", "gemini-3.1-pro"]).optional().describe("LLM model for generated overlays"),
|
|
53103
53286
|
understand: external_exports.enum(["auto", "off", "required"]).optional().describe("Analyze video before generated overlay (default: auto)"),
|
|
53104
53287
|
understandingPrompt: external_exports.string().optional().describe("Custom prompt for video understanding"),
|
|
53105
53288
|
position: external_exports.enum(["full", "center", "top-left", "top-right", "bottom-left", "bottom-right"]).optional().describe("Lottie overlay position"),
|
|
@@ -54833,7 +55016,7 @@ var inspectRenderTool = defineTool({
|
|
|
54833
55016
|
outputPath: external_exports.string().optional().describe("Optional review report path. Defaults to <project>/review-report.json."),
|
|
54834
55017
|
report: external_exports.boolean().optional().describe("Write review-report.json. Default true."),
|
|
54835
55018
|
ai: external_exports.boolean().optional().describe("Also run Gemini video review and merge findings into review-report.json. Default false."),
|
|
54836
|
-
model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant for ai review. Default flash."),
|
|
55019
|
+
model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant for ai review. Default flash."),
|
|
54837
55020
|
dryRun: external_exports.boolean().optional().describe("Preview resolved inputs without probing video or calling Gemini.")
|
|
54838
55021
|
}),
|
|
54839
55022
|
async execute(args, ctx) {
|
|
@@ -54885,7 +55068,7 @@ var analyzeMediaTool = defineTool({
|
|
|
54885
55068
|
schema: external_exports.object({
|
|
54886
55069
|
source: external_exports.string().describe("Path to image/video or YouTube URL"),
|
|
54887
55070
|
prompt: external_exports.string().describe("Analysis prompt (e.g., 'Describe the scene', 'Count people')"),
|
|
54888
|
-
model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
|
|
55071
|
+
model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
|
|
54889
55072
|
fps: external_exports.number().optional().describe("Frames per second for video sampling (default: 1)"),
|
|
54890
55073
|
start: external_exports.number().optional().describe("Start time in seconds for video analysis"),
|
|
54891
55074
|
end: external_exports.number().optional().describe("End time in seconds for video analysis"),
|
|
@@ -54913,7 +55096,7 @@ var analyzeVideoTool = defineTool({
|
|
|
54913
55096
|
schema: external_exports.object({
|
|
54914
55097
|
source: external_exports.string().describe("Path to video file"),
|
|
54915
55098
|
prompt: external_exports.string().describe("Analysis prompt"),
|
|
54916
|
-
model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
|
|
55099
|
+
model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
|
|
54917
55100
|
fps: external_exports.number().optional().describe("Frames per second for sampling"),
|
|
54918
55101
|
start: external_exports.number().optional().describe("Start time in seconds"),
|
|
54919
55102
|
end: external_exports.number().optional().describe("End time in seconds"),
|
|
@@ -54943,7 +55126,7 @@ var analyzeReviewTool = defineTool({
|
|
|
54943
55126
|
storyboardPath: external_exports.string().optional().describe("Path to storyboard.json for intent comparison"),
|
|
54944
55127
|
autoApply: external_exports.boolean().optional().describe("Automatically apply suggested fixes (default: false)"),
|
|
54945
55128
|
verify: external_exports.boolean().optional().describe("Re-review after applying fixes (default: false)"),
|
|
54946
|
-
model: external_exports.enum(["flash", "flash-2.5", "pro"]).optional().describe("Gemini model variant (default: flash)"),
|
|
55129
|
+
model: external_exports.enum(["flash", "latest", "flash-3", "flash-2.5", "pro", "pro-3.1"]).optional().describe("Gemini model variant (default: flash)"),
|
|
54947
55130
|
outputPath: external_exports.string().optional().describe("Output path for fixed video")
|
|
54948
55131
|
}),
|
|
54949
55132
|
async execute(args) {
|
|
@@ -55027,7 +55210,7 @@ var generateMotionTool = defineTool({
|
|
|
55027
55210
|
"Analyze the base video with Gemini before generating motion graphics: auto, off, or required (default: auto)"
|
|
55028
55211
|
),
|
|
55029
55212
|
understandingPrompt: external_exports.string().optional().describe("Custom prompt for video understanding when --video is provided"),
|
|
55030
|
-
model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-3.1-pro"]).optional().describe("LLM model for code generation (default: sonnet)"),
|
|
55213
|
+
model: external_exports.enum(["sonnet", "opus", "gemini", "gemini-2.5-pro", "gemini-3.1-pro"]).optional().describe("LLM model for code generation (default: sonnet)"),
|
|
55031
55214
|
output: external_exports.string().optional().describe("Output path (TSX if code-only, MP4 if rendered)")
|
|
55032
55215
|
}),
|
|
55033
55216
|
async execute(args) {
|
|
@@ -55292,6 +55475,7 @@ var generateVideoTool = defineTool({
|
|
|
55292
55475
|
"Video provider (default: seedance when FAL_API_KEY is configured, otherwise first configured provider)"
|
|
55293
55476
|
),
|
|
55294
55477
|
image: external_exports.string().optional().describe("Reference image path for image-to-video"),
|
|
55478
|
+
endImage: external_exports.string().optional().describe("Ending frame image path for Seedance image-to-video"),
|
|
55295
55479
|
refImages: external_exports.array(external_exports.string()).optional().describe("Reference images for Seedance reference-to-video"),
|
|
55296
55480
|
refVideos: external_exports.array(external_exports.string()).optional().describe("Reference videos for Seedance reference-to-video"),
|
|
55297
55481
|
refAudio: external_exports.array(external_exports.string()).optional().describe("Reference audio files for Seedance reference-to-video"),
|
|
@@ -55299,7 +55483,7 @@ var generateVideoTool = defineTool({
|
|
|
55299
55483
|
ratio: external_exports.string().optional().describe("Aspect ratio: 16:9, 9:16, 1:1 (default: 16:9)"),
|
|
55300
55484
|
mode: external_exports.string().optional().describe("Kling mode: std or pro"),
|
|
55301
55485
|
negative: external_exports.string().optional().describe("Negative prompt (Seedance/Kling/Veo)"),
|
|
55302
|
-
resolution: external_exports.string().optional().describe("Resolution: 720p, 1080p, 4k
|
|
55486
|
+
resolution: external_exports.string().optional().describe("Resolution: 480p, 720p, 1080p, or 4k depending on provider"),
|
|
55303
55487
|
veoModel: external_exports.string().optional().describe("Veo model: 3.0, 3.1, 3.1-fast"),
|
|
55304
55488
|
runwayModel: external_exports.string().optional().describe("Runway model: gen4.5, gen4_turbo"),
|
|
55305
55489
|
seedanceModel: external_exports.string().optional().describe("Seedance variant: quality or fast (fal.ai only)"),
|