SFX Config Reference — sfx_<slug>_<TAG>.json
The SFX config file maps every sound direction in a parsed episode script to its audio
source and playback parameters. One file covers an entire episode; it is read by
xil produce, xil sfx, xil mix, and xil daw.
Filename pattern: sfx_<slug>_<TAG>.json
(e.g. sfx_the413_S03E02.json, sfx_nightowls_V01C03.json)
Top-level Structure
| Field | Type | Description |
|---|---|---|
show |
string | Show name (informational; slug is derived from project.json) |
season |
int | Season number |
episode |
int | Episode number |
defaults |
object | Fallback values applied to all effects unless overridden per-entry |
effects |
object | Map of direction text → effect config |
defaults Block
All keys are optional. Per-entry values override these.
"defaults": {
"prompt_influence": 0.3,
"volume_percentage": 20,
"ramp_in_seconds": 1.0,
"ramp_out_seconds": 1.0,
"ambience_volume_percentage": 30,
"ambience_ramp_in_seconds": 1.0,
"ambience_ramp_out_seconds": 1.0
}
| Key | Type | Description |
|---|---|---|
prompt_influence |
float 0–1 | How closely the API follows the prompt vs. free creativity. Default 0.3. |
volume_percentage |
float | Playback volume for SFX and MUSIC entries. 100 = unity gain. |
ramp_in_seconds |
float | Fade-in duration in seconds for SFX and MUSIC entries. |
ramp_out_seconds |
float | Fade-out duration in seconds for SFX and MUSIC entries. |
ambience_volume_percentage |
float | Volume for AMBIENCE entries specifically. |
ambience_ramp_in_seconds |
float | Fade-in for AMBIENCE entries. |
ambience_ramp_out_seconds |
float | Fade-out for AMBIENCE entries. |
Category-specific keys (ambience_*) take precedence over the generic ones for
AMBIENCE entries. If no category-specific key exists, the generic key is the fallback.
effects Keys
Each key must exactly match the text field of a parsed direction entry. The parser
emits direction text verbatim from the script, so capitalisation and punctuation matter.
Effect Entry Fields
type
Controls how audio is produced. Most entries don't need this field — the default is
inferred from the key prefix (AMBIENCE:, MUSIC:, SFX:, BEAT, etc.) by the
direction classifier.
| Value | Behaviour |
|---|---|
"sfx" |
(default) Generate via ElevenLabs Sound Effects API or copy from source. |
"silence" |
Generate local silent audio. No API call. |
source
Path to an existing audio file (relative to the project root or absolute).
"SFX: RADIO STATIC — BRIEF TUNING": {
"source": "SFX/sfx_radio-static-tuning-transition.mp3",
"duration_seconds": 1.5
}
- Resolved with
os.path.realpath()before use (symlinks are followed; path traversal is blocked). - If present and the file exists → the file is copied to the shared SFX library. No API credit is spent.
- If present but the file is missing and a
promptis also set → falls back to API generation with a warning. - If present but the file is missing and no
promptis set → raisesFileNotFoundError.
prompt
Text sent to the ElevenLabs Sound Effects API when no usable source file is found.
- If
sourceis absent → API is always called using this prompt. prompt_influence(from this entry ordefaults) controls creativity vs. adherence.
duration_seconds
Meaning depends on context:
| Context | Meaning |
|---|---|
Entry has source, no play_duration |
Clip the source file to this many seconds at mix time |
Entry has no source (API generation) |
Requested generation length sent to ElevenLabs API |
type: "silence" |
Duration of the generated silence |
type: "silence", value 0.0 |
Stop-marker — inserts a boundary in the timeline with no audio |
"AMBIENCE: RADIO BOOTH — SOFT EQUIPMENT HUM": {
"source": "SFX/ambience_radio-booth.mp3",
"duration_seconds": 30.0,
"loop": true
}
play_duration
Percentage of the source file to use (0–100). Applied at stem copy time (XILP002), so the resulting stem file is already trimmed — all downstream tools see the correct duration.
"OUTRO MUSIC": {
"source": "SFX/The Porch Light.mp3",
"volume_percentage": 40,
"play_duration": 25
}
25= use the first 25% of "The Porch Light.mp3".- Only valid when
sourceis set. - Mutually exclusive with
duration_secondsfor music entries; use one or the other. - Best for music where the natural length is unknown and you want a proportional excerpt rather than a hard-coded second count.
loop
Boolean. Controls whether the audio tiles to fill the scene duration.
| Value | Behaviour |
|---|---|
true (default for AMBIENCE) |
Tile the file repeatedly to cover the full scene |
false |
Play the file once; silence fills the remainder of the scene |
"AMBIENCE: OUTDOOR SPRING": {
"source": "SFX/AMBPark-Outdoor_spring_ambie-Elevenlabs.mp3",
"duration_seconds": 30.0,
"loop": true
}
volume_percentage
Per-entry volume override. Overrides the defaults category key for this entry only.
"INTRO MUSIC": {
"source": "SFX/The Porch Light.mp3",
"volume_percentage": 40,
"play_duration": 30
}
100= unity gain (no change).40= 40% of full volume (roughly −8 dB).- Applies to SFX, MUSIC, and AMBIENCE entries.
prompt_influence
Per-entry override for ElevenLabs API creativity control (0.0–1.0).
0.0= maximum creative freedom; ignores prompt text almost entirely.1.0= strict adherence to the prompt.- Falls back to
defaults.prompt_influencewhen absent.
Reserved Keys
Two effect keys have special pipeline behaviour beyond normal playback:
| Key | Behaviour |
|---|---|
"INTRO MUSIC" |
XILP002 reads source and copies it to n001_preamble_sfx.mp3. The play_duration trim is applied at copy time. No API call. |
"OUTRO MUSIC" |
Same as INTRO MUSIC but written as the postamble SFX stem. |
Stop Markers
Use type: "silence" with duration_seconds: 0.0 to insert an ambience boundary
without generating audio. The mixer treats this as an instruction to stop the current
ambience loop at that timeline position.
"AMBIENCE: STOP": {
"type": "silence",
"duration_seconds": 0.0
},
"MUSIC: THEME FADES OUT": {
"type": "silence",
"duration_seconds": 0.0
}
The source field is ignored when duration_seconds is 0.0.
How Fields Combine — Decision Tree
effect entry
│
├── source present and file exists?
│ ├── play_duration set? → trim to % of file at copy time (stem file is pre-trimmed)
│ └── duration_seconds set? → clip to N seconds at mix time
│
├── source absent (or file missing) and prompt set?
│ └── call ElevenLabs API; duration_seconds = requested length
│
└── type = "silence"?
└── duration_seconds = 0.0 → stop marker (no audio)
duration_seconds > 0 → generate local silence
Field Reference Summary
| Field | Type | Default | When used |
|---|---|---|---|
type |
"sfx" | "silence" |
"sfx" |
All entries |
source |
string (path) | — | Source-based entries |
prompt |
string | — | API-generated entries |
duration_seconds |
float | — | Clip/generate/silence length |
play_duration |
float (0–100) | — | Source music % trim |
loop |
bool | true for AMBIENCE |
Tile vs. one-shot |
volume_percentage |
float | from defaults |
Per-entry volume |
prompt_influence |
float 0–1 | from defaults |
API creativity control |
Complete Entry Examples
Silence Beat
Looping Ambience (source)
"AMBIENCE: RADIO BOOTH — SOFT EQUIPMENT HUM, SLIGHT STATIC, INTIMATE": {
"source": "SFX/ambience_radio-booth-soft-equipment-hum-slight-static-intimate.mp3",
"duration_seconds": 30.0,
"loop": true
}
One-shot SFX (source, clipped)
"SFX: RADIO STATIC — BRIEF TUNING": {
"source": "SFX/sfx_radio-static-tuning-transition.mp3",
"duration_seconds": 1.5
}
Music Sting (source, clipped)
"MUSIC: THEME — BRIEF STING, RETURNS SOFT": {
"source": "SFX/MUSCStngr-Short_medieval_melod-Elevenlabs.mp3",
"duration_seconds": 5.0
}
Music with Percentage Trim (source, play_duration)
"OUTRO MUSIC": {
"source": "SFX/The Porch Light.mp3",
"volume_percentage": 40,
"play_duration": 25
}
API-Generated Music
Ambience Stop Marker
See Also
- SFX Reuse Guide — how to minimise ElevenLabs credit spend
- DIRECTION_TYPES — how the parser classifies direction text
xil sfx --dry-run— preview EXISTS / CACHED / NEW status before generatingxil produce --dry-run— full voice + SFX cost estimate