@waits/cadence 0.5.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waits/cadence",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -7,21 +7,30 @@ import { FANTASY, type FantasyLevel } from "./fantasy";
7
7
  * Build the full image-gen prompt for a freeform subject × fantasy level × format.
8
8
  * `style`/`negatives` default to the built-in luminist look; a pack or `--style-file`
9
9
  * can override them. `COMPOSITION` (UI-safe framing) is always engine-supplied.
10
+ * `brand` (from `--brand`, a project's theme palette) appends a last, explicit
11
+ * palette nudge so it dominates any color the base style mentions.
10
12
  */
11
13
  export function composePrompt(opts: {
12
14
  subject: string;
13
15
  level: FantasyLevel;
14
- format: Format;
15
16
  style?: string;
16
17
  negatives?: string;
18
+ format: Format;
19
+ brand?: { accent?: string; paper?: string };
17
20
  }): string {
21
+ const brand = opts.brand?.accent
22
+ ? `Tune the palette toward the brand: a ${opts.brand.accent} accent${opts.brand.paper ? ` over ${opts.brand.paper}-toned light` : ""} — cohesive and harmonious, never garish.`
23
+ : "";
18
24
  return [
19
25
  opts.style ?? STYLE,
20
26
  `Subject: ${opts.subject}.`,
21
27
  FANTASY[opts.level],
22
28
  COMPOSITION[opts.format],
29
+ brand,
23
30
  opts.negatives ?? NEGATIVES,
24
- ].join(" ");
31
+ ]
32
+ .filter(Boolean)
33
+ .join(" ");
25
34
  }
26
35
 
27
36
  export { LANDMARKS, FANTASY };
@@ -18,7 +18,7 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "
18
18
  import { join } from "node:path";
19
19
  import { composePrompt, LANDMARKS, type FantasyLevel } from "../prompts/art/compose";
20
20
  import type { Format } from "../src/schema/beats";
21
- import { findCadenceDir } from "./_theme";
21
+ import { discoverProjectTheme, findCadenceDir } from "./_theme";
22
22
 
23
23
  const SIZE: Record<Format, string> = { "16x9": "1536x1024", "1x1": "1024x1024", "9x16": "1024x1536" };
24
24
 
@@ -79,6 +79,19 @@ const styleFile = flag("--style-file");
79
79
  const style = styleFile ? readFileSync(styleFile, "utf8") : pack.style;
80
80
  const negatives = pack.negatives;
81
81
 
82
+ // --brand: tint generated art toward the project's theme palette (accent + paper).
83
+ let brand: { accent?: string; paper?: string } | undefined;
84
+ if (has("--brand")) {
85
+ const tf = discoverProjectTheme(process.cwd());
86
+ if (tf) {
87
+ const colors = (JSON.parse(readFileSync(tf, "utf8")).colors ?? {}) as Record<string, string>;
88
+ brand = { accent: colors.signalBlue, paper: colors.paper };
89
+ console.error(`· --brand: ${tf} (accent ${brand.accent ?? "—"})`);
90
+ } else {
91
+ console.error("· --brand: no .cadence/theme.json found — generating unbranded");
92
+ }
93
+ }
94
+
82
95
  // A job = one image to generate. Freeform `--prompt` (needs `--name`) wins;
83
96
  // otherwise pull subjects from the pack via --landmark/--all.
84
97
  type Job = { subject: string; slug: string; label: string };
@@ -117,7 +130,7 @@ if (!process.env.OPENAI_API_KEY) {
117
130
  }
118
131
 
119
132
  async function generate(job: Job) {
120
- const prompt = composePrompt({ subject: job.subject, level, format, style, negatives });
133
+ const prompt = composePrompt({ subject: job.subject, level, format, style, negatives, brand });
121
134
  const fname = `${job.slug}-${level}-${format}.png`;
122
135
  process.stdout.write(`· ${fname} … `);
123
136
  const res = await fetch("https://api.openai.com/v1/images/generations", {
package/scripts/theme.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  * the palette and writes a themes/<name>.json. See the cadence skill.
13
13
  */
14
14
  import { mkdirSync, writeFileSync } from "node:fs";
15
- import { join } from "node:path";
15
+ import { dirname, join } from "node:path";
16
16
  import { deriveTheme } from "../src/theme/derive";
17
17
 
18
18
  const args = process.argv.slice(2);
@@ -61,8 +61,8 @@ if (!accent) {
61
61
  const name = flag("--name") ?? "brand";
62
62
  const theme = deriveTheme({ name, accent, ink: flag("--ink"), paper: flag("--paper"), gold: flag("--gold") });
63
63
 
64
- mkdirSync("themes", { recursive: true });
65
64
  const out = flag("--out") ?? join("themes", `${name}.json`);
65
+ mkdirSync(dirname(out), { recursive: true });
66
66
  writeFileSync(out, JSON.stringify(theme, null, 2));
67
67
 
68
68
  // Portable design summary — a human-readable companion to the JSON.