@amg555/frameforge-mcp 2.3.3 → 2.3.5
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 +44 -0
- package/README.md +3 -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 +1 -1
- 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/plugins/video-pipeline/skills/video-pipeline/references/providers.md +11 -0
- package/scripts/deep-validate.js +2 -2
- package/scripts/html-renderer/new-project.mjs +2 -2
- package/src/cli/doctor.js +12 -5
- package/src/harness/bin/harness.mjs +20 -7
- package/src/mcp-server/server.js +1 -1
- package/src/video-renderer/renderer.js +222 -60
- package/src/video-renderer/scene-animator.js +459 -0
- package/src/workflows/assets.js +4 -0
- package/src/workflows/render.js +12 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,50 @@ All notable changes to FrameForge are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [2.3.5] — 2026-11-09
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Integrated Code-Driven Scene Animator** (`src/video-renderer/scene-animator.js`):
|
|
11
|
+
- Dynamic 24fps HTML5/Canvas animation generator adhering to pure-function-of-time contract `seek(t)`
|
|
12
|
+
- Contextual motion graphic themes: Code IDE/terminal typing, Data charts & counters, Network node graphs, Flow diagrams, and floating Ken-Burns image cards
|
|
13
|
+
- Dynamic gradient backgrounds with ambient particle systems and perspective motion grids
|
|
14
|
+
- High-performance Chromium harness rendering + direct FFmpeg BT.709 H.264 VUI muxing
|
|
15
|
+
- **Full Multilingual & Malayalam Font Support**:
|
|
16
|
+
- Direct font resolver for Malayalam & Indic scripts (`Nirmala.ttc`, `Noto Sans Malayalam`, `Malayalam Sangam MN`, `Kartika`, `Meera`, `Manjari`)
|
|
17
|
+
- FFmpeg `text_shaping=1` HarfBuzz layout integration preserving complex conjuncts, chillu letters, and viramas
|
|
18
|
+
- Unicode-safe slicing and UTF-8 handling in caption and narration filters
|
|
19
|
+
- Updated `engine.css`, `engine.js`, and `new-project.mjs` typography stacks for seamless multilingual rendering
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Replaced static solid-color slideshow fallback in `renderer.js` with live code-driven animation engine
|
|
23
|
+
- Fixed `--flag value` space-separated argument parsing in `harness.mjs` CLI
|
|
24
|
+
- Fixed `--out` directory path resolution in `cmdFrames` frame exporter
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## [2.3.4] — 2026-11-09
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Full Code-Driven Video Production Harness** (`src/harness/`, `bin/harness.mjs`, `npx frameforge-harness`):
|
|
32
|
+
- H1 Browser resolution & GPU auto-selection (Direct3D11 / Metal / ANGLE)
|
|
33
|
+
- H2 Deterministic frame stepper & virtual clock injection
|
|
34
|
+
- H3 Resumable atomic frame worker pool (`.tmp` + `renameSync`, <1000B corruption checks)
|
|
35
|
+
- H4 Visual review generators: contact sheets, motion strips, 9:16 mobile crop previews
|
|
36
|
+
- H5 3-point history-leak & frame purity verification gate ($a === b \land a === c$) with `frames_sha256` digest
|
|
37
|
+
- H6 Pixel luminance and blind-spot frame math (blank, blown, corner-confined detection)
|
|
38
|
+
- H7 Determinism primitives in `engine.js` (`boilSeed`, `kf`, `onTwos`, `seg`, `pulse`, `shots`)
|
|
39
|
+
- H8 Broadcast-grade BT.709 color encoding & x264 VUI parameter tags
|
|
40
|
+
- H9 Unified CLI commands (`doctor`, `storyboard`, `verify`, `sheet`, `strip`, `crop`, `pixels`, `frames`, `encode`, `all`)
|
|
41
|
+
- **MCP `render_animation` parity**: added `verify`, `doctor`, `pixels` modes and structured `purityReport` return object.
|
|
42
|
+
- **VoxForge**: added `VOXFORGE_URL` detection to system doctor and documented in all provider tables.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- Fixed relative module imports in scaffolded projects (`./browser.mjs`, etc.).
|
|
46
|
+
- Enforced BT.709 color tags across all procedural scene fallbacks in `renderer.js`.
|
|
47
|
+
- Included `plugins/` skill templates and assets in npm package distribution.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
7
51
|
## [2.3.2] — 2026-11-06
|
|
8
52
|
|
|
9
53
|
### 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
|
|
|
@@ -219,6 +219,7 @@ Switch any provider with one `.env` change — no code changes.
|
|
|
219
219
|
| Provider | Free? | Key needed |
|
|
220
220
|
|----------|-------|------------|
|
|
221
221
|
| `edge-tts` | ✅ free, offline | none — **default** |
|
|
222
|
+
| `voxforge` | ✅ free, local/private | none — `VOXFORGE_URL` ([VoxForge](https://github.com/AMG555/VoxForge)) |
|
|
222
223
|
| `elevenlabs` | paid | `ELEVENLABS_API_KEY` |
|
|
223
224
|
| `azure` | paid | `AZURE_SPEECH_KEY` + `AZURE_SPEECH_REGION` |
|
|
224
225
|
| `openai` | paid | `OPENAI_API_KEY` |
|
|
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.5",
|
|
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",
|
|
@@ -41,7 +41,7 @@ IDE Agent (IBM Bob / Codex / opencode / Cursor / Windsurf / Claude Code)
|
|
|
41
41
|
│ LLM provider: PROVIDER_LLM=groq|openrouter|anthropic|gemini
|
|
42
42
|
│ |mistral|together|cerebras|openai
|
|
43
43
|
│ |ollama|webhook
|
|
44
|
-
│ TTS provider: PROVIDER_TTS=edge-tts|elevenlabs|azure|openai|webhook
|
|
44
|
+
│ TTS provider: PROVIDER_TTS=edge-tts|voxforge|elevenlabs|azure|openai|webhook
|
|
45
45
|
│ Visuals: Code-driven animations (default) + user media (video_path / image_path)
|
|
46
46
|
│
|
|
47
47
|
▼ Optional: queue_full_pipeline
|
|
@@ -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,
|
|
@@ -52,6 +52,17 @@ PROVIDER_TTS=edge-tts
|
|
|
52
52
|
# Voice list: edge-tts --list-voices
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
### voxforge (free, private multi-engine neural TTS & voice cloning in Rust)
|
|
56
|
+
```bash
|
|
57
|
+
PROVIDER_TTS=voxforge
|
|
58
|
+
VOXFORGE_URL=http://localhost:5005 # or your self-hosted VoxForge workstation URL
|
|
59
|
+
# Optional:
|
|
60
|
+
VOXFORGE_KEY=... # optional auth token if enabled
|
|
61
|
+
VOXFORGE_VOICE=default # voice/clone reference
|
|
62
|
+
VOXFORGE_MODEL=voxforge-v1 # engine model (XTTS, Piper, Kokoro, Whisper)
|
|
63
|
+
```
|
|
64
|
+
Repo: [AMG555/VoxForge](https://github.com/AMG555/VoxForge) — local, private neural TTS & voice cloning workstation.
|
|
65
|
+
|
|
55
66
|
### elevenlabs (voice cloning)
|
|
56
67
|
```bash
|
|
57
68
|
PROVIDER_TTS=elevenlabs
|
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.5', code.includes("version: '2.3.5'"));
|
|
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.5', cfWorker.includes("'2.3.5'"));
|
|
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/doctor.js
CHANGED
|
@@ -73,19 +73,26 @@ if (ffprobe.status === 0) {
|
|
|
73
73
|
hasCriticalFailure = true;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// 4. Voice Engine (edge-tts or Cloud API)
|
|
76
|
+
// 4. Voice Engine (edge-tts, VoxForge, or Cloud API)
|
|
77
77
|
const edgeTts = spawnSync('edge-tts', ['--version'], { encoding: 'utf8', timeout: 5000, shell: process.platform === 'win32' });
|
|
78
|
-
const hasCloudTts = Boolean(
|
|
78
|
+
const hasCloudTts = Boolean(
|
|
79
|
+
process.env.ELEVENLABS_API_KEY ||
|
|
80
|
+
process.env.AZURE_SPEECH_KEY ||
|
|
81
|
+
process.env.OPENAI_API_KEY ||
|
|
82
|
+
process.env.CUSTOM_TTS_URL ||
|
|
83
|
+
process.env.WEBHOOK_TTS_URL ||
|
|
84
|
+
process.env.VOXFORGE_URL
|
|
85
|
+
);
|
|
79
86
|
|
|
80
87
|
if (edgeTts.status === 0) {
|
|
81
88
|
pass('Voice Engine', `edge-tts CLI available (${(edgeTts.stdout || '').trim()})`);
|
|
82
89
|
} else if (hasCloudTts) {
|
|
83
|
-
pass('Voice Engine', 'Cloud
|
|
90
|
+
pass('Voice Engine', 'TTS provider (VoxForge or Cloud API) configured via environment');
|
|
84
91
|
} else {
|
|
85
92
|
warn(
|
|
86
93
|
'Voice Engine',
|
|
87
|
-
'Neither edge-tts CLI nor
|
|
88
|
-
'Run "pip install edge-tts" for free offline voiceover, or set OPENAI_API_KEY / ELEVENLABS_API_KEY in .env'
|
|
94
|
+
'Neither edge-tts CLI nor configured TTS provider detected',
|
|
95
|
+
'Run "pip install edge-tts" for free offline voiceover, set VOXFORGE_URL (VoxForge), or set OPENAI_API_KEY / ELEVENLABS_API_KEY in .env'
|
|
89
96
|
);
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -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),
|