Lunaria is a family of soothing, moderate-contrast color palettes for terminals, text editors, and technical documentation. Lunaria's colors were generated algorithmically, employing the cutting edge of color science: the CAM16 color appearance model and its associated uniform color space and chromatic adaptation transform. Lunaria includes three distinct palettes:

Every palette contains 55 colors, with role-descriptive names like deëmphasized foreground, soft red, terminal low green, and background blue. Each palette uses the same names, even though the colors denoted by those names differ. This makes life easy for designers: Once you've created a web page or editor theme using one Lunaria palette, the other palettes are a string substitution away.

Palette structure

A Lunaria palette consists of seven neutral colors, seven groups of six foreground chromatics (all based on the same six hues), and six background chromatics.


NeutralsThe neutral colors each have several aliases. First, they can be named according to their shade — from darkest to lightest: deep black, black, dark gray, medium gray, light gray, white, bright white. Foreground/background combinations for ordinary text are either dark gray on white or light gray on black. Alternatively, the neutrals can be named by their role in either a regular or inverse color scheme. A regular scheme is dark-on-light for the Light palette and light-on-dark for the Dark and Eclipse palettes. In an inverse scheme, these combinations are reversed. The intent is for designers to use a regular scheme for all the main parts of the screen, and an inverse scheme to accent small areas. The following table shows the roles of the neutral colors in each of the two schemes.

Regular schemeColorInverse scheme
Emphasized background
BackgroundEmphasized foreground
Deëmphasized backgroundForeground
Deëmphasized foregroundDeëmphasized foreground
ForegroundDeëmphasized background
Emphasized foregroundBackground
Emphasized background

The terms emphasized and deëmphasized should respectively be understood as “increased contrast” and “decreased contrast”. In the case of background colors, they are somewhat misleading, since any modulation in either direction tends to provide emphasis.

Large headings and other display text should always be set in the emphasized foreground color, as the regular foreground color will look washed-out. Small, boldface text, however, works about as well in either color. I prefer to use the regular color for table headings and the emphasized color for bold body text (e.g. to style the HTML <strong> element). In any case, use of the emphasized foreground color should always be complemented by some other form of emphasis such as large or bold text: it's too subtle to stand on its own.

You can use alpha-channel transparency to achieve intermediate steps between background colors. The background of the above table is deëmphasized with 50% opacity, resulting in a composite color at the midpoint between regular and deëmphasized.

Foreground chromatics

Foreground chromaticsThere are seven groups of foreground chromatics. Each group contains six colors: a red, a yellow, a green, a blue, a violet, and a magenta. Hues are spaced at regular 1/7 intervals on the CAM16 color wheel, skipping a step at cyan on account of the human eye's poor sensitivity to hue contrast in that region of the spectrum. All groups use the same six hues, while differing in lightness and chromaticity.

We begin by introducing the soft colors:

When using Lunaria for syntax highlighting, the soft colors are your workhorses. Use them for marking basic syntax elements such as string literals when you want to make their lexical status apparent with drawing the eye toward them. All the soft colors have the same lightness as medium gray, so they are equally legible against regular and inverse backgrounds. This equal, medium lightness along with their rather low saturation makes them fungible and devoid of any individual psychological associations. They can be permuted freely with little consequence.

When you need a little more punch, use the vivid or (against an inverse background) inverse vivid colors:

The vivid colors have more individuality than the soft colors. Their higher saturation attaches more cultural baggage to their respective hues. For example, vivid red and vivid yellow are the clear choices for error and warning squiggles. Vivid magenta and vivid blue are appropriate for visited and unvisited hyperlinks. The vivid colors have unequal lightness: in both the regular and inverse schemes, the cooler colors are darker than the warmer ones. All of them have more contrast with the background than the soft colors do.

The high contrast and inverse high contrast colors are for accommodating visually-impaired readers. They are fully as dark or light as their respective neutral foreground. More about these later, in the Accessible Design section.

The final two foreground groups are the low and high terminal colors, intended for theming 16-color ANSI terminals. High and low red, yellow, green, and magenta, and the neutrals black, dark gray, light gray, and white, all map to their eponymous ANSI colors. Lunaria's blues map to ANSI's cyans, and Lunaria's violets map to ANSI's blues.

I'll be honest: These colors are not my favorite part of the palette. Compared to the other foreground groups, they look ugly and chaotic. They must, though, because they're the solution to an ugly and chaotic problem: maintaining readability when the programmers of terminal applications select color combinations that are dubious to begin with and then assume that they will render on everyone else's terminal the same way they render on their own. What makes this particularly difficult is that ANSI colors aren't always foreground colors. Lunaria's other foreground groups — even if you occasionally opt for a “reverse video” effect by using the regular background color as a foreground atop a vivid-colored background — are always contrasted with a small, known set of neutral colors, no matter which may be on top. Nobody in their right mind would put Lunaria vivid green on a vivid blue background; even Medieval armorers knew better than this. But with the ANSI colors, such combinations are all too common, and so we must accommodate them.

The lightnesses of the Lunaria terminal colors are determined such that their log-luminances (after accounting for flare) are a linear transformation of the log-luminances of the “classic” ANSI terminal colors (which range from #000000 for black to #ffffff for white), into the new range of Lunaria black to Lunaria white. Since Lunaria's range is narrower, all contrast ratios become slightly compressed but they remain essentially intact. For the Light palette, the target range is actually a little darker: from Lunaria deep black to 2/3 of Lunaria white. This makes high yellow readable against a white background.

Background chromatics

Background chromaticsThe background chromatics are useful for marking regions of text, such as clipboard selections, search matches, and insertions and deletions. The six colors are based on the four cardinal hues of the opponent process model, providing yellow/blue and red/green dichotomies that are in some sense psychologically “pure”.

Opaque (100%)Dodrantopaque (75%)Semiopaque (50%)Quadrantopaque (25%)Octantopaque (12.5%)

The colors are named background red, background green, background yellow, background blue, background light yellow, and background dark blue. In the Light palette, background light yellow has the alias “background highlight” and background dark blue has the alias “background lowlight”; in the Dark and Eclipse palettes, these aliases are swapped.

The fully-opaque background chromatics are almost always too saturated; the middle three opacities should be used most often. Selected text on this page is quadrantopaque lowlight. Dodrantopaque highlight is a good color for search matches — something which regretably can't be demonstrated here because CSS doesn't support it, but it would look like this.

Accessible Design

Although Lunaria is foremost meant to be enjoyed by readers with normal vision, with a little extra care it can accommodate certain visual impairments as well. In particular, we'll discuss colorblindness and impaired contrast sensitivity.

Lunaria should be fully usable by anomalous trichromats (those with protoanomaly, deuteranomaly, or tritanomaly) without any special consideration on the part of the designer. Any two Lunaria colors easily distinguishable by those with normal vision should remain easily distinguishble with anomalous cones.

Dichromats (those with protanopia, deuteranopia, or tritanopia) will struggle to distinguish some of Lunaria's forgeground colors from each other, and protanopes may struggle to distinguish magenta from gray. Dichromats looking to customize their editor's syntax highlighting should probably look elsewhere. Designers using Lunaria for media that will be consumed by general audiences with an unknown range of disabilities should follow the general best practice of never relying solely on color for conveying important information. Underline your hyperlinks. Yes, it makes them ugly. Do it anyway.

Lunaria's foreground color groups vary in their degree of contrast with the regular background color, and therefore in their suitability for readers with impaired contrast sensitivity. The following table summarizes which parts of the Light palette adhere to various standards that define contrast requirements.

Soft colorsYesIf large or boldNo
Vivid colorsYesYesIf large or bold
High contrast colorsYesYesYes
Terminal colorsNoNoNo

ISO 9241 sets contrast standards for users with normal vision. WCAG AA is for users with the mild contrast impairment that usually accompanies 20/40 vision, and WCAG AAA is for users with the moderate contrast impairment that usually accompanies 20/80 vision. There is no standard for severe impairment, since such users typically rely on screen readers. WCAG defines “large” text as 14 points or larger and leaves “bold” deliberately undefined.

Both ISO 9241 and WCAG pessimistically assume 5% flare for computing contrast ratios; this is higher than what any of the Lunaria palettes are optimized for. Under better viewing conditions, the Dark and Eclipse palettes meet the same contrast thresholds as is asserted for the Light palette in the table above, but at 5% flare they do not, so these palettes can be considered to comply with the spirit but not the letter of the ISO and WCAG recommendations. Note that sites can claim WCAG compliance as long as some “conforming alternate version” satisfies all its requirements, so even a strict reading of WCAG does not forbid you from making the Dark and Eclipse palettes available as long as the Light palette is available as well and you restrict yourself to the compliant color groups.

Although Lunaria's terminal colors do not consistently meet any standard for contrast, users with impaired contrast sensitivity should investigate Hyper, a terminal emulator which includes a contrast-enhancement feature. When Hyper encounters a foreground/background combination that does not satsify a user-specified minimum contrast ratio, it will adjust the lightness of the foreground color while preserving its hue.