@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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -2
  3. package/dist/asset-server.d.ts +7 -0
  4. package/dist/asset-server.d.ts.map +1 -0
  5. package/dist/asset-server.js +69 -0
  6. package/dist/asset-server.js.map +1 -0
  7. package/dist/captions.d.ts +17 -0
  8. package/dist/captions.d.ts.map +1 -0
  9. package/dist/captions.js +23 -0
  10. package/dist/captions.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +87 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/config.d.ts +49 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +76 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/export.d.ts +19 -0
  20. package/dist/export.d.ts.map +1 -0
  21. package/dist/export.js +66 -0
  22. package/dist/export.js.map +1 -0
  23. package/dist/fixtures.d.ts +13 -0
  24. package/dist/fixtures.d.ts.map +1 -0
  25. package/dist/fixtures.js +49 -0
  26. package/dist/fixtures.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +14 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/init.d.ts +2 -0
  32. package/dist/init.d.ts.map +1 -0
  33. package/{src/init.ts → dist/init.js} +39 -54
  34. package/dist/init.js.map +1 -0
  35. package/dist/narration.d.ts +32 -0
  36. package/dist/narration.d.ts.map +1 -0
  37. package/dist/narration.js +86 -0
  38. package/dist/narration.js.map +1 -0
  39. package/dist/overlays/index.d.ts +13 -0
  40. package/dist/overlays/index.d.ts.map +1 -0
  41. package/dist/overlays/index.js +45 -0
  42. package/dist/overlays/index.js.map +1 -0
  43. package/dist/overlays/manifest.d.ts +5 -0
  44. package/dist/overlays/manifest.d.ts.map +1 -0
  45. package/dist/overlays/manifest.js +52 -0
  46. package/dist/overlays/manifest.js.map +1 -0
  47. package/dist/overlays/motion.d.ts +4 -0
  48. package/dist/overlays/motion.d.ts.map +1 -0
  49. package/dist/overlays/motion.js +25 -0
  50. package/dist/overlays/motion.js.map +1 -0
  51. package/dist/overlays/templates.d.ts +8 -0
  52. package/dist/overlays/templates.d.ts.map +1 -0
  53. package/dist/overlays/templates.js +102 -0
  54. package/dist/overlays/templates.js.map +1 -0
  55. package/dist/overlays/types.d.ts +46 -0
  56. package/dist/overlays/types.d.ts.map +1 -0
  57. package/dist/overlays/types.js +25 -0
  58. package/dist/overlays/types.js.map +1 -0
  59. package/dist/overlays/zones.d.ts +23 -0
  60. package/dist/overlays/zones.d.ts.map +1 -0
  61. package/dist/overlays/zones.js +117 -0
  62. package/dist/overlays/zones.js.map +1 -0
  63. package/dist/pipeline.d.ts +3 -0
  64. package/dist/pipeline.d.ts.map +1 -0
  65. package/dist/pipeline.js +109 -0
  66. package/dist/pipeline.js.map +1 -0
  67. package/dist/record.d.ts +15 -0
  68. package/dist/record.d.ts.map +1 -0
  69. package/dist/record.js +110 -0
  70. package/dist/record.js.map +1 -0
  71. package/dist/tts/align.d.ts +26 -0
  72. package/dist/tts/align.d.ts.map +1 -0
  73. package/dist/tts/align.js +53 -0
  74. package/dist/tts/align.js.map +1 -0
  75. package/dist/tts/cache.d.ts +31 -0
  76. package/dist/tts/cache.d.ts.map +1 -0
  77. package/dist/tts/cache.js +51 -0
  78. package/dist/tts/cache.js.map +1 -0
  79. package/dist/tts/engine.d.ts +41 -0
  80. package/dist/tts/engine.d.ts.map +1 -0
  81. package/dist/tts/engine.js +108 -0
  82. package/dist/tts/engine.js.map +1 -0
  83. package/dist/tts/generate.d.ts +21 -0
  84. package/dist/tts/generate.d.ts.map +1 -0
  85. package/dist/tts/generate.js +61 -0
  86. package/dist/tts/generate.js.map +1 -0
  87. package/dist/tts/kokoro.d.ts +30 -0
  88. package/dist/tts/kokoro.d.ts.map +1 -0
  89. package/dist/tts/kokoro.js +66 -0
  90. package/dist/tts/kokoro.js.map +1 -0
  91. package/package.json +13 -1
  92. package/.claude/settings.local.json +0 -34
  93. package/DESIGN.md +0 -261
  94. package/docs/enhancement-proposal.md +0 -262
  95. package/docs/superpowers/plans/2026-03-12-argo.md +0 -208
  96. package/docs/superpowers/plans/2026-03-12-editorial-overlay-system.md +0 -1560
  97. package/docs/superpowers/plans/2026-03-13-npm-rename-skill-showcase.md +0 -499
  98. package/docs/superpowers/specs/2026-03-13-npm-rename-skill-showcase-design.md +0 -109
  99. package/skills/argo-demo-creator.md +0 -355
  100. package/src/asset-server.ts +0 -81
  101. package/src/captions.ts +0 -36
  102. package/src/cli.ts +0 -97
  103. package/src/config.ts +0 -125
  104. package/src/export.ts +0 -93
  105. package/src/fixtures.ts +0 -50
  106. package/src/index.ts +0 -41
  107. package/src/narration.ts +0 -31
  108. package/src/overlays/index.ts +0 -54
  109. package/src/overlays/manifest.ts +0 -68
  110. package/src/overlays/motion.ts +0 -27
  111. package/src/overlays/templates.ts +0 -121
  112. package/src/overlays/types.ts +0 -73
  113. package/src/overlays/zones.ts +0 -82
  114. package/src/pipeline.ts +0 -120
  115. package/src/record.ts +0 -123
  116. package/src/tts/align.ts +0 -75
  117. package/src/tts/cache.ts +0 -65
  118. package/src/tts/engine.ts +0 -147
  119. package/src/tts/generate.ts +0 -83
  120. package/src/tts/kokoro.ts +0 -51
  121. package/tests/asset-server.test.ts +0 -67
  122. package/tests/captions.test.ts +0 -76
  123. package/tests/cli.test.ts +0 -131
  124. package/tests/config.test.ts +0 -150
  125. package/tests/e2e/fake-server.ts +0 -45
  126. package/tests/e2e/record.e2e.test.ts +0 -131
  127. package/tests/export.test.ts +0 -155
  128. package/tests/fixtures.test.ts +0 -74
  129. package/tests/init.test.ts +0 -77
  130. package/tests/narration.test.ts +0 -120
  131. package/tests/overlays/index.test.ts +0 -73
  132. package/tests/overlays/manifest.test.ts +0 -120
  133. package/tests/overlays/motion.test.ts +0 -34
  134. package/tests/overlays/templates.test.ts +0 -69
  135. package/tests/overlays/types.test.ts +0 -36
  136. package/tests/overlays/zones.test.ts +0 -49
  137. package/tests/pipeline.test.ts +0 -177
  138. package/tests/record.test.ts +0 -87
  139. package/tests/tts/align.test.ts +0 -118
  140. package/tests/tts/cache.test.ts +0 -110
  141. package/tests/tts/engine.test.ts +0 -204
  142. package/tests/tts/generate.test.ts +0 -177
  143. package/tests/tts/kokoro.test.ts +0 -25
  144. 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)