The site is under maintenance, so logging in is temporarily unavailable. All resources and the MCP still work.

AI Skills

The new Audio API

By Roblox Vibecoders · roblox-audio-api

Use when adding music, sound effects, 3D positional audio, voice chat, audio effects (reverb, EQ, muffling, ducking) or audio-reactive visuals to a Roblox game. Covers the modular Audio API (AudioPlayer, AudioEmitter, AudioListener, AudioDeviceOutput, AudioDeviceInput, Wire, effects, AudioAnalyzer) that replaces legacy Sound, SoundGroup and SoundEffect.

Install it

Terminal
mkdir -p ~/.claude/skills/roblox-audio-api && curl -fsSL https://robloxvibecoders.com/skills/roblox-audio-api/SKILL.md -o ~/.claude/skills/roblox-audio-api/SKILL.md

Skills in ~/.claude/skills work in every project. Put them in your project's .claude/skills folder to share them with your team.

What your AI reads

SKILL.md
---
name: roblox-audio-api
description: Use when adding music, sound effects, 3D positional audio, voice chat, audio effects (reverb, EQ, muffling, ducking) or audio-reactive visuals to a Roblox game. Covers the modular Audio API (AudioPlayer, AudioEmitter, AudioListener, AudioDeviceOutput, AudioDeviceInput, Wire, effects, AudioAnalyzer) that replaces legacy Sound, SoundGroup and SoundEffect.
---

# The new Audio API

Roblox audio is now built from small objects joined by **Wires**, like real audio gear. Roblox's docs discourage
`Sound`, `SoundGroup` and `SoundEffect` for new work in favor of these objects.

| Object | Real-world equivalent | Pins |
|---|---|---|
| `AudioPlayer` | a media player: loads and plays an asset | Output |
| `AudioEmitter` | a speaker placed in the 3D world | Input |
| `AudioListener` | a microphone in the 3D world that hears emitters | Output |
| `AudioDeviceOutput` | the player's headphones or speakers | Input |
| `AudioDeviceInput` | a player's real microphone (voice chat) | Output |
| `Wire` | a cable: `SourceInstance` -> `TargetInstance` | - |
| Effects (`AudioReverb`, `AudioEqualizer`, `AudioFader`, `AudioCompressor`, `AudioFilter`, `AudioEcho`, `AudioChorus`, `AudioDistortion`, `AudioFlanger`, `AudioPitchShifter`, `AudioTremolo`, `AudioLimiter`, `AudioGate`) | pedals and mixer channels | Input, Output |
| `AudioAnalyzer` | a level meter / spectrum analyzer | Input |

A `Wire` uses the `Output` pin of its source and the `Input` pin of its target by default (`SourceName`,
`TargetName`). `AudioCompressor` also has a `Sidechain` input pin. `Wire.Connected` tells you whether the wire is
actually carrying audio. Audio processing is disabled on the server; the server only replicates the setup and
`Play`/`Stop`.

## 2D audio (music, UI sounds)

Player -> Wire -> DeviceOutput. Nothing positional.

```luau
-- LocalScript: per-player music
local SoundService = game:GetService("SoundService")

local music = Instance.new("AudioPlayer")
music.Asset = "rbxassetid://1234567890"
music.Looping = true
music.Volume = 0.5 -- 0 to 10
music.Parent = SoundService

local output = Instance.new("AudioDeviceOutput")
output.Parent = SoundService

local wire = Instance.new("Wire")
wire.SourceInstance = music
wire.TargetInstance = output
wire.Parent = music

music:Play()
```

`AudioDeviceOutput.Player` limits who hears it; leave it nil and everyone hears the wired streams.

## 3D audio (positional)

Player -> Wire -> Emitter, heard by a Listener -> Wire -> DeviceOutput.

1. Listener: in Studio select **SoundService** and set **ListenerLocation** (`DefaultListenerLocation`) to
   `Character` or `Camera`. The engine then creates the `AudioListener` and an `AudioDeviceOutput` wired to it for
   each player. (`Default` only creates a camera listener in voice-enabled experiences; `None` means you build it.)
2. Emitter: put an `AudioEmitter` under a part, attachment or model. It plays from its parent's position.

```luau
-- Server Script: a radio on a part, heard by everyone nearby
local radio = workspace.Radio

local player = Instance.new("AudioPlayer")
player.Asset = "rbxassetid://1234567890"
player.Looping = true
player.Parent = radio

local emitter = Instance.new("AudioEmitter")
emitter.DistanceAttenuationMode = Enum.DistanceAttenuationMode.Linear
emitter.DistanceAttenuationBounds = NumberRange.new(10, 80) -- full volume within 10 studs, silent at 80
emitter.Parent = radio

local wire = Instance.new("Wire")
wire.SourceInstance = player
wire.TargetInstance = emitter
wire.Parent = radio

player:Play() -- Play and Stop called on the server replicate to clients
```

Distance falloff: `DistanceAttenuationMode` is `Custom` by default; with any other mode (`Inverse`,
`InverseTapered`, `Linear`, `LinearSquared`) the `DistanceAttenuationBounds` range is used. For `Custom`, give a
curve of distance -> volume (0 to 1), up to 400 points; an empty curve means inverse-square falloff:

```luau
emitter:SetDistanceAttenuation({ [0] = 1, [50] = 0.5, [70] = 0 })
```

More emitter/listener controls:

- `PositionType = Enum.EmitterPositionType.Instance` plus `PositionInstance` makes an emitter follow another
  instance without being parented to it (same for listeners with `ListenerPositionType`).
- `AudioInteractionGroup`: an emitter is heard only by listeners with the same group string. Use it for radio
  channels, phone calls or team-only audio.
- `SetAngleAttenuation(curve)`: directional speakers (volume by angle from the emitter's LookVector).
- Acoustic simulation (muffling through walls, bending around corners, reverb): `SoundService.AcousticSimulationEnabled`
  plus `AcousticSimulationEnabled` on the emitter and the listener. Set `BasePart.AudioCanCollide = false` on parts
  that should not block sound (foliage, glass panes, decorations).

## Effects and mixing

Put effects in the chain between source and destination. Order matters. Several players can share one effect.

```luau
-- Music bus: music -> fader -> EQ -> output (instead of wiring music straight to the output).
-- The fader can be tweened for fades; the EQ muffles the music underwater.
local fader = Instance.new("AudioFader")
fader.Volume = 1 -- 0 to 10
fader.Parent = SoundService

local eq = Instance.new("AudioEqualizer")
eq.Bypass = true -- turn on when the camera goes underwater
eq.HighGain = -30 -- dB, -80 to 10
eq.MidGain = -10
eq.Parent = SoundService

local function connect(source: Instance, target: Instance)
	local w = Instance.new("Wire")
	w.SourceInstance = source
	w.TargetInstance = target
	w.Parent = target
	return w
end

connect(music, fader)
connect(fader, eq)
connect(eq, output)
```

- `AudioReverb` for rooms and caves (`DecayTime`, `WetLevel`, `DryLevel`, `Density`, `Diffusion`).
- `AudioCompressor` evens out loud bursts; wire dialogue into its `Sidechain` pin to duck music under speech.
- `AudioFilter` (`FilterType`, `Frequency`, `Q`, `Gain`) for low-pass muffling or radio sound.
- `AudioPitchShifter.Pitch` changes pitch without changing speed; `AudioPlayer.PlaybackSpeed` (0 to 20) changes
  both.
- Every effect has `Bypass` to switch it off without rewiring.

## Voice chat

In Studio set `VoiceChatService.UseAudioApi` to **Enabled**. Then each voice-eligible player gets an
`AudioDeviceInput` (parented to their `Player`), an `AudioEmitter` on their character, and the camera gets an
`AudioListener`. Set `VoiceChatService.EnableDefaultVoice = false` (Studio property) to build your own routing, for
example walkie-talkies: wire a player's `AudioDeviceInput` into effects and an emitter with a shared
`AudioInteractionGroup`. `AudioDeviceInput.Muted`, `Volume`, `AccessType` and `SetUserIdAccessList` control who can
hear a microphone.

## Audio-reactive visuals

Wire anything into an `AudioAnalyzer` and read it on the client every frame:

```luau
local analyzer = Instance.new("AudioAnalyzer")
analyzer.SpectrumEnabled = true
analyzer.Parent = SoundService
connect(music, analyzer)

local speakerCone = workspace.Stage.SpeakerCone
game:GetService("RunService").RenderStepped:Connect(function()
	local level = analyzer.RmsLevel        -- smoother than PeakLevel
	local bands = analyzer:GetSpectrum()   -- RMS levels from 0 Hz to 24,000 Hz
	speakerCone.Size = Vector3.new(2, 2, 2) * (1 + level)
end)
```

`RmsLevel` is always 0 and `GetSpectrum` returns an empty array on the server. Analyzers fed by voice
(`AudioDeviceInput`) return an empty spectrum.

## Character sounds

`SoundService.CharacterSoundsUseNewApi` (set in Studio) makes the default footstep, jump and swim sounds use
`AudioPlayer` and `AudioEmitter` instead of `Sound`.

## When legacy Sound is still fine

`Sound` is discouraged, not removed. Keep it when maintaining a working game built on `Sound` and `SoundGroup`,
or for a quick prototype. For new systems use the Audio API: it gives you routing, real buses, sidechain ducking,
analyzers, voice and interaction groups. Don't build one mix out of both systems: `SoundGroup` volumes and
`SoundEffect`s don't touch `AudioPlayer` streams.

## Mistakes to avoid

- An `AudioPlayer` with no wire, or a wire with only one end set: it plays silently. Check `Wire.Connected`.
- An `AudioEmitter` whose parent is not a part, attachment, model or camera: it is silent.
- 3D audio with `ListenerLocation = None` and no listener of your own.
- Setting `AutoPlay` and expecting it to work on players created through replication: it is meant for Studio setup.
  Call `:Play()`.
- Reading `AudioAnalyzer` on the server.
- Using deprecated `AudioPlayer.AssetId`; the property is `Asset` (or `AudioContent`).
- Creating a new `AudioPlayer` per gunshot and never destroying it. Reuse players or `:Destroy()` them on `Ended`.