@amg555/frameforge-mcp 2.3.4 → 2.3.6
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/CHANGELOG.md +45 -0
- package/README.md +2 -2
- package/out/frames/f000000.jpg +0 -0
- package/out/frames/f000001.jpg +0 -0
- package/out/frames/f000002.jpg +0 -0
- package/out/frames/f000003.jpg +0 -0
- package/out/frames/f000004.jpg +0 -0
- package/out/frames/f000005.jpg +0 -0
- package/out/frames/f000006.jpg +0 -0
- package/out/frames/f000007.jpg +0 -0
- package/out/frames/f000008.jpg +0 -0
- package/out/frames/f000009.jpg +0 -0
- package/out/frames/f000010.jpg +0 -0
- package/out/frames/f000011.jpg +0 -0
- package/out/frames/f000012.jpg +0 -0
- package/out/frames/f000013.jpg +0 -0
- package/out/frames/f000014.jpg +0 -0
- package/out/frames/f000015.jpg +0 -0
- package/out/frames/f000016.jpg +0 -0
- package/out/frames/f000017.jpg +0 -0
- package/out/frames/f000018.jpg +0 -0
- package/out/frames/f000019.jpg +0 -0
- package/out/frames/f000020.jpg +0 -0
- package/out/frames/f000021.jpg +0 -0
- package/out/frames/f000022.jpg +0 -0
- package/out/frames/f000023.jpg +0 -0
- package/out/frames/f000024.jpg +0 -0
- package/out/frames/f000025.jpg +0 -0
- package/out/frames/f000026.jpg +0 -0
- package/out/frames/f000027.jpg +0 -0
- package/out/frames/f000028.jpg +0 -0
- package/out/frames/f000029.jpg +0 -0
- package/out/frames/f000030.jpg +0 -0
- package/out/frames/f000031.jpg +0 -0
- package/out/frames/f000032.jpg +0 -0
- package/out/frames/f000033.jpg +0 -0
- package/out/frames/f000034.jpg +0 -0
- package/out/frames/f000035.jpg +0 -0
- package/out/frames/f000036.jpg +0 -0
- package/out/frames/f000037.jpg +0 -0
- package/out/frames/f000038.jpg +0 -0
- package/out/frames/f000039.jpg +0 -0
- package/out/frames/f000040.jpg +0 -0
- package/out/frames/f000041.jpg +0 -0
- package/out/frames/f000042.jpg +0 -0
- package/out/frames/f000043.jpg +0 -0
- package/out/frames/f000044.jpg +0 -0
- package/out/frames/f000045.jpg +0 -0
- package/out/frames/f000046.jpg +0 -0
- package/out/frames/f000047.jpg +0 -0
- package/package.json +2 -2
- package/plugins/video-pipeline/skills/video-pipeline/SKILL.md +25 -12
- package/plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.css +2 -2
- package/plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.js +1 -1
- package/scripts/deep-validate.js +2 -2
- package/scripts/html-renderer/new-project.mjs +2 -2
- package/src/cli/make.js +6 -0
- package/src/harness/bin/harness.mjs +20 -7
- package/src/mcp-server/server.js +57 -7
- package/src/video-renderer/renderer.js +268 -60
- package/src/video-renderer/scene-animator.js +1241 -0
- package/src/workflows/assets.js +23 -2
- package/src/workflows/render.js +32 -9
- package/src/workflows/script.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,51 @@ All notable changes to FrameForge are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [2.3.6] — 2026-11-09
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Full-Canvas Cinematic Procedural Entities** (`src/video-renderer/scene-animator.js`):
|
|
11
|
+
- Completely eliminated the rigid PPT card slideshow pattern. Every scene now renders a living, full-canvas animated universe.
|
|
12
|
+
- 3D Celestial Orbital Simulation: Earth with rotating longitude/latitude wireframes, tilted elliptical orbits, orbiting satellites with solar panels, expanding spherical radio wavefront pulses, and ground target beacon.
|
|
13
|
+
- 3D Rotating DNA Double-Helix: Sinusoidal backbones with perspective depth, nucleotide base-pair rungs, and molecular spore drift.
|
|
14
|
+
- Full-Canvas Financial Candlesticks: Realistic Japanese candlesticks with upper/lower wicks, glowing Exponential Moving Average (EMA) ribbon curve, volume bars, and price tickers.
|
|
15
|
+
- 3D Tactical Radar Globe: Rotating spherical grid with 360-degree radar sweep sector and pinging incident coordinates.
|
|
16
|
+
- 3D Wireframe Polyhedra: Pure mathematical 3D perspective projection (octahedron/cubes) with coordinate axes.
|
|
17
|
+
- Historical Milestone Roadmaps: Flowing chronological paths with golden era seals and progressive illumination pulses.
|
|
18
|
+
- Full-Canvas Neural Mesh: 4-tier neural network with glowing energy packets traveling along active synapses.
|
|
19
|
+
- **Direct Agent Code & HTML Execution** (`src/video-renderer/renderer.js`, `src/mcp-server/server.js`, `src/workflows/render.js`, `src/workflows/assets.js`):
|
|
20
|
+
- Added support for `html` (complete page conforming to `window.DURATION` and `window.seek(t)`) and `code` (canvas drawing instructions for `t`) across `create_video_from_script`, `render_from_scenes`, and workflow pipelines.
|
|
21
|
+
- Enables Claude Code, Opus 5.5, Cursor, and IBM Bob to write custom animation programs that FrameForge renders directly without template overrides.
|
|
22
|
+
- Added `wrapCodeInHarnessHtml()` helper to embed pure Canvas drawing code into a compliant virtual-clock harness page.
|
|
23
|
+
- **Cinematic Broadcast Lower-Third Overlays**:
|
|
24
|
+
- Replaced repetitive center-card text with glassmorphic lower-third broadcast banners leaving the upper 75% of the frame completely open for motion graphics.
|
|
25
|
+
- Accent color left tab, tag pills, high-contrast drop-shadow typography, and subtle bottom progress bar.
|
|
26
|
+
- **Multilingual Typography Integration**:
|
|
27
|
+
- Full native DirectWrite/HarfBuzz font support for Malayalam (`Nirmala UI`, `Noto Sans Malayalam`), Hindi/Devanagari, Tamil, Telugu, Arabic, and CJK with zero broken glyphs.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## [2.3.5] — 2026-11-09
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Integrated Code-Driven Scene Animator** (`src/video-renderer/scene-animator.js`):
|
|
35
|
+
- Dynamic 24fps HTML5/Canvas animation generator adhering to pure-function-of-time contract `seek(t)`
|
|
36
|
+
- Contextual motion graphic themes: Code IDE/terminal typing, Data charts & counters, Network node graphs, Flow diagrams, and floating Ken-Burns image cards
|
|
37
|
+
- Dynamic gradient backgrounds with ambient particle systems and perspective motion grids
|
|
38
|
+
- High-performance Chromium harness rendering + direct FFmpeg BT.709 H.264 VUI muxing
|
|
39
|
+
- **Full Multilingual & Malayalam Font Support**:
|
|
40
|
+
- Direct font resolver for Malayalam & Indic scripts (`Nirmala.ttc`, `Noto Sans Malayalam`, `Malayalam Sangam MN`, `Kartika`, `Meera`, `Manjari`)
|
|
41
|
+
- FFmpeg `text_shaping=1` HarfBuzz layout integration preserving complex conjuncts, chillu letters, and viramas
|
|
42
|
+
- Unicode-safe slicing and UTF-8 handling in caption and narration filters
|
|
43
|
+
- Updated `engine.css`, `engine.js`, and `new-project.mjs` typography stacks for seamless multilingual rendering
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- Replaced static solid-color slideshow fallback in `renderer.js` with live code-driven animation engine
|
|
47
|
+
- Fixed `--flag value` space-separated argument parsing in `harness.mjs` CLI
|
|
48
|
+
- Fixed `--out` directory path resolution in `cmdFrames` frame exporter
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
7
52
|
## [2.3.4] — 2026-11-09
|
|
8
53
|
|
|
9
54
|
### Added
|
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
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
|
-
[](#testing)
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amg555/frameforge-mcp",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.6",
|
|
4
4
|
"description": "FrameForge — AI video production engine for agentic IDEs. npx @amg555/frameforge-mcp. FFmpeg + TTS run on your machine. 17 MCP tools.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"start:local-render": "cross-env RENDER_MODE=full WORKER_PORT=3211 node src/worker/server-render-free.js",
|
|
31
31
|
"db:migrate": "node scripts/db-migrate.js",
|
|
32
32
|
"validate": "node scripts/deep-validate.js",
|
|
33
|
-
"test": "node --test src/pipeline/retry-policy.test.js src/pipeline/telemetry.test.js src/pipeline/artifact-manifest.test.js src/pipeline/artifact-retention.test.js src/pipeline/external-adapter.test.js src/workflows/publishing.test.js src/workflows/script.test.js src/animation/animation-system.test.js src/fact-checker/review-gate.test.js src/fact-checker/checker.test.js src/utils/log-redaction.test.js src/worker/server-render-free.test.js src/worker/server.test.js src/mcp-server/server.test.js src/quality-gate/gate.test.js src/shorts-extractor/extractor.test.js src/audio-mixer/mixer.test.js src/video-renderer/renderer.test.js plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.test.js src/harness/lib/pixels.test.js src/harness/lib/verify-purity.test.js src/harness/harness.test.js src/integration.test.js",
|
|
33
|
+
"test": "node --test src/pipeline/retry-policy.test.js src/pipeline/telemetry.test.js src/pipeline/artifact-manifest.test.js src/pipeline/artifact-retention.test.js src/pipeline/external-adapter.test.js src/workflows/publishing.test.js src/workflows/script.test.js src/animation/animation-system.test.js src/fact-checker/review-gate.test.js src/fact-checker/checker.test.js src/utils/log-redaction.test.js src/worker/server-render-free.test.js src/worker/server.test.js src/mcp-server/server.test.js src/quality-gate/gate.test.js src/shorts-extractor/extractor.test.js src/audio-mixer/mixer.test.js src/video-renderer/scene-animator.test.js src/video-renderer/renderer.test.js plugins/video-pipeline/skills/video-pipeline/assets/project/reel/engine.test.js src/harness/lib/pixels.test.js src/harness/lib/verify-purity.test.js src/harness/harness.test.js src/integration.test.js",
|
|
34
34
|
"lint": "echo 'No linter configured — add eslint for production'",
|
|
35
35
|
"check-credentials": "node src/utils/log-redaction.js",
|
|
36
36
|
"generate-assets": "node scripts/generate-initial-assets.js",
|
|
@@ -137,21 +137,36 @@ npm run setup
|
|
|
137
137
|
|
|
138
138
|
## Workflow (step-by-step)
|
|
139
139
|
|
|
140
|
-
### Path 1 — Agent-First (
|
|
140
|
+
### Path 1 — Agent-First (Code-Driven Motion Graphics or Direct Custom Code)
|
|
141
141
|
|
|
142
|
-
**You are already running an LLM
|
|
143
|
-
them to FrameForge for rendering. No
|
|
144
|
-
FrameForge
|
|
142
|
+
**You are already running an LLM (Claude Code / Opus 5.5 / Cursor / Bob) — use it.**
|
|
143
|
+
Write the scenes yourself and hand them to FrameForge for rendering. No external API key needed.
|
|
144
|
+
FrameForge renders full-canvas, broadcast-quality motion graphics (24fps pure function of `t`) with zero slideshow/card patterns:
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
- **Option A — Natural Description:** Provide `visual_description` (e.g. "Earth rotating with 4 satellite orbits and microwave beams intersecting"). FrameForge automatically synthesizes a full-canvas procedural 3D/2D animation entity (orbital mechanics, 3D DNA helix, candlestick charts, neural mesh, 3D wireframe polyhedra).
|
|
147
|
+
- **Option B — Direct Agent Code:** Provide `html` (complete page with `window.DURATION` & `window.seek(t)`) or `code` (canvas drawing instructions for `t`). FrameForge executes your program directly via headless Chromium.
|
|
148
|
+
- **Option C — Multilingual & Regional Scripts:** Pass `language: "ml"` (Malayalam), `"hi"` (Hindi), etc. Native DirectWrite/HarfBuzz font stacks (`Nirmala UI`, `Noto Sans Malayalam`) render conjuncts without broken glyphs.
|
|
149
|
+
|
|
150
|
+
```js
|
|
147
151
|
create_video_from_script({
|
|
152
|
+
topic: "GPS Satellites and Orbital Mechanics",
|
|
153
|
+
style: "cosmic_space",
|
|
154
|
+
language: "en",
|
|
148
155
|
scenes: [
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
visual_description: "
|
|
156
|
+
{
|
|
157
|
+
narration: "GPS uses trilateration from atomic clock satellites orbiting Earth.",
|
|
158
|
+
caption: "TRILATERATION",
|
|
159
|
+
visual_description: "3D Earth rotating with 4 satellite orbits and microwave beams converging",
|
|
160
|
+
// Optional: you can pass your own Canvas code or complete HTML:
|
|
161
|
+
// code: "ctx.fillStyle = '#0c1116'; ctx.fillRect(0,0,W,H); ..."
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
narration: "Relativistic time dilation requires nanosecond daily corrections.",
|
|
165
|
+
caption: "TIME DILATION",
|
|
166
|
+
visual_description: "Quantum atomic clock oscillation with compounding nanosecond curve"
|
|
167
|
+
}
|
|
153
168
|
],
|
|
154
|
-
title: "How
|
|
169
|
+
title: "How GPS Actually Works"
|
|
155
170
|
})
|
|
156
171
|
```
|
|
157
172
|
|
|
@@ -160,8 +175,6 @@ Then deliver it:
|
|
|
160
175
|
publish_video({ productionId, masterPath, channels: ["file"] })
|
|
161
176
|
```
|
|
162
177
|
|
|
163
|
-
> **Image generation fallback:** If the configured image provider is unavailable, FrameForge automatically falls back to a dark-background placeholder per scene — the render completes. Switch to `PROVIDER_IMAGE=falai` for a more reliable free provider.
|
|
164
|
-
|
|
165
178
|
### Path 2 — Code-Driven Animated Video (Playwright + ffmpeg, no AI images)
|
|
166
179
|
|
|
167
180
|
Use when: the user wants Remotion-style motion graphics, image gen is unavailable, or they ask for "animated video" or "make it look good". Every pixel is a pure function of time `t`.
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
--danger: #ef4444;
|
|
22
22
|
|
|
23
23
|
/* Typography scale */
|
|
24
|
-
--font-body: -apple-system, "Segoe UI", system-ui, sans-serif;
|
|
24
|
+
--font-body: -apple-system, "Segoe UI", "Nirmala UI", "Noto Sans Malayalam", "Malayalam Sangam MN", "Kartika", "Meera", "Manjari", system-ui, sans-serif;
|
|
25
25
|
--font-mono: "Fira Code", "Cascadia Code", "Consolas", monospace;
|
|
26
|
-
--font-display: "Archivo", "Segoe UI", system-ui, sans-serif;
|
|
26
|
+
--font-display: "Archivo", "Nirmala UI", "Noto Sans Malayalam", "Malayalam Sangam MN", "Kartika", "Meera", "Manjari", -apple-system, "Segoe UI", system-ui, sans-serif;
|
|
27
27
|
|
|
28
28
|
/* Spacing */
|
|
29
29
|
--gap-sm: 8px;
|
|
@@ -331,7 +331,7 @@ export function shots(shotList = []) {
|
|
|
331
331
|
* @param {{ font, color, x, y, size, weight, align, opacity, duration }} opts
|
|
332
332
|
*/
|
|
333
333
|
export function text(str, {
|
|
334
|
-
font = '48px/1.3 system-ui',
|
|
334
|
+
font = '48px/1.3 "Nirmala UI", "Noto Sans Malayalam", "Malayalam Sangam MN", "Kartika", system-ui, sans-serif',
|
|
335
335
|
color = '#ffffff',
|
|
336
336
|
x = 'center',
|
|
337
337
|
y = 100,
|
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.3.
|
|
23
|
+
check('SERVER_INFO version 2.3.6', code.includes("version: '2.3.6'"));
|
|
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('voxforge TTS provider', code.includes('voxforge'));
|
|
@@ -293,7 +293,7 @@ check('cf-worker has checkRateLimit', cfWorker.includes('checkRateLimit'));
|
|
|
293
293
|
check('cf-worker hashes token (SHA-256)', cfWorker.includes('SHA-256'));
|
|
294
294
|
check('cf-worker uses RATE_LIMITS KV', cfWorker.includes('env.RATE_LIMITS'));
|
|
295
295
|
check('cf-worker returns 429 on limit', cfWorker.includes('429'));
|
|
296
|
-
check('cf-worker version 2.3.
|
|
296
|
+
check('cf-worker version 2.3.6', cfWorker.includes("'2.3.6'"));
|
|
297
297
|
check('wrangler.toml has kv_namespaces',fs.readFileSync('./cloudflare-mcp/wrangler.toml','utf8').includes('kv_namespaces'));
|
|
298
298
|
|
|
299
299
|
// ── plugins/skills present ────────────────────────────────────────────────
|
|
@@ -97,7 +97,7 @@ const indexHtml = `<!DOCTYPE html>
|
|
|
97
97
|
<!-- Preload primary typeface — must resolve before frame 0 (fonts.ready gate) -->
|
|
98
98
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
99
99
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
100
|
-
<link href="https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
|
100
|
+
<link href="https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,100..900;1,100..900&family=Noto+Sans+Malayalam:wght@400;600;700;800;900&display=swap" rel="stylesheet">
|
|
101
101
|
<link rel="stylesheet" href="reel/engine.css">
|
|
102
102
|
<style>
|
|
103
103
|
/* Project-level overrides — edit here */
|
|
@@ -105,7 +105,7 @@ const indexHtml = `<!DOCTYPE html>
|
|
|
105
105
|
--primary: #ffffff;
|
|
106
106
|
--accent: #3b82f6;
|
|
107
107
|
--bg: #0d1117;
|
|
108
|
-
--font: 'Archivo', system-ui, sans-serif;
|
|
108
|
+
--font: 'Archivo', 'Nirmala UI', 'Noto Sans Malayalam', 'Malayalam Sangam MN', 'Kartika', system-ui, sans-serif;
|
|
109
109
|
}
|
|
110
110
|
</style>
|
|
111
111
|
</head>
|
package/src/cli/make.js
CHANGED
|
@@ -410,6 +410,9 @@ async function runSingleVideo(args, topic, outDir, workflows) {
|
|
|
410
410
|
skipImages,
|
|
411
411
|
skipTts: args.noTts,
|
|
412
412
|
enableAiImages,
|
|
413
|
+
topic,
|
|
414
|
+
title,
|
|
415
|
+
style: args.style || '',
|
|
413
416
|
});
|
|
414
417
|
log('Assets', `✅ ${assetsResult.sceneCount} scenes prepared`);
|
|
415
418
|
|
|
@@ -418,6 +421,9 @@ async function runSingleVideo(args, topic, outDir, workflows) {
|
|
|
418
421
|
const renderResult = await runRender({
|
|
419
422
|
productionId,
|
|
420
423
|
sceneAssets: assetsResult.sceneAssets,
|
|
424
|
+
topic,
|
|
425
|
+
title,
|
|
426
|
+
style: args.style || '',
|
|
421
427
|
});
|
|
422
428
|
if (!renderResult.passed) {
|
|
423
429
|
throw new Error(`Quality gate FAILED: ${JSON.stringify(renderResult.qcReport?.checks?.filter(c => !c.passed).map(c => c.name))}`);
|
|
@@ -39,8 +39,19 @@ const extras = [];
|
|
|
39
39
|
for (let i = 1; i < argv.length; i++) {
|
|
40
40
|
const arg = argv[i];
|
|
41
41
|
if (arg.startsWith('--')) {
|
|
42
|
-
const
|
|
43
|
-
|
|
42
|
+
const eqIdx = arg.indexOf('=');
|
|
43
|
+
if (eqIdx !== -1) {
|
|
44
|
+
const k = arg.slice(2, eqIdx);
|
|
45
|
+
const v = arg.slice(eqIdx + 1);
|
|
46
|
+
flags[k] = v;
|
|
47
|
+
} else {
|
|
48
|
+
const k = arg.slice(2);
|
|
49
|
+
if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
|
|
50
|
+
flags[k] = argv[++i];
|
|
51
|
+
} else {
|
|
52
|
+
flags[k] = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
44
55
|
} else {
|
|
45
56
|
extras.push(arg);
|
|
46
57
|
}
|
|
@@ -56,7 +67,7 @@ function resolveProjectFile(filename, fallback) {
|
|
|
56
67
|
const HTML_FILE = flags.html ? path.resolve(CWD, flags.html) : resolveProjectFile('index.html', resolveProjectFile('studio.html'));
|
|
57
68
|
const OUT_DIR = flags.outDir ? path.resolve(CWD, flags.outDir) : path.join(CWD, 'out');
|
|
58
69
|
const CHECK_DIR = path.join(OUT_DIR, 'check');
|
|
59
|
-
const FRAMES_DIR = path.join(OUT_DIR, 'frames');
|
|
70
|
+
const FRAMES_DIR = flags.frames ? path.resolve(CWD, flags.frames) : flags.out ? path.resolve(CWD, flags.out) : path.join(OUT_DIR, 'frames');
|
|
60
71
|
const PURITY_LOG = path.join(CHECK_DIR, 'purity_report.json');
|
|
61
72
|
|
|
62
73
|
fs.mkdirSync(OUT_DIR, { recursive: true });
|
|
@@ -214,17 +225,19 @@ async function cmdFrames() {
|
|
|
214
225
|
const fps = parseInt(flags.fps || '30', 10);
|
|
215
226
|
const workers = parseInt(flags.workers || '4', 10);
|
|
216
227
|
const duration = flags.duration ? parseFloat(flags.duration) : 2.0;
|
|
217
|
-
const
|
|
228
|
+
const first = flags.first !== undefined ? parseInt(flags.first, 10) : 0;
|
|
229
|
+
const last = flags.last !== undefined ? parseInt(flags.last, 10) : (Math.round(duration * fps) - 1);
|
|
230
|
+
const totalFrames = last - first + 1;
|
|
218
231
|
|
|
219
|
-
console.log(`📦 Rendering Frame Range [
|
|
232
|
+
console.log(`📦 Rendering Frame Range [${first}..${last}] (${totalFrames} frames @ ${fps}fps, workers=${workers})`);
|
|
220
233
|
const { browser } = await launchHarnessBrowser();
|
|
221
234
|
|
|
222
235
|
const res = await renderFrameJobs({
|
|
223
236
|
browser,
|
|
224
237
|
htmlPath: HTML_FILE,
|
|
225
238
|
framesDir: FRAMES_DIR,
|
|
226
|
-
first
|
|
227
|
-
last
|
|
239
|
+
first,
|
|
240
|
+
last,
|
|
228
241
|
fps,
|
|
229
242
|
workers,
|
|
230
243
|
width: parseInt(flags.width || '1920', 10),
|
package/src/mcp-server/server.js
CHANGED
|
@@ -349,9 +349,14 @@ const TOOLS = {
|
|
|
349
349
|
skipTts: { type: 'boolean', default: false, description: 'Skip TTS synthesis (use audio_path in scenes)' },
|
|
350
350
|
withMusic: { type: 'boolean', default: true },
|
|
351
351
|
musicVolume: { type: 'number', default: 0.07 },
|
|
352
|
+
topic: { type: 'string', description: 'Overall topic/genre for visual theme and aesthetic selection' },
|
|
353
|
+
style: { type: 'string', description: 'Visual style/theme override (e.g. cinematic_documentary, finance_executive, cyber_tech, retro_synthwave, nature_organic, hype_sports, minimal_luxury, breaking_news, cosmic_space)' },
|
|
354
|
+
theme: { type: 'string', description: 'Theme preset alias' },
|
|
355
|
+
title: { type: 'string', description: 'Video title' },
|
|
356
|
+
language: { type: 'string', description: 'BCP-47 language hint (e.g. ml, hi, en, ta)' },
|
|
352
357
|
},
|
|
353
358
|
},
|
|
354
|
-
handler: async ({ productionId, scenes, orientation = 'landscape', skipImages = false, skipTts = false, withMusic = true, musicVolume = 0.07 }) => {
|
|
359
|
+
handler: async ({ productionId, scenes, orientation = 'landscape', skipImages = false, skipTts = false, withMusic = true, musicVolume = 0.07, topic = '', style = '', theme = '', title = '', language = '' }) => {
|
|
355
360
|
const syncFs = require('fs');
|
|
356
361
|
const { runAssets } = require('../workflows/assets');
|
|
357
362
|
const { runRender } = require('../workflows/render');
|
|
@@ -392,6 +397,11 @@ const TOOLS = {
|
|
|
392
397
|
parallelism: 4,
|
|
393
398
|
skipImages,
|
|
394
399
|
skipTts,
|
|
400
|
+
topic,
|
|
401
|
+
style,
|
|
402
|
+
theme,
|
|
403
|
+
title,
|
|
404
|
+
language,
|
|
395
405
|
imageWidth: renderWidth,
|
|
396
406
|
imageHeight: renderHeight,
|
|
397
407
|
});
|
|
@@ -404,6 +414,11 @@ const TOOLS = {
|
|
|
404
414
|
musicVolume,
|
|
405
415
|
renderWidth,
|
|
406
416
|
renderHeight,
|
|
417
|
+
topic,
|
|
418
|
+
style,
|
|
419
|
+
theme,
|
|
420
|
+
title,
|
|
421
|
+
language,
|
|
407
422
|
});
|
|
408
423
|
|
|
409
424
|
if (!renderResult.passed) {
|
|
@@ -518,8 +533,9 @@ Named presets (set EXTERNAL_PLATFORM_NAME to one of these and omit platformUrl):
|
|
|
518
533
|
description: `Agent-first video creation. YOU (the IDE agent) provide the complete scenes array — FrameForge renders it.
|
|
519
534
|
Features:
|
|
520
535
|
- Code-driven animation and kinetic typography by default (broadcast quality, zero AI artifacts).
|
|
536
|
+
- Supports direct agent/user code: pass "html" (complete page with window.seek(t)) or "code" (canvas drawing instructions for t).
|
|
537
|
+
- Procedural full-canvas cinematic animations (celestial orbits, DNA helices, candlestick charts, neural nets, 3D wireframe geometry).
|
|
521
538
|
- Supports manual user clips (video_path) and manual images (image_path).
|
|
522
|
-
- Optional AI diffusion generation via enableAiImages: true.
|
|
523
539
|
- No internal LLM or research required. Primary path for Claude Code, IBM Bob, Cursor, and any agentic IDE.
|
|
524
540
|
|
|
525
541
|
Example scene:
|
|
@@ -527,6 +543,8 @@ Example scene:
|
|
|
527
543
|
"narration": "The text spoken aloud in this scene",
|
|
528
544
|
"caption": "OVERLAY TEXT",
|
|
529
545
|
"visual_description": "Description of the scene visual / animation",
|
|
546
|
+
"html": "<!doctype html>... window.seek = async (t) => { ... }",
|
|
547
|
+
"code": "/* canvas drawing code for t */",
|
|
530
548
|
"camera_hint": "zoom_in",
|
|
531
549
|
"music_mood": "energetic",
|
|
532
550
|
"image_path": "/optional/your/own/image.jpg",
|
|
@@ -537,7 +555,7 @@ Example scene:
|
|
|
537
555
|
type: 'object',
|
|
538
556
|
required: ['scenes'],
|
|
539
557
|
properties: {
|
|
540
|
-
scenes: { type: 'array', description: 'Complete scenes array written by the agent. Each scene: { narration, caption, visual_description, camera_hint?, music_mood?, image_path?, video_path?, audio_path?, voice? }' },
|
|
558
|
+
scenes: { type: 'array', description: 'Complete scenes array written by the agent. Each scene: { narration, caption, visual_description, html?, code?, camera_hint?, music_mood?, image_path?, video_path?, audio_path?, voice? }' },
|
|
541
559
|
title: { type: 'string', description: 'Video title' },
|
|
542
560
|
orientation: { type: 'string', enum: ['landscape', 'portrait'], default: 'landscape', description: 'Output orientation. "landscape" = 1920×1080 (16:9, YouTube/desktop). "portrait" = 1080×1920 (9:16, TikTok/Reels/Shorts).' },
|
|
543
561
|
voice: { type: 'string', description: 'edge-tts voice ID for all scenes, e.g. "ml-IN-MidhunNeural" (Malayalam male), "en-US-BrianNeural" (English). Per-scene voice field overrides this. Full list: edge-tts --list-voices' },
|
|
@@ -546,10 +564,13 @@ Example scene:
|
|
|
546
564
|
parallelism: { type: 'number', default: 1, description: 'Concurrent TTS synthesis requests (default: 1).' },
|
|
547
565
|
withMusic: { type: 'boolean', default: true },
|
|
548
566
|
musicVolume: { type: 'number', default: 0.07 },
|
|
567
|
+
topic: { type: 'string', description: 'Overall topic/genre for visual aesthetic and background motion (e.g. "Kerala history", "crypto finance", "AI robotics")' },
|
|
568
|
+
style: { type: 'string', description: 'Visual style/theme override (e.g. cinematic_documentary, finance_executive, cyber_tech, retro_synthwave, nature_organic, hype_sports, minimal_luxury, breaking_news, cosmic_space)' },
|
|
569
|
+
theme: { type: 'string', description: 'Theme preset alias' },
|
|
549
570
|
productionId: { type: 'string', description: 'Optional — reuse an existing productionId' },
|
|
550
571
|
},
|
|
551
572
|
},
|
|
552
|
-
handler: async ({ scenes, title = 'FrameForge Video', orientation = 'landscape', voice, language, skipTts = false, parallelism = 1, withMusic = true, musicVolume = 0.07, productionId }) => {
|
|
573
|
+
handler: async ({ scenes, title = 'FrameForge Video', orientation = 'landscape', voice, language, skipTts = false, parallelism = 1, withMusic = true, musicVolume = 0.07, topic = '', style = '', theme = '', productionId }) => {
|
|
553
574
|
const { runAssets } = require('../workflows/assets');
|
|
554
575
|
const { runRender } = require('../workflows/render');
|
|
555
576
|
|
|
@@ -595,6 +616,12 @@ Example scene:
|
|
|
595
616
|
video_path: s.video_path || null,
|
|
596
617
|
audio_path: s.audio_path || null,
|
|
597
618
|
voice: s.voice || null, // per-scene voice override
|
|
619
|
+
html: s.html || null,
|
|
620
|
+
code: s.code || s.animation_code || null,
|
|
621
|
+
topic: s.topic || topic || '',
|
|
622
|
+
style: s.style || style || '',
|
|
623
|
+
theme: s.theme || theme || '',
|
|
624
|
+
language: s.language || language || '',
|
|
598
625
|
character: s.character || { character_id: 'none', pose: 'none', emotion: 'neutral', position: { x: 0.5, y: 0.8, scale: 1.0 } },
|
|
599
626
|
focal_point: s.focal_point || { x: 0.5, y: 0.35, weight: 0.8 },
|
|
600
627
|
overlay: s.overlay || { type: 'none' },
|
|
@@ -608,8 +635,31 @@ Example scene:
|
|
|
608
635
|
const renderWidth = orientation === 'portrait' ? 1080 : 1920;
|
|
609
636
|
const renderHeight = orientation === 'portrait' ? 1920 : 1080;
|
|
610
637
|
|
|
611
|
-
const assetsResult = await runAssets({
|
|
612
|
-
|
|
638
|
+
const assetsResult = await runAssets({
|
|
639
|
+
productionId: pid,
|
|
640
|
+
scenes: processedScenes,
|
|
641
|
+
parallelism,
|
|
642
|
+
skipTts,
|
|
643
|
+
voice: resolvedVoice,
|
|
644
|
+
topic,
|
|
645
|
+
style,
|
|
646
|
+
theme,
|
|
647
|
+
title,
|
|
648
|
+
language,
|
|
649
|
+
});
|
|
650
|
+
const renderResult = await runRender({
|
|
651
|
+
productionId: pid,
|
|
652
|
+
sceneAssets: assetsResult.sceneAssets,
|
|
653
|
+
withMusic,
|
|
654
|
+
musicVolume,
|
|
655
|
+
renderWidth,
|
|
656
|
+
renderHeight,
|
|
657
|
+
topic,
|
|
658
|
+
style,
|
|
659
|
+
theme,
|
|
660
|
+
title,
|
|
661
|
+
language,
|
|
662
|
+
});
|
|
613
663
|
|
|
614
664
|
if (!renderResult.passed) {
|
|
615
665
|
return { productionId: pid, passed: false, qcReport: renderResult.qcReport };
|
|
@@ -1372,7 +1422,7 @@ Operations (used with action="edit"):
|
|
|
1372
1422
|
|
|
1373
1423
|
const SERVER_INFO = {
|
|
1374
1424
|
name: 'video-pipeline',
|
|
1375
|
-
version: '2.3.
|
|
1425
|
+
version: '2.3.6',
|
|
1376
1426
|
};
|
|
1377
1427
|
|
|
1378
1428
|
const CAPABILITIES = {
|