Tutorial · Menus and sound

How to add a music player to your Roblox game

Music sets the mood of a game more than any model, and a mute button is the first thing many players look for. This guide adds both: a playlist that plays every song in a folder in shuffled order, with a small player in the corner that shows the song name and lets each player skip or mute. Then it adds sound effects that play when someone touches a part, heard by everyone nearby.

Updated 23 October 20266 min readBeginnerLuau

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
-- 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

Explorer: a folder of songs and one LocalScript
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 false to 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
  1. Get the script
  2. How it works
  3. 1. Songs
  4. 2. Player
  5. 3. Touch sounds
  6. Common errors
  7. With RoCode
  8. Questions
  9. Sources

How sound works in Roblox

Where a Sound lives decides how it sounds
Sound insideHeardUse it for
A part or attachmentFrom that spot, quieter with distanceSound effects: a door, a coin, a waterfall.
SoundService or a folder in itEverywhere at the same volumeBackground 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

  1. In the Explorer, hover over SoundService, click + and insert a Folder named Music.
  2. 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.
  3. Or import your own: audio you made or have permission to use, uploaded through the Asset Manager or Creator Hub.
  4. 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
-- 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 in the part named TouchSound
-- 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

  1. Press Play. Music starts and the song name shows in the bottom-right corner.
  2. Press >>: the next song starts. Press On: it says Off and the music goes quiet.
  3. 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.

You type

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.

RoCode does
  • 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

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.

Try RoCode on your own place.

Free every day, no card required. Install the plugin, describe the feature, and review what lands in Studio.