@koda-sl/baker-cli 0.79.0 → 0.81.1

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/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  defaultRegistry,
10
10
  generateCatalog,
11
11
  validateCanvasDeep
12
- } from "./chunk-CCO34ACK.js";
12
+ } from "./chunk-NBNUNCY7.js";
13
13
 
14
14
  // src/cli.ts
15
15
  import { defineCommand as defineCommand141, runMain } from "citty";
@@ -9200,11 +9200,19 @@ function buildOverlayHtml(input) {
9200
9200
  const blueprint = VideoBlueprint.parse(input);
9201
9201
  const blocks = [
9202
9202
  [
9203
- "<!-- \u2B07 OVERLAY LAYER \u2014 this is YOUR HTML to paint. The reference's overlays are",
9204
- " seeded below as plain elements (text + position class + data-start/data-dur).",
9205
- " Restyle freely in <style>, regroup, animate, swap a logo placeholder for a",
9206
- " real <img> you drop in this dir. The runtime only shows/hides by timestamp;",
9207
- " it makes NO styling decisions. Positions: edit the .pos-* classes or add your own. -->"
9203
+ "<!-- \u2B07 OVERLAY LAYER \u2014 this is YOUR HTML to paint, and it is a REAL Hyperframes",
9204
+ " composition (our hyperframe_render runs the genuine `npx hyperframes` renderer).",
9205
+ " The reference's overlays are seeded below as plain elements (text + position",
9206
+ " class + data-start/data-dur). Restyle freely in <style>, regroup, animate, swap a",
9207
+ " logo placeholder for a real <img> you drop in this dir. But you can do FAR more:",
9208
+ " \u2022 pull a ready-made block \u2014 `npx hyperframes add <id>` (lower-third, social card,",
9209
+ " stat counter, chart, code, logo sting) \u2014 and nest it as a",
9210
+ ' <div data-composition-src="compositions/<id>.html" data-start data-track-index ...> clip;',
9211
+ " \u2022 drive a real caption track off the transcript (karaoke / themed / kinetic);",
9212
+ " \u2022 animate with the named GSAP motion-rule vocabulary, not just fade/slide/pop;",
9213
+ " \u2022 frame a talking head as a video-call / PIP / split.",
9214
+ " See ../.claude/skills/creative-canvas-ads/references/hyperframes/ (start at README.md).",
9215
+ " Positions: edit the .pos-* classes or add your own. -->"
9208
9216
  ].join("\n")
9209
9217
  ];
9210
9218
  for (const scene of blueprint.scenes) {
@@ -9435,7 +9443,7 @@ function buildMotionBoard(blueprint, sceneTurns) {
9435
9443
  ].sort((a, b) => a.at_s - b.at_s);
9436
9444
  return {
9437
9445
  scene: i,
9438
- role: scene.narrative_role?.trim() || inferNarrativeRole(i, blueprint.scenes.length),
9446
+ role: resolveSceneRole(scene, i, blueprint.scenes.length),
9439
9447
  window_s: [round(start_s), round(end_s)],
9440
9448
  storyboard_frames: [`s${i}_start`, `s${i}_end`],
9441
9449
  spoken,
@@ -9472,22 +9480,44 @@ function inferNarrativeRole(index, total) {
9472
9480
  if (index === total - 1) return "cta";
9473
9481
  return "body";
9474
9482
  }
9483
+ function resolveSceneRole(scene, index, total) {
9484
+ return scene.narrative_role?.trim() || inferNarrativeRole(index, total);
9485
+ }
9486
+ function findHookSceneIndex(blueprint) {
9487
+ const total = blueprint.scenes.length;
9488
+ return blueprint.scenes.findIndex((s, i) => resolveSceneRole(s, i, total) === "hook");
9489
+ }
9490
+ var HOOK_OPENER_CRITERIA = "statement not question; benefit by ~2s; first frame legible SOUND-OFF in ~1s (the feed plays muted); no bait-and-switch (the hook sets up the body)";
9491
+ function recraftTextForRole(role, sceneIndex) {
9492
+ if (role === "hook") {
9493
+ return `[RECRAFT HOOK \u2014 the #1 decision, but usually the LIGHTEST move wins: this hook already worked, so default to KEEPING it and building on top (swap only the specifics for ours). REBUILD only when it doesn't transfer \u2014 a claim we lack or a different funnel/awareness stage \u2014 by reaching for its deeper INNER MECHANIC and delivering that truthfully. DIAGNOSE (device + mechanic + stage) \u2192 DECIDE keep/adapt/rebuild \u2192 hold the opener to criteria: ${HOOK_OPENER_CRITERIA}. It lives on s${sceneIndex}_start (first frame) + the scene-${sceneIndex} overlay. See references/hook-craft.md + meta-ads-playbook \xA710/\xA739.]`;
9494
+ }
9495
+ if (role === "cta") {
9496
+ return "[RECRAFT CTA \u2014 the close: state what to do (where to go) + what to expect (offer/bundle/discount) for OUR brand; soft for top-of-funnel, hard for bottom. Do NOT render the reference's words. See references/script-craft.md.]";
9497
+ }
9498
+ return `[RECRAFT: rewrite this ${role} for OUR brand \u2014 true claims only; do NOT render the reference's words. See references/script-craft.md + meta-ads-playbook.]`;
9499
+ }
9475
9500
  function buildScriptRecraft(blueprint) {
9476
9501
  const total = blueprint.scenes.length;
9477
9502
  return blueprint.scenes.map((scene, i) => {
9478
- const role = scene.narrative_role?.trim() || inferNarrativeRole(i, total);
9503
+ const role = resolveSceneRole(scene, i, total);
9479
9504
  const original = (scene.dialogue ?? []).map((d) => d.line?.trim()).filter((l) => Boolean(l)).join(" ");
9480
9505
  return {
9481
9506
  scene: i,
9482
9507
  role,
9483
9508
  original_line: original || null,
9484
- recraft: `[RECRAFT: rewrite this ${role} for OUR brand \u2014 true claims only; do NOT render the reference's words. See references/script-craft.md + meta-ads-playbook.]`
9509
+ recraft: recraftTextForRole(role, i)
9485
9510
  };
9486
9511
  });
9487
9512
  }
9488
9513
  function buildVideoTodo(report, overlayCount, floatingCount, opts, blueprint) {
9514
+ const hookSceneIndex = findHookSceneIndex(blueprint);
9515
+ const h = hookSceneIndex;
9489
9516
  return {
9490
- recraft_the_script_first: "VIDEO IS INSPIRATION, NOT A CLONE. Before rendering, re-craft the script (hook \u2192 body \u2192 CTA) for OUR brand \u2014 the reference already won in-market, but its hook is targeting and may not transfer. Work the per-scene `script_recraft` checklist below; see references/script-craft.md + the meta-ads-playbook skill.",
9517
+ recraft_the_script_first: `VIDEO IS INSPIRATION, NOT A CLONE. Before rendering, re-craft the script (hook \u2192 body \u2192 CTA) for OUR brand \u2014 the reference already won in-market, but its hook is targeting and may not transfer.${h >= 0 ? " The HOOK is the #1 decision (see the `hook` todo);" : ""} ${h >= 0 ? "then work" : "Work"} the per-scene \`script_recraft\` checklist. References: references/hook-craft.md (the hook), references/script-craft.md (body/CTA) + the meta-ads-playbook skill.`,
9518
+ ...h >= 0 ? {
9519
+ hook: `THE HOOK IS THE HIGHEST-LEVERAGE BEAT \u2014 the first frame + first 3\u20134s decide whether the ad is watched at all, and the hook is TARGETING. But highest-leverage does NOT mean always rewrite: this hook already won, so MOST OF THE TIME you KEEP it and build on top (swap only the specifics). REBUILD is the exception \u2014 only when it doesn't transfer (a claim we lack or a different funnel/awareness stage), and then by reaching for its deeper INNER MECHANIC and delivering that truthfully, not inventing a new opener from nothing. For scene ${h}: DIAGNOSE it (device + mechanic + what stage it targets), DECIDE keep/adapt/rebuild, then hold the opener to the criteria \u2014 ${HOOK_OPENER_CRITERIA}. The hook lives across s${h}_start (the scroll-stopping first frame), the scene-${h} overlay text, the s${h}_clip line, an optional ~0.5s micro-hook, and the ramp into the body. Full diagnose\u2192decide\u2192(keep/adapt/rebuild) discipline + the proven hook-type menu: references/hook-craft.md (+ meta-ads-playbook \xA710/\xA717/\xA739).`
9520
+ } : {},
9491
9521
  script_recraft: buildScriptRecraft(blueprint),
9492
9522
  edit_frames_in_place: "Each s<i>_start / s<i>_end node has its own editable params.prompt (FRAME DESCRIPTION). Edit per frame; the blueprint is only a shared style reference. Frames are CLEAN PLATES \u2014 they render no on-screen text; all text is the overlay HTML layer.",
9493
9523
  frames_mode: opts.frames ?? "generate",
@@ -9519,17 +9549,20 @@ function buildVideoTodo(report, overlayCount, floatingCount, opts, blueprint) {
9519
9549
  "Nail the PACK SHOT \u2014 the final product hero sells (motivated camera move, light matched to the rest of the ad).",
9520
9550
  "Geometry/objects drifting frame to frame? A MAP beats a paragraph \u2014 drop a high-angle schematic still (marked positions) as an extra el_*/reference rather than adding more words.",
9521
9551
  "Before/after (dry\u2192wet, skeptic\u2192believer) = two SEPARATE locked reference images \u2014 don't ask words to transform a subject mid-scene (cheaper and more reliable than re-rolling clips).",
9522
- "The hook is VISUAL-FIRST: the feed plays muted, so scene 1's opening frame + its overlay text must read sound-off in ~1 second \u2014 don't bury the hook in the spoken line alone (meta-ads-playbook \xA739 visual-hooks-beat-audio, \xA748 the 1-second/feed-native rule)."
9552
+ "The hook is VISUAL-FIRST: the feed plays muted, so the hook scene's opening frame + its overlay text must read sound-off in ~1 second \u2014 don't bury the hook in the spoken line alone (meta-ads-playbook \xA739 visual-hooks-beat-audio, \xA748 the 1-second/feed-native rule). The hook is also the #1 re-craft decision \u2014 diagnose/decide/rebuild it against criteria in references/hook-craft.md (see the `hook` todo)."
9523
9553
  ]
9524
9554
  },
9525
- transitions: "Scene-to-scene cuts the deconstruct flagged as fade/whip/zoom/dissolve/swipe are reproduced as an ffmpeg xfade at the boundary (everything else stays a hard cut). The overlap is consumed from extra generated footage, so the picture stays exactly on the audio timeline. To change a transition, edit the scene's `transition_out.type` in prompt.json and re-scaffold, or hand-edit the `spine` node's ffmpeg args.",
9555
+ transitions: "Scene-to-scene cuts the deconstruct flagged as fade/whip/zoom/dissolve/swipe are reproduced as an ffmpeg xfade at the boundary (everything else stays a hard cut). The overlap is consumed from extra generated footage, so the picture stays exactly on the audio timeline. To change a transition, edit the scene's `transition_out.type` in prompt.json and re-scaffold, or hand-edit the `spine` node's ffmpeg args. For a richer HERO cut (whip-pan, glitch, light-leak, gravitational-lens\u2026), the overlay layer can run a Hyperframes shader/CSS transition instead \u2014 see references/hyperframes/blueprints-and-transitions.md (pick 2\u20133 transition types total; the motion IS the handoff).",
9556
+ overlay_capabilities: 'The overlay layer (video-overlay-composition/index.html) is a REAL Hyperframes composition, not a plain text layer \u2014 our hyperframe_render node runs the genuine `npx hyperframes` renderer. So it can do far more than fade/slide/pop: (1) PULL a ready-made block \u2014 `npx hyperframes catalog --type block` then `npx hyperframes add <id>` into the composition dir, and nest it with a <div data-composition-src="compositions/<id>.html" data-start data-track-index data-width data-height> clip (~97 blocks: lower-thirds, social-proof cards, stat counters, charts, code, logo stings); (2) animate with the named GSAP motion-rule vocabulary (kinetic-beat-slam, svg-path-draw, counting-dynamic-scale, multi-phase-camera\u2026); (3) frame a talking head as a video-call/PIP/split. The whole engine + how to build new effects is documented in references/hyperframes/ (start at README.md \u2192 catalog.md, motion-rules.md). Reach for this whenever the reference\'s graphics are richer than plain text.',
9557
+ caption_system: "Sound-off feed = burned-in captions carry the message. The deconstruct produced a word-level transcript \u2014 drive a real caption track off it (karaoke highlight \u2192 themed \u2192 kinetic), not hand-typed text. Floor: `npx hyperframes add caption-highlight` (TikTok karaoke); escalate by content register (caption-kinetic-slam for hype, caption-editorial-emphasis for premium, caption-neon-glow for AI/crypto). Group on meaning, sync within 80ms. Full ladder + transcript contract: references/hyperframes/captions-and-audio.md.",
9558
+ talking_head_overlay: "For a scene where a presenter shows something (screen-share, app demo, product, a 'video call' look), frame the talking-head clip in the overlay composition: presenter full-bleed \u2192 shrinks to a rounded corner PIP pill while a content card takes the stage (or split/stack/overlay-glass-card). The pattern, the #video-wrap\u2192corner-pill tween, the glass call card, and the corner-coord presets are in references/hyperframes/talking-head-and-overlays.md. A ready exemplar ships as the `video-call-composition` move \u2014 copy it next to your canvas, drop brand fonts in the dir, point a `hyperframe_render` at it with the presenter clip as its `background`.",
9526
9559
  text_overlays: {
9527
9560
  count: overlayCount,
9528
9561
  note: "Seeded as editable HTML inside `#overlay-root` in video-overlay-composition/index.html (text + a .pos-* class + data-start/data-dur). PAINT it: restyle the CSS, build lower-thirds/tickers, drop brand-*.otf for on-brand type. The runtime only shows/hides by timestamp."
9529
9562
  },
9530
9563
  floating_elements: {
9531
9564
  count: floatingCount,
9532
- note: floatingCount > 0 ? "Seeded as commented <img> stubs in index.html (each names the `baker images icon/sticker/gif/logo` command to source it) \u2014 source the asset, drop it in video-overlay-composition/, uncomment the <img>." : "none detected by the deconstruct \u2014 see `completeness_check`, the reference may still have icons/stickers it missed."
9565
+ note: floatingCount > 0 ? "Seeded as commented <img> stubs in index.html (each names the `baker images icon/sticker/gif/logo` command to source it) \u2014 source the asset, drop it in video-overlay-composition/, uncomment the <img>. For a graphic that should ANIMATE (a lower-third, a social-proof/review card, a stat counter, a chart, a logo sting), prefer a ready-made Hyperframes block instead of a static <img>: `npx hyperframes add <id>` and nest it (see `overlay_capabilities` + references/hyperframes/catalog.md)." : "none detected by the deconstruct \u2014 see `completeness_check`, the reference may still have icons/stickers it missed."
9533
9566
  },
9534
9567
  sound_effects: {
9535
9568
  count: report.sfx_count,