The minimal theme has just undergone a complete rewrite. It’s now dynamically generated just like godot’s own built-in theme, so it supports editor settings and fixes some issues that couldn’t be fixed before!

Why minimal theme?

Minimal theme solves two things:

  1. Removes excessive UI decorations.
  2. Adds whitespace where it helps readability.

By decorations I mean borders and lines, you can see them everywhere throughout the editor. One example that has a lot of them is the animation player (top one is the built-in theme, bottom is minimal theme):

As for the whitespace example, one of the PRs that I opened this year was to allow customizing section headers in the inspector. Property sections and properties themselves belong to different levels of semantic hierarchy (one includes the other) and making sections occupy more space makes it easier to understand this relationship at a glance.

Even though I made this theme mostly for practical reasons (I just want the UI to disappear and not distract me), UI design is a subject to personal taste. There are no strict rules, no right and wrong, just likes and dislikes.

Problems of 1.0

One of the first things that I realized when I got into theming is that there are no variables or expressions in godot themes. Also, unlike CSS, godot themes don’t have relative units. There are only pixel units. When you define a stylebox, whatever content margins you define are pixel values that the end user is gonna get, no matter the display dpi.

Of course different editor scales require different content margins in pixels. Which is why my theme came in 2 variants - a regular version for 100% editor scale and a HiDPI version for higher editor scales.

I could have generated different theme resource files through python or whatever, but every added option would have doubled the amount of files. With HiDPI I had 2 variations. But some people have been asking to make a light theme. If I were to do that we’d have 4 themes. If I were to also add support for increased margins to make it mobile-friendly we’d have 8 themes. And so on.

If themes only support pixels, how come Godot’s own editor theme supports different editor scales, not to mention all of the other settings? That’s because it’s generated entirely in C++! There’s no .tres anywhere on disk. When you change any theme-related setting it runs the whole theme generation logic in C++ again.

2.0

Several weeks ago Yuri Sizov reached out to me and suggested using a built-in script on the theme resource itself to combine the regular and HiDPI theme resources into one. Originally he suggested to embed two (or more) theme chunks into a single resource and merge them together using Theme.merge_with() depending on selected editor settings.

After some discussion we decided that instead of merging two resources it makes more sense to just generate the whole thing entirely from code just like it’s done in the built-in theme. This gives the most control with the least amount of lines.

This made the theme shrink by 1.3K LOC (~150%), even though it does much more now:

This is due to the fact that the high dpi file is not needed anymore because the theme can read editor scale from editor settings to calculate the correct margins.

Btw Yuri also wrote an in-depth article about this idea, you can check it out here!

The idea is simple - whatever goes into the _init() method of the resource script gets executed when the theme is loaded, so we can make calls to set_constant(), set_stylebox(), set_color(), etc to generate the theme from the theme itself. Of course since it’s GDScript we can also read editor settings from it just like from any other tool script.

And it gets better - the _init() runs every time any of the theme-related settings are changed in the editor settings. So when you change the base color or the spacing values godot will regenerate the custom theme automatically using those values.

It took several hours to convert the theme from a resource to a script. But it took much longer than that to eliminate all of redundancy, make sure all of the relevant editor settings are supported and test everything.

Colors

The main monochrome color that I’m using with this theme is #252525. Most apps seem to be monochrome these days so it blends well with the rest of the pack.

For non-monochrome options I like:

  • #22262B which is close to what I use in vscode (github dark theme)
  • #1E1E2D which is less subtle but looks really nice

Looks like this with the second option:

But, of course, now that the theme has proper support for colors you can choose whatever color you want!

Light theme?

As I mentioned before, psychopaths light theme enjoyers sometimes asked for the light theme support. Now that we have full control over the theme generation it must be easy to support the light theme, right? Well, kinda.

I made sure to support it at least as well as godot supports its own light theme (or maybe a little better than that).

It works and it’s usable:

It’s a big W for the minimal theme, but there are still some things that could be improved, especially on the engine side.

When you select the Light preset, it sets the contrast to -0.06, which is a very specific value that has a much lower absolute value than the default 0.3 contrast. Tbh I don’t know why it does that because to me it starts being usable when you set the contrast to at least -0.4 (which is what you see in the screenshot above).

For that reason, to make it just work™ out of the box I silently disallow values higher than -0.4 in the light theme:

if not dark_theme and contrast < 0 and contrast > -0.4:
    contrast = -0.4

It’s a targeted fix, but I imagine it’s a good thing when the light theme just works™, especially when “Follow system theme” setting exists.

Also worth noting that some things don’t actually account for the light theme at all, for example fps stats are barely readable on the white background, and they aren’t themable:

So there are some minor issues with the light theme, but nothing a few PRs can’t fix.

Also keep in mind that some icons don’t actually update when you swap the preset to Light so you may have to restart godot after changing the color preset.

What’s next?

With a @tool script in the theme resource technically I could do more than what custom themes normally allow to do. For example, one of the limitations of theming in godot is that there’s no equivalent of CSS selectors, so there’s no way to style elements based on their position in the hierarchy. They need to have unique classes or theme variations. For example recently I had to open a PR to make sidebars themable. With GDScript I could inject all of the theme variations from the theme itself without opening any pull requests.

It’s also possible to change the layout of the UI itself - reposition elements, hide them, etc.

However doing that would make it harder for me to maintain the theme because it would make it dependent on certain editor node hierarchy and it might also potentially clash with other addons. I believe it’s best to keep this logic only to theme generation. For complex UI modifications it’s best to make actual addons, although we will need global addons in godot to make that feasible.

So all things considered it would be nice if godot theming had some equivalent of CSS selectors, I imagine UI-heavy exported apps would benefit from this too.

Download

You can download the theme from its GitHub page.

I tried to account for everything but since this is a full rewrite it’s possible that I missed something. Will be patching things as we go.

Hope you enjoy the theme and I wish you happy holidays!