@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.
@@ -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.2",
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.2] — 2026-11-12
7
+ ## [2.7.3] — 2026-11-12
8
8
 
9
9
  ### Added
10
- - **Full Reference Documentation for all 28 MCP Tools**: Complete parameter schemas and usage examples in `plugins/video-pipeline/skills/video-pipeline/references/mcp-tools.md` covering all animation, scene generation, QA, editor, and media ingestion tools.
11
- - **mix_audio_pro.py Broadcast Parity**: Synchronized Python audio processor with `mixer.js` — 13 procedural SFX generators, 5 room profiles + computed Sabine RT60 acoustic simulation, platform LUFS presets (YouTube, Podcast, Broadcast, Netflix, Instagram), noise gate (-60dBFS), 300Hz mud notch, and automatic `sfx-events.json` loader for `window.__events` contract.
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
  [![npm](https://img.shields.io/npm/v/@amg555/frameforge-mcp.svg?label=npm)](https://www.npmjs.com/package/@amg555/frameforge-mcp)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
11
11
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
12
- [![Version](https://img.shields.io/badge/version-2.7.2-blue.svg)](CHANGELOG.md)
12
+ [![Version](https://img.shields.io/badge/version-2.7.3-blue.svg)](CHANGELOG.md)
13
13
  [![MCP Spec](https://img.shields.io/badge/MCP-2024--11--05-blue.svg)](https://modelcontextprotocol.io/)
14
14
  [![Tests](https://img.shields.io/badge/tests-658%20passing-brightgreen.svg)](#testing)
15
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amg555/frameforge-mcp",
3
- "version": "2.7.2",
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.2",
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
  {
@@ -122,7 +122,7 @@
122
122
  "status": "synced"
123
123
  }
124
124
  },
125
- "version": "2.7.2",
125
+ "version": "2.7.3",
126
126
  "updatedCount": 2,
127
127
  "pendingUpdates": [
128
128
  {
@@ -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/mix_audio.py` builds the final audio track
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
- 10. Run verify.py (7-gate QC)
38
- 11. If QC fails: identify the responsible chapter, re-assign to a fresh subagent
39
- 12. Mux audio: render.mjs mux --audio=audio/final_mix.wav
40
- 13. Final verify.py pass
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
@@ -403,7 +403,7 @@ No network requests — reads the local manifest only. Returns:
403
403
  ```json
404
404
  {
405
405
  "lastSync": "2026-11-11T20:00:00Z",
406
- "manifestVersion": "2.7.2",
406
+ "manifestVersion": "2.7.3",
407
407
  "totalRepos": 9,
408
408
  "syncedCount": 9,
409
409
  "repos": [
@@ -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.2', code.includes("version: '2.7.2'"));
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.2', cfWorker.includes("'2.7.2'"));
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/mix_audio.py',
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/mix_audio.py`);
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
 
@@ -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.2 — plan_video_edit with J/L-cut support (lemo-opuscar DIRECTOR.md)\n`;
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.2 — lemo-opuscar DIRECTOR.md format*\n`;
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.2', pendingUpdates: [] };
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.2',
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.2',
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.2',
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.2';
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.2',
269
+ version: manifest.version || '2.7.3',
270
270
  pendingUpdates: pending,
271
271
  hasUpdates: pending.length > 0,
272
272
  repos: manifest.repos || {},