Skip to main content
ambient-bed is a skill from the Summer skill library: a guide your AI agent reads when the task matches, so it builds the good version on the first try. Generate a long looping location ambience (forest, dungeon, city, cave) on the Ambient bus.

When your agent uses it

  • Generating a long looping location ambience — forest at dawn, dungeon air, city street, spaceship hum, cave drip — non-melodic and low-energy
  • A location feels silent and needs a continuous soundscape beneath the score and effects

Install

summer setup installs every skill for your agent. To add only this one:
Swap claude-code for your agent, such as codex or cursor. See Skills for every option.

The skill

Overview

An ambient bed is the air of a place. Forest at dawn, dungeon corridor, spaceship hum, market street, ocean cave. It plays at low energy under everything else and is never melodic. Players rarely notice a bed, but they notice the silence when a level has none. This is not music. Use assets.generate_audio({ capability: 'sound_effects' }), not { capability: 'music' }: the SFX model renders texture, the music model renders melody. Generated at 15–22 seconds (the SFX duration ceiling) and looped with a Summer Engine import loop point and optional crossfade.

When to use

  • Location bed for a level, room, biome, or zone.
  • Background hum / drone under dialogue scenes.
  • Atmosphere layer that complements a music track.

When NOT to use

  • Short event SFX (<5s) → sound-effect.
  • Music with melody / chord progression → music-track.
  • Voice barks → voice-line.

Steps

1. Read the audio bible

The bible’s Ambient layer SFX class names the character — usually “continuous, low presence, no looping melody”. Honor it. The mix rules sit ambient at the bus level the bible defined (typically Ambient bus around -12 dB).

2. Identify the location

Ask if it’s not pinned by context:
Which location’s ambience? Be specific — “forest at dawn with light wind and distant birds” beats “outdoors”. The model needs the time of day, the weather, and 2–3 sound sources.

3. Build the prompt — environment + time + weather + 2–3 sources + density + duration

The SFX model renders ambient texture well when the prompt names sound sources, not moods. Prompts that work:
Prompts that DON’T work:

4. Density — keep it low

A bed should be boring. Ask for sparse events.
  • every 6 seconds rather than often.
  • occasional not frequent.
  • distant not close.
  • low not loud.
If the user wants a busier bed (market, party), still prevent foreground events: no recognisable words, no individual loud sounds, general crowd murmur.

5. Generate at the duration ceiling

Name modelId: "eleven_text_to_sound_v2" with loop: true: it is the only sound-effect model that makes seamless loops, and without a modelId the person’s default sound-effect model runs, which may not loop. sound_effects reads from text, not prompt — without text the call is refused (text_required). (prompt is the music capability’s field.) The clip comes back as WAV, so a .wav target path is correct. 22s is the SFX ceiling. Always generate at the ceiling for ambient — longer cycle means less recognized repetition. If the model returns a clip with a loud event near the start or end (a sudden bird right at 0:00), regenerate. That kills loop seamlessness.

6. Mark the seamless loop in Summer Engine’s Import dock

WAV and MP3 use different importers with different option names — do not copy the MP3 block from music-track here. The WAV importer has no loop / loop_offset; it has an edit/loop_mode enum plus sample-frame bounds. In Summer Engine, select the .wav and open the Import dock: The .import file:
edit/loop_mode is 0 = Detect From WAV, 1 = Disabled, 2 = Forward, 3 = Ping-Pong, 4 = Backward — Forward is 2, not 1. edit/loop_begin / edit/loop_end are integer sample frames, not seconds; to skip a 0.5 s fade-in artifact at 44.1 kHz set edit/loop_begin = 22050. After changing, click Reimport.

7. Crossfade-loop pattern for seamlessness

Generated SFX clips are not gapless. Even with the loop mode set, you will often hear a small click at the loop point. Fix it with a two-player crossfade in code:
This eliminates the click and adds variation through phase-overlap (the loop overlaps itself by fade_seconds so the bed never repeats identically).

8. Wire the bed as AudioStreamPlayer on the Ambient bus

For most beds, non-positional is correct (the player is in the place; the bed isn’t an emitter):
Or attach the script in step 7 to a Node, set its stream to the imported audio, and skip the AudioStreamPlayer node — the script provides its own. For positional beds (ambience emitting from a fountain, a campfire, a vent) use AudioStreamPlayer3D with attenuation. The bible’s 3D attenuation: inverse-square, 25m rule applies.

9. Layer multiple beds for depth

Real places have layered ambiences. A forest at dawn might be:
  • Bed A (loud): wind through leaves loop, -12 dB
  • Bed B (medium): distant bird calls loop, -18 dB
  • Bed C (occasional): one-shot SFX of a single bird call, fired by a Timer with random 8–20s interval
This is more expensive (3 generations) but produces a bed that doesn’t sound like a 22-second loop. Reserve for hub locations or extended scenes.

Reference card — prompts by environment

Anti-patterns

  • Using assets.generate_audio({ capability: 'music' }) for an ambient bed. Music model adds melody. You don’t want melody.
  • Foreground events in the bed. A wolf howl, an explosion, a clear word — these promote themselves and the bed becomes annoying.
  • Bed louder than -10 dB on its bus. Beds belong under everything; default is -12 dB to -15 dB.
  • No loop point set. The clip plays once and silence follows.
  • Single-clip looping without crossfade. Audible click every 22s.
  • Same bed everywhere. Different rooms / biomes need different beds. The transition (room A → room B) is what sells the world.

Edge cases

  • Bed too busy on regen. Add sparse, quiet, low, distant to the prompt.
  • Bed has musical content you didn’t ask for. Add no music, no melody, no chords.
  • Bed has voices when you wanted abstract. Add no voices, no recognisable words.
  • Loop click after import dock setup. Use the crossfade script (step 7).
  • Need positional bed (a campfire crackle). Use AudioStreamPlayer3D with max_distance matching the campfire’s reasonable hearing radius (4–8m typical).
  • Multi-room transitions. Use Areas; on player enter, fade in destination bed and fade out source bed over 1.5s.

Without Summer Engine

In a session without Summer Engine tools (the assets profile; the summer-assets skill has the whole loop), do steps 1-5 and stop when the bed exists. Skip steps 6-9: the loop point, the crossfade script and the AudioStreamPlayer are Summer Engine work. Save the file where the person asked with out (the summer-assets skill says how), and tell them the path and format. Tell the person it is a long bed made to loop: their engine either loops it with a short crossfade or plays two copies that overlap.

Fallback (no MCP)

Print the SFX prompt and the import dock settings. User runs via the Summer dashboard and imports manually.

Handoff

Bed forest_dawn.wav wired to Level/AmbientBed, looping with crossfade. Next:
  • Generate the night counterpart for time-of-day transitions.
  • Add a layered occasional bird-call SFX with a randomized Timer for depth.
  • For multi-room transitions, gate beds with Area3D triggers and fade with the same crossfade pattern.

See also

  • audio-direction — defines the Ambient layer class
  • sound-effect — short event SFX layered over the bed
  • music-track — melodic music layered over the bed
  • adaptive-music — state-driven crossfades use the same pattern

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.
Source: library/skills/ambient-bed/SKILL.md, rendered from summer-engine@4.3.0 on npm.