Files
clawbot/skills/remotion-prompt-video/render.mjs

90 lines
2.6 KiB
JavaScript

/**
* render.mjs - Renders a video from a VideoScript JSON file.
*
* Usage: node render.mjs <script.json> [output.mp4]
*/
import { bundle } from "@remotion/bundler";
import { renderMedia, selectComposition } from "@remotion/renderer";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function main() {
const args = process.argv.slice(2);
if (args.length < 1) {
console.error("Usage: node render.mjs <script.json> [output.mp4]");
process.exit(1);
}
const scriptPath = path.resolve(args[0]);
const outputPath = args[1]
? path.resolve(args[1])
: path.join(__dirname, "out", "video.mp4");
// Ensure output directory exists
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
console.log("Loading script:", scriptPath);
const script = JSON.parse(fs.readFileSync(scriptPath, "utf-8"));
console.log(`Video: "${script.title}"`);
console.log(` Scenes: ${script.scenes.length}`);
console.log(` Duration: ${script.totalDurationInSeconds}s`);
console.log(` Resolution: ${script.width}x${script.height}`);
console.log(` FPS: ${script.fps}`);
const totalFrames = script.totalDurationInSeconds * script.fps;
console.log("\nBundling Remotion project...");
const bundleLocation = await bundle({
entryPoint: path.resolve(__dirname, "src/index.ts"),
webpackOverride: (config) => config,
});
console.log("Selecting composition...");
const composition = await selectComposition({
serveUrl: bundleLocation,
id: "PromptVideo",
inputProps: { script },
});
// Override composition metadata with our script values
composition.durationInFrames = totalFrames;
composition.fps = script.fps;
composition.width = script.width;
composition.height = script.height;
console.log(`Rendering ${totalFrames} frames to ${outputPath} ...`);
let lastProgress = 0;
await renderMedia({
composition,
serveUrl: bundleLocation,
codec: "h264",
outputLocation: outputPath,
inputProps: { script },
onProgress: ({ progress }) => {
const pct = Math.floor(progress * 100);
if (pct >= lastProgress + 10) {
lastProgress = pct;
process.stdout.write(` ${pct}%\r`);
}
},
});
const stats = fs.statSync(outputPath);
console.log(`\nDone! ${outputPath} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`);
}
main().catch((err) => {
console.error("Render failed:", err.message || err);
process.exit(1);
});