@argo-video/cli 0.1.0 → 0.2.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/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/asset-server.d.ts +7 -0
- package/dist/asset-server.d.ts.map +1 -0
- package/dist/asset-server.js +69 -0
- package/dist/asset-server.js.map +1 -0
- package/dist/captions.d.ts +17 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +23 -0
- package/dist/captions.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +87 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +49 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +76 -0
- package/dist/config.js.map +1 -0
- package/dist/export.d.ts +19 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +66 -0
- package/dist/export.js.map +1 -0
- package/dist/fixtures.d.ts +13 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +49 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.d.ts.map +1 -0
- package/{src/init.ts → dist/init.js} +39 -54
- package/dist/init.js.map +1 -0
- package/dist/narration.d.ts +32 -0
- package/dist/narration.d.ts.map +1 -0
- package/dist/narration.js +86 -0
- package/dist/narration.js.map +1 -0
- package/dist/overlays/index.d.ts +13 -0
- package/dist/overlays/index.d.ts.map +1 -0
- package/dist/overlays/index.js +45 -0
- package/dist/overlays/index.js.map +1 -0
- package/dist/overlays/manifest.d.ts +5 -0
- package/dist/overlays/manifest.d.ts.map +1 -0
- package/dist/overlays/manifest.js +52 -0
- package/dist/overlays/manifest.js.map +1 -0
- package/dist/overlays/motion.d.ts +4 -0
- package/dist/overlays/motion.d.ts.map +1 -0
- package/dist/overlays/motion.js +25 -0
- package/dist/overlays/motion.js.map +1 -0
- package/dist/overlays/templates.d.ts +8 -0
- package/dist/overlays/templates.d.ts.map +1 -0
- package/dist/overlays/templates.js +102 -0
- package/dist/overlays/templates.js.map +1 -0
- package/dist/overlays/types.d.ts +46 -0
- package/dist/overlays/types.d.ts.map +1 -0
- package/dist/overlays/types.js +25 -0
- package/dist/overlays/types.js.map +1 -0
- package/dist/overlays/zones.d.ts +23 -0
- package/dist/overlays/zones.d.ts.map +1 -0
- package/dist/overlays/zones.js +117 -0
- package/dist/overlays/zones.js.map +1 -0
- package/dist/pipeline.d.ts +3 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +109 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/record.d.ts +15 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +110 -0
- package/dist/record.js.map +1 -0
- package/dist/tts/align.d.ts +26 -0
- package/dist/tts/align.d.ts.map +1 -0
- package/dist/tts/align.js +53 -0
- package/dist/tts/align.js.map +1 -0
- package/dist/tts/cache.d.ts +31 -0
- package/dist/tts/cache.d.ts.map +1 -0
- package/dist/tts/cache.js +51 -0
- package/dist/tts/cache.js.map +1 -0
- package/dist/tts/engine.d.ts +41 -0
- package/dist/tts/engine.d.ts.map +1 -0
- package/dist/tts/engine.js +108 -0
- package/dist/tts/engine.js.map +1 -0
- package/dist/tts/generate.d.ts +21 -0
- package/dist/tts/generate.d.ts.map +1 -0
- package/dist/tts/generate.js +61 -0
- package/dist/tts/generate.js.map +1 -0
- package/dist/tts/kokoro.d.ts +30 -0
- package/dist/tts/kokoro.d.ts.map +1 -0
- package/dist/tts/kokoro.js +66 -0
- package/dist/tts/kokoro.js.map +1 -0
- package/package.json +13 -1
- package/.claude/settings.local.json +0 -34
- package/DESIGN.md +0 -261
- package/docs/enhancement-proposal.md +0 -262
- package/docs/superpowers/plans/2026-03-12-argo.md +0 -208
- package/docs/superpowers/plans/2026-03-12-editorial-overlay-system.md +0 -1560
- package/docs/superpowers/plans/2026-03-13-npm-rename-skill-showcase.md +0 -499
- package/docs/superpowers/specs/2026-03-13-npm-rename-skill-showcase-design.md +0 -109
- package/skills/argo-demo-creator.md +0 -355
- package/src/asset-server.ts +0 -81
- package/src/captions.ts +0 -36
- package/src/cli.ts +0 -97
- package/src/config.ts +0 -125
- package/src/export.ts +0 -93
- package/src/fixtures.ts +0 -50
- package/src/index.ts +0 -41
- package/src/narration.ts +0 -31
- package/src/overlays/index.ts +0 -54
- package/src/overlays/manifest.ts +0 -68
- package/src/overlays/motion.ts +0 -27
- package/src/overlays/templates.ts +0 -121
- package/src/overlays/types.ts +0 -73
- package/src/overlays/zones.ts +0 -82
- package/src/pipeline.ts +0 -120
- package/src/record.ts +0 -123
- package/src/tts/align.ts +0 -75
- package/src/tts/cache.ts +0 -65
- package/src/tts/engine.ts +0 -147
- package/src/tts/generate.ts +0 -83
- package/src/tts/kokoro.ts +0 -51
- package/tests/asset-server.test.ts +0 -67
- package/tests/captions.test.ts +0 -76
- package/tests/cli.test.ts +0 -131
- package/tests/config.test.ts +0 -150
- package/tests/e2e/fake-server.ts +0 -45
- package/tests/e2e/record.e2e.test.ts +0 -131
- package/tests/export.test.ts +0 -155
- package/tests/fixtures.test.ts +0 -74
- package/tests/init.test.ts +0 -77
- package/tests/narration.test.ts +0 -120
- package/tests/overlays/index.test.ts +0 -73
- package/tests/overlays/manifest.test.ts +0 -120
- package/tests/overlays/motion.test.ts +0 -34
- package/tests/overlays/templates.test.ts +0 -69
- package/tests/overlays/types.test.ts +0 -36
- package/tests/overlays/zones.test.ts +0 -49
- package/tests/pipeline.test.ts +0 -177
- package/tests/record.test.ts +0 -87
- package/tests/tts/align.test.ts +0 -118
- package/tests/tts/cache.test.ts +0 -110
- package/tests/tts/engine.test.ts +0 -204
- package/tests/tts/generate.test.ts +0 -177
- package/tests/tts/kokoro.test.ts +0 -25
- package/tsconfig.json +0 -19
package/DESIGN.md
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
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
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
# Enhancement Proposal: Editorial Overlay System
|
|
2
|
-
|
|
3
|
-
## Summary
|
|
4
|
-
|
|
5
|
-
Argo's current caption system renders a single bottom-centered text pill. That's enough for narration subtitles but not for editorial demo videos where text feels composed into the frame — headline cards with kicker/title/body hierarchy, callout annotations, image-backed panels at different screen positions.
|
|
6
|
-
|
|
7
|
-
This proposal evolves `src/captions.ts` from a single-style caption helper into a zone-based overlay system with pluggable templates.
|
|
8
|
-
|
|
9
|
-
## Goals
|
|
10
|
-
|
|
11
|
-
- Make captions feel designed, not appended.
|
|
12
|
-
- Support editorial overlays: headline cards, callouts, image-backed panels.
|
|
13
|
-
- Keep narration timing and overlay visuals separate so demos stay easy to author.
|
|
14
|
-
- Preserve the simple default path — `showCaption` and `withCaption` continue to work unchanged.
|
|
15
|
-
|
|
16
|
-
## Current System
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
captions.ts
|
|
20
|
-
├── OVERLAY_ID = 'argo-caption-overlay' ← single element, replaced on each call
|
|
21
|
-
├── CAPTION_STYLES = { ... } ← one hardcoded style object
|
|
22
|
-
├── injectOverlay(page, text) ← creates div, sets textContent + styles
|
|
23
|
-
├── showCaption(page, scene, text, dur) ← inject → wait → remove
|
|
24
|
-
├── withCaption(page, scene, text, action) ← inject → action → remove (try/finally)
|
|
25
|
-
└── hideCaption(page) ← remove by ID
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Limitations:
|
|
29
|
-
- One overlay type, one placement, one visual treatment.
|
|
30
|
-
- Single DOM element — showing a new caption removes the previous one globally.
|
|
31
|
-
- No support for images, rich cards, or animation.
|
|
32
|
-
- No way to have two overlays visible simultaneously (e.g., subtitle + headline card).
|
|
33
|
-
|
|
34
|
-
## Design Decisions
|
|
35
|
-
|
|
36
|
-
### Zone-based coexistence
|
|
37
|
-
|
|
38
|
-
Overlays are placed into **zones**. Each zone is a screen region that holds at most one overlay at a time. Showing an overlay in a zone automatically replaces any existing overlay in that zone, but overlays in different zones coexist independently.
|
|
39
|
-
|
|
40
|
-
Zones:
|
|
41
|
-
- `bottom-center` (default — current caption position)
|
|
42
|
-
- `top-left`
|
|
43
|
-
- `top-right`
|
|
44
|
-
- `bottom-left`
|
|
45
|
-
- `bottom-right`
|
|
46
|
-
- `center`
|
|
47
|
-
|
|
48
|
-
DOM IDs become `argo-overlay-{zone}` instead of the current single `argo-caption-overlay`.
|
|
49
|
-
|
|
50
|
-
This gives editorial power (subtitle + headline card visible simultaneously) without requiring manual dismissal of every overlay.
|
|
51
|
-
|
|
52
|
-
### Asset injection via local server
|
|
53
|
-
|
|
54
|
-
Image overlays (`image-card`) reference local files like `assets/diagram.png`. These need to be accessible inside the Playwright browser context.
|
|
55
|
-
|
|
56
|
-
**Approach: local asset server.** A tiny HTTP server (same pattern as the E2E fake server) serves files from the project's asset directory during recording. It starts automatically before `record` and stops after.
|
|
57
|
-
|
|
58
|
-
Why not base64 data URIs: a 2MB screenshot becomes ~2.7MB of serialized DOM, slowing `page.evaluate`. Asset server keeps the DOM clean and scales to many images.
|
|
59
|
-
|
|
60
|
-
### Templates, not a theme system
|
|
61
|
-
|
|
62
|
-
v1 ships with hardcoded visual presets per template — no theme tokens. Each template has one opinionated look that works well on dark and light backgrounds. Theme customization (typography, colors, spacing tokens) is a future enhancement once real usage patterns emerge.
|
|
63
|
-
|
|
64
|
-
### Motion: two presets only
|
|
65
|
-
|
|
66
|
-
CSS animations during Playwright recording are frame-rate dependent. v1 supports two safe presets:
|
|
67
|
-
- `fade-in` — opacity 0→1 over 300ms
|
|
68
|
-
- `slide-in` — translateX + opacity over 400ms
|
|
69
|
-
|
|
70
|
-
Staggered multi-element reveals (kicker, then title, then body) are deferred to v2 — they require careful timing coordination that's hard to get right at variable recording FPS.
|
|
71
|
-
|
|
72
|
-
## Overlay Templates
|
|
73
|
-
|
|
74
|
-
### `lower-third` (default)
|
|
75
|
-
|
|
76
|
-
The current caption style, refined. Bottom-center translucent pill with text.
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
┌─────────────────────────────────────────┐
|
|
80
|
-
│ │
|
|
81
|
-
│ │
|
|
82
|
-
│ │
|
|
83
|
-
│ ┌─────────────────────────────┐ │
|
|
84
|
-
│ │ Caption text here │ │
|
|
85
|
-
│ └─────────────────────────────┘ │
|
|
86
|
-
└─────────────────────────────────────────┘
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Fields: `text`
|
|
90
|
-
|
|
91
|
-
### `headline-card`
|
|
92
|
-
|
|
93
|
-
A card with optional kicker (small caps label), title (large), and body (smaller). Backdrop blur + translucent background.
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
┌─────────────────────────────────────────┐
|
|
97
|
-
│ ┌──────────────────────┐ │
|
|
98
|
-
│ │ KICKER LABEL │ │
|
|
99
|
-
│ │ Title text here │ │
|
|
100
|
-
│ │ Body text here │ │
|
|
101
|
-
│ └──────────────────────┘ │
|
|
102
|
-
│ │
|
|
103
|
-
└─────────────────────────────────────────┘
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Fields: `kicker?`, `title`, `body?`
|
|
107
|
-
|
|
108
|
-
### `callout`
|
|
109
|
-
|
|
110
|
-
A compact annotation bubble for pointing out UI elements. Meant for short text.
|
|
111
|
-
|
|
112
|
-
Fields: `text`
|
|
113
|
-
|
|
114
|
-
### `image-card`
|
|
115
|
-
|
|
116
|
-
An image with optional title and body caption below it. Image loaded from the asset server.
|
|
117
|
-
|
|
118
|
-
```
|
|
119
|
-
┌─────────────────────────────────────────┐
|
|
120
|
-
│ ┌─────────────────┐ │
|
|
121
|
-
│ │ ┌───────────┐ │ │
|
|
122
|
-
│ │ │ image │ │ │
|
|
123
|
-
│ │ └───────────┘ │ │
|
|
124
|
-
│ │ Title │ │
|
|
125
|
-
│ │ Body text │ │
|
|
126
|
-
│ └─────────────────┘ │
|
|
127
|
-
└─────────────────────────────────────────┘
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Fields: `src`, `title?`, `body?`
|
|
131
|
-
|
|
132
|
-
## Authoring Model
|
|
133
|
-
|
|
134
|
-
### Overlay manifest (`demos/example.overlays.json`)
|
|
135
|
-
|
|
136
|
-
A new file, separate from the voiceover manifest. Maps scenes to overlay cues.
|
|
137
|
-
|
|
138
|
-
```json
|
|
139
|
-
[
|
|
140
|
-
{
|
|
141
|
-
"scene": "intro",
|
|
142
|
-
"type": "lower-third",
|
|
143
|
-
"text": "Hacker News — the front page of the internet"
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"scene": "browse",
|
|
147
|
-
"type": "headline-card",
|
|
148
|
-
"placement": "top-left",
|
|
149
|
-
"kicker": "LOCAL EXECUTION",
|
|
150
|
-
"title": "WebGPU + Transformers.js",
|
|
151
|
-
"body": "Models cache after first load.",
|
|
152
|
-
"motion": "slide-in"
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
"scene": "rerank",
|
|
156
|
-
"type": "image-card",
|
|
157
|
-
"placement": "top-right",
|
|
158
|
-
"src": "assets/rerank-diagram.png",
|
|
159
|
-
"title": "Cross-encoder reranking"
|
|
160
|
-
}
|
|
161
|
-
]
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
Rules:
|
|
165
|
-
- `scene` links to `narration.mark()` calls in the demo script.
|
|
166
|
-
- `type` selects the template. Default: `lower-third`.
|
|
167
|
-
- `placement` selects the zone. Default: `bottom-center`.
|
|
168
|
-
- `motion` selects the entrance animation. Default: none (instant appear).
|
|
169
|
-
- Template-specific fields (`kicker`, `title`, `body`, `src`, `text`) vary by type.
|
|
170
|
-
|
|
171
|
-
### Programmatic API
|
|
172
|
-
|
|
173
|
-
The existing `showCaption`/`withCaption` API stays unchanged as sugar for `lower-third` overlays. New overlays are shown via a new function:
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
import { showOverlay, hideOverlay, withOverlay } from 'argo';
|
|
177
|
-
|
|
178
|
-
// Show a headline card in the top-left zone
|
|
179
|
-
await showOverlay(page, 'browse', {
|
|
180
|
-
type: 'headline-card',
|
|
181
|
-
placement: 'top-left',
|
|
182
|
-
kicker: 'LOCAL EXECUTION',
|
|
183
|
-
title: 'WebGPU + Transformers.js',
|
|
184
|
-
motion: 'slide-in',
|
|
185
|
-
}, 4000);
|
|
186
|
-
|
|
187
|
-
// Hide a specific zone
|
|
188
|
-
await hideOverlay(page, 'top-left');
|
|
189
|
-
|
|
190
|
-
// Overlay around an action
|
|
191
|
-
await withOverlay(page, 'rerank', {
|
|
192
|
-
type: 'image-card',
|
|
193
|
-
placement: 'top-right',
|
|
194
|
-
src: 'assets/diagram.png',
|
|
195
|
-
title: 'Reranking pipeline',
|
|
196
|
-
}, async () => {
|
|
197
|
-
await page.click('.rerank-button');
|
|
198
|
-
});
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Backward compatibility: `showCaption(page, scene, text, dur)` becomes equivalent to `showOverlay(page, scene, { type: 'lower-third', text }, dur)`.
|
|
202
|
-
|
|
203
|
-
### Auto-overlay from manifest
|
|
204
|
-
|
|
205
|
-
When a `<demo>.overlays.json` file exists alongside the voiceover manifest, the recording fixture automatically injects overlays at their matching `narration.mark()` timestamps. This means users can define overlays purely in JSON without touching the demo script — the programmatic API is for advanced use only.
|
|
206
|
-
|
|
207
|
-
## Implementation Plan
|
|
208
|
-
|
|
209
|
-
### Phase 1: Zone-based overlay renderer
|
|
210
|
-
|
|
211
|
-
1. Refactor `src/captions.ts` → `src/overlays.ts`
|
|
212
|
-
- Replace single `OVERLAY_ID` with `argo-overlay-{zone}` scheme
|
|
213
|
-
- Extract template rendering into a `renderTemplate(type, fields)` → HTML+styles function
|
|
214
|
-
- Implement `lower-third` template (current caption style, now zone-aware)
|
|
215
|
-
- Implement `showOverlay`, `hideOverlay`, `withOverlay`
|
|
216
|
-
- Re-export `showCaption`, `withCaption`, `hideCaption` as thin wrappers
|
|
217
|
-
|
|
218
|
-
2. Add CSS animation injection for `fade-in` and `slide-in` presets
|
|
219
|
-
|
|
220
|
-
3. Update `src/index.ts` exports
|
|
221
|
-
|
|
222
|
-
### Phase 2: Editorial templates
|
|
223
|
-
|
|
224
|
-
4. Implement `headline-card` template (kicker + title + body, backdrop blur)
|
|
225
|
-
5. Implement `callout` template
|
|
226
|
-
6. Implement `image-card` template
|
|
227
|
-
|
|
228
|
-
### Phase 3: Asset server + image support
|
|
229
|
-
|
|
230
|
-
7. Extract `tests/e2e/fake-server.ts` pattern into `src/asset-server.ts`
|
|
231
|
-
- Serves files from a configurable asset directory
|
|
232
|
-
- Auto-starts before recording, auto-stops after
|
|
233
|
-
- Only starts if an overlay manifest references image assets
|
|
234
|
-
|
|
235
|
-
8. Wire asset server URL into `image-card` template `src` resolution
|
|
236
|
-
|
|
237
|
-
### Phase 4: Manifest-driven overlays
|
|
238
|
-
|
|
239
|
-
9. Define overlay manifest schema and loader in `src/overlays/manifest.ts`
|
|
240
|
-
10. Wire manifest loading into the recording fixture
|
|
241
|
-
- If `<demo>.overlays.json` exists, auto-inject overlays at matching scene marks
|
|
242
|
-
|
|
243
|
-
### Phase 5: Polish
|
|
244
|
-
|
|
245
|
-
11. Update `argo init` templates with overlay examples
|
|
246
|
-
12. Update README with overlay documentation
|
|
247
|
-
13. Add tests for each template, zone management, and manifest loading
|
|
248
|
-
|
|
249
|
-
## Migration
|
|
250
|
-
|
|
251
|
-
- `showCaption`, `withCaption`, `hideCaption` remain exported and unchanged.
|
|
252
|
-
- Existing demos work without modification.
|
|
253
|
-
- The overlay manifest is optional — demos without one behave exactly as before.
|
|
254
|
-
- `src/captions.ts` is replaced by `src/overlays.ts` but all original exports are preserved.
|
|
255
|
-
|
|
256
|
-
## Out of Scope (v1)
|
|
257
|
-
|
|
258
|
-
- Theme tokens / custom styling
|
|
259
|
-
- Staggered multi-element animation
|
|
260
|
-
- Overlay transitions (exit animations)
|
|
261
|
-
- Overlay positioning relative to DOM elements (e.g., "anchor to this button")
|
|
262
|
-
- Video-time overlays via ffmpeg (all overlays render in-browser during recording)
|