@keepylabs/cutroom 0.4.0 → 0.5.0

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.
Files changed (2) hide show
  1. package/cutroom.mjs +40 -2
  2. package/package.json +11 -4
package/cutroom.mjs CHANGED
@@ -21921,11 +21921,31 @@ function applyFixes(words, fixes = []) {
21921
21921
  return f ? { ...w, w: f.to } : w;
21922
21922
  }).filter((w) => w.w);
21923
21923
  }
21924
+ var brandFile = () => join3(HOME(), "brand.json");
21925
+ function getBrand() {
21926
+ try {
21927
+ return JSON.parse(readFileSync2(brandFile(), "utf8"));
21928
+ } catch {
21929
+ return null;
21930
+ }
21931
+ }
21932
+ async function setBrand(input) {
21933
+ if (input.reset) {
21934
+ rmSync(brandFile(), { force: true });
21935
+ return { brand: null, saved: "Back to the default look." };
21936
+ }
21937
+ const { reset, ...fields } = input;
21938
+ const next = { ...getBrand() ?? {}, ...Object.fromEntries(Object.entries(fields).filter(([, v]) => v)) };
21939
+ await call("compose", { duration: 2, words: [], brand: next, check_only: true });
21940
+ mkdirSync3(HOME(), { recursive: true });
21941
+ writeFileSync2(brandFile(), JSON.stringify(next, null, 2));
21942
+ return { brand: next, saved: brandFile(), next: "Every render now uses these. Render a draft to see them." };
21943
+ }
21924
21944
  async function renderReel(input) {
21925
21945
  const pj = resolveProject(input.project);
21926
21946
  const work = join3(pj.folder, ".cutroom");
21927
21947
  const words = applyFixes(pj.words, input.fixes);
21928
- const { html } = await call("compose", { duration: pj.duration, words, layout: input.layout, caption: input.caption, effects: input.effects ?? [], emphasis: input.emphasis });
21948
+ const { html } = await call("compose", { duration: pj.duration, words, layout: input.layout, caption: input.caption, effects: input.effects ?? [], emphasis: input.emphasis, brand: getBrand() ?? void 0 });
21929
21949
  await ensureFonts(work);
21930
21950
  const out = join3(pj.folder, `${pj.name}${input.draft ? "-draft" : ""}.mp4`);
21931
21951
  const tmp = join3(work, "render.mp4");
@@ -22012,9 +22032,11 @@ Finish a video (raw talking-head file: edit it, add captions or effects, make it
22012
22032
  5. After they approve (or after changes), render_reel without draft for the final.
22013
22033
  6. Explain any QA issue in plain words with its time, and offer the fix.
22014
22034
 
22035
+ Brand: before a user's first render, call show_brand; if none is set, offer to set it with set_brand. If they give a website or logo instead of colors, pick 3 colors from it (background, accent, highlight), show them, and save on a yes.
22036
+
22015
22037
  Results are saved in ~/Cutroom. Study only for other creators' reels: never reuse their words, footage or branding.`;
22016
22038
  await serveStdio(() => {
22017
- const server = new McpServer({ name: "cutroom", version: "0.4.0" }, { instructions: INSTRUCTIONS });
22039
+ const server = new McpServer({ name: "cutroom", version: "0.5.0" }, { instructions: INSTRUCTIONS });
22018
22040
  server.registerTool("cutroom_doctor", {
22019
22041
  description: "Check Cutroom is ready: ffmpeg on this computer and an active membership key. Returns each check with the exact fix. Run it first, and whenever a tool fails.",
22020
22042
  inputSchema: object({})
@@ -22052,6 +22074,22 @@ ${m.text}`;
22052
22074
  description: "The Cutroom finishing menu: layouts, caption styles and effects (with the text each effect needs), plus timing rules. Read it before render_reel.",
22053
22075
  inputSchema: object({})
22054
22076
  }, async () => safe(() => call("styles")));
22077
+ server.registerTool("set_brand", {
22078
+ description: "Save the user's brand kit, used by every render from now on (kept on this computer only). Hex colors: background, text, accent (big caption words, chart), highlight (word highlight, DM bubble, ticks, follow button), number (number pop); font: sans, serif or mono. Only the fields given change. reset:true goes back to the default look.",
22079
+ inputSchema: object({
22080
+ background: string2().optional(),
22081
+ text: string2().optional(),
22082
+ accent: string2().optional(),
22083
+ highlight: string2().optional(),
22084
+ number: string2().optional(),
22085
+ font: _enum(["sans", "serif", "mono"]).optional(),
22086
+ reset: boolean2().optional()
22087
+ })
22088
+ }, async (input) => safe(() => setBrand(input)));
22089
+ server.registerTool("show_brand", {
22090
+ description: "Show the brand kit renders use right now (or that the default look is in use).",
22091
+ inputSchema: object({})
22092
+ }, async () => safe(() => getBrand() ?? "No brand kit set: renders use the default look. Set one with set_brand."));
22055
22093
  server.registerTool("prepare_footage", {
22056
22094
  description: "Step 1 of finishing a talking-head video on this computer: cuts long pauses, fits it to 1080x1920, and transcribes it with word timings. Returns the project folder and the timed transcript to plan captions and effects from. Takes about a minute.",
22057
22095
  inputSchema: object({
package/package.json CHANGED
@@ -1,11 +1,18 @@
1
1
  {
2
2
  "name": "@keepylabs/cutroom",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Cutroom for Claude Code: hooks and scripts with scoring, reel breakdowns, creator teardowns, and finishing your own videos with QA. Needs a Keepy Labs membership key.",
5
5
  "type": "module",
6
- "bin": { "cutroom": "cutroom.mjs" },
7
- "files": ["cutroom.mjs", "README.md"],
8
- "engines": { "node": ">=20" },
6
+ "bin": {
7
+ "cutroom": "cutroom.mjs"
8
+ },
9
+ "files": [
10
+ "cutroom.mjs",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
9
16
  "license": "UNLICENSED",
10
17
  "homepage": "https://keepylabs.com",
11
18
  "author": "Keepy Labs"