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,171 @@
1
+ # Background Music
2
+
3
+ ## When this is loaded
4
+
5
+ You were routed here from [audio.md](../../audio.md) because the user wants to add background music to their video. This reference covers sourcing, approving, and managing music assets.
6
+
7
+ ## Overview
8
+
9
+ Each music asset is a slug-named folder under `audio/originals/music/`. Music assets are immutable once used in a rendered track. The agent sources them (BYO, ElevenLabs, or Openverse), gets user approval, then references them in the audio plan as cues with volume curves and ducking.
10
+
11
+ ## Sourcing decision
12
+
13
+ Ask the user how they want to source background music. Always ask when starting a new sourcing job, even if existing music in the project used a specific source -- don't assume continuity with prior assets.
14
+
15
+ > How would you like to source background music?
16
+ >
17
+ > 1. **Bring your own** -- drop an audio file (mp3/wav) into the project and I will set it up.
18
+ > 2. **Generate with ElevenLabs** -- describe the music you want and I will generate it via the ElevenLabs Music Generation API. **Requires a paid plan and API key.**
19
+ > 3. **Search Openverse** -- search for freely-licensed music online. No API key required, free to use.
20
+
21
+ Based on the answer, load the appropriate provider reference:
22
+
23
+ - **BYO** -- load [providers/manual.md](providers/manual.md)
24
+ - **ElevenLabs** -- load [providers/elevenlabs.md](providers/elevenlabs.md)
25
+ - **Openverse** -- load [providers/openverse.md](providers/openverse.md)
26
+
27
+ ## Folder structure
28
+
29
+ ```
30
+ audio/originals/music/
31
+ uplift_piano/
32
+ audio.mp3 # source audio (immutable after approval)
33
+ music.ts # typed metadata with rich notes
34
+ generate.sh # only for ElevenLabs-sourced music
35
+ tense_synth/
36
+ audio.mp3
37
+ music.ts
38
+ generate.sh
39
+ ```
40
+
41
+ ## Slug naming
42
+
43
+ Music folders use short, semantic, snake_case names that describe the track's character:
44
+
45
+ - `uplift_piano`
46
+ - `tense_synth`
47
+ - `calm_ambient`
48
+ - `energetic_percussion`
49
+ - `corporate_upbeat`
50
+
51
+ The slug should convey the mood/instrument at a glance. Avoid generic names like `music_1` or `track_a`.
52
+
53
+ ## `music.ts` metadata
54
+
55
+ Each music asset has a typed metadata file. The `notes` field is the key differentiator from SFX -- it should contain rich musical detail:
56
+
57
+ ```ts
58
+ import type { MusicAsset } from "videowright";
59
+
60
+ export const music: MusicAsset = {
61
+ name: "Uplift piano",
62
+ description: "Solo piano, gentle build to optimistic resolution",
63
+ length_s: 64.2,
64
+ source: "elevenlabs",
65
+ notes: `
66
+ BPM: 95
67
+ Key: C major
68
+ Mood: hopeful, restrained
69
+ Structure: ambient intro 0-8s, theme enters 8s, build 22-34s, beat drops at 34.2s, gentle outro 50s+
70
+ Loops: cleanly at the bar boundary (every ~10.1s after 8s)
71
+ `,
72
+ };
73
+
74
+ export default music;
75
+ ```
76
+
77
+ Fields:
78
+
79
+ | Field | Required | Description |
80
+ |---|---|---|
81
+ | `name` | Yes | Human-readable name for display and reference. |
82
+ | `description` | Yes | One-line summary of the track's character. |
83
+ | `length_s` | Yes | Duration in seconds, measured via ffprobe. Round to 1 decimal place. |
84
+ | `source` | Yes | `"elevenlabs"`, `"user"`, or `"openverse"`. Records provenance. |
85
+ | `notes` | Yes (strongly encouraged) | Free-text musical detail. See "What to capture in notes" below. |
86
+
87
+ If the `MusicAsset` type is not yet exported from videowright, use an inline type annotation or `any` -- the shape is what matters.
88
+
89
+ ### What to capture in notes
90
+
91
+ The `notes` field is free text. There are no structured fields for BPM, key, or mood -- instead, mix any useful detail freely. Common things worth noting:
92
+
93
+ - **BPM** -- critical for beat-aligned visuals
94
+ - **Key** -- useful if combining with other musical elements
95
+ - **Mood** -- helps the agent choose volume curves and placement
96
+ - **Structure** -- timestamps of sections (intro, build, drop, outro). Essential for slicing and ducking.
97
+ - **Loop points** -- where the track loops cleanly, if applicable
98
+ - **Beat positions** -- where notable rhythmic events land (useful as sync anchors)
99
+ - **Instrument palette** -- what instruments are present
100
+ - **Frequency range** -- if the track is mostly low-end, high-end, or full-spectrum
101
+
102
+ Not all fields apply to every track. Write what is useful. Even brief notes ("ambient, no strong beat, loops after 8s") are better than nothing.
103
+
104
+ ## Approval UX
105
+
106
+ After a music asset is sourced (file in place, `music.ts` written), present it for approval:
107
+
108
+ 1. **Print a clickable absolute `file://` link** to the audio file:
109
+
110
+ ```
111
+ Listen to the music track:
112
+ file:///absolute/path/to/audio/originals/music/uplift_piano/audio.mp3
113
+ ```
114
+
115
+ 2. **Prompt with exactly two options:**
116
+
117
+ > 1. **Approve** -- lock this asset for use in the audio plan.
118
+ > 2. **Discard and request changes** -- delete this asset and try again.
119
+
120
+ 3. **On Approve:**
121
+ - The asset is locked. Its folder and contents must not be modified or deleted.
122
+ - Proceed to integrate it into the audio plan (see "Integration into audio plan" below).
123
+
124
+ 4. **On Discard:**
125
+ - Delete the entire asset folder:
126
+ ```bash
127
+ rm -rf audio/originals/music/<slug>/
128
+ ```
129
+ - Ask: "What should change about this music?"
130
+ - Take feedback and re-source (loop back to the provider flow).
131
+
132
+ ### Pre-use deletion only
133
+
134
+ A music folder can only be deleted if it has **never been used** in a rendered track. Once a track references it (via a plan snapshot), deletion would corrupt the snapshot. If the user asks to delete a used asset, refuse and explain which track(s) reference it.
135
+
136
+ ## Integration into audio plan
137
+
138
+ After approval, the music is ready to be referenced in `audio/audio_plan.md` as a cue. See [../cue_template.md](../cue_template.md) for the cue format.
139
+
140
+ Typical music cue:
141
+
142
+ ```
143
+ ### Cue 1 -- Background music
144
+ Source: audio/originals/music/uplift_piano/
145
+ Slice: 0-45.0
146
+ Place at: 0.0
147
+ Volume: 100% from 0s, ramps to 15% over 2.8-3.0s (VO starts at 3.0s), 15% from 3.0-22.0s, ramps to 50% over 22.0-22.3s (animation beat), ramps to 15% over 23.5-23.7s, 15% from 23.7-40.0s, ramps to 80% over 40.0-40.2s (outro), fade out 43.0-45.0s
148
+ Fades: fade in 0-0.5s, fade out 43.0-45.0s
149
+ Notes: Music bed throughout. Ducked under all VO segments. Rises during visual-only transitions and outro.
150
+ ```
151
+
152
+ Key points:
153
+ - `Source:` points to the music folder.
154
+ - `Volume:` expresses the full ducking curve explicitly. The agent writes the actual levels at each point in time -- no opaque "duck under VO" directives. See [../styles.md](../styles.md) for level guidance.
155
+ - Music typically spans most or all of the video. Use `Slice:` to trim if the track is longer than needed.
156
+ - Ducking ramps should be ~0.2s (see [../styles.md](../styles.md)).
157
+ - If the track has a strong beat, align visual transitions to beat boundaries where possible (compute from BPM in notes).
158
+
159
+ ## One track or many?
160
+
161
+ For most product/demo videos (30s-3min), **one music track** is sufficient. The ducking curve provides enough variation. Multiple tracks increase complexity -- only use them if the video has distinct tonal sections requiring genuinely different music.
162
+
163
+ ## Edge cases
164
+
165
+ | Situation | Behavior |
166
+ |---|---|
167
+ | 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). |
168
+ | Music is much longer than the video | Use `Slice:` in the cue to take only the needed portion. |
169
+ | User wants music but no VO | Music plays at full level throughout. No ducking needed. Volume curve is simple: fade in, hold at 100%, fade out. |
170
+ | User wants to swap music after a track is built | Source a new music asset in a new slug folder, approve it, update the audio plan cues to reference the new slug, rebuild the track. |
171
+ | User provides a copyrighted track | Agent does not police copyright. Note in `music.ts` notes if the user mentions licensing (e.g., "Licensed via Epidemic Sound"). |
@@ -0,0 +1,170 @@
1
+ # ElevenLabs Music Generation
2
+
3
+ ## When this is loaded
4
+
5
+ The user chose ElevenLabs to generate background music. This reference covers the Music 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 **Music Generation** 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 music generation. Longer tracks cost more credits. A 60-second track typically costs 2,000-5,000 credits depending on complexity. 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/music-generation`
19
+
20
+ **Request body:**
21
+
22
+ ```json
23
+ {
24
+ "text": "<prompt describing the desired music>",
25
+ "duration_seconds": 60,
26
+ "prompt_influence": 0.5
27
+ }
28
+ ```
29
+
30
+ | Field | Required | Description |
31
+ |---|---|---|
32
+ | `text` | Yes | Natural-language description of the music. See prompt-writing tips below. |
33
+ | `duration_seconds` | No | Target duration in seconds. If omitted, the API chooses (usually 30s). Recommended: specify to match your video length. |
34
+ | `prompt_influence` | No | 0.0-1.0. Higher values follow the prompt more literally; lower values give more creative freedom. 0.5 is a good starting point for music. |
35
+
36
+ **Response:** The API returns raw audio bytes (mp3) directly in the response body.
37
+
38
+ ## `generate.sh` template
39
+
40
+ Write this script to `audio/originals/music/<slug>/generate.sh` for reproducibility:
41
+
42
+ ```bash
43
+ #!/bin/bash
44
+ # Generated Music: <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/music/${SLUG}"
63
+ mkdir -p "${OUTPUT_DIR}"
64
+
65
+ curl -X POST "https://api.elevenlabs.io/v1/music-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 "Music 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
+ Music generation prompts benefit from structure. Include these dimensions:
85
+
86
+ ### Specify genre and instruments
87
+ - Good: "Ambient electronic with soft piano chords and warm synth pads"
88
+ - Bad: "Background music"
89
+
90
+ ### Describe mood and energy arc
91
+ - Good: "Starts minimal and hopeful, builds gradually, reaches an optimistic peak at 30s, then settles into a gentle outro"
92
+ - Bad: "Happy music"
93
+
94
+ ### Mention tempo and rhythm
95
+ - Good: "Moderate tempo around 90-100 BPM, light percussion, no heavy drums"
96
+ - Bad: "Not too fast"
97
+
98
+ ### Describe the use case
99
+ - Good: "Background music for a product demo video. Needs to sit behind voiceover without competing. Should feel professional and modern."
100
+ - Bad: "Music for a video"
101
+
102
+ ### Useful descriptors for product/demo videos
103
+
104
+ | Dimension | Good choices |
105
+ |---|---|
106
+ | Genre | ambient, corporate, indie electronic, lo-fi, minimal, cinematic |
107
+ | Instruments | piano, synth pads, soft guitar, muted percussion, strings, bells |
108
+ | Mood | professional, optimistic, calm, confident, innovative, warm |
109
+ | Energy | low-energy, mid-energy, building, steady, dynamic |
110
+ | Avoid | aggressive drums, heavy bass drops, distorted guitars, vocals |
111
+
112
+ ### Duration guidance
113
+
114
+ Match the music duration to your video:
115
+ - Request slightly longer than needed (add 5-10s buffer). You can slice in the audio plan.
116
+ - For videos with intro + content + outro: request the full duration so you get a natural arc.
117
+ - For looping backgrounds: request at least one full musical phrase (usually 16-32s at standard tempos) so the loop point sounds clean.
118
+
119
+ ## Post-generation workflow
120
+
121
+ After the curl command succeeds:
122
+
123
+ 1. **Verify the file exists and is non-empty:**
124
+ ```bash
125
+ ls -la audio/originals/music/<slug>/audio.mp3
126
+ ```
127
+
128
+ 2. **Measure duration via ffprobe:**
129
+ ```bash
130
+ ffprobe -v error -show_entries format=duration \
131
+ -of default=noprint_wrappers=1:nokey=1 \
132
+ audio/originals/music/<slug>/audio.mp3
133
+ ```
134
+
135
+ 3. **Ask the user to listen and describe the track.** Before writing metadata, ask the user to play the track and report:
136
+ - BPM (can often be inferred from the prompt's requested tempo; otherwise ask the user to estimate)
137
+ - Key (if discernible)
138
+ - Structure (where sections change, where the energy peaks)
139
+ - Any notable moments (beat drops, transitions, loop points)
140
+
141
+ 4. **Write `music.ts`** with rich metadata (see [../music.md](../music.md) for the shape). Set `source: "elevenlabs"`. Include all observed musical details in the `notes` field.
142
+
143
+ 5. **Trigger the approval UX** (see [../music.md](../music.md) -- Approval UX section).
144
+
145
+ ## Iteration on discard
146
+
147
+ If the user discards and requests changes:
148
+
149
+ 1. Delete the folder: `rm -rf audio/originals/music/<slug>/`
150
+ 2. Ask what should change about the music.
151
+ 3. Adjust the prompt based on feedback. Common adjustments:
152
+ - "Too energetic" -- add "calm", "minimal", "ambient", reduce tempo
153
+ - "Too boring" -- add "building", "dynamic", increase tempo, add percussion
154
+ - "Wrong mood" -- change mood descriptors entirely
155
+ - "Too short" -- increase `duration_seconds`
156
+ - "Instruments are wrong" -- specify desired instruments, explicitly exclude unwanted ones ("no drums", "no vocals")
157
+ - "Needs a stronger ending" -- describe the outro in the prompt ("resolves to a clear final chord")
158
+ 4. Re-run with the updated prompt. Write a new `generate.sh` reflecting the new parameters.
159
+
160
+ ## Troubleshooting
161
+
162
+ | Issue | Resolution |
163
+ |---|---|
164
+ | 401 Unauthorized | Check `ELEVENLABS_API_KEY` in `.env`. Ensure the key has Music Generation permission. |
165
+ | 422 Unprocessable Entity | Prompt may be problematic. Keep prompts 20-500 characters. Avoid special characters. |
166
+ | Empty or 0-byte response | API may have failed silently. Retry. If persistent, try a shorter duration or different prompt. |
167
+ | Generated music does not match prompt | Increase `prompt_influence` (try 0.6-0.8). Be more specific about instruments and mood. |
168
+ | Music has vocals/singing | Add "instrumental only, no vocals, no singing" to the prompt. |
169
+ | Rate limited (429) | Wait and retry. Check quota at https://elevenlabs.io/app/subscription. |
170
+ | Track is shorter than requested | The API may cap duration. Try requesting in smaller segments or accept the shorter track. |
@@ -0,0 +1,140 @@
1
+ # Manual Music (Bring Your Own)
2
+
3
+ ## When this is loaded
4
+
5
+ The user has their own music audio file and wants to add it to the project. This is the BYO path from [../music.md](../music.md).
6
+
7
+ ## Overview
8
+
9
+ The manual flow takes a user-provided music file, places it in the correct folder, gathers rich 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 music track. The slug should describe the track's character in short snake_case:
14
+
15
+ - `uplift_piano`
16
+ - `calm_ambient`
17
+ - `energetic_corporate`
18
+ - `dark_synth_intro`
19
+
20
+ Create the directory:
21
+
22
+ ```bash
23
+ mkdir -p audio/originals/music/<slug>/
24
+ ```
25
+
26
+ ## Step 2: Get the audio file
27
+
28
+ Ask the user for the file. Two options:
29
+
30
+ 1. **File path.** The user provides a path to an existing file. Copy it into the folder:
31
+ ```bash
32
+ cp /path/to/their/file.mp3 audio/originals/music/<slug>/audio.mp3
33
+ ```
34
+
35
+ 2. **Drop-in.** Ask the user to place the file directly:
36
+ > Place your music file at `audio/originals/music/<slug>/audio.mp3` (or `audio.wav`).
37
+
38
+ ### Supported formats
39
+
40
+ - MP3 and WAV are standard. Both work with ffmpeg.
41
+ - Other formats (M4A, OGG, FLAC, AIFF) are also accepted by ffmpeg.
42
+ - No specific sample rate or bitrate requirements.
43
+
44
+ ## Step 3: Gather metadata
45
+
46
+ Music metadata should be richer than SFX. Ask the user:
47
+
48
+ > I need details about this music track. Please share as much as you know:
49
+ >
50
+ > 1. **Name** -- a short descriptive name (e.g., "Uplift piano")
51
+ > 2. **Description** -- one sentence summary (e.g., "Solo piano, gentle build to optimistic resolution")
52
+ > 3. **Notes** -- any musical detail you know. Helpful things to include:
53
+ > - BPM (tempo)
54
+ > - Key (e.g., C major, A minor)
55
+ > - Mood (e.g., hopeful, tense, calm)
56
+ > - Structure (e.g., "intro 0-8s, main theme 8-30s, outro 30-40s")
57
+ > - Loop points (where it loops cleanly, if applicable)
58
+ > - Instrument palette
59
+ > - Licensing info (if relevant)
60
+ >
61
+ > Even partial info is useful -- I will ask follow-up questions if needed.
62
+
63
+ ### Agent-observed details
64
+
65
+ After the user provides their info, the agent should also note any additional observations in `notes`:
66
+
67
+ - If BPM was not provided, ask the user to estimate or measure it after listening
68
+ - Ask the user about any structural transitions (energy changes, instrument entrances)
69
+ - Ask whether the track has a clean ending or fades out
70
+ - Ask whether it loops well
71
+
72
+ Combine user-provided info and agent observations into the `notes` field.
73
+
74
+ ## Step 4: Measure duration
75
+
76
+ Use ffprobe to get the exact length:
77
+
78
+ ```bash
79
+ ffprobe -v error -show_entries format=duration \
80
+ -of default=noprint_wrappers=1:nokey=1 \
81
+ audio/originals/music/<slug>/audio.mp3
82
+ ```
83
+
84
+ Round to 1 decimal place for `length_s`.
85
+
86
+ ## Step 5: Write `music.ts`
87
+
88
+ Create `audio/originals/music/<slug>/music.ts`:
89
+
90
+ ```ts
91
+ import type { MusicAsset } from "videowright";
92
+
93
+ export const music: MusicAsset = {
94
+ name: "<name from user>",
95
+ description: "<description from user>",
96
+ length_s: <measured duration>,
97
+ source: "user",
98
+ notes: `
99
+ <combined notes from user + agent observations>
100
+ `,
101
+ };
102
+
103
+ export default music;
104
+ ```
105
+
106
+ Set `source: "user"` to record that this was a BYO asset.
107
+
108
+ There is no `generate.sh` for BYO assets.
109
+
110
+ ## Step 6: Trigger approval UX
111
+
112
+ Follow the approval flow from [../music.md](../music.md):
113
+
114
+ 1. Print the clickable `file://` link to the audio file.
115
+ 2. Prompt: Approve or Discard and request changes.
116
+ 3. On Approve: asset is locked, ready for use in the audio plan.
117
+ 4. On Discard: delete the folder, ask what to change, loop back.
118
+
119
+ For BYO assets, "discard and request changes" means the user needs to provide a different file. Ask them to supply a different track.
120
+
121
+ ## Expected folder state after approval
122
+
123
+ ```
124
+ audio/originals/music/<slug>/
125
+ audio.mp3 # user-provided audio (immutable after approval)
126
+ music.ts # typed metadata with rich notes
127
+ ```
128
+
129
+ No `generate.sh` for BYO assets.
130
+
131
+ ## Edge cases
132
+
133
+ | Situation | Behavior |
134
+ |---|---|
135
+ | Track has vocals | Warn that vocals may conflict with voiceover. Suggest an instrumental version if available, or note that heavy ducking will be needed. |
136
+ | Track is very short (< 10s) | May need looping. Note loop-ability in `notes`. See [../../ffmpeg_cookbook.md](../../ffmpeg_cookbook.md) for `aloop`. |
137
+ | Track is very long (> 5min) | Fine -- the audio plan will use `Slice:` to take only the needed portion. |
138
+ | User does not know BPM/key | That is fine. BPM is optional -- ask the user to estimate if needed. Key is optional. Write what is known. |
139
+ | User mentions licensing/attribution | Record in `notes` (e.g., "Licensed via Artlist, attribution required in credits"). The agent does not enforce licensing. |
140
+ | User wants to replace after approval | Cannot edit in place. Source a new version in a new slug folder and update audio plan cues. |