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-
|
|
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
|
-
|
|
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" ? "
|
|
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
|
-
|
|
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-
|
|
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(
|
|
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
|
-
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
"
|
|
91
|
-
"
|
|
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
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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-
|
|
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.
|
|
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: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storyforge",
|
|
3
|
-
"version": "0.
|
|
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": {
|