@koda-sl/baker-cli 0.296.0-dev.f25aa60dd → 0.298.0-dev.52a1f12f8
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 +36 -12
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -38223,6 +38223,15 @@ var scaffoldStaticAdCommand = defineCommand110({
|
|
|
38223
38223
|
}
|
|
38224
38224
|
});
|
|
38225
38225
|
|
|
38226
|
+
// src/commands/studio/avatarModel.ts
|
|
38227
|
+
function pinnedModelHint(input) {
|
|
38228
|
+
if (!input.avatar || !input.model) return null;
|
|
38229
|
+
if (input.model === DEFAULT_VIDEO_GENERATE_MODEL) return null;
|
|
38230
|
+
const speaks = input.generateAudio ?? true;
|
|
38231
|
+
if (!speaks) return null;
|
|
38232
|
+
return `You pinned --model ${input.model} on a speaking avatar. Without it this clip routes to ${DEFAULT_VIDEO_GENERATE_MODEL}, which was chosen for exactly this case: the better picture, both orientations, and audio always on. Drop --model unless the user asked for a specific one \u2014 and note ${input.model} may not take the length or the reference you are counting on.`;
|
|
38233
|
+
}
|
|
38234
|
+
|
|
38226
38235
|
// src/commands/canvas/scaffold-ad.ts
|
|
38227
38236
|
import { copyFile, cp, mkdir as mkdir7, readFile as readFile16, stat as stat4, writeFile as writeFile9 } from "fs/promises";
|
|
38228
38237
|
import path24 from "path";
|
|
@@ -38954,6 +38963,10 @@ function resolveShippedCanvasDir(name, startDir, exists2 = existsSync5, maxDepth
|
|
|
38954
38963
|
}
|
|
38955
38964
|
|
|
38956
38965
|
// src/commands/canvas/scaffold-ad.ts
|
|
38966
|
+
function pinnedOnAvatar(handle, model) {
|
|
38967
|
+
const hint = pinnedModelHint({ avatar: handle ?? void 0, model, generateAudio: true });
|
|
38968
|
+
return hint ? [hint] : [];
|
|
38969
|
+
}
|
|
38957
38970
|
var AD_IMAGE_MODEL = "openai/gpt-image-2.5-sunburst";
|
|
38958
38971
|
var SHIPPED_COMPOSITION_DIR = resolveShippedCanvasDir("video-overlay-composition", import.meta.dirname);
|
|
38959
38972
|
var SHIPPED_CAPTIONS_DIR = resolveShippedCanvasDir("tiktok-captions-composition", import.meta.dirname);
|
|
@@ -38971,6 +38984,12 @@ registerSchema({
|
|
|
38971
38984
|
required: false,
|
|
38972
38985
|
description: "Cast this avatar as the ad's recurring person \u2014 the same flag, the same word and the same meaning as on `baker studio generate` and `baker studio animate`. Every beat they appear in is grounded on their identity sheet and their subject description is copied verbatim, so it is one face throughout and the same face as the rest of the company's work. Overrides `cast.avatar` in the spec. `baker avatars list` shows who there is."
|
|
38973
38986
|
},
|
|
38987
|
+
"no-brand": {
|
|
38988
|
+
type: "boolean",
|
|
38989
|
+
description: "Build the ad with no logo and no closing card. For a company that has no mark yet, or an ad they asked to keep plain. Never a way past a missing file: if they HAVE a logo, put it in src/brand/logos/ instead \u2014 an ad wearing a drawn or stand-in mark is a different company's ad.",
|
|
38990
|
+
required: false,
|
|
38991
|
+
default: false
|
|
38992
|
+
},
|
|
38974
38993
|
"video-model": {
|
|
38975
38994
|
type: "string",
|
|
38976
38995
|
required: false,
|
|
@@ -39002,6 +39021,12 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39002
39021
|
required: false,
|
|
39003
39022
|
description: "Which curated video model renders the shots. Defaults to the one the lane picks; pass this only to compare models on the same brief, because mixing models across a campaign changes how the same face reads. `baker canvas catalog` lists what each one takes."
|
|
39004
39023
|
},
|
|
39024
|
+
"no-brand": {
|
|
39025
|
+
type: "boolean",
|
|
39026
|
+
required: false,
|
|
39027
|
+
default: false,
|
|
39028
|
+
description: "Build the ad with no logo and no closing card. For a company with no mark yet, or an ad they asked to keep plain \u2014 never a way past a missing file."
|
|
39029
|
+
},
|
|
39005
39030
|
slug: {
|
|
39006
39031
|
type: "string",
|
|
39007
39032
|
required: false,
|
|
@@ -39140,19 +39165,20 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39140
39165
|
}
|
|
39141
39166
|
const resolvedLogo = spec.data.brand?.logo?.trim();
|
|
39142
39167
|
const logoExists = resolvedLogo ? await stat4(resolvedLogo).then(() => true, () => false) : false;
|
|
39143
|
-
|
|
39168
|
+
const noBrand = Boolean(args["no-brand"]);
|
|
39169
|
+
if (!logoExists && !noBrand) {
|
|
39144
39170
|
writeJson({
|
|
39145
39171
|
ok: false,
|
|
39146
39172
|
error: {
|
|
39147
39173
|
code: "VALIDATION_ERROR",
|
|
39148
39174
|
message: resolvedLogo ? `The brand mark at \`${resolvedLogo}\` does not exist, so this ad has no logo to put on screen.` : `This company has no brand mark in \`${BRAND_DIR}/logos/\`, so an ad cannot carry its logo.`,
|
|
39149
|
-
fix: `Put the client's real mark in \`${BRAND_DIR}/logos/\` \u2014 an SVG is best, a PNG is fine \u2014 and run this again. Ask them for it if you have to; do NOT draw one, and do not pass a placeholder. The mark is drawn on every frame and on the closing card, so a stand-in ships an ad wearing the wrong brand.`
|
|
39175
|
+
fix: `Put the client's real mark in \`${BRAND_DIR}/logos/\` \u2014 an SVG is best, a PNG is fine \u2014 and run this again. Ask them for it if you have to; do NOT draw one, and do not pass a placeholder. The mark is drawn on every frame and on the closing card, so a stand-in ships an ad wearing the wrong brand. If this ad genuinely carries no brand \u2014 they have no logo yet, or they asked for it plain \u2014 pass \`--no-brand\` and say in your reply that it went out unbranded.`
|
|
39150
39176
|
}
|
|
39151
39177
|
});
|
|
39152
39178
|
process.exit(1);
|
|
39153
39179
|
return;
|
|
39154
39180
|
}
|
|
39155
|
-
if (resolvedLogo?.toLowerCase().endsWith(".svg")) {
|
|
39181
|
+
if (!noBrand && resolvedLogo?.toLowerCase().endsWith(".svg")) {
|
|
39156
39182
|
const svg = await readFile16(resolvedLogo, "utf-8").catch(() => null);
|
|
39157
39183
|
if (svg === null) {
|
|
39158
39184
|
writeJson({
|
|
@@ -39276,6 +39302,13 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39276
39302
|
ok: true,
|
|
39277
39303
|
data: { canvas: outPath, beats: spec.data.beats.length, slug },
|
|
39278
39304
|
hints: [
|
|
39305
|
+
...noBrand ? [
|
|
39306
|
+
"Built with NO brand mark and no closing card, because you passed --no-brand. Say that in your reply: the user is getting an unbranded ad and should know it, not discover it. When they do have a logo, put it in `src/brand/logos/` and re-run without the flag."
|
|
39307
|
+
] : [],
|
|
39308
|
+
// Same reasoning as `studio animate`: a cast avatar that speaks routes to the
|
|
39309
|
+
// default model on purpose, and pinning one discards that silently. An ad's
|
|
39310
|
+
// beats always speak, so there is no silent case to exclude here.
|
|
39311
|
+
...pinnedOnAvatar(handle, requestedModel),
|
|
39279
39312
|
// `--until frames` on anything carrying a face or a mark, because that is where
|
|
39280
39313
|
// getting it wrong is expensive: the pictures cost a fraction of the clips, and
|
|
39281
39314
|
// every defect anyone has caught in a finished ad was visible in them. The run
|
|
@@ -57382,15 +57415,6 @@ import { defineCommand as defineCommand208 } from "citty";
|
|
|
57382
57415
|
// src/commands/studio/animate.ts
|
|
57383
57416
|
import { defineCommand as defineCommand200 } from "citty";
|
|
57384
57417
|
|
|
57385
|
-
// src/commands/studio/avatarModel.ts
|
|
57386
|
-
function pinnedModelHint(input) {
|
|
57387
|
-
if (!input.avatar || !input.model) return null;
|
|
57388
|
-
if (input.model === DEFAULT_VIDEO_GENERATE_MODEL) return null;
|
|
57389
|
-
const speaks = input.generateAudio ?? true;
|
|
57390
|
-
if (!speaks) return null;
|
|
57391
|
-
return `You pinned --model ${input.model} on a speaking avatar. Without it this clip routes to ${DEFAULT_VIDEO_GENERATE_MODEL}, which was chosen for exactly this case: the better picture, both orientations, and audio always on. Drop --model unless the user asked for a specific one \u2014 and note ${input.model} may not take the length or the reference you are counting on.`;
|
|
57392
|
-
}
|
|
57393
|
-
|
|
57394
57418
|
// src/commands/studio/batch.ts
|
|
57395
57419
|
function projectBatch(generation, full) {
|
|
57396
57420
|
const compact3 = {
|