storyforge 0.16.0 → 0.18.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.
|
@@ -5652,13 +5652,40 @@ var renderGeminiRemotion = async (shot, ctx) => {
|
|
|
5652
5652
|
...shot.textAnimation ? { textAnimation: shot.textAnimation } : {},
|
|
5653
5653
|
...shot.textAccent ? { textAccent: shot.textAccent } : {},
|
|
5654
5654
|
...shot.textAccentColor ? { textAccentColor: shot.textAccentColor } : {},
|
|
5655
|
-
...shot.textColor ? { textColor: shot.textColor } : {}
|
|
5655
|
+
...shot.textColor ? { textColor: shot.textColor } : {},
|
|
5656
|
+
// ── Tesla-grade primitive composition fields (v10+) ──
|
|
5657
|
+
// These were being silently dropped before this fix, so
|
|
5658
|
+
// ForgeShot's PrimitiveDispatch never fired.
|
|
5659
|
+
...shot.shotKind ? { shotKind: shot.shotKind } : {},
|
|
5660
|
+
...shot.heroText ? { heroText: shot.heroText } : {},
|
|
5661
|
+
...shot.chipLabel ? { chipLabel: shot.chipLabel } : {},
|
|
5662
|
+
...shot.statBadges ? { statBadges: shot.statBadges } : {},
|
|
5663
|
+
...shot.bars ? { bars: shot.bars } : {},
|
|
5664
|
+
...shot.comparisonImage ? { comparisonImage: shot.comparisonImage } : {},
|
|
5665
|
+
...shot.photoFilter ? { photoFilter: shot.photoFilter } : {},
|
|
5666
|
+
...typeof shot.vignette === "boolean" ? { vignette: shot.vignette } : {},
|
|
5667
|
+
// v11+ template dispatch — picks a cinematic Tier-1 composition.
|
|
5668
|
+
...shot.template ? { template: shot.template } : {}
|
|
5656
5669
|
},
|
|
5657
5670
|
null,
|
|
5658
5671
|
2
|
|
5659
5672
|
)
|
|
5660
5673
|
);
|
|
5661
|
-
const
|
|
5674
|
+
const TEMPLATE_COMP_IDS = {
|
|
5675
|
+
"hero-number": { h: "HeroNumber", v: "HeroNumberVertical" },
|
|
5676
|
+
"bar-comparison": { h: "BarComparison", v: "BarComparisonVertical" },
|
|
5677
|
+
"stat-row": { h: "StatRow", v: "StatRowVertical" }
|
|
5678
|
+
};
|
|
5679
|
+
const templateComp = shot.template ? TEMPLATE_COMP_IDS[shot.template.slug] : null;
|
|
5680
|
+
const compId = templateComp ? ctx.aspect === "9:16" ? templateComp.v : templateComp.h : ctx.aspect === "9:16" ? "ForgeShotVertical" : "ForgeShot";
|
|
5681
|
+
if (shot.template) {
|
|
5682
|
+
const propsData = JSON.parse(fs4.readFileSync(propsPath, "utf-8"));
|
|
5683
|
+
Object.assign(propsData, shot.template.props);
|
|
5684
|
+
if (!propsData.backdropImage && propsData.imagePath) {
|
|
5685
|
+
propsData.backdropImage = propsData.imagePath;
|
|
5686
|
+
}
|
|
5687
|
+
fs4.writeFileSync(propsPath, JSON.stringify(propsData, null, 2));
|
|
5688
|
+
}
|
|
5662
5689
|
ctx.progress.emit({
|
|
5663
5690
|
phase: "compositing",
|
|
5664
5691
|
shotId: shot.id,
|
|
@@ -5759,6 +5786,71 @@ function overlayFontSize(aspect) {
|
|
|
5759
5786
|
function escapeHtml(s) {
|
|
5760
5787
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5761
5788
|
}
|
|
5789
|
+
function wrapLlmHyperframesHtml(rawHtml, opts) {
|
|
5790
|
+
const { width, height } = dimensionsForAspect(opts.aspect);
|
|
5791
|
+
const compositionId = `forge-shot-${opts.shotId}`;
|
|
5792
|
+
const lower = rawHtml.toLowerCase();
|
|
5793
|
+
const hasDoctype = lower.includes("<!doctype");
|
|
5794
|
+
const hasHtmlTag = /<html[\s>]/i.test(rawHtml);
|
|
5795
|
+
const hasBody = /<body[\s>]/i.test(rawHtml);
|
|
5796
|
+
const hasCompositionId = rawHtml.includes("data-composition-id");
|
|
5797
|
+
const hasTimelineRegistration = /window\.__timelines\s*\[/.test(rawHtml);
|
|
5798
|
+
const hasGsapTimeline = /gsap\.timeline\s*\(/.test(rawHtml);
|
|
5799
|
+
let patched = rawHtml;
|
|
5800
|
+
if (hasGsapTimeline && !hasTimelineRegistration) {
|
|
5801
|
+
patched = patched.replace(
|
|
5802
|
+
/(<script\b[^>]*>)([\s\S]*?gsap\.timeline\s*\([\s\S]*?)(<\/script>)/i,
|
|
5803
|
+
(_full, open, body, close) => {
|
|
5804
|
+
const inject = `
|
|
5805
|
+
window.__timelines = window.__timelines || {};
|
|
5806
|
+
window.__timelines[${JSON.stringify(compositionId)}] = tl;
|
|
5807
|
+
try { tl.pause(); } catch(e) {}
|
|
5808
|
+
`;
|
|
5809
|
+
return `${open}${body}${inject}${close}`;
|
|
5810
|
+
}
|
|
5811
|
+
);
|
|
5812
|
+
}
|
|
5813
|
+
if (!hasCompositionId) {
|
|
5814
|
+
if (hasBody) {
|
|
5815
|
+
patched = patched.replace(
|
|
5816
|
+
/<body([^>]*)>([\s\S]*?)<\/body>/i,
|
|
5817
|
+
(_full, attrs, inner) => `<body${attrs}><div id="root" data-composition-id="${compositionId}" data-start="0" data-width="${width}" data-height="${height}">${inner}</div></body>`
|
|
5818
|
+
);
|
|
5819
|
+
} else {
|
|
5820
|
+
const scripts = [];
|
|
5821
|
+
const styles = [];
|
|
5822
|
+
const visible = patched.replace(/<script[\s\S]*?<\/script>/gi, (m) => {
|
|
5823
|
+
scripts.push(m);
|
|
5824
|
+
return "";
|
|
5825
|
+
}).replace(/<style[\s\S]*?<\/style>/gi, (m) => {
|
|
5826
|
+
styles.push(m);
|
|
5827
|
+
return "";
|
|
5828
|
+
});
|
|
5829
|
+
patched = styles.join("") + `<div id="root" data-composition-id="${compositionId}" data-start="0" data-width="${width}" data-height="${height}">` + visible + `</div>` + scripts.join("");
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
if (!hasDoctype || !hasHtmlTag || !hasBody) {
|
|
5833
|
+
patched = `<!doctype html>
|
|
5834
|
+
<html lang="en">
|
|
5835
|
+
<head>
|
|
5836
|
+
<meta charset="utf-8" />
|
|
5837
|
+
<title>${compositionId}</title>
|
|
5838
|
+
<style>
|
|
5839
|
+
html,body{margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden;background:#000;font-family:'Inter',system-ui,sans-serif;}
|
|
5840
|
+
</style>
|
|
5841
|
+
</head>
|
|
5842
|
+
<body>
|
|
5843
|
+
${patched}
|
|
5844
|
+
</body>
|
|
5845
|
+
</html>`;
|
|
5846
|
+
} else {
|
|
5847
|
+
patched = patched.replace(
|
|
5848
|
+
/<head([^>]*)>/i,
|
|
5849
|
+
(_m, attrs) => `<head${attrs}><style>html,body{margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden;background:#000;}</style>`
|
|
5850
|
+
);
|
|
5851
|
+
}
|
|
5852
|
+
return patched;
|
|
5853
|
+
}
|
|
5762
5854
|
|
|
5763
5855
|
// ../pipeline/src/clip-render/engines/hyperframes.ts
|
|
5764
5856
|
var HyperFramesNotInstalledError = class extends Error {
|
|
@@ -5818,7 +5910,11 @@ ${stderrTail}`));
|
|
|
5818
5910
|
}
|
|
5819
5911
|
function resolveShotHtml(shot, aspect) {
|
|
5820
5912
|
if (shot.hyperframesHtml && shot.hyperframesHtml.trim().length > 0) {
|
|
5821
|
-
return shot.hyperframesHtml
|
|
5913
|
+
return wrapLlmHyperframesHtml(shot.hyperframesHtml, {
|
|
5914
|
+
shotId: shot.id,
|
|
5915
|
+
durationSec: shot.durationSec,
|
|
5916
|
+
aspect
|
|
5917
|
+
});
|
|
5822
5918
|
}
|
|
5823
5919
|
if (shot.imagePath || shot.overlayText) {
|
|
5824
5920
|
return buildHyperframesHtml(shot, {
|
|
@@ -7201,6 +7297,11 @@ var renderHyperframesRunPod = async (shot, ctx) => {
|
|
|
7201
7297
|
}
|
|
7202
7298
|
ctx.progress.emit({ phase: "preparing", shotId: shot.id });
|
|
7203
7299
|
const dims = ctx.aspect === "9:16" ? { width: 1080, height: 1920 } : { width: 1920, height: 1080 };
|
|
7300
|
+
const wrappedHtml = wrapLlmHyperframesHtml(shot.hyperframesHtml, {
|
|
7301
|
+
shotId: shot.id,
|
|
7302
|
+
durationSec: shot.durationSec,
|
|
7303
|
+
aspect: ctx.aspect
|
|
7304
|
+
});
|
|
7204
7305
|
const status = await runJob(
|
|
7205
7306
|
endpointId,
|
|
7206
7307
|
{
|
|
@@ -7209,7 +7310,7 @@ var renderHyperframesRunPod = async (shot, ctx) => {
|
|
|
7209
7310
|
// so the payload must be nested under `input_data`.
|
|
7210
7311
|
input: {
|
|
7211
7312
|
input_data: {
|
|
7212
|
-
html:
|
|
7313
|
+
html: wrappedHtml,
|
|
7213
7314
|
durationSec: shot.durationSec,
|
|
7214
7315
|
fps: ctx.fps,
|
|
7215
7316
|
width: dims.width,
|
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-WSSTXFPC.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.18.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.18.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": {
|