Bring Back Studio's Darker Theme, Color by Color
Studio's dark theme got lighter and the script editor now reads as washed-out gray instead of near-black. The general theme and the UI skin are two toggles, but the editor palette is 27 properties you can rewrite by script — and a local plugin does it in one click.
AI-assisted draft, reviewed, tested and edited by a human before publishing. See our Editorial Policy. · Reviewed by Gustavo Cantino, 9/15/26 Editorial Policy

The "darker" theme you want back isn't a single button — it's three separate things Studio pulled apart over time. The first is the general theme, Dark versus Light, which lives in File > Studio Settings. The second is the interface update that lightened the gray of Dark itself: if your build still has the toggle in Beta Features, you can turn it off; if it doesn't, that ship sailed. And the third — the one almost everybody is missing without being able to name it — is the script editor palette, that near-black background with dark green comments that turned into a light gray with no contrast.
Good news: the third one is 100% recoverable, color by color, and it's the one you stare at for hours on end. And it's editable by script, which means you don't have to click through 27 color pickers by hand.
The dark theme got lighter and you want the old one back
Open File > Studio Settings (Alt+S) and go to Studio. Scroll down to the script editor color section. You'll count more than 25 properties: Background Color, Text Color, Comment Color, String Color, Number Color, Keyword Color, Operator Color, Error Color, Warning Color, Todo Color, Whitespace Color, and it keeps going. Each one opens a color picker where you type three RGB fields. Fixing this by hand means typing close to 80 numbers in a row, in a panel that scrolls, with no decent search bar. It takes 10 to 15 minutes if you already know the values — and you don't, because Studio never shows you what the old value was.
Worse: these settings have no Ctrl+Z. Changing a color in Studio Settings does not go into the place's undo stack. Get Background Color wrong and close the window, and the previous value is gone.
And there's a third problem, the one that bites later: Studio Settings is per machine, not per account. Format the PC, reinstall Studio, sit down at a new laptop for a trip — palette wiped again. Team Create shares none of this either: your partner is still on light gray while you already fixed yours.
So the goal here isn't "change some colors." It's turning your palette into a file you can apply on any machine in two clicks, and that you can undo.
The three places the darker theme went
1. The general theme. File > Studio Settings > Studio > Theme. If it's on Light, switch it to Dark and you're done — 80% of the people who ask this ended up on Light without noticing, usually after a reinstall. If it's already on Dark and still looks bright, your problem is item 2 or item 3.
You can do this by script too, but there's a catch. This is the wrong way:
settings().Studio.Theme = "Dark"
-- Unable to assign property Theme. StudioTheme expected, got stringTheme doesn't take text, it takes a StudioTheme object. The right way is to pull it from the list Studio itself exposes:
local studio = settings().Studio
for _, theme in studio:GetAvailableThemes() do
if theme.Name == "Dark" then
studio.Theme = theme
end
end2. The interface update. When Studio refreshed the UI, the background gray of the windows went up a shade. That's not a color you edit: it's the application skin. While the feature is in beta, it shows up in File > Beta Features with a checkbox — unchecking it, restarting Studio and going back to the old look works. Once the feature leaves beta, the toggle disappears from the list and there is no rollback. It's worth opening Beta Features and checking; if there's nothing UI-related there, jump to item 3 and don't waste time hunting for a plugin "that makes Studio black" — a plugin doesn't repaint Studio's own frame, only the windows the plugin itself creates.
3. The script editor palette. Here you control everything. Every one of those properties is reachable from code, using the exact name shown in the panel, spaces included. Test it with a single line in the Command Bar:
settings().Studio["Background Color"] = Color3.fromRGB(20, 20, 20)Open any script: the background darkened instantly. Close and reopen Studio: still dark. It persists because it's user configuration, not place configuration — it has nothing to do with the game you have open, you don't need to publish anything, and it won't get committed to Team Create.
From there it's just repeating that line for each color. Except repeating it 27 times in the Command Bar, pasting and fixing typos, is exactly the manual work we're trying to avoid. That's what the artifact below is for.
Bonus almost nobody wires up: if you write plugins with their own interface, the theme is readable from code too. Instead of hardcoding a gray that looks awful for anyone on Light, ask the theme:
local theme = settings().Studio.Theme
frame.BackgroundColor3 = theme:GetColor(Enum.StudioStyleGuideColor.MainBackground)The plugin that rewrites the whole palette in one click
The artifact is a local plugin with two buttons: Backup and Apply.
To install: create a new Script anywhere in the Explorer (ServerStorage works), paste the code, right-click the Script and pick "Save as Local Plugin". Save it as DarkerTheme and restart Studio. A toolbar called "Darker Theme" shows up in the Plugins tab.
Click Backup first. It reads the current value of every one of the colors and prints it to the Output already formatted as a Luau table — you just copy the block from the Output and paste it into a text file of your own. That's your undo button, because Studio doesn't have one.
Then click Apply. It walks the palette and writes property by property inside a pcall. The pcall is there because the color list changes between Studio versions: if your build doesn't have "Luau Keyword Color", for example, the write fails on that one line and the rest goes through. At the end it prints how many were applied and how many were skipped, with the names of the skipped ones. If you see "27 applied, 0 skipped", you nailed the whole build.
The RGB values in there are a reconstruction of the old dark, not an official Roblox dump. Treat it as a starting point: open the PALETTE table, change the numbers that bother you, save the plugin again and click Apply. The whole cycle takes about 5 seconds, so you can tune it color by color with a script open next to it.
The expensive mistake: applying the palette without saving the old one
The mistake that hurts is clicking Apply before clicking Backup. There's no Ctrl+Z for Studio Settings, there's no "restore defaults" button that gives your old customization back, and the list keeps no history. If you had a palette you tuned two years ago and you overwrote it, it's gone. Run Backup, copy the Output into a file, and keep that file in the same repo as the game. It's a 30-line .txt that's worth more than the plugin.
The second mistake is going too dark. A background at RGB 0,0,0 with dark green comments looks great in a screenshot and destroys your eyes in two hours. The public reference is WCAG: minimum contrast of 4.5:1 between text and background for normal text, 7:1 if you want comfort over long reading sessions. Comments and strings are the two that usually fall below that when people darken the background without brightening the text in the same proportion. Run your Background Color and your Comment Color through a contrast checker before locking the palette in.
Third: don't confuse Studio Settings with Game Settings. None of this goes into your game, it affects no player, it doesn't ship on publish. If you went into Game Settings looking for a theme, you're in the wrong panel.
Fourth, for anyone going after the raw file: these settings usually live in a GlobalSettings_13.xml inside %LOCALAPPDATA%\Roblox. Editing that XML with Studio open is throwing money away — Studio rewrites the file on exit and erases what you typed. If you're going to touch it, close Studio first. But the plugin does the same job with no risk of corrupting the file.
What to measure next
Test the palette on a real script, not on an empty one: open a 300-line module of yours, with comments, a long string, a number, a method call and a deliberate syntax error. That's where you find out that Error Color vanished into the new background, or that Todo Color came out identical to Comment Color.
Then measure two concrete things. One: the contrast of Text Color against Background Color, aiming at 7:1. Two: how many properties Backup managed to read on your build — if the Output lists fewer items than PALETTE has, Studio renamed something and your palette is incomplete without you noticing.
Finally, make the palette travel. The local plugin file is an .rbxmx in a Plugins folder on your machine; copy it into the team repo and everyone applies the same scheme in two clicks, including you on the new PC. That's the difference between "I fixed my Studio" and "the whole team reads code the same way."
And if you maintain plugins with their own interface, the natural next step is hooking into ThemeChanged, so your window repaints itself when someone toggles Dark and Light:
settings().Studio.ThemeChanged:Connect(function()
-- repaint your widget's Frames and TextLabels here
end)Ready-to-use artifact
--!strict
-- Darker Theme — rewrites Studio's script editor palette back to a dark scheme.
-- Install: paste into a new Script anywhere in the Explorer (ServerStorage works),
-- right-click the Script > "Save as Local Plugin", name it DarkerTheme, restart Studio.
-- Click BACKUP first: it dumps your current colors to the Output as a Luau table.
-- Studio Settings has no Ctrl+Z, so that dump is your only undo.
-- settings().Studio is indexed by the exact property name shown in the panel,
-- spaces included, so we cast to any to keep --!strict quiet.
local studio = settings().Studio :: any
type Entry = { name: string, rgb: { number } }
-- Reconstruction of the old dark palette. Change any number, save the plugin
-- again and click Apply — the whole cycle takes about 5 seconds.
local PALETTE: { Entry } = {
{ name = "Background Color", rgb = { 20, 20, 20 } },
{ name = "Text Color", rgb = { 204, 204, 204 } },
{ name = "Selection Color", rgb = { 255, 255, 255 } },
{ name = "Selection Background Color", rgb = { 17, 85, 204 } },
{ name = "Find Selection Background Color", rgb = { 88, 88, 60 } },
{ name = "Warning Color", rgb = { 255, 200, 0 } },
{ name = "Error Color", rgb = { 255, 68, 68 } },
{ name = "Ruler Color", rgb = { 60, 60, 60 } },
{ name = "Whitespace Color", rgb = { 40, 40, 40 } },
{ name = "Current Line Highlight Color", rgb = { 34, 34, 34 } },
{ name = "Debugger Current Line Color", rgb = { 60, 60, 20 } },
{ name = "Debugger Error Line Color", rgb = { 90, 30, 30 } },
{ name = "Operator Color", rgb = { 204, 204, 204 } },
{ name = "Number Color", rgb = { 255, 198, 0 } },
{ name = "String Color", rgb = { 173, 241, 149 } },
{ name = "Comment Color", rgb = { 60, 120, 60 } },
{ name = "Bool Color", rgb = { 255, 198, 0 } },
{ name = "Function Color", rgb = { 132, 214, 247 } },
{ name = "Local Color", rgb = { 248, 109, 124 } },
{ name = "Self Color", rgb = { 248, 109, 124 } },
{ name = "Luau Keyword Color", rgb = { 248, 109, 124 } },
{ name = "Function Name Color", rgb = { 132, 214, 247 } },
{ name = "Keyword Color", rgb = { 248, 109, 124 } },
{ name = "Method Color", rgb = { 132, 214, 247 } },
{ name = "Property Color", rgb = { 151, 255, 235 } },
{ name = "Nil Color", rgb = { 255, 198, 0 } },
{ name = "TODO Color", rgb = { 0, 170, 255 } },
}
-- Reads every color in PALETTE and prints it back as a Luau table you can paste
-- into a text file. Properties that don't exist on this build are just not listed.
local function backup()
local lines: { string } = { "local BACKUP = {" }
local read = 0
for _, entry in PALETTE do
local ok, value = pcall(function()
return studio[entry.name]
end)
if ok and typeof(value) == "Color3" then
read += 1
table.insert(lines, string.format(
'\t{ name = "%s", rgb = { %d, %d, %d } },',
entry.name,
math.round(value.R * 255),
math.round(value.G * 255),
math.round(value.B * 255)
))
end
end
table.insert(lines, "}")
print(table.concat(lines, "\n"))
print(string.format("[Darker Theme] backup: %d of %d properties read on this build.", read, #PALETTE))
end
-- Writes the palette property by property. Each write is wrapped in its own pcall
-- because the color list changes between Studio versions: a missing name fails
-- that single line and the rest still goes through.
local function apply()
local applied = 0
local skipped: { string } = {}
for _, entry in PALETTE do
local color = Color3.fromRGB(entry.rgb[1], entry.rgb[2], entry.rgb[3])
local ok = pcall(function()
studio[entry.name] = color
end)
if ok then
applied += 1
else
table.insert(skipped, entry.name)
end
end
print(string.format("[Darker Theme] %d applied, %d skipped.", applied, #skipped))
if #skipped > 0 then
print("[Darker Theme] skipped: " .. table.concat(skipped, ", "))
end
end
local toolbar = plugin:CreateToolbar("Darker Theme")
local backupButton = toolbar:CreateButton(
"Backup",
"Print the current palette to the Output as a Luau table",
"rbxasset://textures/ui/GuiImagePlaceholder.png"
)
local applyButton = toolbar:CreateButton(
"Apply",
"Write the PALETTE table into Studio Settings",
"rbxasset://textures/ui/GuiImagePlaceholder.png"
)
backupButton.ClickableWhenViewportHidden = true
applyButton.ClickableWhenViewportHidden = true
backupButton.Click:Connect(function()
backupButton:SetActive(false)
backup()
end)
applyButton.Click:Connect(function()
applyButton:SetActive(false)
apply()
end)


