@vibeframe/cli 0.104.2 → 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.
Files changed (2) hide show
  1. package/dist/index.js +65 -18
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -26478,7 +26478,7 @@ YAML cues that drive narration, backdrop generation, and timing.
26478
26478
 
26479
26479
  \`\`\`yaml
26480
26480
  narration: "Introduce the promise in one crisp sentence."
26481
- backdrop: "Cinematic abstract technology backdrop, precise light, premium editorial feel"
26481
+ backdrop: "Topic-aligned editorial background plate, abstract visual system, no readable text, no logos, no consumer products, clean negative space for HTML overlays"
26482
26482
  duration: 4
26483
26483
  \`\`\`
26484
26484
 
@@ -26489,7 +26489,7 @@ screen and one spoken breath.
26489
26489
 
26490
26490
  \`\`\`yaml
26491
26491
  narration: "Show the mechanism or proof point that makes the promise believable."
26492
- backdrop: "Layered interface details, subtle motion trails, high-contrast product storytelling"
26492
+ backdrop: "Topic-aligned analytical background plate, abstract dashboard structure, no readable text, no product photos, no shoes, no unrelated objects"
26493
26493
  duration: 4
26494
26494
  \`\`\`
26495
26495
 
@@ -26500,7 +26500,7 @@ before/after.
26500
26500
 
26501
26501
  \`\`\`yaml
26502
26502
  narration: "Close with the action the viewer should remember."
26503
- backdrop: "Resolved hero frame, confident final composition, clean negative space"
26503
+ backdrop: "Resolved editorial background plate, confident final composition, clean negative space, no readable text, no logos, no unrelated products"
26504
26504
  duration: 4
26505
26505
  \`\`\`
26506
26506
 
@@ -26633,7 +26633,11 @@ npx hyperframes render
26633
26633
  \`\`\`
26634
26634
  4. Videos use \`muted\` with a separate \`<audio>\` element for the audio track.
26635
26635
  5. Sub-compositions use \`data-composition-src="compositions/file.html"\`.
26636
- 6. Only deterministic logic \u2014 no \`Date.now()\`, \`Math.random()\`, or network fetches.
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.
26637
26641
 
26638
26642
  ## Linting \u2014 run after changes
26639
26643
 
@@ -29061,13 +29065,18 @@ Requirements (non-negotiable):
29061
29065
  producer's seek lands past the timeline's natural end and visibility state
29062
29066
  goes stale \u2014 the hold phase renders BLACK. Anchor the timeline to the full
29063
29067
  beat duration via either:
29064
- 1. A subtle idle motion spanning 0\u2192duration on a parent element, e.g.
29065
- \`tl.fromTo(".scene-content", { scale: 1.0 }, { scale: 1.015, duration: <beat>, ease: "none" }, 0);\`
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);\`
29066
29070
  (Ken-Burns, breathing opacity, gradient drift \u2014 should be barely
29067
29071
  perceptible so it doesn't compete with entry/exit beats).
29068
29072
  2. OR an explicit \`tl.set(target, { ...natural state... }, <beat - 0.001>)\`
29069
29073
  anchor at the end.
29070
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.
29071
29080
  - Timed children inside the composition have \`class="clip"\` plus
29072
29081
  \`data-start\`, \`data-duration\`, \`data-track-index\`.
29073
29082
  - If \`assets/backdrop-${ctx.beat.id}.png\` exists, use that local file as the
@@ -29137,7 +29146,9 @@ Reference shape (verbatim \u2014 match this skeleton exactly, no DOCTYPE / html
29137
29146
  const tl = gsap.timeline({ paused: true });
29138
29147
  // Idle motion spanning full beat duration \u2014 required to keep timeline
29139
29148
  // length aligned with data-duration (otherwise hold phase goes black).
29140
- tl.fromTo(".scene-content", { scale: 1.0 }, { scale: 1.015, duration: <sec>, ease: "none" }, 0);
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);
29141
29152
  // entry tweens
29142
29153
  window.__timelines["${compositionId}"] = tl;
29143
29154
  </script>
@@ -58370,6 +58381,32 @@ var init_build_cache = __esm({
58370
58381
  }
58371
58382
  });
58372
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
+
58373
58410
  // src/commands/_shared/build-plan.ts
58374
58411
  import { existsSync as existsSync44 } from "node:fs";
58375
58412
  import { readFile as readFile40 } from "node:fs/promises";
@@ -58463,6 +58500,7 @@ async function createBuildPlan(opts) {
58463
58500
  const voice = stringOrUndefined3(cue.voice) ?? resolved.voice;
58464
58501
  const narrationText = stringOrUndefined3(cue.narration);
58465
58502
  const backdropPrompt = stringOrUndefined3(cue.backdrop);
58503
+ const augmentedBackdropPrompt = backdropPrompt ? augmentBackdropPrompt(backdropPrompt) : null;
58466
58504
  const videoPrompt = stringOrUndefined3(cue.video);
58467
58505
  const musicPrompt = stringOrUndefined3(cue.music);
58468
58506
  const genericReference = resolveGenericAssetReference(projectDir, cue.asset);
@@ -58482,9 +58520,9 @@ async function createBuildPlan(opts) {
58482
58520
  voice,
58483
58521
  ext: resolved.narration.resolved === "elevenlabs" ? "mp3" : "wav"
58484
58522
  }) : null;
58485
- const backdropCache = backdropPrompt && !backdropReference ? backdropCacheDescriptor({
58523
+ const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
58486
58524
  beatId: beat.id,
58487
- cue: backdropPrompt,
58525
+ cue: augmentedBackdropPrompt,
58488
58526
  provider: resolved.image.resolved,
58489
58527
  quality: imageQuality,
58490
58528
  size: imageSize2,
@@ -59014,6 +59052,7 @@ var init_build_plan = __esm({
59014
59052
  init_build_asset_reference();
59015
59053
  init_build_cache();
59016
59054
  init_build_asset_metadata();
59055
+ init_build_backdrop_prompt();
59017
59056
  init_composer_resolve();
59018
59057
  init_storyboard_parse();
59019
59058
  init_project_config();
@@ -60428,8 +60467,9 @@ async function dispatchNarration(beat, ctx) {
60428
60467
  async function dispatchBackdrop(beat, ctx) {
60429
60468
  const reference = assetReferenceForBeat(ctx.projectDir, "backdrop", beat);
60430
60469
  if (reference) return referencePrimitiveOutcome("backdrop", beat, ctx, reference);
60431
- const prompt3 = stringOrUndefined4(beat.cues?.backdrop);
60432
- if (!prompt3) return { status: "no-cue" };
60470
+ const cue = stringOrUndefined4(beat.cues?.backdrop);
60471
+ if (!cue) return { status: "no-cue" };
60472
+ const prompt3 = augmentBackdropPrompt(cue);
60433
60473
  const rel = `assets/backdrop-${beat.id}.png`;
60434
60474
  const abs = join22(ctx.projectDir, rel);
60435
60475
  const size = ctx.imageSize ?? "1536x1024";
@@ -61407,6 +61447,7 @@ var init_scene_build = __esm({
61407
61447
  init_root_sync();
61408
61448
  init_build_cache();
61409
61449
  init_build_asset_metadata();
61450
+ init_build_backdrop_prompt();
61410
61451
  init_ai_video();
61411
61452
  init_music();
61412
61453
  init_status_jobs();
@@ -71397,7 +71438,7 @@ init_source();
71397
71438
  // package.json
71398
71439
  var package_default = {
71399
71440
  name: "@vibeframe/cli",
71400
- version: "0.104.2",
71441
+ version: "0.104.3",
71401
71442
  description: "VibeFrame CLI - natural language video editing from the terminal",
71402
71443
  private: false,
71403
71444
  license: "MIT",
@@ -79966,7 +80007,7 @@ function fourBeatDraft(opts) {
79966
80007
  title: scenic ? "First light" : "Hook",
79967
80008
  duration: opts.durations[0],
79968
80009
  narration: scenic ? `The first light reaches ${opts.product} before the day begins.` : `${opts.product} starts with one clear promise.`,
79969
- backdrop: scenic ? `misty mountain ridge at sunrise, golden light, fog layers, cinematic ${opts.theme}` : `polished opening frame for ${opts.product}, ${opts.theme}, clear hero subject`,
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`,
79970
80011
  motion: scenic ? "quiet title reveal, soft parallax, slow camera drift" : "large readable headline, restrained camera push, immediate value reveal",
79971
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."
79972
80013
  },
@@ -79975,7 +80016,7 @@ function fourBeatDraft(opts) {
79975
80016
  title: scenic ? "The path appears" : "Proof",
79976
80017
  duration: opts.durations[1],
79977
80018
  narration: scenic ? "A clear path appears when every step is visible." : "The proof appears when each step is visible.",
79978
- backdrop: scenic ? "ridge trail emerging through fog, warm sunrise edge light, high contrast" : `concrete proof frame for ${opts.product}, visible workflow, before and after 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`,
79979
80020
  motion: scenic ? "thin line traces the path, small labels fade in" : "interface panels or proof points slide into place with precise transitions",
79980
80021
  body: "Connect the visual proof to the promise in one focused moment."
79981
80022
  },
@@ -79993,7 +80034,7 @@ function fourBeatDraft(opts) {
79993
80034
  title: scenic ? "Day one" : "Close",
79994
80035
  duration: opts.durations[3],
79995
80036
  narration: scenic ? `${opts.product}. Day one begins here.` : `${opts.product} is ready to show.`,
79996
- backdrop: scenic ? "wide mountain ridge at peak golden hour, valley filled with warm light" : `resolved final frame for ${opts.product}, clean negative space, confident lockup`,
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`,
79997
80038
  motion: "clean final title, slow settling motion, gentle fade to the final frame",
79998
80039
  body: "End with a quiet branded title and no new idea."
79999
80040
  }
@@ -80006,7 +80047,7 @@ function threeBeatDraft(opts) {
80006
80047
  title: "Hook",
80007
80048
  duration: opts.durations[0],
80008
80049
  narration: `${opts.product} starts with one clear promise.`,
80009
- backdrop: `polished opening frame for ${opts.product}, ${opts.theme}, clear hero subject`,
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`,
80010
80051
  motion: "large readable headline, restrained camera push, immediate value reveal",
80011
80052
  body: "Make the value obvious in one beat."
80012
80053
  },
@@ -80015,7 +80056,7 @@ function threeBeatDraft(opts) {
80015
80056
  title: "Proof",
80016
80057
  duration: opts.durations[1],
80017
80058
  narration: "The proof appears when each step is visible.",
80018
- backdrop: `concrete proof frame for ${opts.product}, visible workflow, before and after contrast`,
80059
+ backdrop: `topic-aligned proof background plate for ${opts.product}, abstract workflow structure, no readable text, no product photos, no shoes, no unrelated objects`,
80019
80060
  motion: "layered panels, highlighted cause and effect, precise transitions",
80020
80061
  body: "Show the mechanism, metric, or before/after that makes the promise believable."
80021
80062
  },
@@ -80024,7 +80065,7 @@ function threeBeatDraft(opts) {
80024
80065
  title: "Close",
80025
80066
  duration: opts.durations[2],
80026
80067
  narration: `${opts.product} is ready to show.`,
80027
- backdrop: `resolved final frame for ${opts.product}, clean negative space, confident lockup`,
80068
+ backdrop: `resolved editorial background plate for ${opts.product}, clean negative space, confident lockup, no readable text, no logos, no unrelated products`,
80028
80069
  motion: "clean final title, subtle parallax, gentle fade to the final frame",
80029
80070
  body: "End on the product name, offer, command, or memorable final line."
80030
80071
  }
@@ -80257,6 +80298,12 @@ principles, type system, and visual-identity hard-gate. The same skill
80257
80298
  governs \`vibe scene lint\` so your authored HTML and the linter stay in
80258
80299
  agreement.
80259
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
+
80260
80307
  To retro-install on a project scaffolded before this command existed, run
80261
80308
  \`vibe scene install-skill [--host all]\`.
80262
80309
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeframe/cli",
3
- "version": "0.104.2",
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/ai-providers": "0.104.2",
187
- "@vibeframe/core": "0.104.2"
186
+ "@vibeframe/core": "0.104.3",
187
+ "@vibeframe/ai-providers": "0.104.3"
188
188
  },
189
189
  "engines": {
190
190
  "node": ">=20"