@koda-sl/baker-cli 0.265.0-dev.1f1c09c80 → 0.265.2-dev.1f1c09c80
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 +75 -32
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -32651,12 +32651,13 @@ function buildAdBrandOverlay(opts) {
|
|
|
32651
32651
|
const parts = [
|
|
32652
32652
|
"<!-- Brand layer, emitted by `baker canvas scaffold-ad`. The mark and the closing",
|
|
32653
32653
|
" card are drawn HERE, by the composition \u2014 never generated as a picture, because",
|
|
32654
|
-
" a video model garbles a wordmark every time. Restyle freely
|
|
32655
|
-
"
|
|
32654
|
+
" a video model garbles a wordmark every time. Restyle freely, but keep the",
|
|
32655
|
+
" data-start/data-dur attributes and the script below: that script is what shows",
|
|
32656
|
+
" and hides these, and the host composition has nothing that would. -->"
|
|
32656
32657
|
];
|
|
32657
32658
|
if (logo) {
|
|
32658
32659
|
parts.push(
|
|
32659
|
-
`<img class="
|
|
32660
|
+
`<img class="clip brand-mark" src="${escapeHtml2(logo.file)}" alt="${escapeHtml2(logo.alt)}" data-start="0" data-dur="${totalS}" />`
|
|
32660
32661
|
);
|
|
32661
32662
|
}
|
|
32662
32663
|
const cardBits = [];
|
|
@@ -32668,24 +32669,61 @@ function buildAdBrandOverlay(opts) {
|
|
|
32668
32669
|
cardBits.push(`<div class="endcard-cta"${style}>${escapeHtml2(cta.trim())}</div>`);
|
|
32669
32670
|
}
|
|
32670
32671
|
parts.push(
|
|
32671
|
-
`<div class="
|
|
32672
|
+
`<div class="clip endcard" data-start="${cardAtS}" data-dur="${cardDurationS}" data-role="cta">`,
|
|
32672
32673
|
...cardBits.map((b) => ` ${b}`),
|
|
32673
|
-
"</div>"
|
|
32674
|
+
"</div>",
|
|
32675
|
+
brandLayerDriver()
|
|
32674
32676
|
);
|
|
32675
32677
|
return parts.join("\n");
|
|
32676
32678
|
}
|
|
32679
|
+
function brandLayerDriver() {
|
|
32680
|
+
return [
|
|
32681
|
+
"<script>",
|
|
32682
|
+
" (function () {",
|
|
32683
|
+
" var els = Array.prototype.slice.call(document.querySelectorAll('.brand-mark, .endcard'));",
|
|
32684
|
+
" if (!els.length) return;",
|
|
32685
|
+
" els.forEach(function (el) { gsap.set(el, { visibility: 'hidden' }); });",
|
|
32686
|
+
" function attach(tl) {",
|
|
32687
|
+
" if (!tl) return;",
|
|
32688
|
+
" els.forEach(function (el) {",
|
|
32689
|
+
" var at = parseFloat(el.getAttribute('data-start') || '0') || 0;",
|
|
32690
|
+
" var dur = parseFloat(el.getAttribute('data-dur') || '0') || 0;",
|
|
32691
|
+
" tl.set(el, { visibility: 'visible' }, at);",
|
|
32692
|
+
" if (dur > 0) tl.set(el, { visibility: 'hidden' }, at + dur);",
|
|
32693
|
+
" });",
|
|
32694
|
+
" }",
|
|
32695
|
+
" var store = window.__timelines || {};",
|
|
32696
|
+
" var main = store.main;",
|
|
32697
|
+
" if (main) { attach(main); return; }",
|
|
32698
|
+
" Object.defineProperty(store, 'main', {",
|
|
32699
|
+
" configurable: true,",
|
|
32700
|
+
" get: function () { return main; },",
|
|
32701
|
+
" set: function (tl) { main = tl; attach(tl); },",
|
|
32702
|
+
" });",
|
|
32703
|
+
" window.__timelines = store;",
|
|
32704
|
+
" })();",
|
|
32705
|
+
"</script>"
|
|
32706
|
+
].join("\n");
|
|
32707
|
+
}
|
|
32677
32708
|
function adBrandOverlayCss() {
|
|
32678
32709
|
return [
|
|
32679
32710
|
" /* --- brand layer (baker canvas scaffold-ad) --- */",
|
|
32680
|
-
" .
|
|
32681
|
-
"
|
|
32682
|
-
"
|
|
32711
|
+
" /* Positioned by this block alone. The composition that actually renders an ad",
|
|
32712
|
+
" is the caption track, which has no .pos-* helpers \u2014 relying on them put the",
|
|
32713
|
+
" brand layer in a file nothing opens and shipped an empty green end plate. */",
|
|
32714
|
+
" .brand-mark { position: absolute; top: 90px; left: 56px; width: 220px; height: auto;",
|
|
32715
|
+
" opacity: 0.92; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.45)); }",
|
|
32716
|
+
" .endcard { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);",
|
|
32717
|
+
" display: flex; flex-direction: column; align-items: center; gap: 56px;",
|
|
32683
32718
|
" width: 100%; max-width: 1080px; padding: 0 60px; text-align: center; }",
|
|
32684
32719
|
" .endcard-logo { width: 620px; max-width: 78%; height: auto; }",
|
|
32685
32720
|
" /* Capped and wrapping, not sized to its content: measured in a real browser,",
|
|
32686
32721
|
" `GET YOUR FREE QUOTE` renders 948px wide against a 1080px canvas, so the next",
|
|
32687
32722
|
" slightly longer call to action runs off the frame. Two lines beat an edge. */",
|
|
32688
|
-
"
|
|
32723
|
+
" /* Declares its own family: rendered without one it inherited the document",
|
|
32724
|
+
" default and the call to action came out in Times, beside sans-serif captions. */",
|
|
32725
|
+
" .endcard-cta { font-family: 'BrandFont', 'Arial Black', 'Helvetica Neue', Arial, sans-serif;",
|
|
32726
|
+
" font-size: 64px; font-weight: 900; text-transform: uppercase;",
|
|
32689
32727
|
" letter-spacing: 0.01em; color: #fff; padding: 28px 58px; border-radius: 56px;",
|
|
32690
32728
|
" max-width: 900px; line-height: 1.15; background: rgba(0,0,0,0.82); }"
|
|
32691
32729
|
].join("\n");
|
|
@@ -32694,7 +32732,11 @@ function injectAdBrandOverlay(indexHtml, overlayHtml) {
|
|
|
32694
32732
|
if (!overlayHtml.trim()) return indexHtml;
|
|
32695
32733
|
const withCss = indexHtml.replace(" </style>", `${adBrandOverlayCss()}
|
|
32696
32734
|
</style>`);
|
|
32697
|
-
return withCss.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
32735
|
+
if (withCss.includes("<!--OVERLAYS-->")) return withCss.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
32736
|
+
const rootClose = withCss.lastIndexOf("</div>");
|
|
32737
|
+
if (rootClose === -1) return withCss;
|
|
32738
|
+
return `${withCss.slice(0, rootClose)}${overlayHtml}
|
|
32739
|
+
${withCss.slice(rootClose)}`;
|
|
32698
32740
|
}
|
|
32699
32741
|
|
|
32700
32742
|
// src/commands/canvas/composition-path.ts
|
|
@@ -32796,18 +32838,35 @@ var scaffoldAdCommand = defineCommand104({
|
|
|
32796
32838
|
await writeSceneFiles(outDir, blueprint);
|
|
32797
32839
|
await writeFile9(blueprintStylePath, renderStyleProjectionFromValue(blueprint), "utf8");
|
|
32798
32840
|
const logoPath = spec.data.brand?.logo?.trim();
|
|
32841
|
+
const opts = {
|
|
32842
|
+
imageModel: AD_IMAGE_MODEL,
|
|
32843
|
+
videoModel: DEFAULT_VIDEO_GENERATE_MODEL,
|
|
32844
|
+
overlayCompositionPath: path23.relative(outDir, compositionDest),
|
|
32845
|
+
captionsCompositionPath: path23.relative(outDir, captionsDest),
|
|
32846
|
+
blueprintPath: path23.relative(outDir, blueprintPath),
|
|
32847
|
+
blueprintStylePath: path23.relative(outDir, blueprintStylePath),
|
|
32848
|
+
aspect: spec.data.format.aspect_ratio,
|
|
32849
|
+
resolution: spec.data.format.resolution,
|
|
32850
|
+
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
32851
|
+
// The composition's default of 3 is TikTok karaoke styling; applied to an ad
|
|
32852
|
+
// it overrode the clause rule on every line and rendered "IS STANDARD. WE".
|
|
32853
|
+
// 8 is the composition's own maximum and clears every beat measured here.
|
|
32854
|
+
captionWordsPerGroup: 8
|
|
32855
|
+
};
|
|
32856
|
+
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data), opts);
|
|
32857
|
+
const renderNode3 = canvas.nodes.find((n) => n.type === "hyperframe_render");
|
|
32858
|
+
const renderedDir = renderNode3 ? path23.join(outDir, String(renderNode3.params?.composition ?? "")) : null;
|
|
32799
32859
|
let staged = null;
|
|
32800
|
-
if (logoPath) {
|
|
32860
|
+
if (logoPath && renderedDir) {
|
|
32801
32861
|
const ext = path23.extname(logoPath) || ".png";
|
|
32802
|
-
const dest = path23.join(compositionDest, `brand-mark${ext}`);
|
|
32803
32862
|
try {
|
|
32804
|
-
await copyFile(logoPath,
|
|
32863
|
+
await copyFile(logoPath, path23.join(renderedDir, `brand-mark${ext}`));
|
|
32805
32864
|
staged = { file: `brand-mark${ext}`, alt: spec.data.brand?.name ?? "brand" };
|
|
32806
32865
|
} catch {
|
|
32807
32866
|
}
|
|
32808
32867
|
}
|
|
32809
32868
|
const closing = blueprint.scenes[blueprint.scenes.length - 1];
|
|
32810
|
-
const overlayHtml = endCardWanted(spec.data) && closing ? buildAdBrandOverlay({
|
|
32869
|
+
const overlayHtml = endCardWanted(spec.data) && closing && renderedDir ? buildAdBrandOverlay({
|
|
32811
32870
|
logo: staged,
|
|
32812
32871
|
cta: endCardCta(spec.data),
|
|
32813
32872
|
cardAtS: closing.start_s,
|
|
@@ -32815,27 +32874,11 @@ var scaffoldAdCommand = defineCommand104({
|
|
|
32815
32874
|
totalS: blueprint.estimated_duration_s,
|
|
32816
32875
|
accent: firstHex(spec.data.brand?.palette)
|
|
32817
32876
|
}) : "";
|
|
32818
|
-
if (overlayHtml) {
|
|
32819
|
-
const indexPath = path23.join(
|
|
32877
|
+
if (overlayHtml && renderedDir) {
|
|
32878
|
+
const indexPath = path23.join(renderedDir, "index.html");
|
|
32820
32879
|
const html = await readFile15(indexPath, "utf-8");
|
|
32821
32880
|
await writeFile9(indexPath, injectAdBrandOverlay(html, overlayHtml), "utf-8");
|
|
32822
32881
|
}
|
|
32823
|
-
const opts = {
|
|
32824
|
-
imageModel: AD_IMAGE_MODEL,
|
|
32825
|
-
videoModel: DEFAULT_VIDEO_GENERATE_MODEL,
|
|
32826
|
-
overlayCompositionPath: path23.relative(outDir, compositionDest),
|
|
32827
|
-
captionsCompositionPath: path23.relative(outDir, captionsDest),
|
|
32828
|
-
blueprintPath: path23.relative(outDir, blueprintPath),
|
|
32829
|
-
blueprintStylePath: path23.relative(outDir, blueprintStylePath),
|
|
32830
|
-
aspect: spec.data.format.aspect_ratio,
|
|
32831
|
-
resolution: spec.data.format.resolution,
|
|
32832
|
-
// A beat is one clause and one card, so the cap has to clear a whole clause.
|
|
32833
|
-
// The composition's default of 3 is TikTok karaoke styling; applied to an ad
|
|
32834
|
-
// it overrode the clause rule on every line and rendered "IS STANDARD. WE".
|
|
32835
|
-
// 8 is the composition's own maximum and clears every beat measured here.
|
|
32836
|
-
captionWordsPerGroup: 8
|
|
32837
|
-
};
|
|
32838
|
-
const canvas = scaffoldVideoCanvas(blueprint, adSpecCastElements(spec.data), opts);
|
|
32839
32882
|
await writeFile9(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
32840
32883
|
`, "utf-8");
|
|
32841
32884
|
writeJson({
|