From 8370ef74d114a87fa09cb9b48fc6876ac75380bd Mon Sep 17 00:00:00 2001 From: vidgen-bot Date: Tue, 18 Aug 2026 09:53:34 -0400 Subject: [PATCH 1/2] Add npm run new scaffold for videos --- scripts/new.mjs | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 scripts/new.mjs diff --git a/scripts/new.mjs b/scripts/new.mjs new file mode 100644 index 0000000..b0b0694 --- /dev/null +++ b/scripts/new.mjs @@ -0,0 +1,102 @@ +#!/usr/bin/env node +// npm run new -- — scaffold the two files a new video needs: +// posts/-.json the script (title/tagline/script placeholders + empty claims[]) +// src/scenes/data/.ts a minimal valid SceneSpec with one commented example beat +// +// Follows the shapes in posts/104-dev-workflow.json and src/scenes/data/097.ts. +// The scaffold never touches src/scenes/index.ts or src/posts.ts — registering a +// scene for playback stays a manual, reviewed step. + +import { mkdirSync, writeFileSync, existsSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = dirname(dirname(fileURLToPath(import.meta.url))); + +const [, , numArg, slugArg] = process.argv; + +if (!numArg || !slugArg) { + console.error("usage: npm run new -- "); + console.error(" npm run new -- 109 build-frames"); + process.exit(1); +} +if (!/^\d{3}$/.test(numArg)) { + console.error(`error: must be three digits, got "${numArg}"`); + process.exit(1); +} +if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slugArg)) { + console.error(`error: must be lowercase kebab-case, got "${slugArg}"`); + process.exit(1); +} + +const slug = `${numArg}-${slugArg}`; + +const postPath = join(root, "posts", `${slug}.json`); +if (existsSync(postPath)) { + console.error(`already exists: ${postPath}`); + process.exit(1); +} +const scenePath = join(root, "src", "scenes", "data", `${numArg}.ts`); +if (existsSync(scenePath)) { + console.error(`already exists: ${scenePath}`); + process.exit(1); +} + +mkdirSync(dirname(postPath), { recursive: true }); +mkdirSync(dirname(scenePath), { recursive: true }); + +writeFileSync( + postPath, + JSON.stringify( + { + slug, + title: "Replace me — a short title", + tagline: "Replace me — the one-line hook", + accent: "#f97316", + outro: "Replace me — the closer line.", + script: "Replace me — the full voiceover script.", + fallbackDurationSeconds: 45, + claims: [], + }, + null, + 2, + ) + "\n", +); +console.log(`wrote ${postPath}`); + +writeFileSync( + scenePath, + `import type { SceneSpec } from \"../schema\"; + +// ${numArg} — ${slug}: choreography as pure data. Study src/scenes/data/097.ts +// and 104.ts before writing beats: every sentence gets a visual beat, beats +// anchor to spoken words (never absolute seconds), and nothing enters the +// caption band or collides with the mascot box — the compiler enforces both. +export const scene${numArg}: SceneSpec = { + slug: \"${slug}\", + // Beats are anchored to voiceover words: { word: \"^regex$\", nth?, offset? }. + // Uncomment and extend once the script is in place. + beats: [ + { + id: \"example\", + in: { word: \"^Replace$\", offset: 0.1 }, + out: { word: \"^me$\", offset: 0.4 }, + slot: \"center-low\", + prop: { + kind: \"card\", + width: 560, + states: [{ text: [{ text: \"✨ your first beat — anchor it to speech\" }] }], + }, + note: \"example beat; delete and write real beats anchored to the script\", + }, + ], +}; +`, +); +console.log(`wrote ${scenePath}`); + +console.log(`\nScaffolded ${slug}. Next:`); +console.log(` 1. Edit ${postPath} — title, tagline, script, and claims[].`); +console.log(` 2. Edit ${scenePath} — replace the example beat with real choreography.`); +console.log(` 3. Register the post in src/scenes/index.ts and src/posts.ts (manual, reviewed).`); +console.log(` 4. Run npm run lint && npm test before opening a PR.`); From 121c9e4e7ede79c4d0d0e845b02cd2d04ee17a96 Mon Sep 17 00:00:00 2001 From: vidgen-bot Date: Tue, 18 Aug 2026 09:53:50 -0400 Subject: [PATCH 2/2] Register npm run new script --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index eb7cc81..64aaa39 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ironclaw-video-kit", "version": "1.0.0", - "description": "IronClaw creator video kit \u2014 animated mascot, ElevenLabs voiceover, demo-footage compositing", + "description": "IronClaw creator video kit — animated mascot, ElevenLabs voiceover, demo-footage compositing", "private": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -20,6 +20,7 @@ }, "scripts": { "dev": "remotion studio", + "new": "node scripts/new.mjs", "voiceover": "node --env-file-if-exists=.env scripts/voiceover.mjs", "voiceover:all": "node --env-file-if-exists=.env scripts/voiceover-all.mjs", "poses": "python3 scripts/make-poses.py", @@ -40,4 +41,4 @@ "ws": "^8.21.0", "esbuild": "^0.28.1" } -} \ No newline at end of file +}