storyforge 0.12.1 → 0.13.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.
@@ -5,7 +5,7 @@ import {
5
5
  probeDuration,
6
6
  renderPlaceholderShot,
7
7
  runCmd
8
- } from "./chunk-EA4U7ASE.js";
8
+ } from "./chunk-NSB32ZRA.js";
9
9
  import {
10
10
  log
11
11
  } from "./chunk-GJQ45C5W.js";
@@ -5876,6 +5876,8 @@ var renderManimRemotion = async (shot, ctx) => {
5876
5876
  propsPath,
5877
5877
  "--output",
5878
5878
  ctx.sceneOutPath,
5879
+ "--frames",
5880
+ `0-${totalFrames - 1}`,
5879
5881
  "--concurrency",
5880
5882
  "4"
5881
5883
  ],
@@ -5883,11 +5885,33 @@ var renderManimRemotion = async (shot, ctx) => {
5883
5885
  );
5884
5886
  if (r.code !== 0) {
5885
5887
  const tail = r.stderr.split("\n").slice(-5).join(" ").slice(0, 300);
5886
- fs5.copyFileSync(manimSceneOut, ctx.sceneOutPath);
5888
+ const clampRes = await runCmd(
5889
+ "ffmpeg",
5890
+ [
5891
+ "-y",
5892
+ "-i",
5893
+ manimSceneOut,
5894
+ "-t",
5895
+ String(shot.durationSec),
5896
+ "-c:v",
5897
+ "libx264",
5898
+ "-preset",
5899
+ "medium",
5900
+ "-crf",
5901
+ "18",
5902
+ "-pix_fmt",
5903
+ "yuv420p",
5904
+ ctx.sceneOutPath
5905
+ ],
5906
+ { timeoutMs: 6e4, signal: ctx.signal }
5907
+ );
5908
+ if (clampRes.code !== 0) {
5909
+ fs5.copyFileSync(manimSceneOut, ctx.sceneOutPath);
5910
+ }
5887
5911
  ctx.progress.emit({
5888
5912
  phase: "compositing",
5889
5913
  shotId: shot.id,
5890
- warnings: [`remotion overlay failed, used raw manim: ${tail}`]
5914
+ warnings: [`remotion overlay failed, used raw manim clamped to ${shot.durationSec}s: ${tail}`]
5891
5915
  });
5892
5916
  return;
5893
5917
  }
@@ -5948,7 +5972,7 @@ var renderRemotion = async (shot, ctx) => {
5948
5972
  } else {
5949
5973
  const remotion = requireRemotionRoot();
5950
5974
  entryArg = remotion.entry;
5951
- compId = ctx.aspect === "9:16" ? "ForgeVideoVertical" : "ForgeVideo";
5975
+ compId = ctx.aspect === "9:16" ? "KineticTextVertical" : "KineticText";
5952
5976
  remotionCwd = remotion.cwd;
5953
5977
  }
5954
5978
  const propsPath = path7.join(ctx.tmpDir, "remotion", `${shot.id}_props.json`);
@@ -5958,7 +5982,9 @@ var renderRemotion = async (shot, ctx) => {
5958
5982
  JSON.stringify(
5959
5983
  {
5960
5984
  durationInFrames: durationFrames,
5961
- overlayText: shot.overlayText ?? "",
5985
+ text: shot.overlayText ?? "",
5986
+ accentColor: "#58C4DD",
5987
+ bgColor: "#080A12",
5962
5988
  intent: shot.intent ?? ""
5963
5989
  },
5964
5990
  null,
@@ -8140,7 +8166,7 @@ var BridgePoller = class {
8140
8166
  async invokeStitchFinal(jobId, payload) {
8141
8167
  let stitchFinalVideo;
8142
8168
  try {
8143
- const mod = await import("./stitch-Y35UHIBV.js");
8169
+ const mod = await import("./stitch-P3P6SK6M.js");
8144
8170
  stitchFinalVideo = mod.stitchFinalVideo;
8145
8171
  } catch (err) {
8146
8172
  return {
@@ -3,7 +3,6 @@
3
3
  // ../pipeline/src/clip-render/ffmpeg.ts
4
4
  import { spawn } from "child_process";
5
5
  import * as fs from "fs";
6
- import * as path from "path";
7
6
  var defaultRunner = (cmd, args, { timeoutMs = 3e5, signal, cwd }) => new Promise((resolve, reject) => {
8
7
  const child = spawn(cmd, args, { stdio: ["pipe", "pipe", "pipe"], cwd });
9
8
  let stdout = "";
@@ -81,15 +80,20 @@ async function muxAudio(videoPath, audioPath, outPath, opts = {}) {
81
80
  );
82
81
  }
83
82
  }
84
- function buildConcatArgs(manifestPath, outPath) {
83
+ function buildConcatArgs(scenePaths, outPath) {
84
+ if (scenePaths.length === 0) {
85
+ throw new Error("buildConcatArgs: at least one scene required");
86
+ }
87
+ const inputs = scenePaths.flatMap((p) => ["-i", p]);
88
+ const filterChain = scenePaths.map((_, i) => `[${i}:v]`).join("");
89
+ const filter = `${filterChain}concat=n=${scenePaths.length}:v=1:a=0[v]`;
85
90
  return [
86
91
  "-y",
87
- "-f",
88
- "concat",
89
- "-safe",
90
- "0",
91
- "-i",
92
- manifestPath,
92
+ ...inputs,
93
+ "-filter_complex",
94
+ filter,
95
+ "-map",
96
+ "[v]",
93
97
  "-c:v",
94
98
  "libx264",
95
99
  "-preset",
@@ -98,18 +102,6 @@ function buildConcatArgs(manifestPath, outPath) {
98
102
  "18",
99
103
  "-pix_fmt",
100
104
  "yuv420p",
101
- "-r",
102
- "30",
103
- "-vsync",
104
- "cfr",
105
- // Audio is optional in scene files; -c:a aac is safe even when
106
- // some scenes are silent (lavfi placeholders) — ffmpeg synthesizes
107
- // a silent audio track to match. If the scenes are all silent,
108
- // the output also ends up silent and audio gets added by muxAudio.
109
- "-c:a",
110
- "aac",
111
- "-b:a",
112
- "192k",
113
105
  outPath
114
106
  ];
115
107
  }
@@ -121,22 +113,12 @@ async function concatScenes(scenePaths, outPath, opts = {}) {
121
113
  fs.copyFileSync(scenePaths[0], outPath);
122
114
  return outPath;
123
115
  }
124
- const manifestPath = path.join(path.dirname(outPath), `concat_${path.basename(outPath)}.txt`);
125
- const manifest = scenePaths.map((p) => `file '${p.replace(/'/g, "'\\''")}'`).join("\n") + "\n";
126
- fs.writeFileSync(manifestPath, manifest);
127
- try {
128
- const args = buildConcatArgs(manifestPath, outPath);
129
- const r = await runCmd("ffmpeg", args, opts);
130
- if (r.code !== 0) {
131
- throw new Error(
132
- `ffmpeg concat failed (code ${r.code}): ${r.stderr.split("\n").slice(-5).join(" ")}`
133
- );
134
- }
135
- } finally {
136
- try {
137
- fs.unlinkSync(manifestPath);
138
- } catch {
139
- }
116
+ const args = buildConcatArgs(scenePaths, outPath);
117
+ const r = await runCmd("ffmpeg", args, opts);
118
+ if (r.code !== 0) {
119
+ throw new Error(
120
+ `ffmpeg concat failed (code ${r.code}): ${r.stderr.split("\n").slice(-5).join(" ")}`
121
+ );
140
122
  }
141
123
  return outPath;
142
124
  }
package/dist/index.js CHANGED
@@ -1689,7 +1689,7 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
1689
1689
  return "0.0.0";
1690
1690
  })();
1691
1691
  void (async () => {
1692
- const { BridgePoller } = await import("./bridge-poller-APNLBMPW.js");
1692
+ const { BridgePoller } = await import("./bridge-poller-J7R4YRNI.js");
1693
1693
  const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken2, clientVersion: `storyforge ${pkgVersion}` });
1694
1694
  poller.start();
1695
1695
  })();
@@ -2512,7 +2512,7 @@ function resolveBridgeToken2(explicit) {
2512
2512
  // package.json
2513
2513
  var package_default = {
2514
2514
  name: "storyforge",
2515
- version: "0.12.1",
2515
+ version: "0.13.0",
2516
2516
  description: "StoryForge \u2014 local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
2517
2517
  type: "module",
2518
2518
  bin: {
@@ -5,7 +5,7 @@ import {
5
5
  buildNormalizeClipArgs,
6
6
  probeDuration,
7
7
  runCmd
8
- } from "./chunk-EA4U7ASE.js";
8
+ } from "./chunk-NSB32ZRA.js";
9
9
  import "./chunk-NSPRIPOP.js";
10
10
 
11
11
  // ../pipeline/src/stitch/stitch-final.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
5
5
  "type": "module",
6
6
  "bin": {