@vibeframe/cli 0.104.1 → 0.104.3
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/index.js +127 -53
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -26008,21 +26008,8 @@ async function prompt(question, hidden = false) {
|
|
|
26008
26008
|
});
|
|
26009
26009
|
}
|
|
26010
26010
|
async function getApiKey(envVar, providerName, optionValue) {
|
|
26011
|
-
|
|
26012
|
-
|
|
26013
|
-
}
|
|
26014
|
-
const providerKey = providerKeyForEnvVar(envVar);
|
|
26015
|
-
if (providerKey) {
|
|
26016
|
-
const configKey = await getApiKeyFromConfig(providerKey);
|
|
26017
|
-
if (configKey) {
|
|
26018
|
-
return configKey;
|
|
26019
|
-
}
|
|
26020
|
-
}
|
|
26021
|
-
loadEnv();
|
|
26022
|
-
const envValue = getEnvValue2(envVar);
|
|
26023
|
-
if (envValue) {
|
|
26024
|
-
return envValue;
|
|
26025
|
-
}
|
|
26011
|
+
const configuredKey = await getConfiguredApiKey(envVar, optionValue);
|
|
26012
|
+
if (configuredKey) return configuredKey;
|
|
26026
26013
|
if (!process.stdin.isTTY) {
|
|
26027
26014
|
return null;
|
|
26028
26015
|
}
|
|
@@ -26043,6 +26030,19 @@ async function getApiKey(envVar, providerName, optionValue) {
|
|
|
26043
26030
|
}
|
|
26044
26031
|
return apiKey.trim();
|
|
26045
26032
|
}
|
|
26033
|
+
async function getConfiguredApiKey(envVar, optionValue, options = {}) {
|
|
26034
|
+
if (optionValue) return optionValue;
|
|
26035
|
+
const providerKey = providerKeyForEnvVar(envVar);
|
|
26036
|
+
if (providerKey) {
|
|
26037
|
+
const configKey = await getApiKeyFromConfig(providerKey, { cwd: options.cwd });
|
|
26038
|
+
if (configKey) return configKey;
|
|
26039
|
+
}
|
|
26040
|
+
loadEnv();
|
|
26041
|
+
return getEnvValue2(envVar);
|
|
26042
|
+
}
|
|
26043
|
+
async function hasConfiguredApiKey(envVar, optionValue, options = {}) {
|
|
26044
|
+
return Boolean(await getConfiguredApiKey(envVar, optionValue, options));
|
|
26045
|
+
}
|
|
26046
26046
|
function hasApiKey(envVar) {
|
|
26047
26047
|
loadEnv();
|
|
26048
26048
|
return !!getEnvValue2(envVar);
|
|
@@ -26139,7 +26139,7 @@ var init_api_key = __esm({
|
|
|
26139
26139
|
|
|
26140
26140
|
// src/commands/_shared/tts-resolve.ts
|
|
26141
26141
|
async function resolveTtsProvider(preferred = "auto") {
|
|
26142
|
-
const choice = preferred === "auto" ?
|
|
26142
|
+
const choice = preferred === "auto" ? await getConfiguredApiKey("ELEVENLABS_API_KEY") ? "elevenlabs" : "kokoro" : preferred;
|
|
26143
26143
|
if (choice === "elevenlabs") {
|
|
26144
26144
|
return buildElevenLabs();
|
|
26145
26145
|
}
|
|
@@ -26183,7 +26183,6 @@ var init_tts_resolve = __esm({
|
|
|
26183
26183
|
"use strict";
|
|
26184
26184
|
init_dist2();
|
|
26185
26185
|
init_api_key();
|
|
26186
|
-
init_api_key();
|
|
26187
26186
|
TtsKeyMissingError = class extends Error {
|
|
26188
26187
|
constructor(provider) {
|
|
26189
26188
|
super(
|
|
@@ -26479,7 +26478,7 @@ YAML cues that drive narration, backdrop generation, and timing.
|
|
|
26479
26478
|
|
|
26480
26479
|
\`\`\`yaml
|
|
26481
26480
|
narration: "Introduce the promise in one crisp sentence."
|
|
26482
|
-
backdrop: "
|
|
26481
|
+
backdrop: "Topic-aligned editorial background plate, abstract visual system, no readable text, no logos, no consumer products, clean negative space for HTML overlays"
|
|
26483
26482
|
duration: 4
|
|
26484
26483
|
\`\`\`
|
|
26485
26484
|
|
|
@@ -26490,7 +26489,7 @@ screen and one spoken breath.
|
|
|
26490
26489
|
|
|
26491
26490
|
\`\`\`yaml
|
|
26492
26491
|
narration: "Show the mechanism or proof point that makes the promise believable."
|
|
26493
|
-
backdrop: "
|
|
26492
|
+
backdrop: "Topic-aligned analytical background plate, abstract dashboard structure, no readable text, no product photos, no shoes, no unrelated objects"
|
|
26494
26493
|
duration: 4
|
|
26495
26494
|
\`\`\`
|
|
26496
26495
|
|
|
@@ -26501,7 +26500,7 @@ before/after.
|
|
|
26501
26500
|
|
|
26502
26501
|
\`\`\`yaml
|
|
26503
26502
|
narration: "Close with the action the viewer should remember."
|
|
26504
|
-
backdrop: "Resolved
|
|
26503
|
+
backdrop: "Resolved editorial background plate, confident final composition, clean negative space, no readable text, no logos, no unrelated products"
|
|
26505
26504
|
duration: 4
|
|
26506
26505
|
\`\`\`
|
|
26507
26506
|
|
|
@@ -26554,6 +26553,25 @@ consult this file \u2014 run the generate command directly.
|
|
|
26554
26553
|
Browse named styles: \`vibe scene list-styles\`. Re-seed from one with
|
|
26555
26554
|
\`vibe scene init . --visual-style "Swiss Pulse"\` (idempotent).
|
|
26556
26555
|
|
|
26556
|
+
## Provider keys and project scope
|
|
26557
|
+
|
|
26558
|
+
Use VibeFrame CLI generation for project assets:
|
|
26559
|
+
\`vibe generate image|video|speech ...\`. This lets VibeFrame use keys
|
|
26560
|
+
from \`vibe setup --scope project\`.
|
|
26561
|
+
|
|
26562
|
+
Project-scope keys may live in a parent directory, for example
|
|
26563
|
+
\`../.vibeframe/config.yaml\` when this scene was created by
|
|
26564
|
+
\`vibe init launch\`. The \`vibe\` CLI searches upward automatically, so do
|
|
26565
|
+
not decide keys are missing just because \`.vibeframe/config.yaml\` is not
|
|
26566
|
+
inside this scene folder.
|
|
26567
|
+
|
|
26568
|
+
To verify scope without exposing secrets, run \`vibe doctor --json\` from
|
|
26569
|
+
this directory and inspect \`data.scope.activeScope\` plus
|
|
26570
|
+
\`data.scope.project.configPath\`. Never print config contents. Do not use
|
|
26571
|
+
a host agent's built-in image/audio generation tool for VibeFrame project
|
|
26572
|
+
assets unless the user explicitly requests an external, non-VibeFrame
|
|
26573
|
+
asset.
|
|
26574
|
+
|
|
26557
26575
|
## Skills \u2014 USE THESE FIRST
|
|
26558
26576
|
|
|
26559
26577
|
@SKILL.md
|
|
@@ -26615,7 +26633,11 @@ npx hyperframes render
|
|
|
26615
26633
|
\`\`\`
|
|
26616
26634
|
4. Videos use \`muted\` with a separate \`<audio>\` element for the audio track.
|
|
26617
26635
|
5. Sub-compositions use \`data-composition-src="compositions/file.html"\`.
|
|
26618
|
-
6.
|
|
26636
|
+
6. For render-stable text, do not apply continuous \`scale\`, \`x\`, \`y\`, or
|
|
26637
|
+
\`filter\` tweens to \`.scene-content\` or any ancestor containing live text.
|
|
26638
|
+
Animate background/media layers instead; text/cards should enter briefly and
|
|
26639
|
+
then hold still at their final CSS positions.
|
|
26640
|
+
7. Only deterministic logic \u2014 no \`Date.now()\`, \`Math.random()\`, or network fetches.
|
|
26619
26641
|
|
|
26620
26642
|
## Linting \u2014 run after changes
|
|
26621
26643
|
|
|
@@ -29043,13 +29065,18 @@ Requirements (non-negotiable):
|
|
|
29043
29065
|
producer's seek lands past the timeline's natural end and visibility state
|
|
29044
29066
|
goes stale \u2014 the hold phase renders BLACK. Anchor the timeline to the full
|
|
29045
29067
|
beat duration via either:
|
|
29046
|
-
1. A subtle idle motion spanning 0\u2192duration on a
|
|
29047
|
-
\`tl.fromTo(".
|
|
29068
|
+
1. A subtle idle motion spanning 0\u2192duration on a background/media layer,
|
|
29069
|
+
e.g. \`tl.fromTo(".backdrop", { scale: 1.0 }, { scale: 1.015, duration: <beat>, ease: "none" }, 0);\`
|
|
29048
29070
|
(Ken-Burns, breathing opacity, gradient drift \u2014 should be barely
|
|
29049
29071
|
perceptible so it doesn't compete with entry/exit beats).
|
|
29050
29072
|
2. OR an explicit \`tl.set(target, { ...natural state... }, <beat - 0.001>)\`
|
|
29051
29073
|
anchor at the end.
|
|
29052
29074
|
This is the #2 source of "text disappears mid-beat" bugs after \`.clip\` sizing.
|
|
29075
|
+
- Do not apply continuous \`scale\`, \`x\`, \`y\`, \`filter\`, or other transform
|
|
29076
|
+
tweens to \`.scene-content\` or any ancestor that contains live text/cards.
|
|
29077
|
+
Animate the backdrop/media plane instead; let text enter briefly, then hold
|
|
29078
|
+
still at its final CSS position. Continuous transforms on text ancestors can
|
|
29079
|
+
create subpixel shimmer in screenshot-captured renders.
|
|
29053
29080
|
- Timed children inside the composition have \`class="clip"\` plus
|
|
29054
29081
|
\`data-start\`, \`data-duration\`, \`data-track-index\`.
|
|
29055
29082
|
- If \`assets/backdrop-${ctx.beat.id}.png\` exists, use that local file as the
|
|
@@ -29119,7 +29146,9 @@ Reference shape (verbatim \u2014 match this skeleton exactly, no DOCTYPE / html
|
|
|
29119
29146
|
const tl = gsap.timeline({ paused: true });
|
|
29120
29147
|
// Idle motion spanning full beat duration \u2014 required to keep timeline
|
|
29121
29148
|
// length aligned with data-duration (otherwise hold phase goes black).
|
|
29122
|
-
|
|
29149
|
+
// Keep continuous motion on the background/media layer so live text does
|
|
29150
|
+
// not shimmer from subpixel resampling.
|
|
29151
|
+
tl.fromTo(".backdrop", { scale: 1.0 }, { scale: 1.015, duration: <sec>, ease: "none" }, 0);
|
|
29123
29152
|
// entry tweens
|
|
29124
29153
|
window.__timelines["${compositionId}"] = tl;
|
|
29125
29154
|
</script>
|
|
@@ -32190,7 +32219,7 @@ import { resolve as resolve18 } from "node:path";
|
|
|
32190
32219
|
import { writeFile as writeFile15 } from "node:fs/promises";
|
|
32191
32220
|
async function executeSoundEffect(options) {
|
|
32192
32221
|
try {
|
|
32193
|
-
const apiKey =
|
|
32222
|
+
const apiKey = await getConfiguredApiKey("ELEVENLABS_API_KEY");
|
|
32194
32223
|
if (!apiKey)
|
|
32195
32224
|
return {
|
|
32196
32225
|
success: false,
|
|
@@ -32289,7 +32318,6 @@ var init_sound_effect = __esm({
|
|
|
32289
32318
|
init_ora();
|
|
32290
32319
|
init_dist2();
|
|
32291
32320
|
init_api_key();
|
|
32292
|
-
init_config();
|
|
32293
32321
|
init_output();
|
|
32294
32322
|
init_validate();
|
|
32295
32323
|
}
|
|
@@ -32298,7 +32326,7 @@ var init_sound_effect = __esm({
|
|
|
32298
32326
|
// src/commands/generate/music-status.ts
|
|
32299
32327
|
async function executeMusicStatus(options) {
|
|
32300
32328
|
try {
|
|
32301
|
-
const apiKey =
|
|
32329
|
+
const apiKey = await getConfiguredApiKey("REPLICATE_API_TOKEN", options.apiKey);
|
|
32302
32330
|
if (!apiKey)
|
|
32303
32331
|
return { success: false, error: "REPLICATE_API_TOKEN required for music status" };
|
|
32304
32332
|
const replicate = new ReplicateProvider();
|
|
@@ -32371,7 +32399,6 @@ var init_music_status = __esm({
|
|
|
32371
32399
|
init_source();
|
|
32372
32400
|
init_dist2();
|
|
32373
32401
|
init_api_key();
|
|
32374
|
-
init_config();
|
|
32375
32402
|
init_output();
|
|
32376
32403
|
}
|
|
32377
32404
|
});
|
|
@@ -32452,7 +32479,7 @@ import { resolve as resolve19, dirname as dirname4 } from "node:path";
|
|
|
32452
32479
|
import { writeFile as writeFile16, mkdir as mkdir8 } from "node:fs/promises";
|
|
32453
32480
|
async function executeBackground(options) {
|
|
32454
32481
|
try {
|
|
32455
|
-
const apiKey =
|
|
32482
|
+
const apiKey = await getConfiguredApiKey("OPENAI_API_KEY", options.apiKey);
|
|
32456
32483
|
if (!apiKey)
|
|
32457
32484
|
return { success: false, error: "OPENAI_API_KEY required for background generation" };
|
|
32458
32485
|
const openaiImage = new OpenAIImageProvider();
|
|
@@ -32583,7 +32610,6 @@ var init_background = __esm({
|
|
|
32583
32610
|
init_ora();
|
|
32584
32611
|
init_dist2();
|
|
32585
32612
|
init_api_key();
|
|
32586
|
-
init_config();
|
|
32587
32613
|
init_output();
|
|
32588
32614
|
init_validate();
|
|
32589
32615
|
}
|
|
@@ -33249,7 +33275,7 @@ import { resolve as resolve21 } from "node:path";
|
|
|
33249
33275
|
import { writeFile as writeFile18 } from "node:fs/promises";
|
|
33250
33276
|
async function executeSpeech(options) {
|
|
33251
33277
|
try {
|
|
33252
|
-
const apiKey =
|
|
33278
|
+
const apiKey = await getConfiguredApiKey("ELEVENLABS_API_KEY");
|
|
33253
33279
|
if (!apiKey)
|
|
33254
33280
|
return {
|
|
33255
33281
|
success: false,
|
|
@@ -33464,7 +33490,6 @@ var init_speech = __esm({
|
|
|
33464
33490
|
init_dist2();
|
|
33465
33491
|
init_api_key();
|
|
33466
33492
|
init_tty();
|
|
33467
|
-
init_config();
|
|
33468
33493
|
init_output();
|
|
33469
33494
|
init_validate();
|
|
33470
33495
|
}
|
|
@@ -33817,7 +33842,7 @@ async function executeVideoGenerate(options) {
|
|
|
33817
33842
|
fal: "FAL_API_KEY"
|
|
33818
33843
|
};
|
|
33819
33844
|
const envKey = envKeyMap[provider] || "";
|
|
33820
|
-
const key =
|
|
33845
|
+
const key = await getConfiguredApiKey(envKey, apiKey);
|
|
33821
33846
|
if (!key) return { success: false, error: `${envKeyMap[provider]} required for ${provider}` };
|
|
33822
33847
|
let referenceImage;
|
|
33823
33848
|
let referenceImageBuffer;
|
|
@@ -35073,7 +35098,7 @@ async function executeMusic(options) {
|
|
|
35073
35098
|
try {
|
|
35074
35099
|
const provider = options.provider || "elevenlabs";
|
|
35075
35100
|
if (provider === "elevenlabs") {
|
|
35076
|
-
const apiKey2 =
|
|
35101
|
+
const apiKey2 = await getConfiguredApiKey("ELEVENLABS_API_KEY");
|
|
35077
35102
|
if (!apiKey2)
|
|
35078
35103
|
return {
|
|
35079
35104
|
success: false,
|
|
@@ -35093,7 +35118,7 @@ async function executeMusic(options) {
|
|
|
35093
35118
|
await writeFile23(outputPath2, result2.audioBuffer);
|
|
35094
35119
|
return { success: true, outputPath: outputPath2, provider: "elevenlabs", duration: duration2 };
|
|
35095
35120
|
}
|
|
35096
|
-
const apiKey =
|
|
35121
|
+
const apiKey = await getConfiguredApiKey("REPLICATE_API_TOKEN");
|
|
35097
35122
|
if (!apiKey)
|
|
35098
35123
|
return {
|
|
35099
35124
|
success: false,
|
|
@@ -35328,7 +35353,6 @@ var init_music = __esm({
|
|
|
35328
35353
|
init_ora();
|
|
35329
35354
|
init_dist2();
|
|
35330
35355
|
init_api_key();
|
|
35331
|
-
init_config();
|
|
35332
35356
|
init_output();
|
|
35333
35357
|
init_validate();
|
|
35334
35358
|
init_status_jobs();
|
|
@@ -36395,7 +36419,7 @@ Examples:
|
|
|
36395
36419
|
)
|
|
36396
36420
|
);
|
|
36397
36421
|
}
|
|
36398
|
-
if (providerEnvMap[provider] && !
|
|
36422
|
+
if (providerEnvMap[provider] && !await hasConfiguredApiKey(providerEnvMap[provider], options.apiKey)) {
|
|
36399
36423
|
const resolved = resolveProvider("image");
|
|
36400
36424
|
if (resolved) {
|
|
36401
36425
|
log(source_default.dim(` ${provider} key not found. Using ${resolved.label} instead.`));
|
|
@@ -37835,7 +37859,7 @@ Examples:
|
|
|
37835
37859
|
);
|
|
37836
37860
|
provider = "seedance";
|
|
37837
37861
|
}
|
|
37838
|
-
if (videoEnvMap[provider] && !
|
|
37862
|
+
if (videoEnvMap[provider] && !await hasConfiguredApiKey(videoEnvMap[provider], options.apiKey)) {
|
|
37839
37863
|
const resolved = resolveProvider("video");
|
|
37840
37864
|
if (resolved) {
|
|
37841
37865
|
log(source_default.dim(` ${provider} key not found. Using ${resolved.label} instead.`));
|
|
@@ -58357,6 +58381,32 @@ var init_build_cache = __esm({
|
|
|
58357
58381
|
}
|
|
58358
58382
|
});
|
|
58359
58383
|
|
|
58384
|
+
// src/commands/_shared/build-backdrop-prompt.ts
|
|
58385
|
+
function augmentBackdropPrompt(cue) {
|
|
58386
|
+
const trimmed = cue.trim();
|
|
58387
|
+
const lower = trimmed.toLowerCase();
|
|
58388
|
+
const requestsTextOrMarks = /\b(text|typography|title|headline|label|caption|logo|logos|wordmark|brand mark|brand marks)\b/.test(lower);
|
|
58389
|
+
const forbidsTextOrMarks = /\b(no|without|avoid)\s+(readable\s+)?(text|typography|titles?|headlines?|labels?|captions?|brand\s+logos?|logos?|wordmarks?|brand\s+marks?)\b/.test(
|
|
58390
|
+
lower
|
|
58391
|
+
);
|
|
58392
|
+
const allowsTextOrMarks = requestsTextOrMarks && !forbidsTextOrMarks;
|
|
58393
|
+
const overlayContract = allowsTextOrMarks ? "The image is a video background or end-card plate; do not add any text, logos, charts, or UI beyond what the scene cue explicitly requests." : "The image is a background only; HTML overlays will provide all final text, charts, logos, and UI labels.";
|
|
58394
|
+
const textRule = allowsTextOrMarks ? "If text, logos, or brand marks are explicitly requested, keep them minimal, legible, and do not invent extras." : "No readable text, labels, UI copy, logos, brand marks, watermarks, or invented typography.";
|
|
58395
|
+
return [
|
|
58396
|
+
"Create a 16:9 video background plate for a HyperFrames scene.",
|
|
58397
|
+
overlayContract,
|
|
58398
|
+
`Scene cue: ${trimmed}`,
|
|
58399
|
+
textRule,
|
|
58400
|
+
"Avoid unrelated consumer product photography, shoes, packaging, food, people, celebrity faces, advertisements, and random objects unless explicitly requested by the scene cue.",
|
|
58401
|
+
"Leave generous negative space for overlay text and cards. Keep the result topic-aligned, editorial, cinematic, and non-distracting."
|
|
58402
|
+
].join(" ");
|
|
58403
|
+
}
|
|
58404
|
+
var init_build_backdrop_prompt = __esm({
|
|
58405
|
+
"src/commands/_shared/build-backdrop-prompt.ts"() {
|
|
58406
|
+
"use strict";
|
|
58407
|
+
}
|
|
58408
|
+
});
|
|
58409
|
+
|
|
58360
58410
|
// src/commands/_shared/build-plan.ts
|
|
58361
58411
|
import { existsSync as existsSync44 } from "node:fs";
|
|
58362
58412
|
import { readFile as readFile40 } from "node:fs/promises";
|
|
@@ -58450,6 +58500,7 @@ async function createBuildPlan(opts) {
|
|
|
58450
58500
|
const voice = stringOrUndefined3(cue.voice) ?? resolved.voice;
|
|
58451
58501
|
const narrationText = stringOrUndefined3(cue.narration);
|
|
58452
58502
|
const backdropPrompt = stringOrUndefined3(cue.backdrop);
|
|
58503
|
+
const augmentedBackdropPrompt = backdropPrompt ? augmentBackdropPrompt(backdropPrompt) : null;
|
|
58453
58504
|
const videoPrompt = stringOrUndefined3(cue.video);
|
|
58454
58505
|
const musicPrompt = stringOrUndefined3(cue.music);
|
|
58455
58506
|
const genericReference = resolveGenericAssetReference(projectDir, cue.asset);
|
|
@@ -58469,9 +58520,9 @@ async function createBuildPlan(opts) {
|
|
|
58469
58520
|
voice,
|
|
58470
58521
|
ext: resolved.narration.resolved === "elevenlabs" ? "mp3" : "wav"
|
|
58471
58522
|
}) : null;
|
|
58472
|
-
const backdropCache =
|
|
58523
|
+
const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
|
|
58473
58524
|
beatId: beat.id,
|
|
58474
|
-
cue:
|
|
58525
|
+
cue: augmentedBackdropPrompt,
|
|
58475
58526
|
provider: resolved.image.resolved,
|
|
58476
58527
|
quality: imageQuality,
|
|
58477
58528
|
size: imageSize2,
|
|
@@ -59001,6 +59052,7 @@ var init_build_plan = __esm({
|
|
|
59001
59052
|
init_build_asset_reference();
|
|
59002
59053
|
init_build_cache();
|
|
59003
59054
|
init_build_asset_metadata();
|
|
59055
|
+
init_build_backdrop_prompt();
|
|
59004
59056
|
init_composer_resolve();
|
|
59005
59057
|
init_storyboard_parse();
|
|
59006
59058
|
init_project_config();
|
|
@@ -60415,8 +60467,9 @@ async function dispatchNarration(beat, ctx) {
|
|
|
60415
60467
|
async function dispatchBackdrop(beat, ctx) {
|
|
60416
60468
|
const reference = assetReferenceForBeat(ctx.projectDir, "backdrop", beat);
|
|
60417
60469
|
if (reference) return referencePrimitiveOutcome("backdrop", beat, ctx, reference);
|
|
60418
|
-
const
|
|
60419
|
-
if (!
|
|
60470
|
+
const cue = stringOrUndefined4(beat.cues?.backdrop);
|
|
60471
|
+
if (!cue) return { status: "no-cue" };
|
|
60472
|
+
const prompt3 = augmentBackdropPrompt(cue);
|
|
60420
60473
|
const rel = `assets/backdrop-${beat.id}.png`;
|
|
60421
60474
|
const abs = join22(ctx.projectDir, rel);
|
|
60422
60475
|
const size = ctx.imageSize ?? "1536x1024";
|
|
@@ -61394,6 +61447,7 @@ var init_scene_build = __esm({
|
|
|
61394
61447
|
init_root_sync();
|
|
61395
61448
|
init_build_cache();
|
|
61396
61449
|
init_build_asset_metadata();
|
|
61450
|
+
init_build_backdrop_prompt();
|
|
61397
61451
|
init_ai_video();
|
|
61398
61452
|
init_music();
|
|
61399
61453
|
init_status_jobs();
|
|
@@ -71384,7 +71438,7 @@ init_source();
|
|
|
71384
71438
|
// package.json
|
|
71385
71439
|
var package_default = {
|
|
71386
71440
|
name: "@vibeframe/cli",
|
|
71387
|
-
version: "0.104.
|
|
71441
|
+
version: "0.104.3",
|
|
71388
71442
|
description: "VibeFrame CLI - natural language video editing from the terminal",
|
|
71389
71443
|
private: false,
|
|
71390
71444
|
license: "MIT",
|
|
@@ -79953,7 +80007,7 @@ function fourBeatDraft(opts) {
|
|
|
79953
80007
|
title: scenic ? "First light" : "Hook",
|
|
79954
80008
|
duration: opts.durations[0],
|
|
79955
80009
|
narration: scenic ? `The first light reaches ${opts.product} before the day begins.` : `${opts.product} starts with one clear promise.`,
|
|
79956
|
-
backdrop: scenic ? `misty mountain ridge at sunrise, golden light, fog layers, cinematic ${opts.theme}` : `
|
|
80010
|
+
backdrop: scenic ? `misty mountain ridge at sunrise, golden light, fog layers, cinematic ${opts.theme}` : `topic-aligned editorial background plate for ${opts.product}, ${opts.theme}, no readable text, no logos, no unrelated consumer products, clean negative space for HTML overlays`,
|
|
79957
80011
|
motion: scenic ? "quiet title reveal, soft parallax, slow camera drift" : "large readable headline, restrained camera push, immediate value reveal",
|
|
79958
80012
|
body: scenic ? "Show the mountain identity immediately. Keep text minimal." : "Make the value obvious in the first beat. Avoid setup that delays the payoff."
|
|
79959
80013
|
},
|
|
@@ -79962,7 +80016,7 @@ function fourBeatDraft(opts) {
|
|
|
79962
80016
|
title: scenic ? "The path appears" : "Proof",
|
|
79963
80017
|
duration: opts.durations[1],
|
|
79964
80018
|
narration: scenic ? "A clear path appears when every step is visible." : "The proof appears when each step is visible.",
|
|
79965
|
-
backdrop: scenic ? "ridge trail emerging through fog, warm sunrise edge light, high contrast" : `
|
|
80019
|
+
backdrop: scenic ? "ridge trail emerging through fog, warm sunrise edge light, high contrast" : `topic-aligned proof background plate for ${opts.product}, abstract workflow structure, no readable text, no product photos, no shoes, no unrelated objects`,
|
|
79966
80020
|
motion: scenic ? "thin line traces the path, small labels fade in" : "interface panels or proof points slide into place with precise transitions",
|
|
79967
80021
|
body: "Connect the visual proof to the promise in one focused moment."
|
|
79968
80022
|
},
|
|
@@ -79980,7 +80034,7 @@ function fourBeatDraft(opts) {
|
|
|
79980
80034
|
title: scenic ? "Day one" : "Close",
|
|
79981
80035
|
duration: opts.durations[3],
|
|
79982
80036
|
narration: scenic ? `${opts.product}. Day one begins here.` : `${opts.product} is ready to show.`,
|
|
79983
|
-
backdrop: scenic ? "wide mountain ridge at peak golden hour, valley filled with warm light" : `resolved
|
|
80037
|
+
backdrop: scenic ? "wide mountain ridge at peak golden hour, valley filled with warm light" : `resolved editorial background plate for ${opts.product}, clean negative space, confident lockup, no readable text, no logos, no unrelated products`,
|
|
79984
80038
|
motion: "clean final title, slow settling motion, gentle fade to the final frame",
|
|
79985
80039
|
body: "End with a quiet branded title and no new idea."
|
|
79986
80040
|
}
|
|
@@ -79993,7 +80047,7 @@ function threeBeatDraft(opts) {
|
|
|
79993
80047
|
title: "Hook",
|
|
79994
80048
|
duration: opts.durations[0],
|
|
79995
80049
|
narration: `${opts.product} starts with one clear promise.`,
|
|
79996
|
-
backdrop: `
|
|
80050
|
+
backdrop: `topic-aligned editorial background plate for ${opts.product}, ${opts.theme}, no readable text, no logos, no unrelated consumer products, clean negative space for HTML overlays`,
|
|
79997
80051
|
motion: "large readable headline, restrained camera push, immediate value reveal",
|
|
79998
80052
|
body: "Make the value obvious in one beat."
|
|
79999
80053
|
},
|
|
@@ -80002,7 +80056,7 @@ function threeBeatDraft(opts) {
|
|
|
80002
80056
|
title: "Proof",
|
|
80003
80057
|
duration: opts.durations[1],
|
|
80004
80058
|
narration: "The proof appears when each step is visible.",
|
|
80005
|
-
backdrop: `
|
|
80059
|
+
backdrop: `topic-aligned proof background plate for ${opts.product}, abstract workflow structure, no readable text, no product photos, no shoes, no unrelated objects`,
|
|
80006
80060
|
motion: "layered panels, highlighted cause and effect, precise transitions",
|
|
80007
80061
|
body: "Show the mechanism, metric, or before/after that makes the promise believable."
|
|
80008
80062
|
},
|
|
@@ -80011,7 +80065,7 @@ function threeBeatDraft(opts) {
|
|
|
80011
80065
|
title: "Close",
|
|
80012
80066
|
duration: opts.durations[2],
|
|
80013
80067
|
narration: `${opts.product} is ready to show.`,
|
|
80014
|
-
backdrop: `resolved
|
|
80068
|
+
backdrop: `resolved editorial background plate for ${opts.product}, clean negative space, confident lockup, no readable text, no logos, no unrelated products`,
|
|
80015
80069
|
motion: "clean final title, subtle parallax, gentle fade to the final frame",
|
|
80016
80070
|
body: "End on the product name, offer, command, or memorable final line."
|
|
80017
80071
|
}
|
|
@@ -80212,11 +80266,25 @@ When you run vibe commands programmatically:
|
|
|
80212
80266
|
echo '{"video":"long.mp4","count":3,"aspect":"9:16"}' | vibe remix auto-shorts --stdin --json
|
|
80213
80267
|
\`\`\`
|
|
80214
80268
|
|
|
80215
|
-
## Provider keys
|
|
80269
|
+
## Provider keys and project scope
|
|
80216
80270
|
|
|
80217
|
-
|
|
80218
|
-
\`
|
|
80219
|
-
|
|
80271
|
+
Prefer \`vibe setup --scope project\` for project-local keys. It writes
|
|
80272
|
+
\`.vibeframe/config.yaml\` in the setup directory; when you work from a
|
|
80273
|
+
nested scene directory, the \`vibe\` CLI automatically searches parent
|
|
80274
|
+
directories and uses the nearest project config. Do not assume the config
|
|
80275
|
+
file must exist in the current subdirectory.
|
|
80276
|
+
|
|
80277
|
+
Run \`vibe doctor --json\` from the directory where you will run commands
|
|
80278
|
+
and check \`data.scope.project.configPath\` / \`data.scope.activeScope\` before
|
|
80279
|
+
deciding keys are missing. Never print or copy config file contents.
|
|
80280
|
+
|
|
80281
|
+
For generated project assets, use VibeFrame commands such as
|
|
80282
|
+
\`vibe generate image|video|speech ...\` so these project-scope keys are
|
|
80283
|
+
used. Do not switch to a host agent's built-in image/audio generation tool
|
|
80284
|
+
unless the user explicitly asks for a non-VibeFrame asset.
|
|
80285
|
+
|
|
80286
|
+
\`.env\` is still supported as a gitignored fallback. Copy \`.env.example\`
|
|
80287
|
+
to start if you prefer environment variables.
|
|
80220
80288
|
|
|
80221
80289
|
### Composition rules (scene HTML)
|
|
80222
80290
|
|
|
@@ -80230,6 +80298,12 @@ principles, type system, and visual-identity hard-gate. The same skill
|
|
|
80230
80298
|
governs \`vibe scene lint\` so your authored HTML and the linter stay in
|
|
80231
80299
|
agreement.
|
|
80232
80300
|
|
|
80301
|
+
For render-stable text, do not apply continuous \`scale\`, \`x\`, \`y\`,
|
|
80302
|
+
\`filter\`, or other transform tweens to \`.scene-content\` or any ancestor
|
|
80303
|
+
containing live text/cards. Put ambient zoom/parallax on background or media
|
|
80304
|
+
layers only; text should enter briefly and then hold still at its final CSS
|
|
80305
|
+
position.
|
|
80306
|
+
|
|
80233
80307
|
To retro-install on a project scaffolded before this command existed, run
|
|
80234
80308
|
\`vibe scene install-skill [--host all]\`.
|
|
80235
80309
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.104.
|
|
3
|
+
"version": "0.104.3",
|
|
4
4
|
"description": "VibeFrame CLI - natural language video editing from the terminal",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -183,8 +183,8 @@
|
|
|
183
183
|
"tsx": "^4.21.0",
|
|
184
184
|
"typescript": "^5.3.3",
|
|
185
185
|
"vitest": "^1.2.2",
|
|
186
|
-
"@vibeframe/
|
|
187
|
-
"@vibeframe/
|
|
186
|
+
"@vibeframe/core": "0.104.3",
|
|
187
|
+
"@vibeframe/ai-providers": "0.104.3"
|
|
188
188
|
},
|
|
189
189
|
"engines": {
|
|
190
190
|
"node": ">=20"
|