@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.
@@ -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);
@@ -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
  });
@@ -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 = 'video host',
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
- // If targetDuration is given, adjust scene count guidance (≈ 4.5-5s per scene for high retention).
120
- // No ceiling — long-form documentaries, lectures, and podcasts scale dynamically.
121
- const targetScenes = targetDuration ? Math.max(8, Math.ceil(targetDuration / 4.5)) : Math.max(sceneCount, 55);
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 ${persona} writing a ${format} script.`,
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"). High visual pacing: 4-6 seconds per scene (12-25 spoken words). Never write monolithic 30-50s static scenes. Each scene must have:`,
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 (15-35 words in the specified language, spoken aloud),',
142
- 'caption (3-6 words UPPERCASE, text overlay),',
143
- 'visual_description (vivid description of what the scene looks like — used as image prompt),',
144
- 'character { character_id (free text or "none"), pose, emotion, position {x,y,scale} },',
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 } ],',