@amg555/frameforge-mcp 2.7.8 → 2.7.9
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "frameforge",
|
|
3
3
|
"displayName": "FrameForge — AI Video Production",
|
|
4
4
|
"description": "Full AI video production engine. Produce short-form reels (1080×1920), YouTube videos (1920×1080), or code-driven animated explainers — directly from your IDE. Playwright + FFmpeg renders every frame. 34 MCP tools. Whisper, yt-dlp, broadcast audio, 24 film styles, ClaudeAnimationBase, onetake 39-move library, HyperFrames motion craft. 62 Motion Graphics Styles.",
|
|
5
|
-
"version": "2.7.
|
|
5
|
+
"version": "2.7.9",
|
|
6
6
|
"homepage": "https://github.com/AMG555/FrameForge",
|
|
7
7
|
"plugins": [
|
|
8
8
|
{
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to FrameForge are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [2.7.9] — 2026-11-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **TTS language reliability**: `selectNarratorVoice` now accepts a `langHint` param (BCP-47) and covers 25 languages with the correct edge-tts Neural voice. Added Unicode-range detection for Korean (`\uAC00-\uD7AF`), Kannada (`\u0C80-\u0CFF`), Bengali (`\u0980-\u09FF`), and Cyrillic/Russian (`\u0400-\u04FF`). Punjabi entry corrected to gender-neutral `pa-IN-OjasvNeural` (edge-tts only ships one Punjabi voice).
|
|
11
|
+
- **Language propagated end-to-end**: `render_tts` tool now accepts a `language` field; `runAssets` passes `sceneLang` to every `tts.synthesize()` call; `_edgeTTS` defensive `safeVoice` fallback now uses `_overrides.language`. `TTSProvider` constructor JSDoc documents `opts.language`.
|
|
12
|
+
- **Voice Consistency Lock**: `runAssets` pre-resolves a single canonical narrator voice across all narration text before the scene loop — no more mid-video voice drift from punctuation/script variations. Per-scene `scene.voice` still overrides for intentional multi-speaker dialogue.
|
|
13
|
+
- **Parallelism default**: `runAssets` function default raised from 1 → 4 (matching `create_video_from_script` and `render_from_scenes`); TTS now runs 4 scenes concurrently by default.
|
|
14
|
+
- **TTS retry delay**: `baseDelayMs` in `runAssets` reduced from 8000ms → 2000ms; inter-batch pause skipped entirely for `edge-tts` (local subprocess, no rate limit).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
7
18
|
## [2.7.8] — 2026-11-12
|
|
8
19
|
|
|
9
20
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amg555/frameforge-mcp",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.9",
|
|
4
4
|
"description": "FrameForge — Universal AI video creation & autonomous editing engine for any AI agent, CLI, or IDE. npx @amg555/frameforge-mcp. FFmpeg + TTS on your machine. 34 MCP tools. Whisper transcription, yt-dlp ingestion, broadcast-grade audio, 62 procedural motion styles, 6 viral faceless shorts engines, autonomous video editor with retake/silence cutting, J/L-cuts, timeline export to DaVinci/Premiere.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
package/src/mcp-server/server.js
CHANGED
|
@@ -166,16 +166,17 @@ const TOOLS = {
|
|
|
166
166
|
sceneIndex: { type: 'number' },
|
|
167
167
|
text: { type: 'string' },
|
|
168
168
|
voice: { type: 'string', description: 'Voice ID (e.g. en-US-GuyNeural). Overrides TTS_VOICE env var.' },
|
|
169
|
+
language: { type: 'string', description: 'BCP-47 language hint (e.g. "ml", "hi", "fr"). Auto-selects best voice when voice is not set.' },
|
|
169
170
|
},
|
|
170
171
|
},
|
|
171
|
-
handler: async ({ productionId, sceneIndex, text, voice }) => {
|
|
172
|
+
handler: async ({ productionId, sceneIndex, text, voice, language = '' }) => {
|
|
172
173
|
const vdir = path.join(FILES_DIR, 'video_tmp');
|
|
173
174
|
const outputPath = path.join(vdir, `voice_${sceneIndex}.m4a`);
|
|
174
175
|
await fs.mkdir(vdir, { recursive: true });
|
|
175
176
|
|
|
176
177
|
await retryPol.executeStage('TTS', async () => {
|
|
177
|
-
// voice arg overrides env;
|
|
178
|
-
return tts.synthesize({ text, voice, outputPath });
|
|
178
|
+
// voice arg overrides env; language enables BCP-47 auto-voice selection
|
|
179
|
+
return tts.synthesize({ text, voice, outputPath, language });
|
|
179
180
|
});
|
|
180
181
|
|
|
181
182
|
const stat = await fs.stat(outputPath);
|
|
@@ -2124,7 +2125,7 @@ Professional audio rules applied:
|
|
|
2124
2125
|
planMd += `- L-cuts: current audio extends 0.3s into next clip's video\n\n`;
|
|
2125
2126
|
planMd += `## 🚀 Execution & Approval\n\n`;
|
|
2126
2127
|
planMd += `Review this plan, then execute with \`edit_video\` using the payload in \`edit.json\`.\n`;
|
|
2127
|
-
planMd += `\nGenerated by FrameForge v2.7.
|
|
2128
|
+
planMd += `\nGenerated by FrameForge v2.7.9 — plan_video_edit with J/L-cut support (lemo-opuscar DIRECTOR.md)\n`;
|
|
2128
2129
|
|
|
2129
2130
|
// 8. Build TREATMENT.md (lemo-opuscar DIRECTOR.md — 8-section format)
|
|
2130
2131
|
let treatmentMd = '';
|
|
@@ -2165,7 +2166,7 @@ Professional audio rules applied:
|
|
|
2165
2166
|
treatmentMd += `## 8. Director Notes\n\n`;
|
|
2166
2167
|
treatmentMd += `_Add creative direction, mood references, or client notes here._\n\n`;
|
|
2167
2168
|
treatmentMd += `---\n\n`;
|
|
2168
|
-
treatmentMd += `*Generated by FrameForge v2.7.
|
|
2169
|
+
treatmentMd += `*Generated by FrameForge v2.7.9 — lemo-opuscar DIRECTOR.md format*\n`;
|
|
2169
2170
|
}
|
|
2170
2171
|
|
|
2171
2172
|
// 9. Write outputs
|
|
@@ -2246,7 +2247,7 @@ Professional audio rules applied:
|
|
|
2246
2247
|
handler: async () => {
|
|
2247
2248
|
const syncFs = require('fs');
|
|
2248
2249
|
const { MANIFEST_PATH, REPOSITORIES } = require('../skills/sync-upstream');
|
|
2249
|
-
let manifest = { lastSync: null, repos: {}, version: '2.7.
|
|
2250
|
+
let manifest = { lastSync: null, repos: {}, version: '2.7.9', pendingUpdates: [] };
|
|
2250
2251
|
if (syncFs.existsSync(MANIFEST_PATH)) {
|
|
2251
2252
|
try { manifest = JSON.parse(syncFs.readFileSync(MANIFEST_PATH, 'utf8')); } catch (_) {}
|
|
2252
2253
|
}
|
|
@@ -2293,7 +2294,7 @@ Professional audio rules applied:
|
|
|
2293
2294
|
return {
|
|
2294
2295
|
success: true,
|
|
2295
2296
|
lastSync: manifest.lastSync,
|
|
2296
|
-
manifestVersion: manifest.version || '2.7.
|
|
2297
|
+
manifestVersion: manifest.version || '2.7.9',
|
|
2297
2298
|
totalRepos: repos.length,
|
|
2298
2299
|
syncedCount,
|
|
2299
2300
|
pendingUpdates,
|
|
@@ -3536,7 +3537,7 @@ Get a style id from list_motion_styles first. Source: FrameForge Motion Library
|
|
|
3536
3537
|
|
|
3537
3538
|
const SERVER_INFO = {
|
|
3538
3539
|
name: 'video-pipeline',
|
|
3539
|
-
version: '2.7.
|
|
3540
|
+
version: '2.7.9',
|
|
3540
3541
|
};
|
|
3541
3542
|
|
|
3542
3543
|
const CAPABILITIES = {
|
|
@@ -370,7 +370,10 @@ class TTSProvider {
|
|
|
370
370
|
* picks by gender preference (TTS_VOICE_GENDER=male|female|default).
|
|
371
371
|
*
|
|
372
372
|
* @param {string} [explicitVoice] voice passed by caller (takes priority)
|
|
373
|
-
* @param {string} [text] narration text
|
|
373
|
+
* @param {string} [text] narration text — Unicode range detection selects script-appropriate voice
|
|
374
|
+
* @param {string} [langHint] BCP-47 language code (e.g. 'fr', 'pt') — used when text is Latin-script
|
|
375
|
+
* but the production language is known. Falls back to _overrides.language
|
|
376
|
+
* and then to TTS_LANGUAGE env var.
|
|
374
377
|
* @returns {string}
|
|
375
378
|
*/
|
|
376
379
|
selectNarratorVoice(explicitVoice, text = '', langHint = '') {
|
|
@@ -430,7 +433,7 @@ class TTSProvider {
|
|
|
430
433
|
bn: gender === 'female' ? 'bn-IN-TanishaaNeural' : 'bn-IN-BashkarNeural',
|
|
431
434
|
mr: gender === 'female' ? 'mr-IN-AarohiNeural' : 'mr-IN-ManoharNeural',
|
|
432
435
|
gu: gender === 'female' ? 'gu-IN-DhwaniNeural' : 'gu-IN-NiranjanNeural',
|
|
433
|
-
pa:
|
|
436
|
+
pa: 'pa-IN-OjasvNeural', // edge-tts only has one Punjabi voice (gender-neutral)
|
|
434
437
|
ur: gender === 'female' ? 'ur-PK-UzmaNeural' : 'ur-PK-AsadNeural',
|
|
435
438
|
zh: gender === 'female' ? 'zh-CN-XiaoxiaoNeural' : 'zh-CN-YunjianNeural',
|
|
436
439
|
ja: gender === 'female' ? 'ja-JP-NanamiNeural' : 'ja-JP-KeitaNeural',
|
|
@@ -552,7 +555,8 @@ class TTSProvider {
|
|
|
552
555
|
|
|
553
556
|
const rawPath = outputPath.replace(/\.[^.]+$/, '_raw.mp3');
|
|
554
557
|
const txtPath = rawPath + '.txt';
|
|
555
|
-
|
|
558
|
+
// voice is always pre-resolved by synthesize() — this fallback is purely defensive
|
|
559
|
+
const safeVoice = voice || this.selectNarratorVoice(null, text, this._overrides.language || '');
|
|
556
560
|
// No artificial rate manipulation — use the voice's natural cadence.
|
|
557
561
|
// Only a mild rate adjustment from env (e.g. TTS_RATE='+0%') is supported.
|
|
558
562
|
const rate = this._overrides.rate || process.env.TTS_RATE || '+0%';
|
|
@@ -117,7 +117,7 @@ function fetchJson(url) {
|
|
|
117
117
|
return new Promise((resolve, reject) => {
|
|
118
118
|
const opts = {
|
|
119
119
|
headers: {
|
|
120
|
-
'User-Agent': 'FrameForge-Skill-Sync/2.7.
|
|
120
|
+
'User-Agent': 'FrameForge-Skill-Sync/2.7.9',
|
|
121
121
|
'Accept': 'application/vnd.github.v3+json',
|
|
122
122
|
},
|
|
123
123
|
};
|
|
@@ -188,7 +188,7 @@ async function syncSkills(opts = {}) {
|
|
|
188
188
|
const updatedResults = results.filter(r => r.updated);
|
|
189
189
|
|
|
190
190
|
manifest.lastSync = new Date().toISOString();
|
|
191
|
-
manifest.version = '2.7.
|
|
191
|
+
manifest.version = '2.7.9';
|
|
192
192
|
manifest.updatedCount = updatedCount;
|
|
193
193
|
if (updatedResults.length > 0) {
|
|
194
194
|
manifest.pendingUpdates = updatedResults.map(r => {
|
|
@@ -278,7 +278,7 @@ function getUpstreamSummary() {
|
|
|
278
278
|
return {
|
|
279
279
|
repoCount,
|
|
280
280
|
lastSync: manifest.lastSync,
|
|
281
|
-
version: manifest.version || '2.7.
|
|
281
|
+
version: manifest.version || '2.7.9',
|
|
282
282
|
pendingUpdates: pending,
|
|
283
283
|
hasUpdates: pending.length > 0,
|
|
284
284
|
repos: manifest.repos || {},
|