@amg555/frameforge-mcp 2.4.8 → 2.4.10
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.
- package/package.json +3 -3
- package/plugins/video-pipeline/skills/html-renderer/references/motion-craft.md +92 -0
- package/plugins/video-pipeline/skills/html-renderer/references/render-contract.md +66 -0
- package/plugins/video-pipeline/skills/video-pipeline/references/motion-craft.md +91 -0
- package/plugins/video-pipeline/skills/video-pipeline/references/render-contract.md +65 -0
- package/scripts/deep-validate.js +8 -2
- package/src/harness/bin/harness.mjs +32 -2
- package/src/harness/lib/verify-quality.mjs +252 -0
- package/src/mcp-server/server.js +227 -4
- package/src/video-renderer/renderer.js +7 -1
- package/src/video-renderer/scene-animator.js +1016 -10
- package/src/workflows/assets.js +4 -0
- package/src/workflows/render.js +2 -0
- package/src/workflows/script.js +18 -10
package/src/workflows/assets.js
CHANGED
|
@@ -35,6 +35,8 @@ async function runAssets({
|
|
|
35
35
|
theme = '',
|
|
36
36
|
title = '',
|
|
37
37
|
language = '',
|
|
38
|
+
showCaptions = false,
|
|
39
|
+
showAnchor = false,
|
|
38
40
|
}) {
|
|
39
41
|
const ttsGen = new TTSProvider();
|
|
40
42
|
const sm = new StateMachine({ mode: 'file', stateDir: STATE_DIR });
|
|
@@ -132,6 +134,8 @@ async function runAssets({
|
|
|
132
134
|
speed: scene.speed != null ? scene.speed : 1.0,
|
|
133
135
|
clipVolume: scene.clip_volume != null ? scene.clip_volume : (scene.clipVolume != null ? scene.clipVolume : 0),
|
|
134
136
|
colorGrade: scene.color_grade || scene.colorGrade || null,
|
|
137
|
+
showCaptions: scene.show_captions !== undefined ? scene.show_captions : (scene.showCaptions !== undefined ? scene.showCaptions : showCaptions),
|
|
138
|
+
showAnchor: scene.show_anchor !== undefined ? scene.show_anchor : (scene.showAnchor !== undefined ? scene.showAnchor : showAnchor),
|
|
135
139
|
};
|
|
136
140
|
}));
|
|
137
141
|
results.push(...batchResults);
|
package/src/workflows/render.js
CHANGED
|
@@ -37,6 +37,7 @@ async function runRender({
|
|
|
37
37
|
title = '',
|
|
38
38
|
language = '',
|
|
39
39
|
showCaptions = false,
|
|
40
|
+
showAnchor = false,
|
|
40
41
|
}) {
|
|
41
42
|
const sm = new StateMachine({ mode: 'file', stateDir: STATE_DIR });
|
|
42
43
|
const retryPol = new RetryPolicy({ maxAttempts: 2, baseDelayMs: 15000 });
|
|
@@ -81,6 +82,7 @@ async function runRender({
|
|
|
81
82
|
clipVolume: asset.clipVolume,
|
|
82
83
|
colorGrade: asset.colorGrade,
|
|
83
84
|
showCaptions: asset.showCaptions !== undefined ? asset.showCaptions : showCaptions,
|
|
85
|
+
showAnchor: asset.showAnchor !== undefined ? asset.showAnchor : showAnchor,
|
|
84
86
|
renderWidth,
|
|
85
87
|
renderHeight,
|
|
86
88
|
});
|
package/src/workflows/script.js
CHANGED
|
@@ -15,6 +15,7 @@ const { LLMProvider } = require('../pipeline/providers');
|
|
|
15
15
|
const { StateMachine } = require('../pipeline/state-machine');
|
|
16
16
|
const { RetryPolicy } = require('../pipeline/retry-policy');
|
|
17
17
|
const { Telemetry } = require('../pipeline/telemetry');
|
|
18
|
+
const { detectAnchorRequested } = require('../video-renderer/scene-animator');
|
|
18
19
|
|
|
19
20
|
const os = require('os');
|
|
20
21
|
const FILES_DIR = process.env.N8N_FILES_DIR || require('path').join(os.homedir(), '.frameforge-files');
|
|
@@ -98,7 +99,7 @@ async function runScript({
|
|
|
98
99
|
claims,
|
|
99
100
|
topic,
|
|
100
101
|
style = 'informative',
|
|
101
|
-
persona = '
|
|
102
|
+
persona = 'narrator',
|
|
102
103
|
format = 'YouTube video',
|
|
103
104
|
language = 'en',
|
|
104
105
|
sceneCount = 55,
|
|
@@ -116,13 +117,16 @@ async function runScript({
|
|
|
116
117
|
|
|
117
118
|
const facts = claims.slice(0, 8).map(c => c.safe_wording || c.claim).join('; ');
|
|
118
119
|
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
const
|
|
120
|
+
// Detect whether caller explicitly requested an on-screen anchor / presenter character
|
|
121
|
+
const anchorWanted = detectAnchorRequested(topic);
|
|
122
|
+
const effectivePersona = persona !== 'video host' ? persona : (anchorWanted ? 'video host' : 'narrator');
|
|
123
|
+
|
|
124
|
+
// Fast visual pacing: ≈ 2.5-3.2s per scene cut (never monolithic drags)
|
|
125
|
+
const targetScenes = targetDuration ? Math.max(8, Math.ceil(targetDuration / 2.8)) : Math.max(sceneCount, 55);
|
|
122
126
|
|
|
123
127
|
const raw = await retryPol.executeStage('Script', async () => {
|
|
124
128
|
const system = [
|
|
125
|
-
`You are a ${
|
|
129
|
+
`You are a ${effectivePersona} writing a ${format} script.`,
|
|
126
130
|
`Style: ${style}. Language: ${language}.`,
|
|
127
131
|
`Visual aesthetic for image prompts: ${imageStyle}.`,
|
|
128
132
|
'Output ONLY raw JSON. No markdown. Start with { end with }.',
|
|
@@ -136,12 +140,16 @@ async function runScript({
|
|
|
136
140
|
`STYLE: ${style}`,
|
|
137
141
|
`LANGUAGE: ${language}`,
|
|
138
142
|
'',
|
|
139
|
-
`Write exactly ${targetScenes} scenes (schema_version "2.0.0").
|
|
143
|
+
`Write exactly ${targetScenes} scenes (schema_version "2.0.0"). Fast cinematic visual pacing: 2-3.5 seconds per scene (8-16 spoken words). Scene visual cuts must change frequently. Never write long monolithic scenes. Each scene duration matches the spoken voiceover audio.`,
|
|
144
|
+
anchorWanted
|
|
145
|
+
? 'Include an on-screen host/anchor character in the scenes where appropriate.'
|
|
146
|
+
: 'Do NOT include on-screen host or anchor characters unless asked. Set character to { character_id: "none", pose: "none", emotion: "none" }. Visuals must be dynamic cinematic b-roll, motion graphics, animated diagrams, comparisons, processes, and data visualizations.',
|
|
147
|
+
'Each scene must have:',
|
|
140
148
|
'scene_id (integer), schema_version "2.0.0",',
|
|
141
|
-
'narration (
|
|
142
|
-
'caption (
|
|
143
|
-
'visual_description (vivid description of
|
|
144
|
-
'character { character_id (
|
|
149
|
+
'narration (8-18 words in the specified language, spoken aloud),',
|
|
150
|
+
'caption (optional 2-4 uppercase words text overlay only if captions requested, otherwise empty string),',
|
|
151
|
+
'visual_description (vivid description of the visual motion graphics / b-roll / diagram / scene — used for code-driven animation),',
|
|
152
|
+
'character { character_id ("none" or identifier), pose, emotion, position {x,y,scale} },',
|
|
145
153
|
'focal_point {x,y,weight},',
|
|
146
154
|
'overlay { type: "prop"|"effect"|"text"|"none" },',
|
|
147
155
|
'sound_effects [ { effect_id, timing: "start"|"middle"|"end", volume } ],',
|