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,243 @@
|
|
|
1
|
+
# Openverse SFX Search
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
The user chose Openverse to find a sound effect. 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., `keyboard+typing`). |
|
|
29
|
+
| `license` | No | Comma-separated license filter. Default: `cc0,pdm,by`. |
|
|
30
|
+
| `category` | No | `music` or `sound_effect`. For SFX, always set `category=sound_effect`. |
|
|
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=keyboard+typing&license=cc0,pdm,by&category=sound_effect&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 sound they need (if not already clear from context). Construct a search query from their description:
|
|
57
|
+
|
|
58
|
+
- Use short, descriptive terms: `keyboard+typing`, `door+slam`, `whoosh`, `notification+chime`
|
|
59
|
+
- Add qualifiers if the user mentioned them: `mechanical+keyboard`, `soft+whoosh`
|
|
60
|
+
|
|
61
|
+
### Step 2: Execute search
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
curl -s "https://api.openverse.org/v1/audio/?q=<query>&license=cc0,pdm,by&category=sound_effect&page_size=20"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If the response is a 429 (rate limited), wait 2 seconds and retry:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
sleep 2
|
|
71
|
+
curl -s "https://api.openverse.org/v1/audio/?q=<query>&license=cc0,pdm,by&category=sound_effect&page_size=20"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Step 3: Evaluate results
|
|
75
|
+
|
|
76
|
+
Parse the JSON response. Filter results for relevance:
|
|
77
|
+
|
|
78
|
+
- Title or tags should match the desired sound
|
|
79
|
+
- Duration should be reasonable for an SFX (typically < 30s)
|
|
80
|
+
- Prefer `cc0` or `pdm` over `by` (no attribution required)
|
|
81
|
+
|
|
82
|
+
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).
|
|
83
|
+
|
|
84
|
+
### Step 4: Multi-choice offer
|
|
85
|
+
|
|
86
|
+
If there are several qualifying matches (3+), offer the user a choice:
|
|
87
|
+
|
|
88
|
+
> We have found several possible SFX matches! Would you like us to:
|
|
89
|
+
>
|
|
90
|
+
> 1. **Download 5 candidates** -- you listen and pick your favorite
|
|
91
|
+
> 2. **Use the top match** -- we will download the best result directly
|
|
92
|
+
|
|
93
|
+
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).
|
|
94
|
+
|
|
95
|
+
If there are fewer than 3 matches, skip the offer and download the best match directly.
|
|
96
|
+
|
|
97
|
+
## Download: single track
|
|
98
|
+
|
|
99
|
+
Download the selected audio file into the SFX folder:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
mkdir -p audio/originals/sfx/<slug>/
|
|
103
|
+
curl -L -o audio/originals/sfx/<slug>/audio.mp3 "<url from response>"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If the source URL points to a `.wav` or other format, save with the appropriate extension.
|
|
107
|
+
|
|
108
|
+
**Important:** Run curl with `-L` to follow redirects. Openverse URLs often redirect to the source hosting.
|
|
109
|
+
|
|
110
|
+
## Download: 5 candidates flow
|
|
111
|
+
|
|
112
|
+
When the user chooses the "download 5" option:
|
|
113
|
+
|
|
114
|
+
### Step A: Create candidates folder
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
mkdir -p audio/originals/sfx/<slug>/candidates/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step B: Download top 5 results
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
curl -L -o audio/originals/sfx/<slug>/candidates/1.mp3 "<url_1>"
|
|
124
|
+
curl -L -o audio/originals/sfx/<slug>/candidates/2.mp3 "<url_2>"
|
|
125
|
+
curl -L -o audio/originals/sfx/<slug>/candidates/3.mp3 "<url_3>"
|
|
126
|
+
curl -L -o audio/originals/sfx/<slug>/candidates/4.mp3 "<url_4>"
|
|
127
|
+
curl -L -o audio/originals/sfx/<slug>/candidates/5.mp3 "<url_5>"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If any download gets a 429, wait 2 seconds and retry that single request.
|
|
131
|
+
|
|
132
|
+
### Step C: Present candidates to user
|
|
133
|
+
|
|
134
|
+
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.
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Here are 5 SFX candidates in:
|
|
138
|
+
file:///absolute/path/to/audio/originals/sfx/<slug>/candidates/
|
|
139
|
+
|
|
140
|
+
1. <title_1> (by <creator_1>, <license_1>, <duration_1>s)
|
|
141
|
+
file:///absolute/path/to/audio/originals/sfx/<slug>/candidates/1.mp3
|
|
142
|
+
|
|
143
|
+
2. <title_2> (by <creator_2>, <license_2>, <duration_2>s)
|
|
144
|
+
file:///absolute/path/to/audio/originals/sfx/<slug>/candidates/2.mp3
|
|
145
|
+
|
|
146
|
+
3. ...
|
|
147
|
+
|
|
148
|
+
Pick a number (1-5), or let me know if you would like to hear more options.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Step D: User picks a winner
|
|
152
|
+
|
|
153
|
+
Once the user picks (e.g., "3"):
|
|
154
|
+
|
|
155
|
+
1. Move the winner into position:
|
|
156
|
+
```bash
|
|
157
|
+
mv audio/originals/sfx/<slug>/candidates/3.mp3 audio/originals/sfx/<slug>/audio.mp3
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
2. Delete the candidates folder:
|
|
161
|
+
```bash
|
|
162
|
+
rm -rf audio/originals/sfx/<slug>/candidates/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
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).
|
|
166
|
+
|
|
167
|
+
4. Proceed to metadata and approval (Step 5 below).
|
|
168
|
+
|
|
169
|
+
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.
|
|
170
|
+
|
|
171
|
+
## Step 5: Measure duration
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
ffprobe -v error -show_entries format=duration \
|
|
175
|
+
-of default=noprint_wrappers=1:nokey=1 \
|
|
176
|
+
audio/originals/sfx/<slug>/audio.mp3
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Round to 1 decimal place for `length_s`.
|
|
180
|
+
|
|
181
|
+
## Step 6: Write `sfx.ts`
|
|
182
|
+
|
|
183
|
+
Create `audio/originals/sfx/<slug>/sfx.ts`:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import type { SfxAsset } from "videowright";
|
|
187
|
+
|
|
188
|
+
export const sfx: SfxAsset = {
|
|
189
|
+
name: "<title from Openverse or user-refined name>",
|
|
190
|
+
description: "<description from Openverse or agent-written summary>",
|
|
191
|
+
length_s: <measured duration>,
|
|
192
|
+
source: "openverse",
|
|
193
|
+
notes: "Openverse: <title> by <creator>. License: <license>. Share link: https://openverse.org/audio/<id>",
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export default sfx;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
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.
|
|
200
|
+
|
|
201
|
+
There is no `generate.sh` for Openverse assets (the download is a one-time fetch, not a reproducible generation).
|
|
202
|
+
|
|
203
|
+
## Step 7: Trigger approval UX
|
|
204
|
+
|
|
205
|
+
Follow the approval flow from [../sfx.md](../sfx.md):
|
|
206
|
+
|
|
207
|
+
1. Print the clickable `file://` link to the audio file.
|
|
208
|
+
2. Prompt: Approve or Discard and request changes.
|
|
209
|
+
3. On Approve: asset is locked, ready for use in the audio plan.
|
|
210
|
+
4. On Discard: delete the folder, ask what to change, search again with adjusted terms.
|
|
211
|
+
|
|
212
|
+
## Iteration on discard
|
|
213
|
+
|
|
214
|
+
If the user discards and requests changes:
|
|
215
|
+
|
|
216
|
+
1. Delete the folder: `rm -rf audio/originals/sfx/<slug>/`
|
|
217
|
+
2. Ask what should change about the sound.
|
|
218
|
+
3. Adjust the search query based on feedback:
|
|
219
|
+
- "Too long" -- filter results by duration
|
|
220
|
+
- "Wrong type of sound" -- change the search terms
|
|
221
|
+
- "Too noisy/quiet" -- try different search terms or suggest BYO/ElevenLabs instead
|
|
222
|
+
4. Re-run the search and download flow.
|
|
223
|
+
|
|
224
|
+
## Expected folder state after approval
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
audio/originals/sfx/<slug>/
|
|
228
|
+
audio.mp3 # downloaded from Openverse (immutable after approval)
|
|
229
|
+
sfx.ts # typed metadata with provenance in notes
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
No `generate.sh` and no `candidates/` folder after approval.
|
|
233
|
+
|
|
234
|
+
## Edge cases
|
|
235
|
+
|
|
236
|
+
| Situation | Behavior |
|
|
237
|
+
|---|---|
|
|
238
|
+
| No results for the query | Broaden search terms. If still nothing, suggest BYO or ElevenLabs. |
|
|
239
|
+
| All results are too long (> 30s) | These may be music tracks miscategorized. Try adding more specific terms or switching to `category=music` if the user actually wants music. |
|
|
240
|
+
| Downloaded file is 0 bytes or corrupt | Delete and retry the download. If persistent, try a different result. |
|
|
241
|
+
| License is `by` (attribution required) | Note in `sfx.ts` notes that attribution is required. The agent does not enforce attribution in the final video but records the obligation. |
|
|
242
|
+
| Rate limited during batch download | Wait 2 seconds between each retry. Do not hammer the API. |
|
|
243
|
+
| User wants to search again after seeing candidates | Delete the candidates folder and re-run with new search terms. |
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Sound Effects (SFX)
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You were routed here from [audio.md](../../audio.md) because the user wants to add sound effects to their video. This reference covers sourcing, approving, and managing SFX assets.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Each SFX is a short audio clip stored in `audio/originals/sfx/<slug>/`. SFX 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.
|
|
10
|
+
|
|
11
|
+
## Sourcing decision
|
|
12
|
+
|
|
13
|
+
Ask the user how they want to source sound effects. Always ask when starting a new sourcing job, even if existing SFX in the project used a specific source -- don't assume continuity with prior assets.
|
|
14
|
+
|
|
15
|
+
> How would you like to source sound effects?
|
|
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 sound you want and I will generate it via the ElevenLabs Sound Generation API. **Requires a paid plan and API key.**
|
|
19
|
+
> 3. **Search Openverse** -- search for freely-licensed sound effects 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
|
+
If the user wants multiple SFX, they may use different sources for each. Ask per-asset or batch as appropriate.
|
|
28
|
+
|
|
29
|
+
## Folder structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
audio/originals/sfx/
|
|
33
|
+
keyboard_typing/
|
|
34
|
+
audio.mp3 # source audio (immutable after approval)
|
|
35
|
+
sfx.ts # typed metadata
|
|
36
|
+
generate.sh # only for ElevenLabs-sourced SFX
|
|
37
|
+
whoosh_swipe/
|
|
38
|
+
audio.mp3
|
|
39
|
+
sfx.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Slug naming
|
|
43
|
+
|
|
44
|
+
SFX folders use short, semantic, snake_case names that describe the sound:
|
|
45
|
+
|
|
46
|
+
- `keyboard_typing`
|
|
47
|
+
- `door_close`
|
|
48
|
+
- `whoosh_swipe`
|
|
49
|
+
- `notification_chime`
|
|
50
|
+
- `paper_shuffle`
|
|
51
|
+
|
|
52
|
+
The slug should be recognizable at a glance in the audio plan. Avoid generic names like `sfx_1` or `sound_effect_a`.
|
|
53
|
+
|
|
54
|
+
## `sfx.ts` metadata
|
|
55
|
+
|
|
56
|
+
Each SFX asset has a typed metadata file:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import type { SfxAsset } from "videowright";
|
|
60
|
+
|
|
61
|
+
export const sfx: SfxAsset = {
|
|
62
|
+
name: "Keyboard typing",
|
|
63
|
+
description: "Mechanical keyboard, fast typing, ~4 second loop",
|
|
64
|
+
length_s: 4.4,
|
|
65
|
+
source: "elevenlabs",
|
|
66
|
+
notes: "Crisp clicks at start, softens after 2s. Loops cleanly.",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default sfx;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Fields:
|
|
73
|
+
|
|
74
|
+
| Field | Required | Description |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `name` | Yes | Human-readable name for display and reference. |
|
|
77
|
+
| `description` | Yes | One-line summary of what the sound is. Used by the agent when selecting SFX for cues. |
|
|
78
|
+
| `length_s` | Yes | Duration in seconds, measured via ffprobe. Round to 1 decimal place. |
|
|
79
|
+
| `source` | Yes | `"elevenlabs"`, `"user"`, or `"openverse"`. Records provenance. |
|
|
80
|
+
| `notes` | No | Free-text observations about the sound. Useful detail: loop points, transient positions, frequency character, anything that helps place it in a mix. |
|
|
81
|
+
|
|
82
|
+
If the `SfxAsset` type is not yet exported from videowright, use an inline type annotation or `any` -- the shape is what matters.
|
|
83
|
+
|
|
84
|
+
## Approval UX
|
|
85
|
+
|
|
86
|
+
After an SFX asset is sourced (file in place, `sfx.ts` written), present it for approval:
|
|
87
|
+
|
|
88
|
+
1. **Print a clickable absolute `file://` link** to the audio file so the user can listen:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Listen to the sound effect:
|
|
92
|
+
file:///absolute/path/to/audio/originals/sfx/keyboard_typing/audio.mp3
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
2. **Prompt with exactly two options:**
|
|
96
|
+
|
|
97
|
+
> 1. **Approve** -- lock this asset for use in the audio plan.
|
|
98
|
+
> 2. **Discard and request changes** -- delete this asset and try again.
|
|
99
|
+
|
|
100
|
+
3. **On Approve:**
|
|
101
|
+
- The asset is now locked. Its folder and contents must not be modified or deleted.
|
|
102
|
+
- Proceed to integrate it into the audio plan (see "Integration into audio plan" below).
|
|
103
|
+
|
|
104
|
+
4. **On Discard:**
|
|
105
|
+
- Delete the entire asset folder:
|
|
106
|
+
```bash
|
|
107
|
+
rm -rf audio/originals/sfx/<slug>/
|
|
108
|
+
```
|
|
109
|
+
- Ask: "What should change about this sound effect?"
|
|
110
|
+
- Take feedback and re-source (loop back to the provider flow).
|
|
111
|
+
|
|
112
|
+
### Pre-use deletion only
|
|
113
|
+
|
|
114
|
+
An SFX 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.
|
|
115
|
+
|
|
116
|
+
## Integration into audio plan
|
|
117
|
+
|
|
118
|
+
After approval, the SFX is ready to be referenced in `audio/audio_plan.md` as a cue. See [../cue_template.md](../cue_template.md) for the cue format.
|
|
119
|
+
|
|
120
|
+
Typical SFX cue:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
### Cue 3 -- Keyboard typing
|
|
124
|
+
Source: audio/originals/sfx/keyboard_typing/
|
|
125
|
+
Slice: full file
|
|
126
|
+
Place at: 5.2
|
|
127
|
+
Volume: 50%
|
|
128
|
+
Fades: fade in 0-0.1s, fade out 4.2-4.4s
|
|
129
|
+
Notes: Typing sound during terminal demo segment. Subtle backdrop.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Key points:
|
|
133
|
+
- `Source:` points to the SFX folder (the build step finds `audio.mp3` within it).
|
|
134
|
+
- `Volume:` for SFX is typically 40-70% of VO level. See [../styles.md](../styles.md) for guidance.
|
|
135
|
+
- Brief fades (0.1-0.3s) prevent clicks. Always add at least a 0.1s fade-in and fade-out.
|
|
136
|
+
- Use `Slice:` if you only need part of the SFX (`Slice: 0.5-2.0` for a 1.5s excerpt).
|
|
137
|
+
|
|
138
|
+
## Multiple SFX per video
|
|
139
|
+
|
|
140
|
+
Videos commonly have 2-5 sound effects. Source and approve them one at a time (or batch if the user prefers), then arrange them as cues in the audio plan. Each SFX gets its own folder under `audio/originals/sfx/`.
|
|
141
|
+
|
|
142
|
+
## Edge cases
|
|
143
|
+
|
|
144
|
+
| Situation | Behavior |
|
|
145
|
+
|---|---|
|
|
146
|
+
| User wants to preview before committing to a source | Fine -- generate or import, play via file:// link, then decide. The approval UX handles this. |
|
|
147
|
+
| SFX is too long (> 10s) | Not an error, but unusual. Confirm with the user that they want a long ambient texture rather than a punctual effect. |
|
|
148
|
+
| User wants to edit an approved SFX | Cannot modify in place (immutable). Source a new version in a new slug folder, approve it, and update the audio plan cues to reference the new slug. |
|
|
149
|
+
| Format is .wav instead of .mp3 | Both are valid. Use whatever the source provides. Reference `audio.wav` instead of `audio.mp3` in the folder. |
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Audio Editing Style Guide
|
|
2
|
+
|
|
3
|
+
## When this is loaded
|
|
4
|
+
|
|
5
|
+
You are authoring or reviewing an audio plan for a product/demo video. This reference encodes opinions about what makes audio sound professional in this context. Apply these principles when writing volume curves, choosing levels, and reviewing mixes.
|
|
6
|
+
|
|
7
|
+
## Music level under speech
|
|
8
|
+
|
|
9
|
+
Music should recede when voiceover is speaking. The ear should never strain to separate the two.
|
|
10
|
+
|
|
11
|
+
| Scenario | Music level | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| VO speaking | 10-20% (roughly -14 to -20 dB below VO) | The music becomes texture, not competition. 15% is a good starting point. |
|
|
14
|
+
| VO pauses (animation beats, transitions) | 40-60% | Music can rise during visual-only moments to fill the space. |
|
|
15
|
+
| No VO at all (intro/outro, silent segments) | 80-100% | Let the music breathe when nothing else needs attention. |
|
|
16
|
+
|
|
17
|
+
These are guidelines, not rules. Trust your ear after rendering -- if the mix sounds right at different levels, those levels are right.
|
|
18
|
+
|
|
19
|
+
## SFX level
|
|
20
|
+
|
|
21
|
+
Sound effects should punctuate, not compete.
|
|
22
|
+
|
|
23
|
+
- **Peak level**: SFX should sit at 40-70% of VO level (e.g., `volume=0.4` to `volume=0.7` when VO is at `volume=1.0`). Loud enough to notice, quiet enough to not startle.
|
|
24
|
+
- **Duration**: keep SFX short. A 0.5-2s effect is typical. Longer ambient textures (server hum, rain) are exceptions.
|
|
25
|
+
- **Entry/exit**: brief fades (0.1-0.3s) prevent clicks and soften the transition. Even a 0.1s fade-in removes the harshness of a cold start.
|
|
26
|
+
|
|
27
|
+
### The "enhance, don't decorate" test
|
|
28
|
+
|
|
29
|
+
Before adding a SFX cue, ask: **would removing this hurt the video?** If no, it is decoration -- skip it. Good SFX makes a moment land (a typing sound while showing a terminal, a whoosh on a fast transition). Bad SFX adds noise without meaning.
|
|
30
|
+
|
|
31
|
+
Signs a SFX is decoration:
|
|
32
|
+
- It does not align with anything on screen.
|
|
33
|
+
- Removing it and the video feels the same.
|
|
34
|
+
- It draws attention to itself rather than to the visual.
|
|
35
|
+
|
|
36
|
+
## Ducking ramps
|
|
37
|
+
|
|
38
|
+
When transitioning music volume (e.g., ducking under VO), use smooth ramps rather than hard cuts.
|
|
39
|
+
|
|
40
|
+
| Ramp duration | Feel | Use for |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| 0.1-0.15s | Near-instant | Emergency ducks, very tight timing |
|
|
43
|
+
| 0.2s | Natural, unnoticeable | Standard duck-under-VO. **This is the default.** |
|
|
44
|
+
| 0.3-0.5s | Gentle, cinematic | Mood transitions, slow fades between sections |
|
|
45
|
+
| 1.0s+ | Dramatic | Deliberate musical swells or long crossfades |
|
|
46
|
+
|
|
47
|
+
The 0.2s ramp is the workhorse. It is fast enough that the listener does not perceive a gap, but slow enough that the volume change is not jarring.
|
|
48
|
+
|
|
49
|
+
### Ramp placement
|
|
50
|
+
|
|
51
|
+
- **Duck start**: begin the ramp 0.1-0.2s **before** the VO starts speaking. This way the music is already quiet when the first word lands.
|
|
52
|
+
- **Duck end**: begin the ramp **at** the last VO word's end timestamp. The music rises as the voice fades, creating a smooth handoff.
|
|
53
|
+
|
|
54
|
+
## Headroom and loudness target
|
|
55
|
+
|
|
56
|
+
### Target: -14 LUFS
|
|
57
|
+
|
|
58
|
+
Aim for an integrated loudness of **-14 LUFS** for the final mix. This is the standard for web and social media delivery (YouTube, Twitter/X, LinkedIn all normalize to roughly this range).
|
|
59
|
+
|
|
60
|
+
- Use the `loudnorm` ffmpeg filter as the final step in the mix chain. See [ffmpeg_cookbook.md](ffmpeg_cookbook.md).
|
|
61
|
+
- True peak should stay below **-1 dBTP** to prevent clipping after codec encoding.
|
|
62
|
+
|
|
63
|
+
### Leave dynamic range
|
|
64
|
+
|
|
65
|
+
Do not over-compress. A product demo benefits from some dynamics -- the VO should be louder than the music bed, SFX should punch above the ambient level. Flattening everything to the same volume makes the mix fatiguing.
|
|
66
|
+
|
|
67
|
+
The `loudnorm` filter with default LRA (loudness range) handles this well. Do not add additional compression unless the mix sounds uneven after loudnorm.
|
|
68
|
+
|
|
69
|
+
## Music selection principles
|
|
70
|
+
|
|
71
|
+
Match the music to the **segment's energy**, not just the overall video tone.
|
|
72
|
+
|
|
73
|
+
| Video moment | Music character |
|
|
74
|
+
|---|---|
|
|
75
|
+
| Intro / title card | Building energy, anticipation. Ambient textures or a gentle melody. |
|
|
76
|
+
| Feature explanation | Steady, supportive. Not distracting. Mid-energy. |
|
|
77
|
+
| Data / stats reveal | Can be more driving. Light percussion or rhythmic pulse. |
|
|
78
|
+
| Demo / terminal segment | Can drop to minimal or ambient. Let the visual speak. |
|
|
79
|
+
| Transition between sections | Brief energy bump. A swell, a beat drop, or a key change. |
|
|
80
|
+
| Outro / CTA | Resolution. Return to the intro's mood or build to a satisfying close. |
|
|
81
|
+
|
|
82
|
+
### One track or many?
|
|
83
|
+
|
|
84
|
+
For most product/demo videos (30s-3min), **one music track** is sufficient. The ducking curve and natural dynamics of the chosen track provide enough variation. Multiple music tracks increase complexity without proportional benefit unless the video has distinct tonal sections (e.g., a serious problem statement followed by an upbeat solution demo).
|
|
85
|
+
|
|
86
|
+
### BPM considerations
|
|
87
|
+
|
|
88
|
+
If the music has a strong beat, align visual transitions to beat boundaries when possible. The agent can read BPM from the `notes` field in `music.ts` and compute beat times: `beat_time = offset + (beat_number * 60 / BPM)`.
|
|
89
|
+
|
|
90
|
+
## Putting it together
|
|
91
|
+
|
|
92
|
+
A well-mixed product demo audio track:
|
|
93
|
+
|
|
94
|
+
1. **Starts with music** at full level (or fading in over 0.5s) during the title card or intro visual.
|
|
95
|
+
2. **Ducks music** smoothly (0.2s ramp) as the VO begins.
|
|
96
|
+
3. **Keeps music at 15%** under all speech segments.
|
|
97
|
+
4. **Raises music** during animation-only beats (visual transitions, data reveals without narration).
|
|
98
|
+
5. **Adds SFX sparingly** at key moments: a typing sound over a terminal demo, a subtle chime on a stat reveal. Each SFX fades in/out over 0.1-0.2s.
|
|
99
|
+
6. **Ends with music rising** as the VO concludes, carrying the outro to a clean fade-out or natural ending.
|
|
100
|
+
7. **Runs through loudnorm** at -14 LUFS as the final mastering step.
|
|
101
|
+
|
|
102
|
+
This pattern produces a polished, professional result. Deviate when the video calls for it, but start here.
|