Helium: A Wedding Between Selenized and OKSolar Color Schemes
by Raymond K. Zhao
Solarized Dark is a famous dark color scheme for code editors and terminals. However, personally I was never a big fan of it, mainly due to the following issues:
-
Its contrast is too low.
-
Accent colors such as green and yellow are not very distinguishable.
From Wikipedia, there were two efforts, namely Selenized and OKSolar, trying to solve the issues above. However, by design, OKSolar did not try to solve the second issue and the contrast between emphasis and normal colors is kept low. On the other hand, Selenized has more distinguishable colors but it is too bright.
So here comes to the question:
Could we combine the approach of OKSolar, which has more uniform color brightness, and the color palette of Selenized, into a single color scheme?
I did some experiments during the past weekend and created a color scheme called Helium [1], which is also used by this website at the time of writing. You can see from the result that green and yellow are distinguishable, different foreground / background colors have a bit of contrast, and the colors are not too bright.
Color Spaces
Here are some backgrounds on the color spaces used by Selenized and OKSolar. Instead of RGB, colors in both color schemes are defined in the tuple , where is the lightness, is the green-red channel, and is the blue-yellow channel. The Cartesian coordinate can be converted to the polar coordinate , where is the chroma, and is the hue.
Color Palette of Selenized
Now, let us examine the colors in Selenized. Fortunately, the author provided the script of generating the color palette. From the script, every color in the palette can be derived from the background color bg_0 and the foreground color fg_0.
Here I only focus on the Selenized Dark. The following snippets are the simplified version of the script for the specific bg_0 and fg_0 used in Selenized Dark.
### MONOTONES
monotones = {
"bg_0": [bg_l, bg_a, bg_b],
"fg_0": [fg_l, fg_a, fg_b],
}
# define additional monotones using contrast
# (0 - lightness like in bg, 1 - like in fg)
# For some reason bright background looks washed out without increased saturation
monotone_spec = {
"bg_1": [1/10, 1.2],
"bg_2": [1/4, 1.2],
"dim_0": [5/8, 1],
"fg_1": [1+1/5, 1],
}
# use weighted average.
def expand_monotone(spec):
relative_lightness, extra_saturation = spec
l = bg_l + relative_lightness * (fg_l - bg_l)
fg_weight = min(relative_lightness, 1)
bg_weight = max(1 - relative_lightness, 0)
a = (fg_weight*fg_a + bg_weight*bg_a) * extra_saturation
b = (fg_weight*fg_b + bg_weight*bg_b) * extra_saturation
return [l, a, b]
for name in monotone_spec:
monotones[name] = expand_monotone(monotone_spec[name]) bg_l and fg_l are the of bg_0 and fg_0, respectively. Let be the contrast between fg_0 and bg_0. of other monotone colors are derived as for some constant .
The of these colors are also adjusted using weighted average between fg_0 and bg_0 with weight . In Selenized Dark, because and , fg_0 has lower chroma than bg_0. Thus, this weighted average will certainly lower the chroma. The script acknowledged the issue and multiplies the weighted average by 1.2.
### ACCENTS
# accent colors lightness shouldn't be exactly uniform, but on the other
# hand they shouldn't be too far away from each other.
accent_l_spread = (fg_l - bg_l)/3
accents = {
"red": [fg_l - 0.84*accent_l_spread, 63, 40],
"orange": [fg_l - 0.48*accent_l_spread, 37, 50],
"yellow": [fg_l - 0.00*accent_l_spread, 6, 68],
"green": [fg_l - 0.36*accent_l_spread, -38, 55],
"cyan": [fg_l - 0.12*accent_l_spread, -40, -4],
"blue": [fg_l - 0.84*accent_l_spread, 0, -57],
"violet": [fg_l - 0.66*accent_l_spread, 30, -45],
"magenta": [fg_l - 0.50*accent_l_spread, 55, -15],
}
# bright accents have the same a* b* coords as regular accents and
# uniformly shifted lightness
br_accent_shift = (fg_l - bg_l)/10
br_accents = {
'br_'+name: [l + br_accent_shift, a, b]
for name, [l, a, b]
in accents.items()
} Here, of each accent color is derived as for some constant . Note that the accent colors have non-uniform lightness by design. in the bright variant of each accent color is increased by .
Creating Helium
In this section, all colors are represented as in the OKLab color space, using the OKLCH Color Picker & Converter.
First, let us compare the and between foreground (i.e., fg_0) and background (i.e., bg_0) in Solarized Dark / Selenized Dark / OKSolar Dark.
| Solarized Dark | |||
|---|---|---|---|
Foreground | 0.6536 | 0.0195 | 203.55 |
Background | 0.2649 | 0.0523 | 218.89 |
0.3887 |
| Selenized Dark | |||
|---|---|---|---|
Foreground | 0.7831 | 0.0157 | 199.15 |
Background | 0.3339 | 0.0512 | 219.52 |
0.4492 |
| OKSolar Dark | |||
|---|---|---|---|
Foreground | 0.718 | 0.017 | 198 |
Background | 0.274 | 0.05 | 219.6 |
0.444 |
You can see Selenized Dark > OKSolar Dark > Solarized Dark in terms of both and . Compared to the Solarized Dark, OKSolar Dark uses a similar in background and increases in foreground to improve the contrast. On the other hand, in Selenized Dark, although is similar to OKSolar Dark, in both background and foreground are increased.
I decided to use the foreground and background of OKSolar Dark for Helium, because it has higher contrast than Solarized Dark, while not being too bright as Selenized Dark.
To adopt the color palette of Selenized, I followed the snippets above, but using in the OKLab color space instead. There are some notable changes:
-
Similar to OKSolar, I used the same in {
bg_0,bg_1,bg_2} and {fg_0,dim_0,fg_1}, respectively, i.e., only changing in each set. This would also solve the problem of reduced chroma in the original script. -
Similar to OKSolar, I used the uniform lightness i.e., same for all accent colors. To minimize the average difference of with the original colors in Selenized Dark, I used a fixed for all accent colors in Helium, which is the median value of all used in the original colors.
Here is the color palette of Helium. Enjoy!
| Helium | RGB | |||
|---|---|---|---|---|
| 0.2740 | 0.0500 | 219.60 | #002d38 |
| 0.7180 | 0.0170 | 198.00 | #98a7a8 |
| 0.3184 | 0.0500 | 219.60 | #0d3844 |
| 0.3850 | 0.0500 | 219.60 | #214a56 |
| 0.5515 | 0.0170 | 198.00 | #677575 |
| 0.8068 | 0.0170 | 198.00 | #b4c3c4 |
| 0.6455 | 0.2008 | 26.30 | #ef4c47 |
| 0.6455 | 0.1472 | 49.30 | #d36e2f |
| 0.6455 | 0.1476 | 90.77 | #b08800 |
| 0.6455 | 0.1738 | 133.21 | #60a319 |
| 0.6455 | 0.1159 | 184.88 | #00a497 |
| 0.6455 | 0.1649 | 255.25 | #3f8eef |
| 0.6455 | 0.1449 | 300.58 | #9d77d8 |
| 0.6455 | 0.1736 | 346.16 | #d55aa4 |
| 0.6899 | 0.2008 | 26.30 | #ff5b54 |
| 0.6899 | 0.1472 | 49.30 | #e27c3e |
| 0.6899 | 0.1476 | 90.77 | #be9600 |
| 0.6899 | 0.1738 | 133.21 | #6eb12e |
| 0.6899 | 0.1159 | 184.88 | #20b2a4 |
| 0.6899 | 0.1649 | 255.25 | #4d9cff |
| 0.6899 | 0.1449 | 300.58 | #aa84e7 |
| 0.6899 | 0.1736 | 346.16 | #e468b1 |
2025-10-09: Because both the Solarized Dark and Light palattes are used in the same Geany theme, I created the light variant of Helium by keeping the same accent colors.
Note: The Helium Light has even lower contrast than the original Solarized.
| Helium Light | RGB | |||
|---|---|---|---|---|
| 0.9730 | 0.0310 | 90.00 | #fef6df |
| 0.5816 | 0.0170 | 219.60 | #707d82 |
| 0.9339 | 0.0310 | 90.00 | #f1e9d2 |
| 0.8751 | 0.0310 | 90.00 | #ded5bf |
| 0.7284 | 0.0170 | 219.60 | #9caaaf |
| 0.5033 | 0.0170 | 219.60 | #5a676b |
| 0.6064 | 0.2008 | 26.30 | #e13e3b |
| 0.6064 | 0.1472 | 49.30 | #c66220 |
| 0.6064 | 0.1476 | 90.77 | #a27d00 |
| 0.6064 | 0.1738 | 133.21 | #559600 |
| 0.6064 | 0.1159 | 184.88 | #00988b |
| 0.6064 | 0.1649 | 255.25 | #3282e2 |
| 0.6064 | 0.1449 | 300.58 | #916bcb |
| 0.6064 | 0.1736 | 346.16 | #c74e97 |