@argo-video/cli 0.1.0 → 0.1.1

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 +66 -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 +44 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +74 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/export.d.ts +18 -0
  20. package/dist/export.d.ts.map +1 -0
  21. package/dist/export.js +64 -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 +36 -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 +9 -0
  36. package/dist/narration.d.ts.map +1 -0
  37. package/dist/narration.js +27 -0
  38. package/dist/narration.js.map +1 -0
  39. package/dist/overlays/index.d.ts +8 -0
  40. package/dist/overlays/index.d.ts.map +1 -0
  41. package/dist/overlays/index.js +34 -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 +7 -0
  52. package/dist/overlays/templates.d.ts.map +1 -0
  53. package/dist/overlays/templates.js +98 -0
  54. package/dist/overlays/templates.js.map +1 -0
  55. package/dist/overlays/types.d.ts +42 -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 +15 -0
  60. package/dist/overlays/zones.d.ts.map +1 -0
  61. package/dist/overlays/zones.js +69 -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 +93 -0
  66. package/dist/pipeline.js.map +1 -0
  67. package/dist/record.d.ts +14 -0
  68. package/dist/record.d.ts.map +1 -0
  69. package/dist/record.js +100 -0
  70. package/dist/record.js.map +1 -0
  71. package/dist/tts/align.d.ts +17 -0
  72. package/dist/tts/align.d.ts.map +1 -0
  73. package/dist/tts/align.js +40 -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 +20 -0
  84. package/dist/tts/generate.d.ts.map +1 -0
  85. package/dist/tts/generate.js +58 -0
  86. package/dist/tts/generate.js.map +1 -0
  87. package/dist/tts/kokoro.d.ts +13 -0
  88. package/dist/tts/kokoro.d.ts.map +1 -0
  89. package/dist/tts/kokoro.js +46 -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
@@ -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)
@@ -1,208 +0,0 @@
1
- # Argo Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** Build Argo — a CLI + library that turns Playwright demo scripts into polished product demo videos with AI-generated voiceover.
6
-
7
- **Architecture:** Four-stage pipeline (TTS → Record → Align → Export) orchestrated by a CLI. Library exports Playwright fixtures and helpers for authoring demos. Kokoro TTS via Transformers.js for local voiceover generation, ffmpeg for final video export.
8
-
9
- **Tech Stack:** TypeScript, Playwright, @huggingface/transformers (Kokoro TTS), ffmpeg (system dep), commander (CLI), vitest (testing)
10
-
11
- ---
12
-
13
- ## File Structure
14
-
15
- ```
16
- argo/
17
- ├── src/
18
- │ ├── index.ts # Public library exports
19
- │ ├── cli.ts # CLI entry point — commander program
20
- │ ├── fixtures.ts # Playwright test fixture (injects narration)
21
- │ ├── narration.ts # NarrationTimeline class
22
- │ ├── captions.ts # DOM caption overlay helpers
23
- │ ├── tts/
24
- │ │ ├── engine.ts # TTSEngine interface + WAV utilities + MockTTSEngine
25
- │ │ ├── kokoro.ts # Kokoro TTS via @huggingface/transformers
26
- │ │ ├── cache.ts # ClipCache — SHA-256 content-addressed caching
27
- │ │ ├── generate.ts # generateClips — reads manifest, checks cache, calls engine
28
- │ │ └── align.ts # Clip alignment with overlap prevention
29
- │ ├── record.ts # Playwright recording wrapper
30
- │ ├── export.ts # ffmpeg video+audio merge
31
- │ ├── pipeline.ts # Orchestrates TTS→record→align→export
32
- │ ├── config.ts # ArgoConfig type, defineConfig(), loadConfig(), demosProject()
33
- │ └── init.ts # Scaffolding: creates demos/, example files, config
34
- ├── tests/
35
- │ ├── config.test.ts
36
- │ ├── narration.test.ts
37
- │ ├── captions.test.ts
38
- │ ├── fixtures.test.ts
39
- │ ├── export.test.ts
40
- │ ├── pipeline.test.ts
41
- │ ├── cli.test.ts
42
- │ ├── init.test.ts
43
- │ └── tts/
44
- │ ├── engine.test.ts
45
- │ ├── kokoro.test.ts
46
- │ ├── cache.test.ts
47
- │ ├── generate.test.ts
48
- │ └── align.test.ts
49
- ├── bin/
50
- │ └── argo.js # CLI bin shim
51
- ├── package.json
52
- ├── tsconfig.json
53
- └── .gitignore
54
- ```
55
-
56
- ---
57
-
58
- ## Chunk 1: Foundation (Tasks 1-4)
59
-
60
- ### Task 1: Project Setup
61
-
62
- **Files:** Create: `package.json`, `tsconfig.json`, `bin/argo.js`, `.gitignore`, `src/index.ts`, `src/cli.ts`
63
-
64
- - [ ] **Step 1.1:** Create package.json with type: module, ESM config, dependencies (commander, @huggingface/transformers), peer deps (playwright, @playwright/test), dev deps (typescript, vitest)
65
- - [ ] **Step 1.2:** Create tsconfig.json (target ES2022, module NodeNext, outDir dist, strict)
66
- - [ ] **Step 1.3:** Create bin/argo.js shim: `#!/usr/bin/env node` + `import('../dist/cli.js')`
67
- - [ ] **Step 1.4:** Create .gitignore (node_modules, dist, .argo, videos, *.tsbuildinfo)
68
- - [ ] **Step 1.5:** Create placeholder src/index.ts and src/cli.ts
69
- - [ ] **Step 1.6:** npm install and verify tsc --noEmit passes
70
- - [ ] **Step 1.7:** Commit: "chore: project setup with deps, tsconfig, and bin shim"
71
-
72
- ### Task 2: Config System
73
-
74
- **Files:** Create: `src/config.ts`, Test: `tests/config.test.ts`
75
-
76
- - [ ] **Step 2.1:** Write failing tests for defineConfig (defaults, merging, custom engine), demosProject (returns Playwright project), loadConfig (defaults, .js, .mjs, explicit path)
77
- - [ ] **Step 2.2:** Run tests — verify they fail
78
- - [ ] **Step 2.3:** Implement ArgoConfig types, defineConfig (deep merge with defaults), demosProject helper, loadConfig (searches for argo.config.ts/.js/.mjs, dynamic import)
79
- - [ ] **Step 2.4:** Run tests — verify they pass
80
- - [ ] **Step 2.5:** Commit: "feat: config system with defineConfig, loadConfig, and demosProject"
81
-
82
- ### Task 3: NarrationTimeline
83
-
84
- **Files:** Create: `src/narration.ts`, Test: `tests/narration.test.ts`
85
-
86
- - [ ] **Step 3.1:** Write failing tests: start sets t=0, mark records elapsed ms, mark throws before start, mark throws on duplicate, getTimings returns copy, flush writes JSON and creates dirs
87
- - [ ] **Step 3.2:** Run tests — verify they fail
88
- - [ ] **Step 3.3:** Implement NarrationTimeline with Map-based timings, Date.now() tracking
89
- - [ ] **Step 3.4:** Run tests — verify they pass
90
- - [ ] **Step 3.5:** Commit: "feat: NarrationTimeline with start, mark, getTimings, and flush"
91
-
92
- ### Task 4: Caption Helpers
93
-
94
- **Files:** Create: `src/captions.ts`, Test: `tests/captions.test.ts`
95
-
96
- - [ ] **Step 4.1:** Write failing tests: showCaption injects+waits+removes, hideCaption removes, withCaption wraps action, withCaption cleans up on throw
97
- - [ ] **Step 4.2:** Run tests — verify they fail
98
- - [ ] **Step 4.3:** Implement showCaption/hideCaption/withCaption using page.evaluate with styled overlay div
99
- - [ ] **Step 4.4:** Run tests — verify they pass
100
- - [ ] **Step 4.5:** Commit: "feat: caption helpers (showCaption, hideCaption, withCaption)"
101
-
102
- ---
103
-
104
- ## Chunk 2: TTS System (Tasks 5-8)
105
-
106
- ### Task 5: TTS Engine Interface + WAV Utilities
107
-
108
- **Files:** Create: `src/tts/engine.ts`, Test: `tests/tts/engine.test.ts`
109
-
110
- - [ ] **Step 5.1:** Write failing tests: createWavBuffer (valid header, correct data size, preserves samples), parseWavHeader (round-trip, rejects small/invalid), MockTTSEngine (interface compliance, valid WAV, records calls)
111
- - [ ] **Step 5.2:** Run tests — verify they fail
112
- - [ ] **Step 5.3:** Implement TTSEngine interface, createWavBuffer (mono 24kHz 32-bit float), parseWavHeader (find data chunk), createMockTTSEngine
113
- - [ ] **Step 5.4:** Run tests — verify they pass
114
- - [ ] **Step 5.5:** Commit: "feat(tts): TTSEngine interface, WAV utilities, and MockTTSEngine"
115
-
116
- ### Task 6: Kokoro TTS Engine
117
-
118
- **Files:** Create: `src/tts/kokoro.ts`, Test: `tests/tts/kokoro.test.ts`
119
-
120
- - [ ] **Step 6.1:** Implement KokoroEngine: lazy-loads pipeline from @huggingface/transformers, generates WAV via createWavBuffer
121
- - [ ] **Step 6.2:** Write integration test (skipped in CI): generates valid WAV, throws on empty text
122
- - [ ] **Step 6.3:** Commit: "feat(tts): KokoroEngine with lazy model loading"
123
-
124
- ### Task 7: Clip Caching
125
-
126
- **Files:** Create: `src/tts/cache.ts`, Test: `tests/tts/cache.test.ts`
127
-
128
- - [ ] **Step 7.1:** Write failing tests: isCached false/true, getCachedClip null/buffer, invalidation on text/voice/speed change, independent per demo
129
- - [ ] **Step 7.2:** Run tests — verify they fail
130
- - [ ] **Step 7.3:** Implement ClipCache: SHA-256 hash of {scene,text,voice,speed}, stores in .argo/<demo>/clips/<hash>.wav
131
- - [ ] **Step 7.4:** Run tests — verify they pass
132
- - [ ] **Step 7.5:** Commit: "feat(tts): ClipCache with SHA-256 content-addressed caching"
133
-
134
- ### Task 8: TTS Generate Command
135
-
136
- **Files:** Create: `src/tts/generate.ts`, Test: `tests/tts/generate.test.ts`
137
-
138
- - [ ] **Step 8.1:** Write failing tests: generates all entries, uses cache on rerun, regenerates only changed, applies defaults, throws on missing file/invalid JSON/missing fields
139
- - [ ] **Step 8.2:** Run tests — verify they fail
140
- - [ ] **Step 8.3:** Implement generateClips: read manifest, validate entries, check cache, call engine, cache results
141
- - [ ] **Step 8.4:** Run tests — verify they pass
142
- - [ ] **Step 8.5:** Commit: "feat(tts): generateClips with manifest parsing and cache integration"
143
-
144
- ---
145
-
146
- ## Chunk 3: Recording & Alignment (Tasks 9-10)
147
-
148
- ### Task 9: Playwright Fixtures
149
-
150
- **Files:** Create: `src/fixtures.ts`, Test: `tests/fixtures.test.ts`
151
-
152
- - [ ] **Step 9.1:** Write failing tests: createNarrationFixture (creates timeline, starts, provides, flushes; flushes on throw), demoType (types with delay, custom delay)
153
- - [ ] **Step 9.2:** Run tests — verify they fail
154
- - [ ] **Step 9.3:** Implement createNarrationFixture factory, demoType helper (pressSequentially), test.extend with narration fixture
155
- - [ ] **Step 9.4:** Run tests — verify they pass
156
- - [ ] **Step 9.5:** Commit: "feat: Playwright fixtures with narration injection and demoType"
157
-
158
- ### Task 10: Alignment
159
-
160
- **Files:** Create: `src/tts/align.ts`, Test: `tests/tts/align.test.ts`
161
-
162
- - [ ] **Step 10.1:** Write failing tests: places clips at timestamps, prevents overlap with 100ms gap, correct output buffer duration, mixes samples at correct positions, handles empty, orders by timestamp, skips unknown scenes
163
- - [ ] **Step 10.2:** Run tests — verify they fail
164
- - [ ] **Step 10.3:** Implement alignClips: filter/sort by timing, overlap prevention, create silence buffer, mix samples
165
- - [ ] **Step 10.4:** Run tests — verify they pass
166
- - [ ] **Step 10.5:** Commit: "feat(tts): clip alignment with overlap prevention and sample mixing"
167
-
168
- ---
169
-
170
- ## Chunk 4: Export, Pipeline, CLI & Init (Tasks 11-14)
171
-
172
- ### Task 11: Export (ffmpeg)
173
-
174
- **Files:** Create: `src/export.ts`, Test: `tests/export.test.ts`
175
-
176
- - [ ] **Step 11.1:** Write failing tests: checkFfmpeg (available/missing), exportVideo (correct args, custom config, missing files, non-zero exit)
177
- - [ ] **Step 11.2:** Run tests — verify they fail
178
- - [ ] **Step 11.3:** Implement checkFfmpeg (execSync ffmpeg -version), exportVideo (spawnSync with -c:v libx264 -preset -crf -c:a aac -shortest)
179
- - [ ] **Step 11.4:** Run tests — verify they pass
180
- - [ ] **Step 11.5:** Commit: "feat: ffmpeg export with configurable encoding options"
181
-
182
- ### Task 12: Pipeline Orchestration
183
-
184
- **Files:** Create: `src/pipeline.ts`, Test: `tests/pipeline.test.ts`
185
-
186
- - [ ] **Step 12.1:** Write failing tests: calls all steps in order (tts → record → export), checks ffmpeg first
187
- - [ ] **Step 12.2:** Implement runPipeline: checkFfmpeg, then generateClips → record → alignClips → exportVideo with console progress
188
- - [ ] **Step 12.3:** Run tests — verify they pass
189
- - [ ] **Step 12.4:** Commit: "feat: pipeline orchestration for end-to-end demo generation"
190
-
191
- ### Task 13: CLI
192
-
193
- **Files:** Create: `src/cli.ts`, Test: `tests/cli.test.ts`
194
-
195
- - [ ] **Step 13.1:** Write failing tests: record/tts generate/tts align/export/pipeline/init commands call correct functions, --config passes to loadConfig
196
- - [ ] **Step 13.2:** Implement createProgram with commander: all commands as thin wrappers that load config and delegate
197
- - [ ] **Step 13.3:** Run tests — verify they pass
198
- - [ ] **Step 13.4:** Commit: "feat: CLI with commander for all pipeline commands"
199
-
200
- ### Task 14: Init + Library Exports
201
-
202
- **Files:** Create: `src/init.ts`, Modify: `src/index.ts`, Test: `tests/init.test.ts`
203
-
204
- - [ ] **Step 14.1:** Write failing tests: creates demos/, example.demo.ts, example.voiceover.json, argo.config.ts; does not overwrite existing
205
- - [ ] **Step 14.2:** Implement init: writeIfMissing for each scaffold file with template content
206
- - [ ] **Step 14.3:** Update src/index.ts: export test, expect, demoType, NarrationTimeline, showCaption, hideCaption, withCaption, defineConfig, demosProject, TTSEngine type
207
- - [ ] **Step 14.4:** Run all tests: `npx vitest run`
208
- - [ ] **Step 14.5:** Commit: "feat: init scaffolding and complete library exports"