/** * render.mjs - Renders a video from a VideoScript JSON file. * * Usage: node render.mjs [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 [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); });