@koda-sl/baker-cli 0.281.1-dev.1f1c09c80 → 0.281.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 CHANGED
@@ -32778,14 +32778,19 @@ var AdSpec = z30.object({
32778
32778
  message: "give `avatar` (a cast avatar's handle) or `description` \u2014 a cast with neither grounds on nothing"
32779
32779
  }).optional(),
32780
32780
  /**
32781
- * A bed, described in words. Omitted leaves the ad dry the engine only wires
32782
- * music when asked, and silence is a legitimate choice.
32781
+ * The bed, described in words or `false` for an ad that is meant to be dry.
32783
32782
  *
32784
- * The bed never plays over the first beat: the opening line is the
32785
- * scroll-stopper and has to read clean. That is the engine's rule, not this
32786
- * one, and it is why the prompt is all this needs to carry.
32783
+ * Omitted lays a soft, neutral bed. It used to leave the ad silent, on the reasoning
32784
+ * that silence is a legitimate choice; it is, but only as a choice. In practice nothing
32785
+ * ever set this, and finished ads shipped with a voice over nothing which reads as
32786
+ * unfinished, not as restraint. A bed is the ordinary case, so it is the default, and
32787
+ * an ad that wants silence says `false` and means it.
32788
+ *
32789
+ * The bed never plays over the first beat: the opening line is the scroll-stopper and
32790
+ * has to read clean. That is the engine's rule, not this one, and it is why the prompt
32791
+ * is all this needs to carry.
32787
32792
  */
32788
- music: z30.string().min(1).optional(),
32793
+ music: z30.union([z30.string().min(1), z30.literal(false)]).optional(),
32789
32794
  /**
32790
32795
  * How the ad closes.
32791
32796
  *
@@ -32981,6 +32986,11 @@ function staticTranscript(spec) {
32981
32986
  }
32982
32987
  return out;
32983
32988
  }
32989
+ function musicBed(spec) {
32990
+ if (spec.music === false) return null;
32991
+ if (typeof spec.music === "string") return spec.music;
32992
+ return "A soft, warm instrumental bed that sits well under a spoken voiceover: gentle acoustic guitar or soft piano with light pads, steady and unobtrusive, no vocals, no lyrics, no drop, no build to a climax, nothing that pulls attention off the voice.";
32993
+ }
32984
32994
  function beatToCamera(spec, beat, isClosingCard) {
32985
32995
  if (isClosingCard) return false;
32986
32996
  if (beat.on_camera !== void 0) return beat.on_camera;
@@ -33081,7 +33091,7 @@ function adSpecToBlueprint(spec) {
33081
33091
  }
33082
33092
  } : {},
33083
33093
  ...spec.brand?.palette?.length ? { style: { palette: spec.brand.palette.map((hex) => ({ hex })) } } : {},
33084
- ...spec.music ? { music: { music_prompt: spec.music } } : {}
33094
+ ...musicBed(spec) ? { music: { music_prompt: musicBed(spec) } } : {}
33085
33095
  },
33086
33096
  scenes
33087
33097
  };
@@ -33243,7 +33253,7 @@ function pickBrandMark(files) {
33243
33253
  const score = (f) => {
33244
33254
  const name = f.toLowerCase();
33245
33255
  let s = 0;
33246
- if (name.endsWith(".svg")) s += 4;
33256
+ if (/\.(png|webp)$/.test(name)) s += 1;
33247
33257
  if (/\b(logo|wordmark|lockup)\b/.test(name)) s += 2;
33248
33258
  if (/\b(mono|white|black|inverse|icon|favicon|mark-only|isotipo)\b/.test(name)) s -= 3;
33249
33259
  return s;
@@ -33449,8 +33459,20 @@ var scaffoldAdCommand = defineCommand105({
33449
33459
  return;
33450
33460
  }
33451
33461
  if (resolvedLogo?.toLowerCase().endsWith(".svg")) {
33452
- const svg = await readFile16(resolvedLogo, "utf-8").catch(() => "");
33453
- if (svg && svgIsLiveText(svg)) {
33462
+ const svg = await readFile16(resolvedLogo, "utf-8").catch(() => null);
33463
+ if (svg === null) {
33464
+ writeJson({
33465
+ ok: false,
33466
+ error: {
33467
+ code: "VALIDATION_ERROR",
33468
+ message: `The brand mark at \`${resolvedLogo}\` could not be read, so there is no way to tell whether it is a real logo or a typed stand-in. An ad is not shipped on a mark nobody could open.`,
33469
+ fix: `Check the file is there and readable, or put the client's logo in \`${BRAND_DIR}/logos/\` \u2014 a PNG at 1000px or wider, or an outlined SVG.`
33470
+ }
33471
+ });
33472
+ process.exit(1);
33473
+ return;
33474
+ }
33475
+ if (svgIsLiveText(svg)) {
33454
33476
  writeJson({
33455
33477
  ok: false,
33456
33478
  error: {