@amg555/frameforge-mcp 2.7.2 → 2.7.3
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +10 -3
- package/README.md +1 -1
- package/package.json +1 -1
- package/plugins/video-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/video-pipeline/skills/.upstream-skills.json +1 -1
- package/plugins/video-pipeline/skills/video-pipeline/assets/project/ANIMATION_GUIDE.md +2 -1
- package/plugins/video-pipeline/skills/video-pipeline/assets/project/pipeline/briefings/orchestrator.md +8 -4
- package/plugins/video-pipeline/skills/video-pipeline/references/mcp-tools.md +1 -1
- package/scripts/deep-validate.js +7 -2
- package/scripts/html-renderer/new-project.mjs +7 -3
- package/src/mcp-server/server.js +5 -5
- package/src/skills/sync-upstream.js +3 -3
|
@@ -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. 28 MCP tools. Whisper, yt-dlp, broadcast audio, 24 film styles, ClaudeAnimationBase, onetake 39-move library, HyperFrames motion craft.",
|
|
5
|
-
"version": "2.7.
|
|
5
|
+
"version": "2.7.3",
|
|
6
6
|
"homepage": "https://github.com/AMG555/FrameForge",
|
|
7
7
|
"plugins": [
|
|
8
8
|
{
|
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,18 @@ All notable changes to FrameForge are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## [2.7.
|
|
7
|
+
## [2.7.3] — 2026-11-12
|
|
8
8
|
|
|
9
9
|
### Added
|
|
10
|
-
- **
|
|
11
|
-
-
|
|
10
|
+
- **Scaffolding update**: `new-project.mjs` now imports `beatAt`, `snapToBeat`, `OM`, `ROOM_SFX`, `event`, `seg` in the generated `edit.js` template; copies `mix_audio_pro.py` into every new project; `npm run mix` uses the professional chain by default.
|
|
11
|
+
- **`orchestrator.md`** updated: step 10 now runs `mix_audio_pro.py --sfx-events` after `render.mjs full`, consuming `out/sfx-events.json` from `window.__events()` automatically.
|
|
12
|
+
- **`ANIMATION_GUIDE.md`** step 4 updated to `mix_audio_pro.py --sfx-events`.
|
|
13
|
+
- **`procedural-sfx.md`**: added `event()` / `window.__events()` usage examples.
|
|
14
|
+
- **4 new `deep-validate.js` checks** covering scaffolder import correctness and pro chain copy.
|
|
15
|
+
- **Full Reference Documentation for all 28 MCP Tools**: Complete parameter schemas and usage examples in `mcp-tools.md`.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- `mix_audio_pro.py` v2.7.3 fully synced with `mixer.js`: 13-type SFX map, 5 room profiles, `PLATFORM_LUFS`, noise gate, mud notch, `sfx-events.json` auto-read, `computed:` room format.
|
|
12
19
|
|
|
13
20
|
### Fixed
|
|
14
21
|
- **Cloudflare Remote Worker alignment**: Synchronized tool count and server versioning.
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/@amg555/frameforge-mcp)
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://nodejs.org/)
|
|
12
|
-
[](CHANGELOG.md)
|
|
13
13
|
[](https://modelcontextprotocol.io/)
|
|
14
14
|
[](#testing)
|
|
15
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amg555/frameforge-mcp",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.3",
|
|
4
4
|
"description": "FrameForge — AI video production engine for agentic IDEs. npx @amg555/frameforge-mcp. FFmpeg + TTS on your machine. 28 MCP tools. Whisper, yt-dlp, broadcast-grade audio, 13-type SFX library, 24 film styles, ClaudeAnimationBase full guide, onetake 39-move library + OM motion primitives, HyperFrames beat-grid, earshot forge DSP, J/L-cut editing, lemo-opuscar TREATMENT.md, upstream auto-update changelog.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "video-pipeline",
|
|
3
3
|
"displayName": "FrameForge Video Pipeline",
|
|
4
|
-
"version": "2.7.
|
|
4
|
+
"version": "2.7.3",
|
|
5
5
|
"description": "End-to-end AI video production. IDE writes scenes → FrameForge renders. Or: scaffold a Playwright+ffmpeg code-driven animation. Or: auto-research and script the video.",
|
|
6
6
|
"skills": [
|
|
7
7
|
{
|
|
@@ -156,7 +156,8 @@ Never capture audio from the browser. Audio is a separate pass:
|
|
|
156
156
|
1. TTS generates audio → word-level timestamps from `scripts/transcribe.py`
|
|
157
157
|
2. Scene resolves animation anchors from those timestamps via `cuePhrase()`
|
|
158
158
|
3. `node scripts/render.mjs full` renders video frames (silent)
|
|
159
|
-
4. `uv run scripts/
|
|
159
|
+
4. `uv run scripts/mix_audio_pro.py --sfx-events --room broadcast --platform youtube` builds the final audio track
|
|
160
|
+
(reads out/sfx-events.json from window.__events() automatically; use `mix_audio.py` for the simple chain)
|
|
160
161
|
5. `node scripts/render.mjs mux` merges with `-c:v copy` (video stream untouched)
|
|
161
162
|
|
|
162
163
|
`cuePhrase(phrase)` **throws a fatal build error** if the phrase cannot be found
|
|
@@ -34,10 +34,14 @@ Use the right effort level at each stage — wrong effort wastes cost or quality
|
|
|
34
34
|
7. Run render.mjs sheet (one sheet per shot)
|
|
35
35
|
8. Review sheets, request patches from the responsible subagent
|
|
36
36
|
9. Run render.mjs full (full encode, all workers)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
→ After full render, out/sfx-events.json is auto-generated from window.__events()
|
|
38
|
+
10. Run mix_audio_pro.py (professional signal chain):
|
|
39
|
+
uv run scripts/mix_audio_pro.py --room broadcast --platform youtube
|
|
40
|
+
(--sfx-events flag reads out/sfx-events.json automatically if present)
|
|
41
|
+
11. Run verify.py (7-gate QC)
|
|
42
|
+
12. If QC fails: identify the responsible chapter, re-assign to a fresh subagent
|
|
43
|
+
13. Mux audio: render.mjs mux --audio=out/audio_mix_pro.m4a
|
|
44
|
+
14. Final verify.py pass
|
|
41
45
|
```
|
|
42
46
|
|
|
43
47
|
## Subagent rules
|
package/scripts/deep-validate.js
CHANGED
|
@@ -20,7 +20,7 @@ check('batch handling', code.includes('Array.isArray(body)'));
|
|
|
20
20
|
check('ping handler', code.includes("method === 'ping'"));
|
|
21
21
|
check('notifications/init', code.includes("notifications/initialized"));
|
|
22
22
|
check('body size limit', code.includes('MAX_BODY_BYTES'));
|
|
23
|
-
check('SERVER_INFO version 2.7.
|
|
23
|
+
check('SERVER_INFO version 2.7.3', code.includes("version: '2.7.3'"));
|
|
24
24
|
check('18 tools defined (incl get_job_status)', code.includes('get_job_status'));
|
|
25
25
|
check('export_to_editor tool defined', code.includes('export_to_editor'));
|
|
26
26
|
check('edit_video tool defined', code.includes('edit_video'));
|
|
@@ -259,6 +259,11 @@ check('log-redaction has Tavily tvly- pattern', redaction.includes('tvly') ||
|
|
|
259
259
|
// ── html-renderer scaffolder ──────────────────────────────────────────────
|
|
260
260
|
console.log('\n=== html-renderer scaffolder ===');
|
|
261
261
|
check('new-project.mjs exists', fs.existsSync('./scripts/html-renderer/new-project.mjs'));
|
|
262
|
+
const newProjectMjs = fs.readFileSync('./scripts/html-renderer/new-project.mjs', 'utf8');
|
|
263
|
+
check('new-project.mjs imports OM and beatAt', newProjectMjs.includes('beatAt') && newProjectMjs.includes('OM'));
|
|
264
|
+
check('new-project.mjs imports event()', newProjectMjs.includes("'event'") || newProjectMjs.includes(', event,'));
|
|
265
|
+
check('new-project.mjs copies mix_audio_pro.py', newProjectMjs.includes("'scripts/mix_audio_pro.py'"));
|
|
266
|
+
check('new-project.mjs npm run mix uses pro', newProjectMjs.includes('mix_audio_pro.py') && newProjectMjs.includes("'mix'"));
|
|
262
267
|
|
|
263
268
|
// ── html-renderer engine assets ──────────────────────────────────────────
|
|
264
269
|
console.log('\n=== html-renderer engine assets ===');
|
|
@@ -362,7 +367,7 @@ check('cf-worker has checkRateLimit', cfWorker.includes('checkRateLimit'));
|
|
|
362
367
|
check('cf-worker hashes token (SHA-256)', cfWorker.includes('SHA-256'));
|
|
363
368
|
check('cf-worker uses RATE_LIMITS KV', cfWorker.includes('env.RATE_LIMITS'));
|
|
364
369
|
check('cf-worker returns 429 on limit', cfWorker.includes('429'));
|
|
365
|
-
check('cf-worker version 2.7.
|
|
370
|
+
check('cf-worker version 2.7.3', cfWorker.includes("'2.7.3'"));
|
|
366
371
|
check('wrangler.toml has kv_namespaces',fs.readFileSync('./cloudflare-mcp/wrangler.toml','utf8').includes('kv_namespaces'));
|
|
367
372
|
|
|
368
373
|
// ── plugins/skills present ────────────────────────────────────────────────
|
|
@@ -133,7 +133,7 @@ const editLines = [
|
|
|
133
133
|
` * If a layer is only active until t=X, it must explicitly hide itself after t=X.`,
|
|
134
134
|
` */`,
|
|
135
135
|
``,
|
|
136
|
-
`import { reel, layer, text, wallCard, stamp, at, stagger, captions, cue, codeCard, terminal, imageCard, chip } from './reel/engine.js';`,
|
|
136
|
+
`import { reel, layer, text, wallCard, stamp, at, stagger, captions, cue, event, codeCard, terminal, imageCard, chip, beatAt, snapToBeat, OM, ROOM_SFX, seg } from './reel/engine.js';`,
|
|
137
137
|
``,
|
|
138
138
|
`// ── Compositor config ────────────────────────────────────────────────────────`,
|
|
139
139
|
`reel({`,
|
|
@@ -303,6 +303,7 @@ copyAsset('scripts/encode.mjs', 'scripts/encode.mjs');
|
|
|
303
303
|
copyAsset('scripts/look.mjs', 'scripts/look.mjs');
|
|
304
304
|
copyAsset('scripts/storyboard-validator.mjs', 'scripts/storyboard-validator.mjs');
|
|
305
305
|
copyAsset('scripts/mix_audio.py', 'scripts/mix_audio.py');
|
|
306
|
+
copyAsset('scripts/mix_audio_pro.py', 'scripts/mix_audio_pro.py');
|
|
306
307
|
copyAsset('scripts/verify.py', 'scripts/verify.py');
|
|
307
308
|
copyAsset('scripts/transcribe.py', 'scripts/transcribe.py');
|
|
308
309
|
copyAsset('scripts/capture.mjs', 'scripts/capture.mjs');
|
|
@@ -335,7 +336,8 @@ const pkg = {
|
|
|
335
336
|
'render:crop': 'node scripts/render.mjs crop 9:16',
|
|
336
337
|
'render:full': 'node scripts/render.mjs full',
|
|
337
338
|
'render:mux': 'node scripts/render.mjs mux',
|
|
338
|
-
'mix': 'uv run scripts/
|
|
339
|
+
'mix': 'uv run scripts/mix_audio_pro.py',
|
|
340
|
+
'mix:basic': 'uv run scripts/mix_audio.py',
|
|
339
341
|
'transcribe': 'uv run scripts/transcribe.py',
|
|
340
342
|
'verify': 'uv run scripts/verify.py',
|
|
341
343
|
'capture': 'node scripts/capture.mjs',
|
|
@@ -397,7 +399,9 @@ console.log(` 2. Edit STORYBOARD.md: fill in shots, events, reads, transit
|
|
|
397
399
|
console.log(` 3. Validate storyboard: node scripts/storyboard-validator.mjs STORYBOARD.md`);
|
|
398
400
|
console.log(` 4. Pre-flight check: node scripts/look.mjs`);
|
|
399
401
|
console.log(` 5. Check visuals: node scripts/render.mjs sheet`);
|
|
400
|
-
console.log(` 6. Mix audio (TTS): uv run scripts/
|
|
402
|
+
console.log(` 6. Mix audio (TTS): uv run scripts/mix_audio_pro.py`);
|
|
403
|
+
console.log(` Professional chain: uv run scripts/mix_audio_pro.py --room broadcast --platform youtube`);
|
|
404
|
+
console.log(` With sfx-events.json: uv run scripts/mix_audio_pro.py --sfx-events`);
|
|
401
405
|
console.log(` 7. Full render: node scripts/render.mjs full`);
|
|
402
406
|
console.log(` 8. Verify quality gates: uv run scripts/verify.py\n`);
|
|
403
407
|
|
package/src/mcp-server/server.js
CHANGED
|
@@ -2120,7 +2120,7 @@ Professional audio rules applied:
|
|
|
2120
2120
|
planMd += `- L-cuts: current audio extends 0.3s into next clip's video\n\n`;
|
|
2121
2121
|
planMd += `## 🚀 Execution & Approval\n\n`;
|
|
2122
2122
|
planMd += `Review this plan, then execute with \`edit_video\` using the payload in \`edit.json\`.\n`;
|
|
2123
|
-
planMd += `\nGenerated by FrameForge v2.7.
|
|
2123
|
+
planMd += `\nGenerated by FrameForge v2.7.3 — plan_video_edit with J/L-cut support (lemo-opuscar DIRECTOR.md)\n`;
|
|
2124
2124
|
|
|
2125
2125
|
// 8. Build TREATMENT.md (lemo-opuscar DIRECTOR.md — 8-section format)
|
|
2126
2126
|
let treatmentMd = '';
|
|
@@ -2161,7 +2161,7 @@ Professional audio rules applied:
|
|
|
2161
2161
|
treatmentMd += `## 8. Director Notes\n\n`;
|
|
2162
2162
|
treatmentMd += `_Add creative direction, mood references, or client notes here._\n\n`;
|
|
2163
2163
|
treatmentMd += `---\n\n`;
|
|
2164
|
-
treatmentMd += `*Generated by FrameForge v2.7.
|
|
2164
|
+
treatmentMd += `*Generated by FrameForge v2.7.3 — lemo-opuscar DIRECTOR.md format*\n`;
|
|
2165
2165
|
}
|
|
2166
2166
|
|
|
2167
2167
|
// 9. Write outputs
|
|
@@ -2242,7 +2242,7 @@ Professional audio rules applied:
|
|
|
2242
2242
|
handler: async () => {
|
|
2243
2243
|
const syncFs = require('fs');
|
|
2244
2244
|
const { MANIFEST_PATH, REPOSITORIES } = require('../skills/sync-upstream');
|
|
2245
|
-
let manifest = { lastSync: null, repos: {}, version: '2.7.
|
|
2245
|
+
let manifest = { lastSync: null, repos: {}, version: '2.7.3', pendingUpdates: [] };
|
|
2246
2246
|
if (syncFs.existsSync(MANIFEST_PATH)) {
|
|
2247
2247
|
try { manifest = JSON.parse(syncFs.readFileSync(MANIFEST_PATH, 'utf8')); } catch (_) {}
|
|
2248
2248
|
}
|
|
@@ -2289,7 +2289,7 @@ Professional audio rules applied:
|
|
|
2289
2289
|
return {
|
|
2290
2290
|
success: true,
|
|
2291
2291
|
lastSync: manifest.lastSync,
|
|
2292
|
-
manifestVersion: manifest.version || '2.7.
|
|
2292
|
+
manifestVersion: manifest.version || '2.7.3',
|
|
2293
2293
|
totalRepos: repos.length,
|
|
2294
2294
|
syncedCount,
|
|
2295
2295
|
pendingUpdates,
|
|
@@ -2820,7 +2820,7 @@ Outputs broadcast-ready 48kHz/192k AAC stereo.`,
|
|
|
2820
2820
|
|
|
2821
2821
|
const SERVER_INFO = {
|
|
2822
2822
|
name: 'video-pipeline',
|
|
2823
|
-
version: '2.7.
|
|
2823
|
+
version: '2.7.3',
|
|
2824
2824
|
};
|
|
2825
2825
|
|
|
2826
2826
|
const CAPABILITIES = {
|
|
@@ -105,7 +105,7 @@ function fetchJson(url) {
|
|
|
105
105
|
return new Promise((resolve, reject) => {
|
|
106
106
|
const opts = {
|
|
107
107
|
headers: {
|
|
108
|
-
'User-Agent': 'FrameForge-Skill-Sync/2.7.
|
|
108
|
+
'User-Agent': 'FrameForge-Skill-Sync/2.7.3',
|
|
109
109
|
'Accept': 'application/vnd.github.v3+json',
|
|
110
110
|
},
|
|
111
111
|
};
|
|
@@ -176,7 +176,7 @@ async function syncSkills(opts = {}) {
|
|
|
176
176
|
const updatedResults = results.filter(r => r.updated);
|
|
177
177
|
|
|
178
178
|
manifest.lastSync = new Date().toISOString();
|
|
179
|
-
manifest.version = '2.7.
|
|
179
|
+
manifest.version = '2.7.3';
|
|
180
180
|
manifest.updatedCount = updatedCount;
|
|
181
181
|
if (updatedResults.length > 0) {
|
|
182
182
|
manifest.pendingUpdates = updatedResults.map(r => {
|
|
@@ -266,7 +266,7 @@ function getUpstreamSummary() {
|
|
|
266
266
|
return {
|
|
267
267
|
repoCount,
|
|
268
268
|
lastSync: manifest.lastSync,
|
|
269
|
-
version: manifest.version || '2.7.
|
|
269
|
+
version: manifest.version || '2.7.3',
|
|
270
270
|
pendingUpdates: pending,
|
|
271
271
|
hasUpdates: pending.length > 0,
|
|
272
272
|
repos: manifest.repos || {},
|