Installs into .claude/skills of the current project.
Are you the author of Music Track?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/summerengine-music-track)
---
name: music-track
description: "Generate a music track: game loops of 30s or more with a loop point, or linear cinematic cues."
license: MIT
compatibility: [Cursor, Claude Code, Windsurf, Codex]
category: audio
user-invocable: true
allowed-tools: Read Grep Glob Write Edit summer_assets_generate_audio summer_assets_search summer_import_from_url summer_add_node summer_set_prop summer_inspect_node summer_call
paths: ["audio/music/**", "scripts/**", "**/*.tscn"]
---
# /music-track — Generate a Loop or Cinematic Music Track
## Overview
ElevenLabs Music renders a track from a prompt. Summer clamps the requested length to **3–600 seconds** before sending it, so anything outside that range is silently pulled to the nearest bound. Quality depends on prompt specificity: tempo (BPM), key, instrumentation, mood, structural cue. "Epic orchestral" returns generic stock music. "85 BPM, D minor, solo cello and detuned upright piano, sparse, melancholic, no drums, 4/4" returns a usable score for a melancholic exploration scene.
This skill produces one track aligned with the audio bible's music style and dynamic music plan, then wires it as an `AudioStreamPlayer` on the `Music` bus with a marked loop point if it's a loop, or as a linear cinematic stream if it's a one-shot.
## When to use
- Looped track for a level, biome, menu, or game state (calm / tension / combat).
- Cinematic linear track for an intro, ending, boss reveal, or cutscene.
- Replacing a placeholder loop with on-bible music.
## When NOT to use
- Short stings / event punctuation (<5s) → use `sound-effect` with class `Stinger`.
- Adaptive layered stems with state-driven crossfades → `adaptive-music`.
- Ambient bed with no melody → `ambient-bed`.
## Steps
### 1. Read the audio bible
```
Read .summer/audio-bible.md
```
The bible names the primary style, tempo range, key center, time signature, and the dynamic music model. This skill writes prompts that respect those numbers.
If no bible exists:
> No `.summer/audio-bible.md`. Music without an audio bible drifts into stock-library territory. Run `/audio-direction` first, or I can ship a one-off with explicit defaults — your call.
### 2. Identify the track's role
Ask if not obvious:
> Which slot in the dynamic music plan? Calm exploration, tension, combat, boss, victory, menu, ending, or one-off cutscene?
Each slot has different rules:
| Slot | Tempo | Energy | Instrumentation density | Loop or linear |
|---|---|---|---|---|
| Calm exploration | bible low end (e.g. 70–90) | Low | Sparse | Loop, ≥45s |
| Tension | mid (e.g. 90–110) | Medium, no drums or sparse pulse | Adds one instrument | Loop, ≥45s |
| Combat | high (e.g. 120–150) | High, full drums | Full | Loop, ≥45s |
| Boss | high or low-and-menacing | Distinct from combat | Distinct, named instrument | Loop, ≥60s |
| Victory sting | n/a | Resolution | n/a | Linear, 4–8s (use SFX skill instead) |
| Menu / title | bible mid | Atmospheric | Anchor instrument | Loop, ≥30s |
| Cutscene | varies | Linear arc | Varies | Linear, 60–180s |
| Ending | varies | Linear arc with resolution | Varies | Linear, 60–300s |
### 3. Build the prompt — tempo + key + instrumentation + mood + structural cue
Prompts that work:
```
85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic
exploration loop, no drums, gentle reverb, even dynamics, 60s
128 BPM, D dorian, 4/4, full orchestral combat, low brass ostinato, taiko drums
on 1 and 3, strings tremolo, urgent, no melodic resolution, 60s loop
90 BPM, A minor, 6/8, lo-fi exploration, vintage Rhodes electric piano,
tape hiss, warm bass, soft brushed snare, no vocals, 45s loop
70 BPM, F minor, 4/4, ambient menu loop, pad layer, distant choir, single
piano motif every 8 bars, no drums, 30s loop with seamless return
110 BPM, C minor harmonic, 4/4, dark synthwave boss intro, gated reverb snare,
arpeggiated bass synth, lead saw on melody, builds to cymbal swell at 0:50,
linear 60s, ends on sustained pad
```
Prompts that DON'T work (and why):
| Bad prompt | Failure mode |
|---|---|
| `epic orchestral combat music` | No tempo, no key, no instrumentation. Generic stock. |
| `Hollow Knight style track` | The model can't reference IPs and won't try to clone style words. |
| `hopeful but sad menu music with strings and stuff` | "Strings and stuff" is vague; model picks the wrong section. |
| `something for the boss fight` | No tempo, no key, no mood vector. Random. |
| `loop` (just the word) | No structure. Returns 30s of music that doesn't loop. |
### 4. Tempo, key, instrumentation specifics that matter
**Tempo (BPM)** — name a single number, not a range. Music model interprets ranges as mid-point with drift. `85 BPM` is better than `80–90 BPM`.
**Key** — name mode (`D minor`, `D dorian`, `D natural minor`, `C minor harmonic`). The bible's modulation rules go here: combat tracks shift to dorian, calm tracks to natural minor.
**Instrumentation** — name 2–4 specific instruments, not sections. `solo cello` not `strings`. `upright piano` not `keys`. `Rhodes electric piano` not `electric piano`. The model's vocabulary is closer to a session musician's than a producer's.
**Mood** — concrete adjectives anchored to motion: `melancholic and slow`, `urgent and driving`, `triumphant and rising`. Avoid genre adjectives like `epic`, `chill`, `hype`.
**Structural cue** — for linear tracks, name the arc: `builds at 0:30 to a hit at 0:50, decays`. For loops, name the cell: `4-bar phrase repeats, instrument swap every 8 bars`.
### 5. Loop vs cinematic decision
| Choose loop when | Choose linear when |
|---|---|
| The slot plays for an unbounded time (level, menu, exploration) | The slot has a known length (cutscene, intro, ending) |
| Player attention is on gameplay | Player attention is on the music |
| You want to layer adaptive stems on top later | The arc is the point |
For loops: generate **≥30s, prefer 45–60s**. Shorter loops are recognized as repetition within 90s of play and become annoying. The bible's "no state stays >90s without variation" rule means even a 60s loop should contain internal variation (instrument swap on alternating cycles).
For linear: generate **≥60s for cutscenes, up to 300s for endings**. Ask for one rendered piece rather than splicing; the model handles long arcs.
### 6. Confirm and call
Show the prompt:
> Prompt:
> `85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic exploration loop, no drums, gentle reverb, 60s loop`
> Duration 60s. This uses credits. Generate?
The `music` capability reads the description from **`prompt`**, not `text` — the mirror image of `sound_effects`. Without `prompt` the call is refused (`prompt_required`).
```
assets.generate_audio({
capability: "music",
prompt: "85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic exploration loop, no drums, gentle reverb, 60s loop",
durationSeconds: 60
})
// Then: summer_import_from_url(url: "<asset.fileUrl>", path: "res://audio/music/calm_exploration.mp3")
```
`durationSeconds` is clamped to 3–600, and a longer track costs more: `dryRun: true` returns the `estimate` in credits first. Music comes back as MP3 (`audio/mpeg`), so a `.mp3` target path is correct.
### 7. Mark the loop point in Summer Engine
ElevenLabs Music does not return a loop-clean cut. You must mark the loop point
in Summer Engine's Import dock so playback returns to the loop point on
completion, not to 0:00.
The MP3 importer exposes exactly five options — `loop`, `loop_offset`, `bpm`, `beat_count`, `bar_beats`. There is **no `loop_mode`** on MP3 or OGG; `loop_mode` belongs to the WAV importer, where it is spelled `edit/loop_mode`.
In `audio/music/calm_exploration.mp3.import`:
```
[params]
loop = true
loop_offset = 0.0
```
If the start has a fade-in but the body is loopable, set `loop_offset = 4.0` (4 seconds of intro skipped on loop, plays full track first time). `bpm` + `beat_count` + `bar_beats` are what you set if you want beat-synced transitions later — see `adaptive-music`.
For seamless looping, the cleaner option is to ask the model to generate a cell (one bar / one phrase) and concatenate; or generate at 60s and trust the model's structural cue. Crossfade looping in code is the practical fallback (step 9).
### 8. Wire it as `AudioStreamPlayer` on the `Music` bus
One script adds the player with its settings; `scenePath` is the exact scene to change:
```
summer_run_script(scenePath="res://main.tscn", source="""
func run(ctx):
ctx.add_node("AudioStreamPlayer", "MusicCalm", null, {
"stream": load("res://audio/music/calm_exploration.mp3"),
"bus": "Music",
"volume_db": -8.0,
"autoplay": true,
})
ctx.save_scene()
""")
```
Music is `AudioStreamPlayer` (not 2D / 3D) — non-positional. The bible's `Music -8 dB` mix sits the music behind SFX where it belongs.
### 9. Crossfade-loop pattern (no marked loop point)
If the loop click bothers the user, crossfade two players. Set `loop = false` in the import file first, so each player stops at the end.
```gdscript
# scripts/audio/MusicLoopCrossfade.gd
extends Node
@export var stream: AudioStream
@export var fade := 1.0
@export var volume_db := -8.0
var _players: Array[AudioStreamPlayer] = []
var _current := 0
func _ready() -> void:
for i in 2:
var p := AudioStreamPlayer.new()
p.stream = stream
p.bus = "Music"
p.volume_db = volume_db
add_child(p)
_players.append(p)
_players[0].play()
func _process(_delta: float) -> void:
var a := _players[_current]
if not a.playing or a.get_playback_position() < stream.get_length() - fade:
return
_current = 1 - _current
var b := _players[_current]
b.volume_db = -80.0
b.play()
var t := create_tween().set_parallel()
t.tween_property(a, "volume_db", -80.0, fade)
t.tween_property(b, "volume_db", volume_db, fade)
t.chain().tween_callback(a.stop)
```
The next player starts `fade` seconds before the current one ends and the two cross over, so the seam is never heard.
## Reference card — prompts by slot
```
Calm explore (folk): 78 BPM, D minor, 6/8, fingerpicked acoustic guitar,
upright bass on 1, soft hand percussion, no melody on
first 8 bars, 60s loop
Tension (orchestral): 95 BPM, D dorian, 4/4, low strings sustained, single
timpani roll every 8 bars, sparse french horn motif,
no drums, 60s loop
Combat (orchestral): 140 BPM, D dorian, 4/4, taiko drums on 1 and 3,
ostinato low brass, strings tremolo, urgent and driving,
no melodic resolution, 60s loop
Boss (synthwave): 110 BPM, C minor harmonic, 4/4, gated snare, arpeggio
bass synth, lead saw on melody, builds at 0:50,
linear 60s
Menu (lo-fi): 70 BPM, F minor, 4/4, vintage Rhodes, tape hiss,
soft brushed snare, single piano motif every 8 bars,
45s loop
Cutscene (cinematic): varies tempo, D minor, 4/4, solo piano opens,
strings enter at 0:20, full orchestra at 0:50,
decay to solo piano at 1:30, linear 120s
```
## Anti-patterns
- **Genre adjectives only.** `epic`, `chill`, `hype` — meaningless.
- **Naming a game or composer.** Model won't replicate; use ingredients.
- **Loop shorter than 30s.** Recognized as repetition fast.
- **Music on `Master` bus at 0 dB.** Buries SFX. Use `Music` bus at `-8 dB`.
- **Generating before reading the bible.** Style drift.
- **Skipping the loop-mark step.** Music returns to 0:00 with a click on every loop.
## Edge cases
- **Clip is 50s but you wanted 60s.** Either regenerate or extend by overlap-crossfading the last 5s onto the start in an audio editor.
- **Loop click on every cycle.** Use the crossfade pattern in step 9.
- **Clip is too long.** Trim the tail in the import dock with `loop_offset`, or in an audio editor.
- **Track sounds nothing like the references.** Re-read the bible; the prompt may be missing the anchor instrument. Add it explicitly.
- **Track has unexpected vocals.** Add `no vocals, instrumental only` to the prompt.
## Without Summer Engine
In a session without Summer Engine tools (the assets profile; the `summer-assets` skill has the whole loop), do steps 1-6 and skip steps 7-9 (loop point, `AudioStreamPlayer`, crossfade script). Save the file where the person asked with `out` (the `summer-assets` skill says how), and tell them the path and format. For a loop track, tell them it is made to loop.
## Fallback (no MCP)
Print the prompt and instruct the user to run via the Summer dashboard, then `summer_import_from_url` the rendered MP3.
## Handoff
> Track `calm_exploration.mp3` wired to `Game/MusicCalm` on the `Music` bus, autoplay on. Next:
> - Mark the loop point in the import dock if the bible calls for looped playback.
> - Generate the tension and combat counterparts with `/music-track` again.
> - To wire state-driven crossfades between calm / tension / combat, run `/adaptive-music`.
## See also
- `audio-direction` — defines style, tempo, key, model
- `adaptive-music` — wiring stems to game state
- `sound-effect` — short stings
- `ambient-bed` — non-melodic location bed
<!-- shell-commands: generated from the operation catalog by npm run generate:registry; do not edit by hand -->
## From a shell
No Summer MCP tools in this session? Run each one as a command; when `summer --version` is missing or below 4.0, use `npx -y summer-engine@latest` in place of `summer`. Fields are flags in kebab-case (`--scene-path res://main.tscn`) or one `--input '<json>'`, and `summer ops describe <op>` prints the exact input. The `summer-cli` skill has the rest.
| In this skill | Command |
|---|---|
| `summer_assets_generate_audio` | `summer assets generate-audio` |
| `summer_assets_search` | `summer assets search` |
| `summer_add_node` | `summer engine add-node` |
| `summer_import_from_url` | `summer engine import-from-url` |
| `summer_inspect_node` | `summer engine inspect-node` |
| `summer_run_script` | `summer engine run-script` |
| `summer_set_prop` | `summer engine set-prop` |
<!-- /shell-commands -->