@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.
- package/.claude/settings.local.json +34 -0
- package/DESIGN.md +261 -0
- package/README.md +192 -0
- package/bin/argo.js +2 -0
- package/docs/enhancement-proposal.md +262 -0
- package/docs/superpowers/plans/2026-03-12-argo.md +208 -0
- package/docs/superpowers/plans/2026-03-12-editorial-overlay-system.md +1560 -0
- package/docs/superpowers/plans/2026-03-13-npm-rename-skill-showcase.md +499 -0
- package/docs/superpowers/specs/2026-03-13-npm-rename-skill-showcase-design.md +109 -0
- package/package.json +38 -0
- package/skills/argo-demo-creator.md +355 -0
- package/src/asset-server.ts +81 -0
- package/src/captions.ts +36 -0
- package/src/cli.ts +97 -0
- package/src/config.ts +125 -0
- package/src/export.ts +93 -0
- package/src/fixtures.ts +50 -0
- package/src/index.ts +41 -0
- package/src/init.ts +114 -0
- package/src/narration.ts +31 -0
- package/src/overlays/index.ts +54 -0
- package/src/overlays/manifest.ts +68 -0
- package/src/overlays/motion.ts +27 -0
- package/src/overlays/templates.ts +121 -0
- package/src/overlays/types.ts +73 -0
- package/src/overlays/zones.ts +82 -0
- package/src/pipeline.ts +120 -0
- package/src/record.ts +123 -0
- package/src/tts/align.ts +75 -0
- package/src/tts/cache.ts +65 -0
- package/src/tts/engine.ts +147 -0
- package/src/tts/generate.ts +83 -0
- package/src/tts/kokoro.ts +51 -0
- package/tests/asset-server.test.ts +67 -0
- package/tests/captions.test.ts +76 -0
- package/tests/cli.test.ts +131 -0
- package/tests/config.test.ts +150 -0
- package/tests/e2e/fake-server.ts +45 -0
- package/tests/e2e/record.e2e.test.ts +131 -0
- package/tests/export.test.ts +155 -0
- package/tests/fixtures.test.ts +74 -0
- package/tests/init.test.ts +77 -0
- package/tests/narration.test.ts +120 -0
- package/tests/overlays/index.test.ts +73 -0
- package/tests/overlays/manifest.test.ts +120 -0
- package/tests/overlays/motion.test.ts +34 -0
- package/tests/overlays/templates.test.ts +69 -0
- package/tests/overlays/types.test.ts +36 -0
- package/tests/overlays/zones.test.ts +49 -0
- package/tests/pipeline.test.ts +177 -0
- package/tests/record.test.ts +87 -0
- package/tests/tts/align.test.ts +118 -0
- package/tests/tts/cache.test.ts +110 -0
- package/tests/tts/engine.test.ts +204 -0
- package/tests/tts/generate.test.ts +177 -0
- package/tests/tts/kokoro.test.ts +25 -0
- 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