videowright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/README.md +91 -0
  2. package/dist/cli/argv.d.ts +28 -0
  3. package/dist/cli/argv.d.ts.map +1 -0
  4. package/dist/cli/argv.js +115 -0
  5. package/dist/cli/argv.js.map +1 -0
  6. package/dist/cli/bin.d.ts +7 -0
  7. package/dist/cli/bin.d.ts.map +1 -0
  8. package/dist/cli/bin.js +10 -0
  9. package/dist/cli/bin.js.map +1 -0
  10. package/dist/cli/dev.d.ts +19 -0
  11. package/dist/cli/dev.d.ts.map +1 -0
  12. package/dist/cli/dev.js +104 -0
  13. package/dist/cli/dev.js.map +1 -0
  14. package/dist/cli/discover.d.ts +29 -0
  15. package/dist/cli/discover.d.ts.map +1 -0
  16. package/dist/cli/discover.js +104 -0
  17. package/dist/cli/discover.js.map +1 -0
  18. package/dist/cli/discover_project.d.ts +29 -0
  19. package/dist/cli/discover_project.d.ts.map +1 -0
  20. package/dist/cli/discover_project.js +108 -0
  21. package/dist/cli/discover_project.js.map +1 -0
  22. package/dist/cli/errors.d.ts +10 -0
  23. package/dist/cli/errors.d.ts.map +1 -0
  24. package/dist/cli/errors.js +13 -0
  25. package/dist/cli/errors.js.map +1 -0
  26. package/dist/cli/ffmpeg.d.ts +57 -0
  27. package/dist/cli/ffmpeg.d.ts.map +1 -0
  28. package/dist/cli/ffmpeg.js +122 -0
  29. package/dist/cli/ffmpeg.js.map +1 -0
  30. package/dist/cli/index.d.ts +7 -0
  31. package/dist/cli/index.d.ts.map +1 -0
  32. package/dist/cli/index.js +152 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/playwright_check.d.ts +44 -0
  35. package/dist/cli/playwright_check.d.ts.map +1 -0
  36. package/dist/cli/playwright_check.js +20 -0
  37. package/dist/cli/playwright_check.js.map +1 -0
  38. package/dist/cli/prompt.d.ts +13 -0
  39. package/dist/cli/prompt.d.ts.map +1 -0
  40. package/dist/cli/prompt.js +47 -0
  41. package/dist/cli/prompt.js.map +1 -0
  42. package/dist/cli/render.d.ts +60 -0
  43. package/dist/cli/render.d.ts.map +1 -0
  44. package/dist/cli/render.js +471 -0
  45. package/dist/cli/render.js.map +1 -0
  46. package/dist/cli/script_cmd.d.ts +26 -0
  47. package/dist/cli/script_cmd.d.ts.map +1 -0
  48. package/dist/cli/script_cmd.js +88 -0
  49. package/dist/cli/script_cmd.js.map +1 -0
  50. package/dist/cli/time_shim.d.ts +44 -0
  51. package/dist/cli/time_shim.d.ts.map +1 -0
  52. package/dist/cli/time_shim.js +390 -0
  53. package/dist/cli/time_shim.js.map +1 -0
  54. package/dist/cli/ts_loader.d.ts +28 -0
  55. package/dist/cli/ts_loader.d.ts.map +1 -0
  56. package/dist/cli/ts_loader.js +95 -0
  57. package/dist/cli/ts_loader.js.map +1 -0
  58. package/dist/cli/vite_helpers.d.ts +62 -0
  59. package/dist/cli/vite_helpers.d.ts.map +1 -0
  60. package/dist/cli/vite_helpers.js +273 -0
  61. package/dist/cli/vite_helpers.js.map +1 -0
  62. package/dist/index.d.ts +11 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +14 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/player/hash_router.d.ts +23 -0
  67. package/dist/player/hash_router.d.ts.map +1 -0
  68. package/dist/player/hash_router.js +49 -0
  69. package/dist/player/hash_router.js.map +1 -0
  70. package/dist/player/hud.d.ts +33 -0
  71. package/dist/player/hud.d.ts.map +1 -0
  72. package/dist/player/hud.js +357 -0
  73. package/dist/player/hud.js.map +1 -0
  74. package/dist/player/index.d.ts +123 -0
  75. package/dist/player/index.d.ts.map +1 -0
  76. package/dist/player/index.js +848 -0
  77. package/dist/player/index.js.map +1 -0
  78. package/dist/player/input.d.ts +14 -0
  79. package/dist/player/input.d.ts.map +1 -0
  80. package/dist/player/input.js +90 -0
  81. package/dist/player/input.js.map +1 -0
  82. package/dist/player/slot.d.ts +22 -0
  83. package/dist/player/slot.d.ts.map +1 -0
  84. package/dist/player/slot.js +43 -0
  85. package/dist/player/slot.js.map +1 -0
  86. package/dist/player/transitions/cut.d.ts +7 -0
  87. package/dist/player/transitions/cut.d.ts.map +1 -0
  88. package/dist/player/transitions/cut.js +9 -0
  89. package/dist/player/transitions/cut.js.map +1 -0
  90. package/dist/player/transitions/fade.d.ts +7 -0
  91. package/dist/player/transitions/fade.d.ts.map +1 -0
  92. package/dist/player/transitions/fade.js +18 -0
  93. package/dist/player/transitions/fade.js.map +1 -0
  94. package/dist/player/transitions/index.d.ts +4 -0
  95. package/dist/player/transitions/index.d.ts.map +1 -0
  96. package/dist/player/transitions/index.js +4 -0
  97. package/dist/player/transitions/index.js.map +1 -0
  98. package/dist/player/transitions/slide.d.ts +6 -0
  99. package/dist/player/transitions/slide.d.ts.map +1 -0
  100. package/dist/player/transitions/slide.js +35 -0
  101. package/dist/player/transitions/slide.js.map +1 -0
  102. package/dist/script/index.d.ts +2 -0
  103. package/dist/script/index.d.ts.map +1 -0
  104. package/dist/script/index.js +2 -0
  105. package/dist/script/index.js.map +1 -0
  106. package/dist/script/script.d.ts +10 -0
  107. package/dist/script/script.d.ts.map +1 -0
  108. package/dist/script/script.js +41 -0
  109. package/dist/script/script.js.map +1 -0
  110. package/dist/segment/SegmentRunner.d.ts +52 -0
  111. package/dist/segment/SegmentRunner.d.ts.map +1 -0
  112. package/dist/segment/SegmentRunner.js +187 -0
  113. package/dist/segment/SegmentRunner.js.map +1 -0
  114. package/dist/segment/defineConfig.d.ts +6 -0
  115. package/dist/segment/defineConfig.d.ts.map +1 -0
  116. package/dist/segment/defineConfig.js +7 -0
  117. package/dist/segment/defineConfig.js.map +1 -0
  118. package/dist/segment/defineSegment.d.ts +7 -0
  119. package/dist/segment/defineSegment.d.ts.map +1 -0
  120. package/dist/segment/defineSegment.js +25 -0
  121. package/dist/segment/defineSegment.js.map +1 -0
  122. package/dist/segment/index.d.ts +5 -0
  123. package/dist/segment/index.d.ts.map +1 -0
  124. package/dist/segment/index.js +4 -0
  125. package/dist/segment/index.js.map +1 -0
  126. package/dist/timeline/index.d.ts +73 -0
  127. package/dist/timeline/index.d.ts.map +1 -0
  128. package/dist/timeline/index.js +142 -0
  129. package/dist/timeline/index.js.map +1 -0
  130. package/dist/timeline/loadAudioTrack.d.ts +18 -0
  131. package/dist/timeline/loadAudioTrack.d.ts.map +1 -0
  132. package/dist/timeline/loadAudioTrack.js +44 -0
  133. package/dist/timeline/loadAudioTrack.js.map +1 -0
  134. package/dist/timeline/loadVoiceover.d.ts +18 -0
  135. package/dist/timeline/loadVoiceover.d.ts.map +1 -0
  136. package/dist/timeline/loadVoiceover.js +38 -0
  137. package/dist/timeline/loadVoiceover.js.map +1 -0
  138. package/dist/timeline/resolveTiming.d.ts +28 -0
  139. package/dist/timeline/resolveTiming.d.ts.map +1 -0
  140. package/dist/timeline/resolveTiming.js +63 -0
  141. package/dist/timeline/resolveTiming.js.map +1 -0
  142. package/dist/timeline/validateTiming.d.ts +29 -0
  143. package/dist/timeline/validateTiming.d.ts.map +1 -0
  144. package/dist/timeline/validateTiming.js +62 -0
  145. package/dist/timeline/validateTiming.js.map +1 -0
  146. package/dist/types.d.ts +216 -0
  147. package/dist/types.d.ts.map +1 -0
  148. package/dist/types.js +6 -0
  149. package/dist/types.js.map +1 -0
  150. package/package.json +47 -0
  151. package/skill/SKILL.md +64 -0
  152. package/skill/assets/hello_world/PLAN.md +31 -0
  153. package/skill/assets/hello_world/README.md +27 -0
  154. package/skill/assets/hello_world/audio/audio_plan.md +14 -0
  155. package/skill/assets/hello_world/segments/hello_intro.ts +69 -0
  156. package/skill/assets/hello_world/segments/hello_outro.ts +71 -0
  157. package/skill/assets/hello_world/timeline.ts +15 -0
  158. package/skill/assets/hello_world/voiceover_script/script.md +10 -0
  159. package/skill/assets/install/package.json +10 -0
  160. package/skill/assets/install/tsconfig.json +23 -0
  161. package/skill/assets/styles/editorial-mono/STYLE.md +124 -0
  162. package/skill/assets/styles/editorial-mono/brand.md +85 -0
  163. package/skill/assets/styles/editorial-mono/reference/animations.jsx +752 -0
  164. package/skill/assets/styles/editorial-mono/reference/scenes.html +563 -0
  165. package/skill/assets/styles/editorial-mono/sample/bullet.ts +101 -0
  166. package/skill/assets/styles/editorial-mono/sample/content.ts +104 -0
  167. package/skill/assets/styles/editorial-mono/sample/cta.ts +113 -0
  168. package/skill/assets/styles/editorial-mono/sample/feature.ts +111 -0
  169. package/skill/assets/styles/editorial-mono/sample/grid.ts +97 -0
  170. package/skill/assets/styles/editorial-mono/sample/kinetic.ts +96 -0
  171. package/skill/assets/styles/editorial-mono/sample/section.ts +101 -0
  172. package/skill/assets/styles/editorial-mono/sample/stat.ts +128 -0
  173. package/skill/assets/styles/editorial-mono/sample/title.ts +97 -0
  174. package/skill/assets/styles/editorial-mono/sample/ui-showcase.ts +159 -0
  175. package/skill/assets/styles/editorial-mono/tokens.css +44 -0
  176. package/skill/assets/styles/iso-diagram/STYLE.md +109 -0
  177. package/skill/assets/styles/iso-diagram/brand.md +32 -0
  178. package/skill/assets/styles/iso-diagram/reference/animations.jsx +673 -0
  179. package/skill/assets/styles/iso-diagram/reference/scenes.html +427 -0
  180. package/skill/assets/styles/iso-diagram/sample/bullet.ts +144 -0
  181. package/skill/assets/styles/iso-diagram/sample/content.ts +192 -0
  182. package/skill/assets/styles/iso-diagram/sample/cta.ts +162 -0
  183. package/skill/assets/styles/iso-diagram/sample/feature.ts +205 -0
  184. package/skill/assets/styles/iso-diagram/sample/grid.ts +181 -0
  185. package/skill/assets/styles/iso-diagram/sample/kinetic.ts +102 -0
  186. package/skill/assets/styles/iso-diagram/sample/section.ts +149 -0
  187. package/skill/assets/styles/iso-diagram/sample/stat.ts +164 -0
  188. package/skill/assets/styles/iso-diagram/sample/title.ts +173 -0
  189. package/skill/assets/styles/iso-diagram/sample/ui-showcase.ts +162 -0
  190. package/skill/assets/styles/iso-diagram/tokens.css +40 -0
  191. package/skill/assets/styles/motion-engineering/STYLE.md +106 -0
  192. package/skill/assets/styles/motion-engineering/brand.md +29 -0
  193. package/skill/assets/styles/motion-engineering/reference/animations.jsx +673 -0
  194. package/skill/assets/styles/motion-engineering/reference/scenes.html +513 -0
  195. package/skill/assets/styles/motion-engineering/sample/bullet.ts +176 -0
  196. package/skill/assets/styles/motion-engineering/sample/content.ts +228 -0
  197. package/skill/assets/styles/motion-engineering/sample/cta.ts +209 -0
  198. package/skill/assets/styles/motion-engineering/sample/feature.ts +299 -0
  199. package/skill/assets/styles/motion-engineering/sample/grid.ts +190 -0
  200. package/skill/assets/styles/motion-engineering/sample/kinetic.ts +159 -0
  201. package/skill/assets/styles/motion-engineering/sample/section.ts +196 -0
  202. package/skill/assets/styles/motion-engineering/sample/stat.ts +230 -0
  203. package/skill/assets/styles/motion-engineering/sample/title.ts +219 -0
  204. package/skill/assets/styles/motion-engineering/sample/ui-showcase.ts +267 -0
  205. package/skill/assets/styles/motion-engineering/tokens.css +40 -0
  206. package/skill/assets/styles/neon-terminal/STYLE.md +105 -0
  207. package/skill/assets/styles/neon-terminal/brand.md +27 -0
  208. package/skill/assets/styles/neon-terminal/reference/animations.jsx +673 -0
  209. package/skill/assets/styles/neon-terminal/reference/scenes.html +387 -0
  210. package/skill/assets/styles/neon-terminal/sample/bullet.ts +113 -0
  211. package/skill/assets/styles/neon-terminal/sample/content.ts +117 -0
  212. package/skill/assets/styles/neon-terminal/sample/cta.ts +131 -0
  213. package/skill/assets/styles/neon-terminal/sample/feature.ts +112 -0
  214. package/skill/assets/styles/neon-terminal/sample/grid.ts +128 -0
  215. package/skill/assets/styles/neon-terminal/sample/kinetic.ts +105 -0
  216. package/skill/assets/styles/neon-terminal/sample/section.ts +96 -0
  217. package/skill/assets/styles/neon-terminal/sample/stat.ts +123 -0
  218. package/skill/assets/styles/neon-terminal/sample/title.ts +122 -0
  219. package/skill/assets/styles/neon-terminal/sample/ui-showcase.ts +127 -0
  220. package/skill/assets/styles/neon-terminal/tokens.css +39 -0
  221. package/skill/assets/styles/risograph/STYLE.md +110 -0
  222. package/skill/assets/styles/risograph/brand.md +26 -0
  223. package/skill/assets/styles/risograph/reference/animations.jsx +673 -0
  224. package/skill/assets/styles/risograph/reference/scenes.html +403 -0
  225. package/skill/assets/styles/risograph/sample/bullet.ts +124 -0
  226. package/skill/assets/styles/risograph/sample/content.ts +135 -0
  227. package/skill/assets/styles/risograph/sample/cta.ts +149 -0
  228. package/skill/assets/styles/risograph/sample/feature.ts +152 -0
  229. package/skill/assets/styles/risograph/sample/grid.ts +123 -0
  230. package/skill/assets/styles/risograph/sample/kinetic.ts +125 -0
  231. package/skill/assets/styles/risograph/sample/section.ts +130 -0
  232. package/skill/assets/styles/risograph/sample/stat.ts +145 -0
  233. package/skill/assets/styles/risograph/sample/title.ts +132 -0
  234. package/skill/assets/styles/risograph/sample/ui-showcase.ts +147 -0
  235. package/skill/assets/styles/risograph/tokens.css +39 -0
  236. package/skill/assets/styles/swiss-console/STYLE.md +107 -0
  237. package/skill/assets/styles/swiss-console/brand.md +37 -0
  238. package/skill/assets/styles/swiss-console/reference/animations.jsx +673 -0
  239. package/skill/assets/styles/swiss-console/reference/scenes.html +420 -0
  240. package/skill/assets/styles/swiss-console/sample/bullet.ts +122 -0
  241. package/skill/assets/styles/swiss-console/sample/content.ts +137 -0
  242. package/skill/assets/styles/swiss-console/sample/cta.ts +109 -0
  243. package/skill/assets/styles/swiss-console/sample/feature.ts +163 -0
  244. package/skill/assets/styles/swiss-console/sample/grid.ts +145 -0
  245. package/skill/assets/styles/swiss-console/sample/kinetic.ts +117 -0
  246. package/skill/assets/styles/swiss-console/sample/section.ts +127 -0
  247. package/skill/assets/styles/swiss-console/sample/stat.ts +148 -0
  248. package/skill/assets/styles/swiss-console/sample/title.ts +148 -0
  249. package/skill/assets/styles/swiss-console/sample/ui-showcase.ts +198 -0
  250. package/skill/assets/styles/swiss-console/tokens.css +39 -0
  251. package/skill/install/INSTALL.md +400 -0
  252. package/skill/references/audio/audio_plan.md +199 -0
  253. package/skill/references/audio/build.md +208 -0
  254. package/skill/references/audio/cue_template.md +219 -0
  255. package/skill/references/audio/ffmpeg_cookbook.md +267 -0
  256. package/skill/references/audio/music/music.md +171 -0
  257. package/skill/references/audio/music/providers/elevenlabs.md +170 -0
  258. package/skill/references/audio/music/providers/manual.md +140 -0
  259. package/skill/references/audio/music/providers/openverse.md +265 -0
  260. package/skill/references/audio/sfx/providers/elevenlabs.md +152 -0
  261. package/skill/references/audio/sfx/providers/manual.md +117 -0
  262. package/skill/references/audio/sfx/providers/openverse.md +243 -0
  263. package/skill/references/audio/sfx/sfx.md +149 -0
  264. package/skill/references/audio/styles.md +102 -0
  265. package/skill/references/audio/sync.md +237 -0
  266. package/skill/references/audio/voiceover/animation_sync.md +142 -0
  267. package/skill/references/audio/voiceover/provider_script.md +153 -0
  268. package/skill/references/audio/voiceover/providers/elevenlabs.md +288 -0
  269. package/skill/references/audio/voiceover/providers/manual.md +100 -0
  270. package/skill/references/audio/voiceover/script_writing.md +100 -0
  271. package/skill/references/audio/voiceover/style_intake.md +56 -0
  272. package/skill/references/audio/voiceover/sync_algorithm.md +167 -0
  273. package/skill/references/audio/voiceover.md +296 -0
  274. package/skill/references/audio.md +135 -0
  275. package/skill/references/authoring_segment.md +446 -0
  276. package/skill/references/create_or_edit_video.md +232 -0
  277. package/skill/references/dev_server.md +157 -0
  278. package/skill/references/export.md +145 -0
  279. package/skill/references/new_video.md +117 -0
  280. package/skill/references/project_structure.md +144 -0
  281. package/skill/references/setup.md +109 -0
  282. package/skill/references/setup_new_style.md +158 -0
  283. package/skill/references/styles.md +154 -0
  284. package/skill/references/testing.md +115 -0
  285. package/skill/references/types.md +240 -0
  286. package/src/cli/entry/components/copy_button.ts +42 -0
  287. package/src/cli/entry/components/download_modal.ts +204 -0
  288. package/src/cli/entry/components/empty_state.ts +55 -0
  289. package/src/cli/entry/components/hide_hud_tab.ts +37 -0
  290. package/src/cli/entry/components/icons.ts +31 -0
  291. package/src/cli/entry/components/top_bar.ts +69 -0
  292. package/src/cli/entry/components/video_card.ts +57 -0
  293. package/src/cli/entry/dev_frame.ts +189 -0
  294. package/src/cli/entry/entry_index.ts +16 -0
  295. package/src/cli/entry/entry_video.ts +24 -0
  296. package/src/cli/entry/index.html +12 -0
  297. package/src/cli/entry/parse_slug.ts +14 -0
  298. package/src/cli/entry/render.html +17 -0
  299. package/src/cli/entry/render_entry.ts +121 -0
  300. package/src/cli/entry/styles/base.css +45 -0
  301. package/src/cli/entry/styles/components.css +605 -0
  302. package/src/cli/entry/styles/tokens.css +44 -0
  303. package/src/cli/entry/video.html +22 -0
  304. package/src/cli/entry/views/homepage.ts +66 -0
  305. package/src/cli/entry/views/video_view.ts +286 -0
  306. package/src/cli/entry/virtual.d.ts +8 -0
@@ -0,0 +1,265 @@
1
+ # Openverse Music Search
2
+
3
+ ## When this is loaded
4
+
5
+ The user chose Openverse to find background music. This reference covers searching the Openverse API, downloading candidates, and the multi-choice approval flow.
6
+
7
+ ## Overview
8
+
9
+ Openverse is a search engine for openly-licensed creative works (audio, images). It aggregates content from multiple sources and exposes a free REST API with no authentication required. All results carry CC0, Public Domain, or CC-BY licenses suitable for video production.
10
+
11
+ ## Prerequisites
12
+
13
+ - `curl` available (standard on macOS/Linux)
14
+ - No API key required
15
+
16
+ ## Rate limiting
17
+
18
+ The Openverse API applies rate limits. If you receive a 429 response, wait 2 seconds and retry. Rate limits expire after ~1 second, so a 2-second pause is always sufficient.
19
+
20
+ ## API endpoint
21
+
22
+ **Search endpoint:** `GET https://api.openverse.org/v1/audio/`
23
+
24
+ **Query parameters:**
25
+
26
+ | Parameter | Required | Description |
27
+ |---|---|---|
28
+ | `q` | Yes | Search query. Use `+` to join words (e.g., `corporate+uplifting`). |
29
+ | `license` | No | Comma-separated license filter. Default: `cc0,pdm,by`. |
30
+ | `category` | No | `music` or `sound_effect`. For music, always set `category=music`. |
31
+ | `page_size` | No | Results per page (1-50). Default: 20. |
32
+
33
+ **Example request:**
34
+
35
+ ```bash
36
+ curl -s "https://api.openverse.org/v1/audio/?q=corporate+uplifting&license=cc0,pdm,by&category=music&page_size=20"
37
+ ```
38
+
39
+ **Response:** JSON object with a `results` array. Each result contains:
40
+
41
+ | Field | Description |
42
+ |---|---|
43
+ | `title` | Name of the audio asset. |
44
+ | `url` | Direct download URL for the audio file. |
45
+ | `creator` | Author/uploader name. |
46
+ | `license` | License identifier (e.g., `cc0`, `by`, `pdm`). |
47
+ | `tags` | Array of tag objects (`{ name: string }`). |
48
+ | `description` | Free-text description (may be empty). |
49
+ | `duration` | Duration in milliseconds. |
50
+ | `id` | UUID identifier for this asset. Used to construct the share link: `https://openverse.org/audio/<id>`. |
51
+
52
+ ## Search workflow
53
+
54
+ ### Step 1: Determine search query
55
+
56
+ Ask the user what mood/style of music they want (if not already clear from context). Construct a search query:
57
+
58
+ - Use mood + genre terms: `corporate+uplifting`, `calm+ambient+piano`, `energetic+electronic`
59
+ - Add qualifiers: `instrumental`, `background`, `no+vocals`
60
+ - Consider the video's tone and duration when selecting terms
61
+
62
+ ### Step 2: Execute search
63
+
64
+ ```bash
65
+ curl -s "https://api.openverse.org/v1/audio/?q=<query>&license=cc0,pdm,by&category=music&page_size=20"
66
+ ```
67
+
68
+ If the response is a 429 (rate limited), wait 2 seconds and retry:
69
+
70
+ ```bash
71
+ sleep 2
72
+ curl -s "https://api.openverse.org/v1/audio/?q=<query>&license=cc0,pdm,by&category=music&page_size=20"
73
+ ```
74
+
75
+ ### Step 3: Evaluate results
76
+
77
+ Parse the JSON response. Filter results for relevance:
78
+
79
+ - Title, tags, or description should match the desired mood/genre
80
+ - Duration should be reasonable for background music (typically 30s-5min)
81
+ - Prefer `cc0` or `pdm` over `by` (no attribution required)
82
+ - Longer tracks are generally better (can always slice; cannot extend)
83
+
84
+ If no results match, try broadening the query (fewer terms, more generic words). If still nothing, inform the user and suggest alternative sources (BYO or ElevenLabs).
85
+
86
+ ### Step 4: Multi-choice offer
87
+
88
+ If there are several qualifying matches (3+), offer the user a choice:
89
+
90
+ > We have found several possible music matches! Would you like us to:
91
+ >
92
+ > 1. **Download 5 candidates** -- you listen and pick your favorite
93
+ > 2. **Use the top match** -- we will download the best result directly
94
+
95
+ If fewer than 5 results qualify, download all qualifying results and adjust the numbered list accordingly (e.g., "Pick a number (1-3)" for 3 candidates).
96
+
97
+ If there are fewer than 3 matches, skip the offer and download the best match directly.
98
+
99
+ ## Download: single track
100
+
101
+ Download the selected audio file into the music folder:
102
+
103
+ ```bash
104
+ mkdir -p audio/originals/music/<slug>/
105
+ curl -L -o audio/originals/music/<slug>/audio.mp3 "<url from response>"
106
+ ```
107
+
108
+ If the source URL points to a `.wav` or other format, save with the appropriate extension.
109
+
110
+ **Important:** Run curl with `-L` to follow redirects. Openverse URLs often redirect to the source hosting.
111
+
112
+ ## Download: 5 candidates flow
113
+
114
+ When the user chooses the "download 5" option:
115
+
116
+ ### Step A: Create candidates folder
117
+
118
+ ```bash
119
+ mkdir -p audio/originals/music/<slug>/candidates/
120
+ ```
121
+
122
+ ### Step B: Download top 5 results
123
+
124
+ ```bash
125
+ curl -L -o audio/originals/music/<slug>/candidates/1.mp3 "<url_1>"
126
+ curl -L -o audio/originals/music/<slug>/candidates/2.mp3 "<url_2>"
127
+ curl -L -o audio/originals/music/<slug>/candidates/3.mp3 "<url_3>"
128
+ curl -L -o audio/originals/music/<slug>/candidates/4.mp3 "<url_4>"
129
+ curl -L -o audio/originals/music/<slug>/candidates/5.mp3 "<url_5>"
130
+ ```
131
+
132
+ If any download gets a 429, wait 2 seconds and retry that single request.
133
+
134
+ ### Step C: Present candidates to user
135
+
136
+ Print a numbered list with clickable `file://` links and brief descriptions. **Internally track each candidate's `id` field** so you can record the winner's share link later.
137
+
138
+ ```
139
+ Here are 5 music candidates in:
140
+ file:///absolute/path/to/audio/originals/music/<slug>/candidates/
141
+
142
+ 1. <title_1> (by <creator_1>, <license_1>, <duration_1>s)
143
+ file:///absolute/path/to/audio/originals/music/<slug>/candidates/1.mp3
144
+
145
+ 2. <title_2> (by <creator_2>, <license_2>, <duration_2>s)
146
+ file:///absolute/path/to/audio/originals/music/<slug>/candidates/2.mp3
147
+
148
+ 3. ...
149
+
150
+ Pick a number (1-5), or let me know if you would like to hear more options.
151
+ ```
152
+
153
+ ### Step D: User picks a winner
154
+
155
+ Once the user picks (e.g., "3"):
156
+
157
+ 1. Move the winner into position:
158
+ ```bash
159
+ mv audio/originals/music/<slug>/candidates/3.mp3 audio/originals/music/<slug>/audio.mp3
160
+ ```
161
+
162
+ 2. Delete the candidates folder:
163
+ ```bash
164
+ rm -rf audio/originals/music/<slug>/candidates/
165
+ ```
166
+
167
+ 3. Record the winner's `id` — use it to write the share link (`https://openverse.org/audio/<id>`) in the metadata `notes` field (Step 6).
168
+
169
+ 4. Proceed to metadata and approval (Step 5 below).
170
+
171
+ If the user asks for more options or none of the 5 work, run a new search with adjusted terms or download the next batch of results.
172
+
173
+ ## Step 5: Measure duration
174
+
175
+ ```bash
176
+ ffprobe -v error -show_entries format=duration \
177
+ -of default=noprint_wrappers=1:nokey=1 \
178
+ audio/originals/music/<slug>/audio.mp3
179
+ ```
180
+
181
+ Round to 1 decimal place for `length_s`.
182
+
183
+ ## Step 6: Write `music.ts`
184
+
185
+ Create `audio/originals/music/<slug>/music.ts`:
186
+
187
+ ```ts
188
+ import type { MusicAsset } from "videowright";
189
+
190
+ export const music: MusicAsset = {
191
+ name: "<title from Openverse or user-refined name>",
192
+ description: "<description from Openverse or agent-written summary>",
193
+ length_s: <measured duration>,
194
+ source: "openverse",
195
+ notes: `
196
+ Openverse: <title> by <creator>. License: <license>.
197
+ Share link: https://openverse.org/audio/<id>
198
+ BPM: <from metadata or user-confirmed>
199
+ Mood: <observed mood>
200
+ Structure: <observed sections if discernible>
201
+ `,
202
+ };
203
+
204
+ export default music;
205
+ ```
206
+
207
+ Set `source: "openverse"` to record provenance. Always include the Openverse share link (`https://openverse.org/audio/<id>`), creator, and license in `notes` for attribution. The `<id>` is the `id` field from the API response.
208
+
209
+ ### Agent-observed details
210
+
211
+ After downloading, the agent should note in `notes` any details available from Openverse metadata (tags, description, title). Additionally, ask the user to listen and confirm:
212
+
213
+ - BPM (only include if provided by Openverse metadata or confirmed by the user — do not estimate)
214
+ - Mood and energy level (infer from tags/title/description)
215
+ - Whether the track likely has vocals (flag as a concern for VO ducking; infer from tags if available)
216
+ - Loop-ability (infer from title/tags if indicated)
217
+ - Any other relevant details from the metadata
218
+
219
+ There is no `generate.sh` for Openverse assets.
220
+
221
+ ## Step 7: Trigger approval UX
222
+
223
+ Follow the approval flow from [../music.md](../music.md):
224
+
225
+ 1. Print the clickable `file://` link to the audio file.
226
+ 2. Prompt: Approve or Discard and request changes.
227
+ 3. On Approve: asset is locked, ready for use in the audio plan.
228
+ 4. On Discard: delete the folder, ask what to change, search again with adjusted terms.
229
+
230
+ ## Iteration on discard
231
+
232
+ If the user discards and requests changes:
233
+
234
+ 1. Delete the folder: `rm -rf audio/originals/music/<slug>/`
235
+ 2. Ask what should change about the music.
236
+ 3. Adjust the search query based on feedback:
237
+ - "Too energetic" -- try `calm`, `ambient`, `gentle`
238
+ - "Too boring" -- try `upbeat`, `energetic`, `dynamic`
239
+ - "Wrong genre" -- change genre terms entirely
240
+ - "Too short" -- filter by duration in results, prefer longer tracks
241
+ - "Has vocals" -- add `instrumental` to query
242
+ 4. Re-run the search and download flow.
243
+
244
+ ## Expected folder state after approval
245
+
246
+ ```
247
+ audio/originals/music/<slug>/
248
+ audio.mp3 # downloaded from Openverse (immutable after approval)
249
+ music.ts # typed metadata with provenance and musical details in notes
250
+ ```
251
+
252
+ No `generate.sh` and no `candidates/` folder after approval.
253
+
254
+ ## Edge cases
255
+
256
+ | Situation | Behavior |
257
+ |---|---|
258
+ | No results for the query | Broaden search terms. If still nothing, suggest BYO or ElevenLabs. |
259
+ | All results are very short (< 15s) | These may be SFX miscategorized as music. Try more specific genre terms or increase `page_size`. |
260
+ | Downloaded file is 0 bytes or corrupt | Delete and retry the download. If persistent, try a different result. |
261
+ | License is `by` (attribution required) | Note in `music.ts` notes that attribution is required. The agent does not enforce attribution in the final video but records the obligation. |
262
+ | Rate limited during batch download | Wait 2 seconds between each retry. Do not hammer the API. |
263
+ | Track has vocals | Warn the user that vocals may conflict with voiceover. Suggest searching with `instrumental` added to the query. |
264
+ | User wants to search again after seeing candidates | Delete the candidates folder and re-run with new search terms. |
265
+ | Music is shorter than the video | Use `aloop` in ffmpeg to loop it. Note loop points in `music.ts` notes. See [../../ffmpeg_cookbook.md](../../ffmpeg_cookbook.md). |
@@ -0,0 +1,152 @@
1
+ # ElevenLabs SFX Generation
2
+
3
+ ## When this is loaded
4
+
5
+ The user chose ElevenLabs to generate a sound effect. This reference covers the Sound Generation API endpoint, prompt-writing tips, and the `generate.sh` template.
6
+
7
+ ## Prerequisites
8
+
9
+ - `ELEVENLABS_API_KEY` set in `.env` at the project root. The key must have **Sound Effects** permission enabled.
10
+ - If the user does not have an API key, guide them through setup: see [../../voiceover/providers/elevenlabs.md](../../voiceover/providers/elevenlabs.md) (Step 2: Get the API key). The same key works for TTS, STT, SFX, and Music.
11
+
12
+ ## Cost notice
13
+
14
+ > **Cost notice:** ElevenLabs charges credits for sound generation. A single SFX generation typically costs 100-500 credits depending on duration. Check your remaining quota at https://elevenlabs.io/app/subscription before generating.
15
+
16
+ ## API endpoint
17
+
18
+ **Endpoint:** `POST https://api.elevenlabs.io/v1/sound-generation`
19
+
20
+ **Request body:**
21
+
22
+ ```json
23
+ {
24
+ "text": "<prompt describing the desired sound>",
25
+ "duration_seconds": 4.0,
26
+ "prompt_influence": 0.3
27
+ }
28
+ ```
29
+
30
+ | Field | Required | Description |
31
+ |---|---|---|
32
+ | `text` | Yes | Natural-language description of the sound to generate. See prompt-writing tips below. |
33
+ | `duration_seconds` | No | Target duration in seconds. If omitted, the API chooses. Recommended: specify for predictable results. |
34
+ | `prompt_influence` | No | 0.0-1.0. Higher values follow the prompt more literally; lower values give the model more creative freedom. Default 0.3 is a good starting point. |
35
+
36
+ **Response:** The API returns raw audio bytes (mp3) directly in the response body (not JSON-wrapped).
37
+
38
+ ## `generate.sh` template
39
+
40
+ Write this script to `audio/originals/sfx/<slug>/generate.sh` for reproducibility:
41
+
42
+ ```bash
43
+ #!/bin/bash
44
+ # Generated SFX: <name>
45
+ # Prompt: <the exact prompt used>
46
+ # Duration: <duration_seconds>s
47
+ # Prompt influence: <prompt_influence>
48
+
49
+ set -euo pipefail
50
+
51
+ # Load API key from .env
52
+ if [ -f .env ]; then
53
+ export $(grep -v '^#' .env | xargs)
54
+ fi
55
+
56
+ if [ -z "${ELEVENLABS_API_KEY:-}" ]; then
57
+ echo "Error: ELEVENLABS_API_KEY not set. Add it to .env" >&2
58
+ exit 1
59
+ fi
60
+
61
+ SLUG="<slug>"
62
+ OUTPUT_DIR="audio/originals/sfx/${SLUG}"
63
+ mkdir -p "${OUTPUT_DIR}"
64
+
65
+ curl -X POST "https://api.elevenlabs.io/v1/sound-generation" \
66
+ -H "xi-api-key: ${ELEVENLABS_API_KEY}" \
67
+ -H "Content-Type: application/json" \
68
+ -d '{
69
+ "text": "<prompt>",
70
+ "duration_seconds": <duration>,
71
+ "prompt_influence": <influence>
72
+ }' \
73
+ --output "${OUTPUT_DIR}/audio.mp3"
74
+
75
+ echo "SFX saved to ${OUTPUT_DIR}/audio.mp3"
76
+ ```
77
+
78
+ Make the script executable: `chmod +x generate.sh`.
79
+
80
+ **Important:** Run `generate.sh` from the **video folder** (the directory containing `timeline.ts`) so that relative paths resolve correctly.
81
+
82
+ ## Prompt-writing tips
83
+
84
+ Good prompts produce better SFX. Follow these guidelines:
85
+
86
+ ### Be specific about the sound source
87
+ - Good: "Mechanical keyboard with cherry blue switches, fast typing, rhythmic"
88
+ - Bad: "Typing sound"
89
+
90
+ ### Describe the acoustic character
91
+ - Good: "Soft whoosh, low frequency, left-to-right pan feel, smooth"
92
+ - Bad: "Whoosh"
93
+
94
+ ### Mention duration behavior
95
+ - Good: "Short door slam, single impact, no reverb tail, 0.5 seconds"
96
+ - Bad: "Door closing"
97
+
98
+ ### Specify what to avoid
99
+ - Good: "Gentle notification chime, no harshness, no echo, clean single tone"
100
+ - Bad: "Notification sound"
101
+
102
+ ### Useful descriptors
103
+
104
+ | Category | Example descriptors |
105
+ |---|---|
106
+ | Character | crisp, warm, metallic, soft, punchy, hollow, bright, dark |
107
+ | Dynamics | sudden, gradual, steady, pulsing, fading |
108
+ | Environment | close-mic, room reverb, outdoor, studio-dry |
109
+ | Duration hints | brief, sustained, one-shot, looping |
110
+
111
+ ## Post-generation workflow
112
+
113
+ After the curl command succeeds:
114
+
115
+ 1. **Verify the file exists and is non-empty:**
116
+ ```bash
117
+ ls -la audio/originals/sfx/<slug>/audio.mp3
118
+ ```
119
+
120
+ 2. **Measure duration via ffprobe:**
121
+ ```bash
122
+ ffprobe -v error -show_entries format=duration \
123
+ -of default=noprint_wrappers=1:nokey=1 \
124
+ audio/originals/sfx/<slug>/audio.mp3
125
+ ```
126
+
127
+ 3. **Write `sfx.ts`** with the metadata (see [../sfx.md](../sfx.md) for the shape). Set `source: "elevenlabs"`.
128
+
129
+ 4. **Trigger the approval UX** (see [../sfx.md](../sfx.md) -- Approval UX section).
130
+
131
+ ## Iteration on discard
132
+
133
+ If the user discards and requests changes:
134
+
135
+ 1. Delete the folder: `rm -rf audio/originals/sfx/<slug>/`
136
+ 2. Ask what should change about the sound.
137
+ 3. Adjust the prompt based on feedback. Common adjustments:
138
+ - "Too harsh" -- add "soft", "gentle", remove "punchy"
139
+ - "Too long" -- reduce `duration_seconds`
140
+ - "Wrong type of sound" -- rewrite the source description
141
+ - "Too quiet/loud" -- this is a mix concern, not a generation concern. The audio file itself should be at a reasonable level; volume is controlled in the audio plan cue.
142
+ 4. Re-run with the updated prompt. Write a new `generate.sh` reflecting the new parameters.
143
+
144
+ ## Troubleshooting
145
+
146
+ | Issue | Resolution |
147
+ |---|---|
148
+ | 401 Unauthorized | Check `ELEVENLABS_API_KEY` in `.env`. Ensure the key has Sound Effects permission. |
149
+ | 422 Unprocessable Entity | Prompt may be too short or too long. Keep prompts 10-200 characters. |
150
+ | Empty or 0-byte response | API may have failed silently. Retry. If persistent, try a different prompt. |
151
+ | Generated sound does not match prompt | Increase `prompt_influence` (try 0.5-0.7). Rephrase the prompt to be more specific. |
152
+ | Rate limited (429) | Wait and retry. Check quota at https://elevenlabs.io/app/subscription. |
@@ -0,0 +1,117 @@
1
+ # Manual SFX (Bring Your Own)
2
+
3
+ ## When this is loaded
4
+
5
+ The user has their own sound effect audio file and wants to add it to the project. This is the BYO path from [../sfx.md](../sfx.md).
6
+
7
+ ## Overview
8
+
9
+ The manual flow takes a user-provided audio file, places it in the correct folder, gathers metadata, and presents it for approval. No API calls needed.
10
+
11
+ ## Step 1: Set up the folder
12
+
13
+ Choose a slug name for this SFX. The slug should describe the sound in short snake_case:
14
+
15
+ - `keyboard_typing`
16
+ - `glass_break`
17
+ - `subtle_chime`
18
+
19
+ Create the directory:
20
+
21
+ ```bash
22
+ mkdir -p audio/originals/sfx/<slug>/
23
+ ```
24
+
25
+ ## Step 2: Get the audio file
26
+
27
+ Ask the user for the file. Two options:
28
+
29
+ 1. **File path.** The user provides a path to an existing file. Copy it into the folder:
30
+ ```bash
31
+ cp /path/to/their/file.mp3 audio/originals/sfx/<slug>/audio.mp3
32
+ ```
33
+
34
+ 2. **Drop-in.** Ask the user to place the file directly:
35
+ > Place your audio file at `audio/originals/sfx/<slug>/audio.mp3` (or `audio.wav`).
36
+
37
+ ### Supported formats
38
+
39
+ - MP3 and WAV are standard. Both work with ffmpeg.
40
+ - Other formats (M4A, OGG, FLAC) are also accepted by ffmpeg. Note the actual extension in the folder.
41
+ - No specific sample rate or bitrate requirements.
42
+
43
+ ## Step 3: Gather metadata
44
+
45
+ Ask the user for:
46
+
47
+ > I need a few details about this sound effect:
48
+ >
49
+ > 1. **Name** -- a short human-readable name (e.g., "Keyboard typing")
50
+ > 2. **Description** -- one sentence describing the sound (e.g., "Mechanical keyboard, fast typing, ~4 second loop")
51
+ > 3. **Notes** (optional) -- any extra detail that might help when mixing (loop points, transient positions, frequency character)
52
+
53
+ If the user does not provide notes, omit the field or leave it empty.
54
+
55
+ ## Step 4: Measure duration
56
+
57
+ Use ffprobe to get the exact length:
58
+
59
+ ```bash
60
+ ffprobe -v error -show_entries format=duration \
61
+ -of default=noprint_wrappers=1:nokey=1 \
62
+ audio/originals/sfx/<slug>/audio.mp3
63
+ ```
64
+
65
+ Round to 1 decimal place for `length_s`.
66
+
67
+ ## Step 5: Write `sfx.ts`
68
+
69
+ Create `audio/originals/sfx/<slug>/sfx.ts`:
70
+
71
+ ```ts
72
+ import type { SfxAsset } from "videowright";
73
+
74
+ export const sfx: SfxAsset = {
75
+ name: "<name from user>",
76
+ description: "<description from user>",
77
+ length_s: <measured duration>,
78
+ source: "user",
79
+ notes: "<notes from user, or omit>",
80
+ };
81
+
82
+ export default sfx;
83
+ ```
84
+
85
+ Set `source: "user"` to record that this was a BYO asset.
86
+
87
+ There is no `generate.sh` for BYO assets (nothing to reproduce).
88
+
89
+ ## Step 6: Trigger approval UX
90
+
91
+ Follow the approval flow from [../sfx.md](../sfx.md):
92
+
93
+ 1. Print the clickable `file://` link to the audio file.
94
+ 2. Prompt: Approve or Discard and request changes.
95
+ 3. On Approve: asset is locked, ready for use in the audio plan.
96
+ 4. On Discard: delete the folder, ask what to change, loop back.
97
+
98
+ For BYO assets, "discard and request changes" means the user needs to provide a different file. Ask them to supply a new recording or file.
99
+
100
+ ## Expected folder state after approval
101
+
102
+ ```
103
+ audio/originals/sfx/<slug>/
104
+ audio.mp3 # user-provided audio (immutable after approval)
105
+ sfx.ts # typed metadata
106
+ ```
107
+
108
+ No `generate.sh` for BYO assets.
109
+
110
+ ## Edge cases
111
+
112
+ | Situation | Behavior |
113
+ |---|---|
114
+ | User provides a stereo file | Fine. ffmpeg handles stereo. Note in `notes` if relevant to mixing. |
115
+ | File is very short (< 0.1s) | Warn that the SFX may be too short to be audible in the mix. Proceed if user confirms. |
116
+ | File is very long (> 30s) | Not typical for SFX. Confirm the user wants a long ambient texture, not a music track. Suggest using [../music/music.md](../music/music.md) for longer audio if appropriate. |
117
+ | User wants to replace after approval | Cannot edit in place. Source a new version in a new slug folder and update audio plan cues. |