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.
- package/README.md +91 -0
- package/dist/cli/argv.d.ts +28 -0
- package/dist/cli/argv.d.ts.map +1 -0
- package/dist/cli/argv.js +115 -0
- package/dist/cli/argv.js.map +1 -0
- package/dist/cli/bin.d.ts +7 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +10 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/dev.d.ts +19 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dev.js +104 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/discover.d.ts +29 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +104 -0
- package/dist/cli/discover.js.map +1 -0
- package/dist/cli/discover_project.d.ts +29 -0
- package/dist/cli/discover_project.d.ts.map +1 -0
- package/dist/cli/discover_project.js +108 -0
- package/dist/cli/discover_project.js.map +1 -0
- package/dist/cli/errors.d.ts +10 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +13 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/ffmpeg.d.ts +57 -0
- package/dist/cli/ffmpeg.d.ts.map +1 -0
- package/dist/cli/ffmpeg.js +122 -0
- package/dist/cli/ffmpeg.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +152 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/playwright_check.d.ts +44 -0
- package/dist/cli/playwright_check.d.ts.map +1 -0
- package/dist/cli/playwright_check.js +20 -0
- package/dist/cli/playwright_check.js.map +1 -0
- package/dist/cli/prompt.d.ts +13 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +47 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/render.d.ts +60 -0
- package/dist/cli/render.d.ts.map +1 -0
- package/dist/cli/render.js +471 -0
- package/dist/cli/render.js.map +1 -0
- package/dist/cli/script_cmd.d.ts +26 -0
- package/dist/cli/script_cmd.d.ts.map +1 -0
- package/dist/cli/script_cmd.js +88 -0
- package/dist/cli/script_cmd.js.map +1 -0
- package/dist/cli/time_shim.d.ts +44 -0
- package/dist/cli/time_shim.d.ts.map +1 -0
- package/dist/cli/time_shim.js +390 -0
- package/dist/cli/time_shim.js.map +1 -0
- package/dist/cli/ts_loader.d.ts +28 -0
- package/dist/cli/ts_loader.d.ts.map +1 -0
- package/dist/cli/ts_loader.js +95 -0
- package/dist/cli/ts_loader.js.map +1 -0
- package/dist/cli/vite_helpers.d.ts +62 -0
- package/dist/cli/vite_helpers.d.ts.map +1 -0
- package/dist/cli/vite_helpers.js +273 -0
- package/dist/cli/vite_helpers.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/player/hash_router.d.ts +23 -0
- package/dist/player/hash_router.d.ts.map +1 -0
- package/dist/player/hash_router.js +49 -0
- package/dist/player/hash_router.js.map +1 -0
- package/dist/player/hud.d.ts +33 -0
- package/dist/player/hud.d.ts.map +1 -0
- package/dist/player/hud.js +357 -0
- package/dist/player/hud.js.map +1 -0
- package/dist/player/index.d.ts +123 -0
- package/dist/player/index.d.ts.map +1 -0
- package/dist/player/index.js +848 -0
- package/dist/player/index.js.map +1 -0
- package/dist/player/input.d.ts +14 -0
- package/dist/player/input.d.ts.map +1 -0
- package/dist/player/input.js +90 -0
- package/dist/player/input.js.map +1 -0
- package/dist/player/slot.d.ts +22 -0
- package/dist/player/slot.d.ts.map +1 -0
- package/dist/player/slot.js +43 -0
- package/dist/player/slot.js.map +1 -0
- package/dist/player/transitions/cut.d.ts +7 -0
- package/dist/player/transitions/cut.d.ts.map +1 -0
- package/dist/player/transitions/cut.js +9 -0
- package/dist/player/transitions/cut.js.map +1 -0
- package/dist/player/transitions/fade.d.ts +7 -0
- package/dist/player/transitions/fade.d.ts.map +1 -0
- package/dist/player/transitions/fade.js +18 -0
- package/dist/player/transitions/fade.js.map +1 -0
- package/dist/player/transitions/index.d.ts +4 -0
- package/dist/player/transitions/index.d.ts.map +1 -0
- package/dist/player/transitions/index.js +4 -0
- package/dist/player/transitions/index.js.map +1 -0
- package/dist/player/transitions/slide.d.ts +6 -0
- package/dist/player/transitions/slide.d.ts.map +1 -0
- package/dist/player/transitions/slide.js +35 -0
- package/dist/player/transitions/slide.js.map +1 -0
- package/dist/script/index.d.ts +2 -0
- package/dist/script/index.d.ts.map +1 -0
- package/dist/script/index.js +2 -0
- package/dist/script/index.js.map +1 -0
- package/dist/script/script.d.ts +10 -0
- package/dist/script/script.d.ts.map +1 -0
- package/dist/script/script.js +41 -0
- package/dist/script/script.js.map +1 -0
- package/dist/segment/SegmentRunner.d.ts +52 -0
- package/dist/segment/SegmentRunner.d.ts.map +1 -0
- package/dist/segment/SegmentRunner.js +187 -0
- package/dist/segment/SegmentRunner.js.map +1 -0
- package/dist/segment/defineConfig.d.ts +6 -0
- package/dist/segment/defineConfig.d.ts.map +1 -0
- package/dist/segment/defineConfig.js +7 -0
- package/dist/segment/defineConfig.js.map +1 -0
- package/dist/segment/defineSegment.d.ts +7 -0
- package/dist/segment/defineSegment.d.ts.map +1 -0
- package/dist/segment/defineSegment.js +25 -0
- package/dist/segment/defineSegment.js.map +1 -0
- package/dist/segment/index.d.ts +5 -0
- package/dist/segment/index.d.ts.map +1 -0
- package/dist/segment/index.js +4 -0
- package/dist/segment/index.js.map +1 -0
- package/dist/timeline/index.d.ts +73 -0
- package/dist/timeline/index.d.ts.map +1 -0
- package/dist/timeline/index.js +142 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/loadAudioTrack.d.ts +18 -0
- package/dist/timeline/loadAudioTrack.d.ts.map +1 -0
- package/dist/timeline/loadAudioTrack.js +44 -0
- package/dist/timeline/loadAudioTrack.js.map +1 -0
- package/dist/timeline/loadVoiceover.d.ts +18 -0
- package/dist/timeline/loadVoiceover.d.ts.map +1 -0
- package/dist/timeline/loadVoiceover.js +38 -0
- package/dist/timeline/loadVoiceover.js.map +1 -0
- package/dist/timeline/resolveTiming.d.ts +28 -0
- package/dist/timeline/resolveTiming.d.ts.map +1 -0
- package/dist/timeline/resolveTiming.js +63 -0
- package/dist/timeline/resolveTiming.js.map +1 -0
- package/dist/timeline/validateTiming.d.ts +29 -0
- package/dist/timeline/validateTiming.d.ts.map +1 -0
- package/dist/timeline/validateTiming.js +62 -0
- package/dist/timeline/validateTiming.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
- package/skill/SKILL.md +64 -0
- package/skill/assets/hello_world/PLAN.md +31 -0
- package/skill/assets/hello_world/README.md +27 -0
- package/skill/assets/hello_world/audio/audio_plan.md +14 -0
- package/skill/assets/hello_world/segments/hello_intro.ts +69 -0
- package/skill/assets/hello_world/segments/hello_outro.ts +71 -0
- package/skill/assets/hello_world/timeline.ts +15 -0
- package/skill/assets/hello_world/voiceover_script/script.md +10 -0
- package/skill/assets/install/package.json +10 -0
- package/skill/assets/install/tsconfig.json +23 -0
- package/skill/assets/styles/editorial-mono/STYLE.md +124 -0
- package/skill/assets/styles/editorial-mono/brand.md +85 -0
- package/skill/assets/styles/editorial-mono/reference/animations.jsx +752 -0
- package/skill/assets/styles/editorial-mono/reference/scenes.html +563 -0
- package/skill/assets/styles/editorial-mono/sample/bullet.ts +101 -0
- package/skill/assets/styles/editorial-mono/sample/content.ts +104 -0
- package/skill/assets/styles/editorial-mono/sample/cta.ts +113 -0
- package/skill/assets/styles/editorial-mono/sample/feature.ts +111 -0
- package/skill/assets/styles/editorial-mono/sample/grid.ts +97 -0
- package/skill/assets/styles/editorial-mono/sample/kinetic.ts +96 -0
- package/skill/assets/styles/editorial-mono/sample/section.ts +101 -0
- package/skill/assets/styles/editorial-mono/sample/stat.ts +128 -0
- package/skill/assets/styles/editorial-mono/sample/title.ts +97 -0
- package/skill/assets/styles/editorial-mono/sample/ui-showcase.ts +159 -0
- package/skill/assets/styles/editorial-mono/tokens.css +44 -0
- package/skill/assets/styles/iso-diagram/STYLE.md +109 -0
- package/skill/assets/styles/iso-diagram/brand.md +32 -0
- package/skill/assets/styles/iso-diagram/reference/animations.jsx +673 -0
- package/skill/assets/styles/iso-diagram/reference/scenes.html +427 -0
- package/skill/assets/styles/iso-diagram/sample/bullet.ts +144 -0
- package/skill/assets/styles/iso-diagram/sample/content.ts +192 -0
- package/skill/assets/styles/iso-diagram/sample/cta.ts +162 -0
- package/skill/assets/styles/iso-diagram/sample/feature.ts +205 -0
- package/skill/assets/styles/iso-diagram/sample/grid.ts +181 -0
- package/skill/assets/styles/iso-diagram/sample/kinetic.ts +102 -0
- package/skill/assets/styles/iso-diagram/sample/section.ts +149 -0
- package/skill/assets/styles/iso-diagram/sample/stat.ts +164 -0
- package/skill/assets/styles/iso-diagram/sample/title.ts +173 -0
- package/skill/assets/styles/iso-diagram/sample/ui-showcase.ts +162 -0
- package/skill/assets/styles/iso-diagram/tokens.css +40 -0
- package/skill/assets/styles/motion-engineering/STYLE.md +106 -0
- package/skill/assets/styles/motion-engineering/brand.md +29 -0
- package/skill/assets/styles/motion-engineering/reference/animations.jsx +673 -0
- package/skill/assets/styles/motion-engineering/reference/scenes.html +513 -0
- package/skill/assets/styles/motion-engineering/sample/bullet.ts +176 -0
- package/skill/assets/styles/motion-engineering/sample/content.ts +228 -0
- package/skill/assets/styles/motion-engineering/sample/cta.ts +209 -0
- package/skill/assets/styles/motion-engineering/sample/feature.ts +299 -0
- package/skill/assets/styles/motion-engineering/sample/grid.ts +190 -0
- package/skill/assets/styles/motion-engineering/sample/kinetic.ts +159 -0
- package/skill/assets/styles/motion-engineering/sample/section.ts +196 -0
- package/skill/assets/styles/motion-engineering/sample/stat.ts +230 -0
- package/skill/assets/styles/motion-engineering/sample/title.ts +219 -0
- package/skill/assets/styles/motion-engineering/sample/ui-showcase.ts +267 -0
- package/skill/assets/styles/motion-engineering/tokens.css +40 -0
- package/skill/assets/styles/neon-terminal/STYLE.md +105 -0
- package/skill/assets/styles/neon-terminal/brand.md +27 -0
- package/skill/assets/styles/neon-terminal/reference/animations.jsx +673 -0
- package/skill/assets/styles/neon-terminal/reference/scenes.html +387 -0
- package/skill/assets/styles/neon-terminal/sample/bullet.ts +113 -0
- package/skill/assets/styles/neon-terminal/sample/content.ts +117 -0
- package/skill/assets/styles/neon-terminal/sample/cta.ts +131 -0
- package/skill/assets/styles/neon-terminal/sample/feature.ts +112 -0
- package/skill/assets/styles/neon-terminal/sample/grid.ts +128 -0
- package/skill/assets/styles/neon-terminal/sample/kinetic.ts +105 -0
- package/skill/assets/styles/neon-terminal/sample/section.ts +96 -0
- package/skill/assets/styles/neon-terminal/sample/stat.ts +123 -0
- package/skill/assets/styles/neon-terminal/sample/title.ts +122 -0
- package/skill/assets/styles/neon-terminal/sample/ui-showcase.ts +127 -0
- package/skill/assets/styles/neon-terminal/tokens.css +39 -0
- package/skill/assets/styles/risograph/STYLE.md +110 -0
- package/skill/assets/styles/risograph/brand.md +26 -0
- package/skill/assets/styles/risograph/reference/animations.jsx +673 -0
- package/skill/assets/styles/risograph/reference/scenes.html +403 -0
- package/skill/assets/styles/risograph/sample/bullet.ts +124 -0
- package/skill/assets/styles/risograph/sample/content.ts +135 -0
- package/skill/assets/styles/risograph/sample/cta.ts +149 -0
- package/skill/assets/styles/risograph/sample/feature.ts +152 -0
- package/skill/assets/styles/risograph/sample/grid.ts +123 -0
- package/skill/assets/styles/risograph/sample/kinetic.ts +125 -0
- package/skill/assets/styles/risograph/sample/section.ts +130 -0
- package/skill/assets/styles/risograph/sample/stat.ts +145 -0
- package/skill/assets/styles/risograph/sample/title.ts +132 -0
- package/skill/assets/styles/risograph/sample/ui-showcase.ts +147 -0
- package/skill/assets/styles/risograph/tokens.css +39 -0
- package/skill/assets/styles/swiss-console/STYLE.md +107 -0
- package/skill/assets/styles/swiss-console/brand.md +37 -0
- package/skill/assets/styles/swiss-console/reference/animations.jsx +673 -0
- package/skill/assets/styles/swiss-console/reference/scenes.html +420 -0
- package/skill/assets/styles/swiss-console/sample/bullet.ts +122 -0
- package/skill/assets/styles/swiss-console/sample/content.ts +137 -0
- package/skill/assets/styles/swiss-console/sample/cta.ts +109 -0
- package/skill/assets/styles/swiss-console/sample/feature.ts +163 -0
- package/skill/assets/styles/swiss-console/sample/grid.ts +145 -0
- package/skill/assets/styles/swiss-console/sample/kinetic.ts +117 -0
- package/skill/assets/styles/swiss-console/sample/section.ts +127 -0
- package/skill/assets/styles/swiss-console/sample/stat.ts +148 -0
- package/skill/assets/styles/swiss-console/sample/title.ts +148 -0
- package/skill/assets/styles/swiss-console/sample/ui-showcase.ts +198 -0
- package/skill/assets/styles/swiss-console/tokens.css +39 -0
- package/skill/install/INSTALL.md +400 -0
- package/skill/references/audio/audio_plan.md +199 -0
- package/skill/references/audio/build.md +208 -0
- package/skill/references/audio/cue_template.md +219 -0
- package/skill/references/audio/ffmpeg_cookbook.md +267 -0
- package/skill/references/audio/music/music.md +171 -0
- package/skill/references/audio/music/providers/elevenlabs.md +170 -0
- package/skill/references/audio/music/providers/manual.md +140 -0
- package/skill/references/audio/music/providers/openverse.md +265 -0
- package/skill/references/audio/sfx/providers/elevenlabs.md +152 -0
- package/skill/references/audio/sfx/providers/manual.md +117 -0
- package/skill/references/audio/sfx/providers/openverse.md +243 -0
- package/skill/references/audio/sfx/sfx.md +149 -0
- package/skill/references/audio/styles.md +102 -0
- package/skill/references/audio/sync.md +237 -0
- package/skill/references/audio/voiceover/animation_sync.md +142 -0
- package/skill/references/audio/voiceover/provider_script.md +153 -0
- package/skill/references/audio/voiceover/providers/elevenlabs.md +288 -0
- package/skill/references/audio/voiceover/providers/manual.md +100 -0
- package/skill/references/audio/voiceover/script_writing.md +100 -0
- package/skill/references/audio/voiceover/style_intake.md +56 -0
- package/skill/references/audio/voiceover/sync_algorithm.md +167 -0
- package/skill/references/audio/voiceover.md +296 -0
- package/skill/references/audio.md +135 -0
- package/skill/references/authoring_segment.md +446 -0
- package/skill/references/create_or_edit_video.md +232 -0
- package/skill/references/dev_server.md +157 -0
- package/skill/references/export.md +145 -0
- package/skill/references/new_video.md +117 -0
- package/skill/references/project_structure.md +144 -0
- package/skill/references/setup.md +109 -0
- package/skill/references/setup_new_style.md +158 -0
- package/skill/references/styles.md +154 -0
- package/skill/references/testing.md +115 -0
- package/skill/references/types.md +240 -0
- package/src/cli/entry/components/copy_button.ts +42 -0
- package/src/cli/entry/components/download_modal.ts +204 -0
- package/src/cli/entry/components/empty_state.ts +55 -0
- package/src/cli/entry/components/hide_hud_tab.ts +37 -0
- package/src/cli/entry/components/icons.ts +31 -0
- package/src/cli/entry/components/top_bar.ts +69 -0
- package/src/cli/entry/components/video_card.ts +57 -0
- package/src/cli/entry/dev_frame.ts +189 -0
- package/src/cli/entry/entry_index.ts +16 -0
- package/src/cli/entry/entry_video.ts +24 -0
- package/src/cli/entry/index.html +12 -0
- package/src/cli/entry/parse_slug.ts +14 -0
- package/src/cli/entry/render.html +17 -0
- package/src/cli/entry/render_entry.ts +121 -0
- package/src/cli/entry/styles/base.css +45 -0
- package/src/cli/entry/styles/components.css +605 -0
- package/src/cli/entry/styles/tokens.css +44 -0
- package/src/cli/entry/video.html +22 -0
- package/src/cli/entry/views/homepage.ts +66 -0
- package/src/cli/entry/views/video_view.ts +286 -0
- 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. |
|