summer-engine 1.5.0 → 2.2.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/{marketplace.json → .claude-plugin/marketplace.json} +3 -3
- package/.claude-plugin/plugin.json +52 -11
- package/.codex-plugin/plugin.json +69 -8
- package/.cursor-plugin/plugin.json +53 -12
- package/.factory-plugin/plugin.json +20 -0
- package/.opencode/INSTALL.md +75 -0
- package/.opencode/plugins/summer.js +9 -6
- package/AGENTS.md +51 -0
- package/CHANGELOG.md +31 -1
- package/CLAUDE.md +5 -0
- package/GEMINI.md +56 -0
- package/README.md +409 -80
- package/_persona/summer/SKILL.md +113 -0
- package/dist/bin/summer.js +0 -0
- package/dist/commands/assets.d.ts +2 -0
- package/dist/commands/assets.js +189 -0
- package/dist/commands/create.js +55 -17
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +127 -0
- package/dist/commands/install.js +2 -2
- package/dist/commands/list.js +24 -5
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +170 -0
- package/dist/commands/scene.d.ts +2 -0
- package/dist/commands/scene.js +290 -0
- package/dist/lib/banner.js +2 -2
- package/dist/lib/log-filters.d.ts +53 -0
- package/dist/lib/log-filters.js +130 -0
- package/dist/lib/plugin-manifests.test.d.ts +1 -0
- package/dist/lib/plugin-manifests.test.js +134 -0
- package/dist/lib/remote-templates.d.ts +25 -0
- package/dist/lib/remote-templates.js +86 -0
- package/dist/lib/skills-registry.d.ts +283 -3
- package/dist/lib/skills-registry.js +522 -2
- package/dist/lib/telemetry.d.ts +13 -0
- package/dist/lib/telemetry.js +63 -0
- package/dist/lib/with-engine.d.ts +14 -0
- package/dist/lib/with-engine.js +109 -0
- package/dist/mcp/tools/asset-tools.js +12 -13
- package/dist/mcp/tools/debug-tools.js +32 -9
- package/dist/mcp/tools/generate-tools.js +101 -0
- package/dist/mcp/tools/with-engine.js +4 -0
- package/gemini-extension.json +2 -2
- package/hooks/pre-commit-doctor.sh +0 -0
- package/hooks/run-hook.cmd +0 -0
- package/hooks/session-start.sh +0 -0
- package/package.json +11 -5
- package/skills/2d-assets/character-portrait/SKILL.md +196 -0
- package/skills/2d-assets/concept-art/SKILL.md +152 -0
- package/skills/2d-assets/pixel-art/SKILL.md +180 -0
- package/skills/2d-assets/skybox-panorama/SKILL.md +207 -0
- package/skills/2d-assets/sprite-sheet/SKILL.md +239 -0
- package/skills/2d-assets/tileable-texture/SKILL.md +205 -0
- package/skills/2d-assets/ui-graphics/SKILL.md +210 -0
- package/skills/3d-assets/character-model/SKILL.md +225 -0
- package/skills/3d-assets/environment-kit/SKILL.md +164 -0
- package/skills/3d-assets/organic-model/SKILL.md +192 -0
- package/skills/3d-assets/prop-model/SKILL.md +133 -0
- package/skills/3d-assets/vehicle-model/SKILL.md +202 -0
- package/skills/README.md +1 -1
- package/skills/_meta/skill-create/SKILL.md +1 -1
- package/skills/_meta/skill-improve/SKILL.md +1 -1
- package/skills/_meta/skill-test/SKILL.md +1 -1
- package/skills/_meta/using-summer/SKILL.md +130 -0
- package/skills/ai-and-npcs/design-npc/SKILL.md +3 -1
- package/skills/animation/animation-tree/SKILL.md +260 -0
- package/skills/animation/facial-and-lipsync/SKILL.md +282 -0
- package/skills/animation/generate-motion/SKILL.md +129 -0
- package/skills/animation/procedural-animation/SKILL.md +234 -0
- package/skills/animation/retarget/SKILL.md +172 -0
- package/skills/asset-pipeline/asset-strategy/SKILL.md +102 -212
- package/skills/audio/adaptive-music/SKILL.md +326 -0
- package/skills/audio/ambient-bed/SKILL.md +278 -0
- package/skills/audio/music-track/SKILL.md +268 -0
- package/skills/audio/sound-effect/SKILL.md +237 -0
- package/skills/audio/voice-line/SKILL.md +253 -0
- package/skills/catalog.yaml +266 -5
- package/skills/character-controllers/fps-controller/SKILL.md +1 -1
- package/skills/debugging/debug/SKILL.md +102 -82
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +1 -1
- package/skills/scene-and-project/browse-templates/SKILL.md +105 -0
- package/skills/scene-and-project/make-game/SKILL.md +159 -346
- package/skills/scene-and-project/new-project/SKILL.md +106 -0
- package/skills/scene-and-project/scene-composition/SKILL.md +1 -1
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
- package/skills/ui-and-ux/ui-basics/SKILL.md +1 -1
- package/skills/video/animated-loop/SKILL.md +200 -0
- package/skills/video/cinematic-cutscene/SKILL.md +204 -0
- package/skills/video/trailer-shot/SKILL.md +203 -0
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +28 -0
- package/skills/visual-effects/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +51 -0
- package/skills/visual-effects/{vfx → game-feel}/SKILL.md +1 -1
- package/skills/visual-effects/recipes/dissolve/SKILL.md +349 -0
- package/skills/visual-effects/recipes/fire/SKILL.md +387 -0
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +330 -0
- package/skills/visual-effects/recipes/lightning/SKILL.md +372 -0
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +377 -0
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +326 -0
- package/skills/visual-effects/recipes/smoke/SKILL.md +381 -0
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +340 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: music-track
|
|
3
|
+
description: Use when generating a looped or cinematic music track. Loops are authored at >=30s with a marked loop point; cinematic tracks at >=60s linear. Trigger on "generate music", "make a calm track", "boss music", "title screen music", "main theme", "exploration loop", "combat track".
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: audio
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read Grep Glob Write Edit summer_generate_audio summer_search_assets summer_import_from_url summer_add_node summer_set_prop summer_inspect_node
|
|
9
|
+
paths: ["audio/music/**", "scripts/**", "**/*.tscn"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /music-track — Generate a Loop or Cinematic Music Track
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
ElevenLabs Music renders 10–300 seconds of music from a prompt. The output quality depends entirely 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.
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
- Looped track for a level, biome, menu, or game state (calm / tension / combat).
|
|
23
|
+
- Cinematic linear track for an intro, ending, boss reveal, or cutscene.
|
|
24
|
+
- Replacing a placeholder loop with on-bible music.
|
|
25
|
+
|
|
26
|
+
## When NOT to use
|
|
27
|
+
|
|
28
|
+
- Short stings / event punctuation (<5s) → use `audio/sound-effect` with class `Stinger`.
|
|
29
|
+
- Adaptive layered stems with state-driven crossfades → `audio/adaptive-music`.
|
|
30
|
+
- Ambient bed with no melody → `audio/ambient-bed`.
|
|
31
|
+
|
|
32
|
+
## Steps
|
|
33
|
+
|
|
34
|
+
### 1. Read the audio bible
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Read .summer/audio-bible.md
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
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.
|
|
41
|
+
|
|
42
|
+
If no bible exists:
|
|
43
|
+
|
|
44
|
+
> 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.
|
|
45
|
+
|
|
46
|
+
### 2. Identify the track's role
|
|
47
|
+
|
|
48
|
+
Ask if not obvious:
|
|
49
|
+
|
|
50
|
+
> Which slot in the dynamic music plan? Calm exploration, tension, combat, boss, victory, menu, ending, or one-off cutscene?
|
|
51
|
+
|
|
52
|
+
Each slot has different rules:
|
|
53
|
+
|
|
54
|
+
| Slot | Tempo | Energy | Instrumentation density | Loop or linear |
|
|
55
|
+
|---|---|---|---|---|
|
|
56
|
+
| Calm exploration | bible low end (e.g. 70–90) | Low | Sparse | Loop, ≥45s |
|
|
57
|
+
| Tension | mid (e.g. 90–110) | Medium, no drums or sparse pulse | Adds one instrument | Loop, ≥45s |
|
|
58
|
+
| Combat | high (e.g. 120–150) | High, full drums | Full | Loop, ≥45s |
|
|
59
|
+
| Boss | high or low-and-menacing | Distinct from combat | Distinct, named instrument | Loop, ≥60s |
|
|
60
|
+
| Victory sting | n/a | Resolution | n/a | Linear, 4–8s (use SFX skill instead) |
|
|
61
|
+
| Menu / title | bible mid | Atmospheric | Anchor instrument | Loop, ≥30s |
|
|
62
|
+
| Cutscene | varies | Linear arc | Varies | Linear, 60–180s |
|
|
63
|
+
| Ending | varies | Linear arc with resolution | Varies | Linear, 60–300s |
|
|
64
|
+
|
|
65
|
+
### 3. Build the prompt — tempo + key + instrumentation + mood + structural cue
|
|
66
|
+
|
|
67
|
+
Prompts that work:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic
|
|
71
|
+
exploration loop, no drums, gentle reverb, even dynamics, 60s
|
|
72
|
+
|
|
73
|
+
128 BPM, D dorian, 4/4, full orchestral combat, low brass ostinato, taiko drums
|
|
74
|
+
on 1 and 3, strings tremolo, urgent, no melodic resolution, 60s loop
|
|
75
|
+
|
|
76
|
+
90 BPM, A minor, 6/8, lo-fi exploration, vintage Rhodes electric piano,
|
|
77
|
+
tape hiss, warm bass, soft brushed snare, no vocals, 45s loop
|
|
78
|
+
|
|
79
|
+
70 BPM, F minor, 4/4, ambient menu loop, pad layer, distant choir, single
|
|
80
|
+
piano motif every 8 bars, no drums, 30s loop with seamless return
|
|
81
|
+
|
|
82
|
+
110 BPM, C minor harmonic, 4/4, dark synthwave boss intro, gated reverb snare,
|
|
83
|
+
arpeggiated bass synth, lead saw on melody, builds to cymbal swell at 0:50,
|
|
84
|
+
linear 60s, ends on sustained pad
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Prompts that DON'T work (and why):
|
|
88
|
+
|
|
89
|
+
| Bad prompt | Failure mode |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `epic orchestral combat music` | No tempo, no key, no instrumentation. Generic stock. |
|
|
92
|
+
| `Hollow Knight style track` | The model can't reference IPs and won't try to clone style words. |
|
|
93
|
+
| `hopeful but sad menu music with strings and stuff` | "Strings and stuff" is vague; model picks the wrong section. |
|
|
94
|
+
| `something for the boss fight` | No tempo, no key, no mood vector. Random. |
|
|
95
|
+
| `loop` (just the word) | No structure. Returns 30s of music that doesn't loop. |
|
|
96
|
+
|
|
97
|
+
### 4. Tempo, key, instrumentation specifics that matter
|
|
98
|
+
|
|
99
|
+
**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`.
|
|
100
|
+
|
|
101
|
+
**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.
|
|
102
|
+
|
|
103
|
+
**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.
|
|
104
|
+
|
|
105
|
+
**Mood** — concrete adjectives anchored to motion: `melancholic and slow`, `urgent and driving`, `triumphant and rising`. Avoid genre adjectives like `epic`, `chill`, `hype`.
|
|
106
|
+
|
|
107
|
+
**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`.
|
|
108
|
+
|
|
109
|
+
### 5. Loop vs cinematic decision
|
|
110
|
+
|
|
111
|
+
| Choose loop when | Choose linear when |
|
|
112
|
+
|---|---|
|
|
113
|
+
| The slot plays for an unbounded time (level, menu, exploration) | The slot has a known length (cutscene, intro, ending) |
|
|
114
|
+
| Player attention is on gameplay | Player attention is on the music |
|
|
115
|
+
| You want to layer adaptive stems on top later | The arc is the point |
|
|
116
|
+
|
|
117
|
+
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).
|
|
118
|
+
|
|
119
|
+
For linear: generate **≥60s for cutscenes, up to 300s for endings**. The model handles long arcs better than people expect; ask for one rendered piece rather than splicing.
|
|
120
|
+
|
|
121
|
+
### 6. Confirm and call
|
|
122
|
+
|
|
123
|
+
Show the prompt:
|
|
124
|
+
|
|
125
|
+
> Prompt:
|
|
126
|
+
> `85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic exploration loop, no drums, gentle reverb, 60s loop`
|
|
127
|
+
> Duration 60s. Cost: ~12 credits. Generate?
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
summer_generate_audio(
|
|
131
|
+
capability: "music",
|
|
132
|
+
prompt: "85 BPM, D minor, 4/4, solo cello and detuned upright piano, sparse, melancholic exploration loop, no drums, gentle reverb, 60s loop",
|
|
133
|
+
durationSeconds: 60
|
|
134
|
+
)
|
|
135
|
+
// Result: { asset: { fileUrl, ... } }
|
|
136
|
+
// Then: summer_import_from_url(url: "<fileUrl>", path: "res://audio/music/calm_exploration.mp3")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`durationSeconds` range is 10–300.
|
|
140
|
+
|
|
141
|
+
### 7. Mark the loop point in Godot
|
|
142
|
+
|
|
143
|
+
ElevenLabs Music does not return a loop-clean cut. You must mark the loop point in Godot's import dock so playback returns to the loop point on completion, not to 0:00.
|
|
144
|
+
|
|
145
|
+
In `audio/music/calm_exploration.mp3.import`:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
[params]
|
|
149
|
+
loop = true
|
|
150
|
+
loop_offset = 0.0
|
|
151
|
+
loop_mode = 0 # 0=disabled, 1=forward, 2=ping-pong, 3=backward
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
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).
|
|
155
|
+
|
|
156
|
+
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 (see step 9).
|
|
157
|
+
|
|
158
|
+
### 8. Wire it as `AudioStreamPlayer` on the `Music` bus
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
summer_add_node(parentPath="/root/Game", type="AudioStreamPlayer", name="MusicCalm")
|
|
162
|
+
summer_set_prop(path="/root/Game/MusicCalm", property="stream", value="res://audio/music/calm_exploration.mp3")
|
|
163
|
+
summer_set_prop(path="/root/Game/MusicCalm", property="bus", value="Music")
|
|
164
|
+
summer_set_prop(path="/root/Game/MusicCalm", property="volume_db", value=-8.0)
|
|
165
|
+
summer_set_prop(path="/root/Game/MusicCalm", property="autoplay", value=true)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Music is `AudioStreamPlayer` (not 2D / 3D) — non-positional. The bible's `Music -8 dB` mix sits the music behind SFX where it belongs.
|
|
169
|
+
|
|
170
|
+
### 9. Crossfade-loop pattern (no marked loop point)
|
|
171
|
+
|
|
172
|
+
If the loop click bothers the user, use a two-player crossfade:
|
|
173
|
+
|
|
174
|
+
```gdscript
|
|
175
|
+
# scripts/audio/MusicLoopCrossfade.gd
|
|
176
|
+
extends Node
|
|
177
|
+
@export var stream: AudioStream
|
|
178
|
+
@export var fade: float = 1.0
|
|
179
|
+
var _a: AudioStreamPlayer
|
|
180
|
+
var _b: AudioStreamPlayer
|
|
181
|
+
var _active: AudioStreamPlayer
|
|
182
|
+
|
|
183
|
+
func _ready() -> void:
|
|
184
|
+
_a = _make_player()
|
|
185
|
+
_b = _make_player()
|
|
186
|
+
_active = _a
|
|
187
|
+
_active.play()
|
|
188
|
+
_active.finished.connect(_on_finished)
|
|
189
|
+
|
|
190
|
+
func _make_player() -> AudioStreamPlayer:
|
|
191
|
+
var p := AudioStreamPlayer.new()
|
|
192
|
+
p.stream = stream
|
|
193
|
+
p.bus = "Music"
|
|
194
|
+
p.volume_db = -8.0
|
|
195
|
+
add_child(p)
|
|
196
|
+
return p
|
|
197
|
+
|
|
198
|
+
func _on_finished() -> void:
|
|
199
|
+
var next := _b if _active == _a else _a
|
|
200
|
+
next.play()
|
|
201
|
+
next.finished.connect(_on_finished, CONNECT_ONE_SHOT)
|
|
202
|
+
_active = next
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The next instance starts at 0:00 the moment the previous finishes — gapless.
|
|
206
|
+
|
|
207
|
+
## Reference card — prompts by slot
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
Calm explore (folk): 78 BPM, D minor, 6/8, fingerpicked acoustic guitar,
|
|
211
|
+
upright bass on 1, soft hand percussion, no melody on
|
|
212
|
+
first 8 bars, 60s loop
|
|
213
|
+
|
|
214
|
+
Tension (orchestral): 95 BPM, D dorian, 4/4, low strings sustained, single
|
|
215
|
+
timpani roll every 8 bars, sparse french horn motif,
|
|
216
|
+
no drums, 60s loop
|
|
217
|
+
|
|
218
|
+
Combat (orchestral): 140 BPM, D dorian, 4/4, taiko drums on 1 and 3,
|
|
219
|
+
ostinato low brass, strings tremolo, urgent and driving,
|
|
220
|
+
no melodic resolution, 60s loop
|
|
221
|
+
|
|
222
|
+
Boss (synthwave): 110 BPM, C minor harmonic, 4/4, gated snare, arpeggio
|
|
223
|
+
bass synth, lead saw on melody, builds at 0:50,
|
|
224
|
+
linear 60s
|
|
225
|
+
|
|
226
|
+
Menu (lo-fi): 70 BPM, F minor, 4/4, vintage Rhodes, tape hiss,
|
|
227
|
+
soft brushed snare, single piano motif every 8 bars,
|
|
228
|
+
45s loop
|
|
229
|
+
|
|
230
|
+
Cutscene (cinematic): varies tempo, D minor, 4/4, solo piano opens,
|
|
231
|
+
strings enter at 0:20, full orchestra at 0:50,
|
|
232
|
+
decay to solo piano at 1:30, linear 120s
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Anti-patterns
|
|
236
|
+
|
|
237
|
+
- **Genre adjectives only.** `epic`, `chill`, `hype` — meaningless.
|
|
238
|
+
- **Naming a game or composer.** Model won't replicate; use ingredients.
|
|
239
|
+
- **Loop shorter than 30s.** Recognized as repetition fast.
|
|
240
|
+
- **Music on `Master` bus at 0 dB.** Buries SFX. Use `Music` bus at `-8 dB`.
|
|
241
|
+
- **Generating before reading the bible.** Style drift.
|
|
242
|
+
- **Skipping the loop-mark step.** Music returns to 0:00 with a click on every loop.
|
|
243
|
+
|
|
244
|
+
## Edge cases
|
|
245
|
+
|
|
246
|
+
- **Clip is 50s but you wanted 60s.** Either regenerate (cheaper than you think) or extend by overlap-crossfading the last 5s onto the start in an audio editor.
|
|
247
|
+
- **Loop click on every cycle.** Use the crossfade pattern in step 9.
|
|
248
|
+
- **Clip is too long.** Trim the tail in the import dock with `loop_offset`, or in an audio editor.
|
|
249
|
+
- **Track sounds nothing like the references.** Re-read the bible; the prompt may be missing the anchor instrument. Add it explicitly.
|
|
250
|
+
- **Track has unexpected vocals.** Add `no vocals, instrumental only` to the prompt.
|
|
251
|
+
|
|
252
|
+
## Fallback (no MCP)
|
|
253
|
+
|
|
254
|
+
Print the prompt and instruct the user to run via the Summer dashboard, then `summer_import_from_url` the rendered MP3.
|
|
255
|
+
|
|
256
|
+
## Handoff
|
|
257
|
+
|
|
258
|
+
> Track `calm_exploration.mp3` wired to `Game/MusicCalm` on the `Music` bus, autoplay on. Next:
|
|
259
|
+
> - Mark the loop point in the import dock if the bible calls for looped playback.
|
|
260
|
+
> - Generate the tension and combat counterparts with `/music-track` again.
|
|
261
|
+
> - To wire state-driven crossfades between calm / tension / combat, run `/adaptive-music`.
|
|
262
|
+
|
|
263
|
+
## See also
|
|
264
|
+
|
|
265
|
+
- `audio/audio-direction` — defines style, tempo, key, model
|
|
266
|
+
- `audio/adaptive-music` — wiring stems to game state
|
|
267
|
+
- `audio/sound-effect` — short stings
|
|
268
|
+
- `audio/ambient-bed` — non-melodic location bed
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sound-effect
|
|
3
|
+
description: Use when generating short SFX one-shots — footsteps, weapon swings, UI clicks, hit impacts, environmental cues. Wires the resulting clip as an AudioStreamPlayer / 2D / 3D and auto-frees on finished. Trigger on "make a sword swing sound", "generate a UI click", "I need a footstep", "add a hit sound", "spawn an SFX".
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: audio
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read Grep Glob Write Edit summer_generate_audio summer_search_assets summer_import_from_url summer_add_node summer_set_prop summer_inspect_node summer_get_scene_tree
|
|
9
|
+
paths: ["audio/sfx/**", "scripts/**", "**/*.tscn"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /sound-effect — Generate a Short SFX One-Shot and Wire It
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
This skill produces one named SFX clip aligned with the audio bible's vocabulary, then wires it into the scene as an AudioStreamPlayer that plays once and frees its parent (or stops cleanly if it's a looped texture). The shape of the prompt is what makes the difference between "metal sword swing whoosh, dry, sharp, 250ms" returning the right clip on the first try and "epic battle sound" returning twenty seconds of musical noise.
|
|
17
|
+
|
|
18
|
+
ElevenLabs SFX (the `sound_effects` capability of `summer_generate_audio`) is *literal*. It treats the prompt as a description of a real sound, not as a vibe. Concrete material + action + intensity beats adjectives every time.
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
- One-shot SFX: footstep, swing, click, hit, impact, pickup, jump, land, door, breath.
|
|
23
|
+
- Short loops < 2s: hum, drone snippet, rain texture (for very short looping ambients prefer `audio/ambient-bed`).
|
|
24
|
+
- Replacing a placeholder beep with something on-bible.
|
|
25
|
+
|
|
26
|
+
## When NOT to use
|
|
27
|
+
|
|
28
|
+
- Music or musical stings → `audio/music-track`.
|
|
29
|
+
- Long location ambience (>5s) → `audio/ambient-bed`.
|
|
30
|
+
- Voice / dialogue → `audio/voice-line`.
|
|
31
|
+
- Defining the *vocabulary* of SFX — that's `audio/audio-direction`. This skill executes against an existing bible.
|
|
32
|
+
|
|
33
|
+
## Steps
|
|
34
|
+
|
|
35
|
+
### 1. Read the audio bible
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Read .summer/audio-bible.md
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If it doesn't exist, ask:
|
|
42
|
+
|
|
43
|
+
> No audio bible at `.summer/audio-bible.md`. Want to run `/audio-direction` first to define the SFX vocabulary, or shall I just one-shot this with sensible defaults?
|
|
44
|
+
|
|
45
|
+
The bible defines an SFX *class* (UI, Pickup positive, Damage, Footstep, Attack, Stinger, Ambient layer, Pickup neutral). Map the user's request to a class. Quote the class's character and DON'Ts back so the prompt obeys them.
|
|
46
|
+
|
|
47
|
+
### 2. Search for an existing clip first
|
|
48
|
+
|
|
49
|
+
Generation is metered. Reuse beats regenerate.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
summer_search_assets(query="<class> <subject>", filter={ kind: "audio" })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If something fits, ask:
|
|
56
|
+
|
|
57
|
+
> Found `audio/sfx/sword_swing_01.wav`. Use this, or generate fresh?
|
|
58
|
+
|
|
59
|
+
### 3. Build the prompt — subject + material + action + intensity + duration cue
|
|
60
|
+
|
|
61
|
+
ElevenLabs SFX responds to literal sound descriptions. Pattern:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
<subject> <material> <action>, <intensity>, <character>, <duration cue>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Working examples (these produce the right clip on the first try):
|
|
68
|
+
|
|
69
|
+
| Goal | Prompt that works | Why |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| Sword swing | `metal sword swing whoosh, dry, sharp, 250ms` | material + action + dry rules out reverb |
|
|
72
|
+
| UI click | `soft woody UI click, short, neutral pitch, 80ms` | material + duration; "click" alone is too vague |
|
|
73
|
+
| Footstep on stone | `single footstep on dry stone, leather sole, mid-weight, 180ms` | surface + footwear + body weight |
|
|
74
|
+
| Player hit | `punchy low-mid body hit impact, slight detune, no tail, 200ms` | "no tail" kills reverb the bible forbids |
|
|
75
|
+
| Coin pickup | `bright metallic coin pickup, warm major-third interval, 300ms, light room reverb` | named interval = melodic shape |
|
|
76
|
+
| Door creak open | `old wooden door creak opening slowly, 1.2s, dry interior` | duration + space |
|
|
77
|
+
| Bow draw | `recurve bow draw, taut string, leather grip, 600ms` | material specificity |
|
|
78
|
+
| Magic cast | `short ice magic cast, crystalline shimmer, ascending, 500ms` | element + pitch motion |
|
|
79
|
+
|
|
80
|
+
Prompts that DON'T work (and why):
|
|
81
|
+
|
|
82
|
+
| Bad prompt | Failure mode |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `epic sword sound` | "Epic" is a vibe; the model can't render a vibe. Returns generic noise. |
|
|
85
|
+
| `cool UI click` | No material, no duration. Returns a 5-second synth blip. |
|
|
86
|
+
| `the sound when the player gets hit really hard and falls down` | Multiple events. Model tries to render all and returns nothing coherent. Split into two SFX. |
|
|
87
|
+
| `swoosh` | Underspecified. Returns inconsistent character every regen. |
|
|
88
|
+
| `realistic gunshot` | "Realistic" is a constraint, not a description. Use `9mm pistol shot, indoor, sharp crack, short tail, 400ms`. |
|
|
89
|
+
|
|
90
|
+
### 4. Confirm and call
|
|
91
|
+
|
|
92
|
+
Show the prompt and the call before running:
|
|
93
|
+
|
|
94
|
+
> Prompt: `metal sword swing whoosh, dry, sharp, 250ms`. Duration 0.5s (model floor). Model: ElevenLabs SFX. Cost: ~1 credit. Generate?
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
summer_generate_audio(
|
|
98
|
+
capability: "sound_effects",
|
|
99
|
+
prompt: "metal sword swing whoosh, dry, sharp, 250ms",
|
|
100
|
+
durationSeconds: 0.5
|
|
101
|
+
)
|
|
102
|
+
// Result: { asset: { fileUrl, ... } }
|
|
103
|
+
// Then: summer_import_from_url(url: "<fileUrl>", path: "res://audio/sfx/sword_swing_01.wav")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`durationSeconds` floor is 0.5, ceiling is 22. If the user wants a 100ms click, generate 0.5s and the player only plays the front; or trim in the engine.
|
|
107
|
+
|
|
108
|
+
### 5. Decision: one-shot vs loop
|
|
109
|
+
|
|
110
|
+
| Use case | Setup |
|
|
111
|
+
|---|---|
|
|
112
|
+
| Footstep, swing, click, hit | One-shot AudioStreamPlayer, `autoplay=false`, fired by code or animation. |
|
|
113
|
+
| Short hum / drone < 2s | Set the imported `AudioStream` `loop=true` in the import dock. |
|
|
114
|
+
|
|
115
|
+
For one-shots, set `Loop` OFF on the import. Default ElevenLabs returns are not loop-clean — looping a one-shot will click.
|
|
116
|
+
|
|
117
|
+
### 6. Wire it into the scene
|
|
118
|
+
|
|
119
|
+
Choose the right player node:
|
|
120
|
+
|
|
121
|
+
| Node | Use for |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `AudioStreamPlayer` | UI, music, non-positional (HUD click, menu confirm) |
|
|
124
|
+
| `AudioStreamPlayer2D` | 2D positional (top-down hit, 2D pickup) |
|
|
125
|
+
| `AudioStreamPlayer3D` | 3D positional (footstep on a 3D character, weapon swing in world) |
|
|
126
|
+
|
|
127
|
+
Add it under the emitting node:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
summer_add_node(parentPath="/root/Game/Player", type="AudioStreamPlayer3D", name="SwingSFX")
|
|
131
|
+
summer_set_prop(path="/root/Game/Player/SwingSFX", property="stream", value="res://audio/sfx/sword_swing_01.wav")
|
|
132
|
+
summer_set_prop(path="/root/Game/Player/SwingSFX", property="bus", value="SFX")
|
|
133
|
+
summer_set_prop(path="/root/Game/Player/SwingSFX", property="volume_db", value=0.0)
|
|
134
|
+
summer_set_prop(path="/root/Game/Player/SwingSFX", property="max_distance", value=25.0)
|
|
135
|
+
summer_set_prop(path="/root/Game/Player/SwingSFX", property="attenuation_model", value=0)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Bus name must match the bible (`SFX`, `UI`, `Ambient`, etc.). If the bus doesn't exist, run `/audio-direction` step 8.
|
|
139
|
+
|
|
140
|
+
### 7. Spawn-and-free pattern (one-shots in flight)
|
|
141
|
+
|
|
142
|
+
For SFX that needs to outlive the emitter (player dies but the death-blow SFX should finish), instantiate a small scene with this script:
|
|
143
|
+
|
|
144
|
+
```gdscript
|
|
145
|
+
# scripts/audio/SfxOneShot.gd
|
|
146
|
+
extends AudioStreamPlayer3D
|
|
147
|
+
|
|
148
|
+
func _ready() -> void:
|
|
149
|
+
finished.connect(queue_free)
|
|
150
|
+
play()
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Save it as a `.tscn`, then `summer_instantiate_scene` at the emitter's global position when the event fires. The node frees itself when the stream finishes — no leaks.
|
|
154
|
+
|
|
155
|
+
### 8. Volume calibration
|
|
156
|
+
|
|
157
|
+
If the clip comes back too quiet:
|
|
158
|
+
|
|
159
|
+
- First try `volume_db` on the player (+3 to +9 typical).
|
|
160
|
+
- If still quiet, the clip itself is hot-low — regenerate with a louder intensity word: `loud`, `forceful`, `heavy`.
|
|
161
|
+
- Never push `volume_db` past +12; clipping artifacts.
|
|
162
|
+
|
|
163
|
+
If it comes back too loud (rare): negative `volume_db`, or trim attack in an editor.
|
|
164
|
+
|
|
165
|
+
### 9. Confirm in scene
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
summer_inspect_node(path="/root/Game/Player/SwingSFX")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Verify `stream`, `bus`, `volume_db`. Trigger it via `summer_play` if the user wants to hear it now.
|
|
172
|
+
|
|
173
|
+
## Reference card — prompt patterns by class
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
UI click: soft woody UI click, neutral pitch, 80ms
|
|
177
|
+
UI confirm: affirmative UI chime, warm minor-third, 250ms
|
|
178
|
+
UI error: flat UI buzz, slight dissonance, 200ms
|
|
179
|
+
Pickup positive: bright pickup, ascending major-third, 300ms, light reverb
|
|
180
|
+
Pickup neutral: small tactile pickup, no melody, 150ms
|
|
181
|
+
Footstep wood: single footstep on hollow wood floor, leather sole, 180ms
|
|
182
|
+
Footstep grass: single footstep on damp grass, soft, 200ms
|
|
183
|
+
Footstep stone: single footstep on dry stone, mid-weight, 180ms
|
|
184
|
+
Hit body: punchy body hit, low-mid thump, no tail, 200ms
|
|
185
|
+
Hit metal: metal-on-metal clang, sharp transient, short ring, 350ms
|
|
186
|
+
Swing whoosh: fast air whoosh from a swung blade, dry, 250ms
|
|
187
|
+
Door creak: old wooden door creak opening, 1.2s, dry interior
|
|
188
|
+
Magic ice: crystalline ice cast, ascending shimmer, 500ms
|
|
189
|
+
Magic fire: whoosh of fire ignition, low rumble, 700ms
|
|
190
|
+
Stinger event: short triumphant brass stinger, 1.5s, hall reverb
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Anti-patterns
|
|
194
|
+
|
|
195
|
+
- **Adjective-only prompts.** `epic`, `cool`, `realistic`, `professional` — meaningless to the model.
|
|
196
|
+
- **Multiple events in one prompt.** Split into two generations.
|
|
197
|
+
- **Looping a non-loop-clean clip.** Will click. Use `audio/ambient-bed` for actual loops.
|
|
198
|
+
- **Skipping the bus.** Default bus is `Master`. SFX must route to the `SFX` bus or the mix breaks.
|
|
199
|
+
- **Generating before searching.** Reuse before regenerate.
|
|
200
|
+
- **Generating before reading the bible.** The clip will fight the rest of the audio.
|
|
201
|
+
|
|
202
|
+
## Edge cases
|
|
203
|
+
|
|
204
|
+
- **Clip too quiet:** `volume_db` first; regenerate with louder intensity word second.
|
|
205
|
+
- **Clip too long:** trim in audio editor or set `AudioStreamPlayer` to `stop()` on a timer.
|
|
206
|
+
- **Footstep needs surface variants:** generate one per material (wood / stone / grass / metal / dirt) and switch in code based on raycast on the floor's `physics_material`.
|
|
207
|
+
- **SFX for an animation event:** wire to the animation's `Call Method Track`, not to `_process`.
|
|
208
|
+
|
|
209
|
+
## Fallback (no MCP)
|
|
210
|
+
|
|
211
|
+
Print the call:
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
ElevenLabs SFX prompt: "metal sword swing whoosh, dry, sharp, 250ms"
|
|
215
|
+
Duration: 0.5s
|
|
216
|
+
Save to: audio/sfx/sword_swing_01.wav
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Tell the user to run it via the Summer dashboard, then `summer_import_from_url` the result.
|
|
220
|
+
|
|
221
|
+
## Handoff
|
|
222
|
+
|
|
223
|
+
After the SFX is wired:
|
|
224
|
+
|
|
225
|
+
> SFX `sword_swing_01.wav` wired to `Player/SwingSFX` on the `SFX` bus. Next:
|
|
226
|
+
> - Trigger it from your attack animation's `Call Method Track` → `play()`.
|
|
227
|
+
> - Generate the parry / clash counterpart with `/sound-effect` again.
|
|
228
|
+
> - For a full footstep system across surfaces, see `audio/footstep-systems`.
|
|
229
|
+
|
|
230
|
+
## See also
|
|
231
|
+
|
|
232
|
+
- `audio/audio-direction` — defines the vocabulary this skill obeys
|
|
233
|
+
- `audio/ambient-bed` — long looping textures
|
|
234
|
+
- `audio/music-track` — music
|
|
235
|
+
- `audio/voice-line` — TTS
|
|
236
|
+
- `_shared/mcp-tools-reference.md`
|
|
237
|
+
- `_shared/godot-version.md` — Godot 4.5 audio nodes
|