@argo-video/cli 0.1.0

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.
Files changed (57) hide show
  1. package/.claude/settings.local.json +34 -0
  2. package/DESIGN.md +261 -0
  3. package/README.md +192 -0
  4. package/bin/argo.js +2 -0
  5. package/docs/enhancement-proposal.md +262 -0
  6. package/docs/superpowers/plans/2026-03-12-argo.md +208 -0
  7. package/docs/superpowers/plans/2026-03-12-editorial-overlay-system.md +1560 -0
  8. package/docs/superpowers/plans/2026-03-13-npm-rename-skill-showcase.md +499 -0
  9. package/docs/superpowers/specs/2026-03-13-npm-rename-skill-showcase-design.md +109 -0
  10. package/package.json +38 -0
  11. package/skills/argo-demo-creator.md +355 -0
  12. package/src/asset-server.ts +81 -0
  13. package/src/captions.ts +36 -0
  14. package/src/cli.ts +97 -0
  15. package/src/config.ts +125 -0
  16. package/src/export.ts +93 -0
  17. package/src/fixtures.ts +50 -0
  18. package/src/index.ts +41 -0
  19. package/src/init.ts +114 -0
  20. package/src/narration.ts +31 -0
  21. package/src/overlays/index.ts +54 -0
  22. package/src/overlays/manifest.ts +68 -0
  23. package/src/overlays/motion.ts +27 -0
  24. package/src/overlays/templates.ts +121 -0
  25. package/src/overlays/types.ts +73 -0
  26. package/src/overlays/zones.ts +82 -0
  27. package/src/pipeline.ts +120 -0
  28. package/src/record.ts +123 -0
  29. package/src/tts/align.ts +75 -0
  30. package/src/tts/cache.ts +65 -0
  31. package/src/tts/engine.ts +147 -0
  32. package/src/tts/generate.ts +83 -0
  33. package/src/tts/kokoro.ts +51 -0
  34. package/tests/asset-server.test.ts +67 -0
  35. package/tests/captions.test.ts +76 -0
  36. package/tests/cli.test.ts +131 -0
  37. package/tests/config.test.ts +150 -0
  38. package/tests/e2e/fake-server.ts +45 -0
  39. package/tests/e2e/record.e2e.test.ts +131 -0
  40. package/tests/export.test.ts +155 -0
  41. package/tests/fixtures.test.ts +74 -0
  42. package/tests/init.test.ts +77 -0
  43. package/tests/narration.test.ts +120 -0
  44. package/tests/overlays/index.test.ts +73 -0
  45. package/tests/overlays/manifest.test.ts +120 -0
  46. package/tests/overlays/motion.test.ts +34 -0
  47. package/tests/overlays/templates.test.ts +69 -0
  48. package/tests/overlays/types.test.ts +36 -0
  49. package/tests/overlays/zones.test.ts +49 -0
  50. package/tests/pipeline.test.ts +177 -0
  51. package/tests/record.test.ts +87 -0
  52. package/tests/tts/align.test.ts +118 -0
  53. package/tests/tts/cache.test.ts +110 -0
  54. package/tests/tts/engine.test.ts +204 -0
  55. package/tests/tts/generate.test.ts +177 -0
  56. package/tests/tts/kokoro.test.ts +25 -0
  57. package/tsconfig.json +19 -0
@@ -0,0 +1,34 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git add:*)",
5
+ "Bash(git commit:*)",
6
+ "Bash(gh repo:*)",
7
+ "Bash(gh api:*)",
8
+ "Bash(/Users/shreyas/work/rnd/argo/bin/argo.js:*)",
9
+ "Bash(chmod +x /Users/shreyas/work/rnd/argo/bin/argo.js)",
10
+ "Bash(npm install:*)",
11
+ "Bash(npx tsc:*)",
12
+ "Bash(ls /Users/shreyas/work/rnd/argo/src/ /Users/shreyas/work/rnd/argo/tests/ 2>/dev/null; ls /Users/shreyas/work/rnd/argo/vitest.config.* 2>/dev/null)",
13
+ "Bash(npx vitest:*)",
14
+ "Bash(CI=true npx vitest run tests/tts/kokoro.test.ts 2>&1)",
15
+ "mcp__plugin_context7_context7__resolve-library-id",
16
+ "mcp__plugin_context7_context7__query-docs",
17
+ "Bash(node -e \"\nimport\\('@huggingface/transformers'\\).then\\(async \\(m\\) => {\n // Check what task maps to what\n console.log\\('SUPPORTED_TASKS keys that include audio or speech:'\\);\n const keys = Object.keys\\(m\\).filter\\(k => k.toLowerCase\\(\\).includes\\('task'\\) || k.toLowerCase\\(\\).includes\\('mapping'\\)\\);\n console.log\\(keys.slice\\(0, 20\\)\\);\n}\\).catch\\(e => console.error\\(e.message\\)\\);\n\" 2>&1)",
18
+ "Bash(node -e \"\nimport\\('@huggingface/transformers'\\).then\\(async \\(m\\) => {\n try {\n const p = await m.pipeline\\('text-to-audio', 'onnx-community/Kokoro-82M-v1.0-ONNX', { dtype: 'fp32' }\\);\n console.log\\('SUCCESS with text-to-audio'\\);\n } catch\\(e\\) {\n console.log\\('text-to-audio error:', e.message\\);\n }\n}\\).catch\\(e => console.error\\(e.message\\)\\);\n\" 2>&1)",
19
+ "Bash(npm ls:*)",
20
+ "Bash(npm run:*)",
21
+ "Bash(node bin/argo.js init 2>&1)",
22
+ "Bash(node bin/argo.js --help 2>&1)",
23
+ "Bash(rm -rf demos argo.config.ts && node bin/argo.js init 2>&1)",
24
+ "Bash(git rm:*)",
25
+ "Bash(rm -f argo.config.ts argo.config.js && rm -rf demos/ && npm run build 2>&1 && node bin/argo.js init 2>&1)",
26
+ "Bash(node -e \"import\\('./dist/config.js'\\).then\\(m => m.loadConfig\\(process.cwd\\(\\)\\)\\).then\\(c => console.log\\(JSON.stringify\\(c, null, 2\\)\\)\\)\" 2>&1)",
27
+ "Bash(rm -rf demos argo.config.* playwright.config.ts && npm run build 2>&1 && node bin/argo.js init 2>&1)",
28
+ "Bash(node bin/argo.js record example 2>&1)",
29
+ "Bash(npx playwright:*)",
30
+ "Bash(npm link:*)",
31
+ "Bash(node bin/argo.js pipeline example 2>&1)"
32
+ ]
33
+ }
34
+ }
package/DESIGN.md ADDED
@@ -0,0 +1,261 @@
1
+ # Argo — Playwright Demo Recording with Voiceover
2
+
3
+ **Date:** 2026-03-12
4
+ **Status:** Draft
5
+
6
+ ## Overview
7
+
8
+ Argo is a standalone, open-source tool that turns Playwright scripts into polished product demo videos with AI-generated voiceover. Developers author demo scripts using Playwright fixtures; anyone can regenerate the final video with a single CLI command.
9
+
10
+ The pipeline: **TTS** (Kokoro generates voiceover clips via Transformers.js, cached) → **record** (Playwright captures video + scene timestamps) → **align** (clips placed at recorded timestamps) → **export** (ffmpeg merges video + audio into MP4).
11
+
12
+ ## Target Users
13
+
14
+ - **Developers** author demo scripts using Playwright's familiar test API
15
+ - **Non-developers** (marketing, DevRel) regenerate videos via CLI without touching code
16
+
17
+ ## Architecture
18
+
19
+ ### Library + CLI
20
+
21
+ Argo ships as a single package with two interfaces:
22
+
23
+ **Library** — Playwright fixtures and helpers for authoring demos:
24
+ - `test`, `expect` — re-exported Playwright fixtures with `narration` auto-injected
25
+ - `NarrationTimeline` — low-level control for manual usage
26
+ - `showCaption`, `hideCaption`, `withCaption` — DOM caption helpers
27
+ - `defineConfig` — creates a full Argo config with sensible defaults
28
+ - `demosProject` — creates a Playwright project entry for integration into existing configs
29
+
30
+ **CLI** — pipeline commands anyone can run:
31
+ - `argo record <demo>` — run Playwright for a specific demo
32
+ - `argo tts generate <manifest>` — generate TTS clips from `.voiceover.json`
33
+ - `argo tts align <demo>` — align clips to recording timestamps
34
+ - `argo export <demo>` — merge video + audio via ffmpeg
35
+ - `argo pipeline <demo>` — all steps end-to-end
36
+ - `argo init` — scaffold demo files + config into a project
37
+
38
+ ### Project Layout
39
+
40
+ ```
41
+ argo/
42
+ ├── src/
43
+ │ ├── index.ts # Library exports
44
+ │ ├── cli.ts # CLI entry point
45
+ │ ├── fixtures.ts # Playwright test fixture (injects narration)
46
+ │ ├── narration.ts # NarrationTimeline class
47
+ │ ├── captions.ts # DOM caption overlay helpers
48
+ │ ├── tts/
49
+ │ │ ├── engine.ts # TTSEngine interface
50
+ │ │ ├── kokoro.ts # Default Kokoro via @huggingface/transformers
51
+ │ │ └── align.ts # Timestamp alignment logic
52
+ │ ├── export.ts # ffmpeg video+audio merge
53
+ │ ├── pipeline.ts # Orchestrates record→tts→align→export
54
+ │ └── config.ts # defineConfig helper + defaults
55
+ ├── bin/
56
+ │ └── argo.js # CLI bin entry
57
+ ├── package.json
58
+ └── tsconfig.json
59
+ ```
60
+
61
+ ### Dependencies
62
+
63
+ - `playwright` — recording engine (peer dependency)
64
+ - `@huggingface/transformers@next` — Kokoro TTS via ONNX in Node.js
65
+ - `ffmpeg` — system dependency for video export (not bundled)
66
+
67
+ No Python required. The entire pipeline runs in Node.js.
68
+
69
+ **ffmpeg detection:** All CLI commands that need ffmpeg (`export`, `pipeline`) check for it on startup and exit with a clear error message + install instructions if missing.
70
+
71
+ ## Authoring API
72
+
73
+ A demo consists of two files:
74
+
75
+ ### Demo Script (`demos/onboarding.demo.ts`)
76
+
77
+ ```ts
78
+ import { test, demoType } from 'argo';
79
+
80
+ test('onboarding', async ({ page, narration }) => {
81
+ // narration.start() is called automatically by the fixture before the test runs
82
+ await page.goto('/');
83
+
84
+ // Show caption + record scene timestamp
85
+ await narration.showCaption(page, 'welcome', 'Welcome to our app', 3000);
86
+
87
+ // Caption around an action
88
+ await narration.withCaption(page, 'signup', 'Sign up in seconds', async () => {
89
+ await page.fill('[name=email]', 'demo@example.com');
90
+ await demoType(page, '[name=password]', 'supersecure');
91
+ });
92
+
93
+ // Timestamp-only scene (no visible caption, used for voiceover alignment)
94
+ narration.mark('dashboard-loaded');
95
+ });
96
+ ```
97
+
98
+ **Constraints:** Each demo file must contain exactly one `test()` block (one video per demo). Use separate demo files for separate videos.
99
+
100
+ **Key API:**
101
+ - `narration.showCaption(page, scene, text, durationMs)` — show overlay + record timestamp
102
+ - `narration.withCaption(page, scene, text, action)` — wrap action with caption
103
+ - `narration.mark(scene)` — record timestamp without visual
104
+ - `demoType(page, selector, text)` — standalone helper, slow-types for demo effect (60ms/char)
105
+ - `narration.start()` — sets timestamp zero; called automatically by fixture before each test
106
+ - `narration.flush()` — writes `.timing.json`; called automatically by fixture after each test
107
+
108
+ ### Voiceover Manifest (`demos/onboarding.voiceover.json`)
109
+
110
+ ```json
111
+ [
112
+ {
113
+ "scene": "welcome",
114
+ "text": "Welcome to Acme — get started in under a minute."
115
+ },
116
+ {
117
+ "scene": "signup",
118
+ "text": "Just enter your email and choose a password.",
119
+ "speed": 0.9
120
+ },
121
+ {
122
+ "scene": "dashboard-loaded",
123
+ "text": "And you're in.",
124
+ "voice": "af_heart"
125
+ }
126
+ ]
127
+ ```
128
+
129
+ Scene names link the manifest to the demo script. `voice` and `speed` are optional (defaults from config).
130
+
131
+ ### Config (`argo.config.ts`, optional)
132
+
133
+ The CLI looks for `argo.config.ts` (or `.js`, `.mjs`) in the current working directory. Override with `--config <path>` on any CLI command.
134
+
135
+ ```ts
136
+ import { defineConfig } from 'argo';
137
+
138
+ export default defineConfig({
139
+ baseURL: 'http://localhost:3000',
140
+ demosDir: 'demos/',
141
+ outputDir: 'videos/',
142
+ tts: {
143
+ defaultVoice: 'af_heart',
144
+ defaultSpeed: 1.0,
145
+ // engine: myCustomTTSEngine
146
+ },
147
+ video: {
148
+ width: 2560,
149
+ height: 1440,
150
+ fps: 30,
151
+ },
152
+ export: {
153
+ preset: 'slow',
154
+ crf: 16,
155
+ },
156
+ });
157
+ ```
158
+
159
+ ## TTS System
160
+
161
+ ### Default Engine: Kokoro via Transformers.js
162
+
163
+ - Uses `@huggingface/transformers@next` with ONNX Kokoro model
164
+ - Runs in Node.js — no Python, no GPU
165
+ - Model downloaded on first run (~80MB ONNX), cached locally
166
+ - Generates one WAV clip per scene
167
+
168
+ ### Alignment
169
+
170
+ 1. Recording produces `.timing.json` (scene name → millisecond timestamp)
171
+ 2. Aligner reads `.timing.json` + clip durations
172
+ 3. Places each clip at its scene's recorded timestamp
173
+ 4. Prevents overlap — clips pushed forward with 100ms minimum gap
174
+ 5. Outputs single `narration-aligned.wav` matching video duration
175
+
176
+ ### Plugin Interface
177
+
178
+ ```ts
179
+ interface TTSEngine {
180
+ generate(text: string, options: {
181
+ voice?: string;
182
+ speed?: number;
183
+ lang?: string;
184
+ }): Promise<Buffer>;
185
+ // Must return a complete WAV file (with headers).
186
+ // Required format: mono, 24kHz, 32-bit float.
187
+ // Argo will resample if needed, but matching this format avoids overhead.
188
+ }
189
+ ```
190
+
191
+ Custom engines (ElevenLabs, OpenAI TTS, Piper, etc.) implement this single method. Argo validates the returned WAV headers and resamples to 24kHz mono if the format doesn't match.
192
+
193
+ ### Clip Caching
194
+
195
+ Clips stored in `.argo/<demoName>/clips/`. Each clip is keyed by a hash of its manifest entry (`scene` + `text` + `voice` + `speed`). When a clip's entry hasn't changed, the cached WAV is reused. When an entry changes (different text, voice, or speed), only that clip is regenerated. This is per-entry, not per-file — reordering entries or changing one scene doesn't invalidate others.
196
+
197
+ ## Recording
198
+
199
+ - `argo record` runs Playwright with the demos project config
200
+ - Uses Playwright's default VP8 encoder (no patching)
201
+ - Higher quality achieved during export via ffmpeg re-encoding
202
+ - Output: `video.webm` + `.timing.json` in `.argo/<demoName>/`
203
+
204
+ ## Export
205
+
206
+ - ffmpeg merges video + aligned audio
207
+ - Re-encodes to `libx264` (compensates for VP8's lower quality)
208
+ - Default: preset slow, crf 16, AAC audio @ 192k
209
+ - Configurable via `argo.config.ts` or CLI flags (`--crf`, `--preset`, `--fps`, `--width`, `--height`)
210
+ - Uses `-shortest` so audio trims to video length
211
+ - Output: `<outputDir>/<demoName>.mp4`
212
+
213
+ ## Pipeline
214
+
215
+ `argo pipeline <demo>` chains all steps:
216
+
217
+ ```
218
+ 1. Generate TTS clips (skip if cached & manifest unchanged)
219
+ 2. Record demo via Playwright → .webm + .timing.json
220
+ 3. Align clips to timestamps → narration-aligned.wav
221
+ 4. Export → final .mp4
222
+ ```
223
+
224
+ Each step is independently runnable.
225
+
226
+ ## `argo init`
227
+
228
+ Scaffolds into an existing project:
229
+ - Creates `demos/` directory
230
+ - Generates sample `example.demo.ts` and `example.voiceover.json`
231
+ - Creates starter `argo.config.ts`
232
+ - Adds `demos` project to `playwright.config.ts` (or creates one) using `defineConfig`
233
+ - Prints next steps
234
+
235
+ ## Playwright Integration
236
+
237
+ Two modes:
238
+
239
+ **Standalone** — Argo provides its own Playwright config via `defineConfig`. Users just install and point at their app URL. `argo init` sets this up.
240
+
241
+ **Integrated** — Power users add a `demos` project to their existing `playwright.config.ts` using the exported config helper:
242
+
243
+ ```ts
244
+ import { demosProject } from 'argo';
245
+
246
+ export default defineConfig({
247
+ projects: [
248
+ // ... existing projects
249
+ demosProject({ baseURL: 'http://localhost:3000' }),
250
+ ],
251
+ });
252
+ ```
253
+
254
+ ## Out of Scope (v1)
255
+
256
+ - Post-render subtitle burn-in via ffmpeg (future enhancement)
257
+ - npm registry publishing
258
+ - Non-Playwright backends (Puppeteer, Cypress)
259
+ - Video editing (cuts, transitions, zooms)
260
+ - Background music / audio mixing
261
+ - GUI / visual editor
package/README.md ADDED
@@ -0,0 +1,192 @@
1
+ ```
2
+ ___
3
+ _____ / /
4
+ / _ | _ __ __ _ ___ / /
5
+ / /_| | | '__|/ _` |/ _ \ / /
6
+ / ___ | | | | (_| | (_) |/ /
7
+ /__/ |_| |_| \__, |\___//__/
8
+ __/ |
9
+ |___/
10
+ ```
11
+
12
+ # @argo-video/cli
13
+
14
+ **Turn Playwright demo scripts into polished product demo videos with AI voiceover.**
15
+
16
+ Write a demo script with Playwright. Add a voiceover manifest. Run one command. Get an MP4 with overlays and narration.
17
+
18
+ ## Showcase
19
+
20
+ <video src="videos/showcase.mp4" width="100%" controls autoplay muted></video>
21
+
22
+ > *This demo was recorded by Argo, using Argo. Yes, really.*
23
+
24
+ ## How it works
25
+
26
+ ```
27
+ TTS Record Align Export
28
+ ─── ────── ───── ──────
29
+ Kokoro Playwright Place clips ffmpeg
30
+ generates captures at scene merges
31
+ voice browser + timestamps video +
32
+ clips scene marks audio
33
+ │ │
34
+ ▼ ▼
35
+ .voiceover.json → narration-aligned.wav → final.mp4
36
+ ```
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ # Install
42
+ npm i -D @argo-video/cli
43
+
44
+ # Initialize project
45
+ npx argo init
46
+
47
+ # Edit your demo script
48
+ vim demos/example.demo.ts
49
+
50
+ # Run the full pipeline
51
+ npx argo pipeline example
52
+
53
+ # Or run steps individually
54
+ npx argo record example
55
+ npx argo tts generate demos/example.voiceover.json
56
+ npx argo export example
57
+ ```
58
+
59
+ ## Writing a demo
60
+
61
+ A demo is two files: a **script** and a **voiceover manifest**.
62
+
63
+ ### Demo script (`demos/my-feature.demo.ts`)
64
+
65
+ ```ts
66
+ import { test } from '@argo-video/cli';
67
+ import { showCaption, withCaption } from '@argo-video/cli';
68
+
69
+ test('my-feature', async ({ page, narration }) => {
70
+ await page.goto('/');
71
+
72
+ narration.mark('intro');
73
+ await showCaption(page, 'intro', 'Welcome to our product', 3000);
74
+
75
+ narration.mark('action');
76
+ await withCaption(page, 'action', 'Watch this', async () => {
77
+ await page.click('#get-started');
78
+ await page.waitForTimeout(2000);
79
+ });
80
+
81
+ narration.mark('done');
82
+ await showCaption(page, 'done', 'That\'s it!', 2000);
83
+ });
84
+ ```
85
+
86
+ ### Voiceover manifest (`demos/my-feature.voiceover.json`)
87
+
88
+ ```json
89
+ [
90
+ { "scene": "intro", "text": "Welcome to our product — let me show you around." },
91
+ { "scene": "action", "text": "Just click get started and you're off." },
92
+ { "scene": "done", "text": "And that's all there is to it.", "voice": "af_heart" }
93
+ ]
94
+ ```
95
+
96
+ Each `scene` in the manifest maps to a `narration.mark()` call in the script. Argo records the timestamp of each mark, generates TTS clips, and aligns them to produce the final narrated video.
97
+
98
+ ## Configuration
99
+
100
+ ### `argo.config.js`
101
+
102
+ ```js
103
+ export default {
104
+ baseURL: 'http://localhost:3000',
105
+ demosDir: 'demos/',
106
+ outputDir: 'videos/',
107
+ tts: { defaultVoice: 'af_heart', defaultSpeed: 1.0 },
108
+ video: { width: 1920, height: 1080, fps: 30 },
109
+ export: { preset: 'slow', crf: 16 },
110
+ };
111
+ ```
112
+
113
+ ### `playwright.config.ts`
114
+
115
+ Argo scaffolds this for you via `argo init`. The key settings:
116
+
117
+ ```ts
118
+ import { defineConfig } from '@playwright/test';
119
+
120
+ export default defineConfig({
121
+ preserveOutput: 'always',
122
+ projects: [{
123
+ name: 'demos',
124
+ testDir: 'demos',
125
+ testMatch: '**/*.demo.ts',
126
+ use: {
127
+ baseURL: process.env.BASE_URL || 'http://localhost:3000',
128
+ viewport: { width: 1920, height: 1080 },
129
+ video: { mode: 'on', size: { width: 1920, height: 1080 } },
130
+ },
131
+ }],
132
+ });
133
+ ```
134
+
135
+ ## CLI
136
+
137
+ ```
138
+ argo init Scaffold demo files + config
139
+ argo record <demo> Record browser session
140
+ argo tts generate <manifest> Generate TTS clips from manifest
141
+ argo export <demo> Merge video + audio to MP4
142
+ argo pipeline <demo> Run all steps end-to-end
143
+ argo --config <path> <command> Use a custom config file
144
+ ```
145
+
146
+ ## API
147
+
148
+ Argo exports Playwright fixtures and helpers for use in demo scripts:
149
+
150
+ ```ts
151
+ import { test, expect, demoType } from '@argo-video/cli';
152
+ import { showCaption, hideCaption, withCaption } from '@argo-video/cli';
153
+ import { defineConfig, demosProject } from '@argo-video/cli';
154
+ ```
155
+
156
+ | Export | Description |
157
+ |--------|-------------|
158
+ | `test` | Playwright `test` with `narration` fixture injected |
159
+ | `expect` | Re-exported from Playwright |
160
+ | `demoType(page, selector, text, delay?)` | Type text character-by-character (cinematic) |
161
+ | `showCaption(page, scene, text, durationMs)` | Show a caption overlay for a duration |
162
+ | `withCaption(page, scene, text, action)` | Show caption during an async action |
163
+ | `hideCaption(page)` | Remove caption overlay |
164
+ | `defineConfig(userConfig)` | Create config with defaults |
165
+ | `demosProject(options)` | Create Playwright project entry |
166
+
167
+ ## Requirements
168
+
169
+ - **Node.js** >= 18
170
+ - **Playwright** >= 1.40 (peer dependency)
171
+ - **ffmpeg** — system install required for export
172
+
173
+ ```bash
174
+ # Install ffmpeg
175
+ brew install ffmpeg # macOS
176
+ apt install ffmpeg # Linux
177
+ choco install ffmpeg # Windows
178
+ ```
179
+
180
+ ## How the pipeline works
181
+
182
+ 1. **TTS** — Kokoro (via `kokoro-js`) generates WAV clips from the voiceover manifest. Clips are cached by content hash in `.argo/<demo>/clips/` so regeneration is instant if text hasn't changed.
183
+
184
+ 2. **Record** — Playwright runs the demo script in a real browser. The `narration` fixture records timestamps for each `mark()` call. Video is captured at native resolution.
185
+
186
+ 3. **Align** — Each TTS clip is placed at its scene's recorded timestamp. Overlapping clips are pushed forward with a 100ms gap. All clips are mixed into a single `narration-aligned.wav`.
187
+
188
+ 4. **Export** — ffmpeg combines the screen recording (WebM) with the aligned narration (WAV) into an H.264 MP4.
189
+
190
+ ## License
191
+
192
+ MIT
package/bin/argo.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/cli.js');