Benjamin Sago / ogham / cairnrefinery / etc…

That Annoying Shade of Blue

About twelve years ago, I didn’t have a gaming computer, but I did have NetHack. I’d leave my laptop on at home and SSH into it from the labs at school using PuTTY. Never got as far as ascending, though I touched one of the altars once.

NetHack, by the way, looks like this:

You miss the jackal.  The kitten bites the jackal.  The jackal is killed!

            ----------------
            |.........<....|
            |...@..........|
            |$..%..........|
            |...f..........-############
            --.-.-----------          ##   # #
              ####                  ###     *
               ###                  #-------.--
                ##########          #|........|
                  -.-----.----      #|........|
                  |...........`######|........|
                  |..........|#######.........|
                  |...........#      |........|
                  ------------       ----------

Ben the Rhizotomist          St:8 Dx:14 Co:15 In:7 Wi:14 Ch:17  Neutral
Dlvl:1  $:1965 HP:2(12) Pw:5(5) AC:7  Exp:1

You were a character on a screen. Menus and prompts were characters on a screen. The dungeon, monsters, and items on the ground were — you guessed it — characters printed to the screen and displayed using ANSI escape codes. It may look basic, but there was a lot of strategy and emotion in those symbols.

One particular infamous critter was the floating eye: it did no damage itself, but if you attacked one, there’d be a ⅔ chance that you’d get temporarily paralysed, usually for a long enough time that something else could come along and kill you when you have no chance to react.

That’s only half the reason why it’s so deadly. The other reason is that it appeared as a particular shade of dark blue that did a very good job of blending into a black terminal background. Mistake that blue e for a blue o, and you’d be dead.

Framebuffer colours

Technically, this wasn’t NetHack’s fault. It couldn’t just pick its own shade of blue, because console applications only had eight colours to work with. Some of them cheated by making bold text slightly brighter, resulting in these sixteen possible colours:

0001020304050607
0809101112131415

You can see what made floating eyes in particular so annoying. (They used colour #4, of course. Not colour #12.)

It’s possible to change these colours into better-looking ones, but not everyone did, or could. PuTTY stores its configuration in the registry, and my school didn’t save registry settings, so I ended up having to change it every time I wanted to play and not die.

The same thing happens with lots of command-line programs. vim highlights comments as blue by default, so if you’re stuck in a Linux framebuffer and need to edit a file, most of it’s going to be unreadable. ls highlights directories as blue, too, meaning you have to squint in order to read anything. These venerable programs used millions of times every day… are they broken?

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).

if [ "$PS1" ]; then
"/etc/profile" 27L, 575C                                 1,1          Top

The problem is that these colours weren’t picked at all.

If you’ve ever wondered why the console colours are in the order they are, look at the table: the last three bits of the number are the same as the blue, green, and red components of the colour respectively.

I can’t find any documentation on where these colours came from — they seem to have been passed down from terminal to terminal since the dawn of time. But this can’t be a coincidence!

This colour palette is flawed in two ways: yellow, purple, and cyan are always going to appear brighter than red, green, and blue, because they’re just two of those colours added together. Add red and green, and you get a yellow as bright as the red and the green combined, rather than the average of the two you’d get if you mixed them.

#BinaryRGB
Black(0)000#000
Red(1)001#F00
Green(2)010#0F0
Yellow(3)011#FF0
Blue(4)100#00F
Purple(5)101#F0F
Cyan(6)110#0FF
White(7)111#FFF

But it also assumes that the human eye is going to respond to all colours the same way. Look again at the set of framebuffer colours above: the green (#0F0) appears brighter than the red (#F00), which appears brighter than the blue (#00F) — and yet they should all have the brightness of one F plus two 0 components. What gives?

It turns out, the bug is in our eyes.

Cone cells and human colour vision

Each RGB pixel on a computer monitor emits a certain amount of red, a certain amount of green, and a certain amount of blue, depending on which colour it’s showing. Human eyes, on the other hand, are not neatly subdivided into red, green, and blue cone cells. We have L, mostly for greenish yellow, M, mostly for yellowish green, and S, for blues and purples. They overlap to varying degrees, and some colours (wavelengths) of light will make all three cone cells respond:

A chart of how effective our cone cells are across wavelengths

A chart of how effective the S, M, and L cone cells are across wavelengths between 400 and 700 nanometres. The chart is normalised so each line has the same maximum.

The reason green (#0F0) appears brighter than blue (#00F) is because of the way the yellowish-green-receiving M cone spans almost the entire visible spectrum, while the blue-and-purple S cone spans under half of it. A green light is going to activate more cone cells than a blue one, making that green appear brighter.

This means you can’t rely on colours to have the same visible brightness, just because they contain the same hex digits!

(Update! I just read a very interesting blog post that goes into a lot more detail. For more information on this, please read Color: From Hexcodes to Eyeballs.)

(Another update, 2022: there are some other factors that should be taken into account here, which the chart above fails to demonstrate. Not only do we have a lot fewer S cells than the other two types, meaning it’s harder for us to pick up blue light to begin with, but it’s also the case that computer screens have been calibrated to emit light at the peak of each cone type’s sensitivity region, not uniformly distributed across it, meaning the “width” of each region in the chart isn’t as important as I said it was. Thanks to those who corrected me here.)

What should software do?

The question remains: If you’re developing command-line software, should you be using dark blue?

NetHack’s DevTeam didn’t seem to mind the blue so much, because NetHack was a game, not productivity software, and you didn’t have to play it. Modern-day games make use of the mouse wheel, even though a decade ago not every mouse had a wheel; the hardware and software that the game is running on is not part of the game itself.

We can’t change human eyes, either. The user base is seven billion and the upgrade procedure is… non-trivial.

But as the author of a very colourful command-line program, I’m hesitant to ship software that, by default, will be unreadable for a certain group of people. Yes, anybody who knows enough about the command-line to use a ls replacement will also probably know how to make everything use their own colour scheme, but that’s not a universal truth, like how I couldn’t save my colours at school.

And having to squint at exa’s output the first time you use it doesn’t exactly make for a good first impression. Rebutting with “But it’s technically your terminal emulator’s fault!” won’t stop anyone from being annoyed.

I’m going to keep on using blue anyway, because the tides are turning.

A few months ago, Microsoft announced that they’d be changing the default Windows console colours so the colours are actually readable:

0001020304050607
0809101112131415

And Linux distributions ship with something decent — here’s Ubuntu:

0001020304050607
0809101112131415

The lone holdout seems to be PuTTY, which, despite regular updates, keeps using a colour scheme from the ’90s.

The point is, there’s no reason why this bug — and it is a bug! — should have stuck around for so long. If your terminal emulator gets told to make text blue, and instead it makes it unreadable, then you can’t say that’s not a problem with the terminal emulator.

I’m sure that whichever terminal first debuted colour support actually displayed them all correctly. But at some point along the way, something got lost. Maybe computer screens have been getting less bright over time, and the effect slowly grew more pronounced. Or maybe an engineer just threw some colours together one day, without testing how they looked together. Whatever it was that happened, people ended up believing that it was supposed to be too dark to read. The Xterm FAQ even says that “there are no standards for terminal colours” as though that were an excuse to implement an absolutely terrible default.

It’s never too late to fix problems like these. Let’s not cling to the past over something that could easily just have been a mistake.