In short
Put your songs as Sound objects in a folder named Music inside SoundService. A LocalScript in StarterPlayerScripts shuffles them, plays one with Sound:Play() and plays the next on Sound.Ended. Because a LocalScript plays it, each player hears and controls their own music: Next and Mute change nothing for anyone else.
- Use audio from the Creator Store, or audio you made or have permission to use. Roblox's asset privacy system controls which audio a game can play.
- A Sound inside a part plays from that spot, louder nearby. A Sound in SoundService plays at the same volume everywhere.
- Name each Sound after its song: the player shows that name.
Get the script
Background music player with Next and Mute
A LocalScript that plays every Sound in SoundService.Music in a shuffled loop, with a small player showing the song name, a Next button and a Mute button.
-- LocalScript in StarterPlayerScripts named MusicPlayer.
-- Plays every Sound inside SoundService.Music in a shuffled loop, with a small
-- player in the corner: song name, Next and Mute. Each player controls their own music.
local Players = game:GetService("Players")
local SoundService = game:GetService("SoundService")
local VOLUME = 0.4 -- 0 to 1
local SHUFFLE = true
local folder = SoundService:WaitForChild("Music")
local songs: { Sound } = {}
for _, child in folder:GetChildren() do
if child:IsA("Sound") then
child.Looped = false
table.insert(songs, child)
end
end
if #songs == 0 then
warn("MusicPlayer: put Sound objects inside SoundService.Music")
return
end
-- The small player in the bottom-right corner
local gui = Instance.new("ScreenGui")
gui.Name = "MusicGui"
gui.ResetOnSpawn = false
local frame = Instance.new("Frame")
frame.AnchorPoint = Vector2.new(1, 1)
frame.Position = UDim2.new(1, -12, 1, -12)
frame.Size = UDim2.fromOffset(260, 44)
frame.BackgroundColor3 = Color3.fromRGB(30, 26, 40)
frame.BackgroundTransparency = 0.15
frame.Parent = gui
local frameCorner = Instance.new("UICorner")
frameCorner.CornerRadius = UDim.new(0, 10)
frameCorner.Parent = frame
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -96, 1, 0)
title.Position = UDim2.fromOffset(10, 0)
title.BackgroundTransparency = 1
title.TextColor3 = Color3.new(1, 1, 1)
title.Font = Enum.Font.Gotham
title.TextSize = 14
title.TextXAlignment = Enum.TextXAlignment.Left
title.TextTruncate = Enum.TextTruncate.AtEnd
title.Parent = frame
local function smallButton(text: string, x: number): TextButton
local b = Instance.new("TextButton")
b.Text = text
b.Size = UDim2.fromOffset(38, 32)
b.Position = UDim2.new(1, x, 0.5, -16)
b.BackgroundColor3 = Color3.fromRGB(110, 80, 220)
b.TextColor3 = Color3.new(1, 1, 1)
b.Font = Enum.Font.GothamBold
b.TextSize = 14
local c = Instance.new("UICorner")
c.CornerRadius = UDim.new(0, 8)
c.Parent = b
b.Parent = frame
return b
end
local nextButton = smallButton(">>", -86)
local muteButton = smallButton("On", -44)
gui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")
local order: { number } = {}
local position = 0
local current: Sound? = nil
local muted = false
-- Off when this player pressed Mute, or turned Music off in a settings menu that sets the
-- Setting_Music attribute (see the settings menu guide)
local function volume(): number
local settingOff = Players.LocalPlayer:GetAttribute("Setting_Music") == false
return if muted or settingOff then 0 else VOLUME
end
local function shuffle()
order = {}
for i = 1, #songs do
table.insert(order, i)
end
if SHUFFLE then
for i = #order, 2, -1 do
local j = math.random(i)
order[i], order[j] = order[j], order[i]
end
end
position = 0
end
local function playNext()
if current then
current:Stop()
end
position += 1
if position > #order then
shuffle()
position = 1
end
local song = songs[order[position]]
current = song
song.Volume = volume()
song:Play()
title.Text = song.Name -- name each Sound after its song
end
for _, song in songs do
song.Ended:Connect(function()
if song == current then
playNext()
end
end)
end
nextButton.Activated:Connect(playNext)
muteButton.Activated:Connect(function()
muted = not muted
muteButton.Text = if muted then "Off" else "On"
if current then
current.Volume = volume()
end
end)
shuffle()
playNext()
RoCode builds it in the place you have open in Roblox Studio, on Windows or macOS with a desktop browser; on a phone the button sends the prompt and the link to your computer. Free to start, with free credits every day. More Roblox Studio scripts
Where to put it
SoundService
Music Folder new
Song One Sound
Song Two Sound
StarterPlayer
StarterPlayerScripts
MusicPlayer LocalScript new
Settings you can change
VOLUMEIn the script- Music volume from 0 to 1. Keep it below sound effects so they stay clear. Default:
0.4. SHUFFLEIn the script- Shuffle the songs. Set it to
falseto play them in the order of the folder. Default:true.
Type-checked with luau-lsp strict against Roblox's API definitions on 23 October 2026. Not playtested in Studio yet: press Play and watch the Output window before you publish.
Prompt for RoCode
Add background music: a Music folder in SoundService with my songs, and a LocalScript that plays them shuffled in a loop at volume 0.4, with a small player in the bottom-right corner showing the song name, a Next button and a Mute button.
On this page
How sound works in Roblox
| Sound inside | Heard | Use it for |
|---|---|---|
| A part or attachment | From that spot, quieter with distance | Sound effects: a door, a coin, a waterfall. |
| SoundService or a folder in it | Everywhere at the same volume | Background music and menu sounds. |
Who starts the Sound matters too. A server Script that calls Play() plays it for everyone. A LocalScript plays it only on that player's device, which is what you want for music, so one player's Mute does not silence the server.
Step 1: Add your songs
- In the Explorer, hover over SoundService, click + and insert a Folder named
Music. - Open the Toolbox, choose the Creator Store tab and the Audio category, and find music you like. Insert it, then drag the Sound into the Music folder.
- Or import your own: audio you made or have permission to use, uploaded through the Asset Manager or Creator Hub.
- Rename each Sound to the song's name. Add as many as you like.
Step 2: The music player
Insert a LocalScript in StarterPlayer > StarterPlayerScripts named MusicPlayer:
-- LocalScript in StarterPlayerScripts named MusicPlayer.
-- Plays every Sound inside SoundService.Music in a shuffled loop, with a small
-- player in the corner: song name, Next and Mute. Each player controls their own music.
local Players = game:GetService("Players")
local SoundService = game:GetService("SoundService")
local VOLUME = 0.4 -- 0 to 1
local SHUFFLE = true
local folder = SoundService:WaitForChild("Music")
local songs: { Sound } = {}
for _, child in folder:GetChildren() do
if child:IsA("Sound") then
child.Looped = false
table.insert(songs, child)
end
end
if #songs == 0 then
warn("MusicPlayer: put Sound objects inside SoundService.Music")
return
end
-- The small player in the bottom-right corner
local gui = Instance.new("ScreenGui")
gui.Name = "MusicGui"
gui.ResetOnSpawn = false
local frame = Instance.new("Frame")
frame.AnchorPoint = Vector2.new(1, 1)
frame.Position = UDim2.new(1, -12, 1, -12)
frame.Size = UDim2.fromOffset(260, 44)
frame.BackgroundColor3 = Color3.fromRGB(30, 26, 40)
frame.BackgroundTransparency = 0.15
frame.Parent = gui
local frameCorner = Instance.new("UICorner")
frameCorner.CornerRadius = UDim.new(0, 10)
frameCorner.Parent = frame
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -96, 1, 0)
title.Position = UDim2.fromOffset(10, 0)
title.BackgroundTransparency = 1
title.TextColor3 = Color3.new(1, 1, 1)
title.Font = Enum.Font.Gotham
title.TextSize = 14
title.TextXAlignment = Enum.TextXAlignment.Left
title.TextTruncate = Enum.TextTruncate.AtEnd
title.Parent = frame
local function smallButton(text: string, x: number): TextButton
local b = Instance.new("TextButton")
b.Text = text
b.Size = UDim2.fromOffset(38, 32)
b.Position = UDim2.new(1, x, 0.5, -16)
b.BackgroundColor3 = Color3.fromRGB(110, 80, 220)
b.TextColor3 = Color3.new(1, 1, 1)
b.Font = Enum.Font.GothamBold
b.TextSize = 14
local c = Instance.new("UICorner")
c.CornerRadius = UDim.new(0, 8)
c.Parent = b
b.Parent = frame
return b
end
local nextButton = smallButton(">>", -86)
local muteButton = smallButton("On", -44)
gui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")
local order: { number } = {}
local position = 0
local current: Sound? = nil
local muted = false
-- Off when this player pressed Mute, or turned Music off in a settings menu that sets the
-- Setting_Music attribute (see the settings menu guide)
local function volume(): number
local settingOff = Players.LocalPlayer:GetAttribute("Setting_Music") == false
return if muted or settingOff then 0 else VOLUME
end
local function shuffle()
order = {}
for i = 1, #songs do
table.insert(order, i)
end
if SHUFFLE then
for i = #order, 2, -1 do
local j = math.random(i)
order[i], order[j] = order[j], order[i]
end
end
position = 0
end
local function playNext()
if current then
current:Stop()
end
position += 1
if position > #order then
shuffle()
position = 1
end
local song = songs[order[position]]
current = song
song.Volume = volume()
song:Play()
title.Text = song.Name -- name each Sound after its song
end
for _, song in songs do
song.Ended:Connect(function()
if song == current then
playNext()
end
end)
end
nextButton.Activated:Connect(playNext)
muteButton.Activated:Connect(function()
muted = not muted
muteButton.Text = if muted then "Off" else "On"
if current then
current.Volume = volume()
end
end)
shuffle()
playNext()
The script turns off Looped on every song, because a looping Sound never fires Ended. It shuffles the list with a Fisher-Yates shuffle, plays the first song, and on each Ended plays the next. After the last one it shuffles again. Mute sets the volume of the current song to 0 instead of stopping it, so unmuting carries on mid-song.
For a settings menu with a Music switch that is saved between sessions, see the settings menu guide: its Music switch works with this folder, and this player checks the same Setting_Music attribute each time it starts a song.
Step 3: Sound effects on touch
For a part that makes a sound when stepped on, such as a squeaky toy, a bell or a trampoline, put a Sound inside the part and this Script beside it:
-- Script inside a part, named TouchSound. Put a Sound inside the same part.
-- Plays the sound when a player touches the part. Everyone nearby hears it.
local Players = game:GetService("Players")
local COOLDOWN = 1 -- seconds before the sound can play again
local part = script.Parent :: BasePart
local sound = part:FindFirstChildOfClass("Sound")
local lastPlayed = -math.huge
part.Touched:Connect(function(hit: BasePart)
local character = hit.Parent
if not (sound and character and character:IsA("Model") and Players:GetPlayerFromCharacter(character)) then
return
end
local now = os.clock()
if now - lastPlayed < COOLDOWN then
return
end
lastPlayed = now
-- A Sound inside a part plays from that spot: louder close by, quieter far away
sound:Play()
end)
A server Script plays it, so everyone nearby hears it, and because the Sound is in a part it comes from that spot. The cooldown stops it restarting many times a second while a player stands on it. For a sound only the player who touched it should hear, such as a coin pickup, play it from a LocalScript instead.
Test it
- Press Play. Music starts and the song name shows in the bottom-right corner.
- Press >>: the next song starts. Press On: it says Off and the music goes quiet.
- Walk onto the part with TouchSound: you hear the sound, louder as you get closer.
Common errors and fixes
Sound problems usually show in the Output window as a warning about the asset.
MusicPlayer: put Sound objects inside SoundService.Music
The folder is empty or has a different name. It must be a Folder named Music directly inside SoundService.
A song plays nothing
Check the Output for an asset permission error. Use audio from the Creator Store or audio you uploaded, and check the Sound's SoundId is set.
The same song plays forever
A Sound with Looped on never ends. The script turns Looped off; check no other script turns it back on.
Everyone hears my touch sound but I wanted only one player
Play it from a LocalScript on that player's device instead of a server Script.
Build it with RoCode
If you would rather not set this up by hand, RoCode can build it in the place you have open. RoCode is an independent AI agent for Roblox Studio, not made by Roblox: you describe the change in a web chat, and its Studio plugin creates the scripts and objects in your Explorer.
Add background music that shuffles the songs in SoundService.Music with a small player that has Next and Mute, and make my trampolines play a boing sound when touched.
- Writes the music player and touch sound scripts and sets up the Music folder
- Is told to compile-check each script with Check Script, and sets undo points around each batch
- Can insert a ready-made settings screen from its premium UI kits, animated, in one of five themes, with working server scripts
RoCode does not pick or upload audio for you: choose songs in the Creator Store or upload your own, and put them in the folder. How RoCode connects to Studio.
Questions
How do I add background music to my Roblox game?
Put Sounds in a folder in SoundService and play them from a LocalScript, moving to the next song on Sound.Ended. Step 2 has a full playlist with Next and Mute.
Why does my music not play?
Most often the audio is private to another account. Use Creator Store audio or audio you uploaded, and check the Output for an asset permission error.
How do I let players mute the music?
Play the music from a LocalScript, then a Mute button can set the volume to 0 for that player only.
How do I play a sound when a part is touched?
Put a Sound in the part and call sound:Play() from a Script on Touched, with a short cooldown. Step 3 has the script.
Sources and further reading
- Roblox Creator Docs: Audio assets. finding Creator Store audio, importing your own and asset privacy
- Roblox Creator Docs: Sound. Play, Ended, Looped and Volume
- Roblox Creator Docs: Sound objects. positional sound in parts and global sound
- Roblox Creator Docs: Play background music. Roblox's own background music tutorial
How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 23 October 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.