Color Palettes

A palette tells a screen which inks its panel can print. Four grayscale palettes map onto the bit-depth classes, five limited color palettes dither every framework token down to a fixed ink set, and screen--color-full paints every token at its actual hex on 12-bit and 24-bit displays.

#

Grayscale palettes

Four palettes cover the panels that print no color. Each one maps onto a bit-depth class on the Screen element, so a grayscale screen carries screen--1bit, screen--2bit, or screen--4bit instead of a palette class.

  • bw (2 levels) renders as screen--1bit. Every token resolves to a black and white dither pattern.
  • gray-4 (4 grays) renders as screen--2bit.
  • gray-16 (16 grays) renders as screen--4bit, where the gray tokens land on solids.
  • gray-256 renders as screen--4bit too. It is a delivery format, not a fifth tier.
#

Two ways to deliver 16 levels

gray-16 and gray-256 share a class because they share the glass: 16 panel levels either way. They differ in who reduces the image.

  • gray-16: the platform posterizes and dithers to those 16 levels before it sends the screen.
  • gray-256: the platform sends a smooth 8-bit PNG and the device quantizes it to its own 16 levels.

Its registry name, Smooth Grayscale (device-quantized), describes that delivery. It is not a claim of 256 displayable grays, and it renders at the 4-bit tier, so author against screen--4bit.

#

Color palette classes

Every color panel the framework supports has a palette class on the Screen element. Five classes cover the limited-ink e-paper panels; screen--color-full covers displays that render arbitrary color.

A device can support more than one palette. Inky Impression 7.3 carries six: black and white, 7-color, 6-color, 4-ink B/W/R/Y, 3-ink B/W/R, and 3-ink B/W/Y. The selected mode picks the class.

Class Inks Panels
screen--color-3bwr Black, white, red Waveshare 7.5" B/W/R
screen--color-3bwy Black, white, yellow No native B/W/Y panel yet, but nine profiles offer it as a mode (Inky Impression 7.3 and 13.3, Seeed E1002 and E1004, and others)
screen--color-4bwry Black, white, red, yellow TRMNL OG (B/W/R/Y), Waveshare 7.5" B/W/R/Y
screen--color-6a Black, white, red, green, blue, yellow Inky Impression 7.3 and 13.3, Seeed E1002 and E1004
screen--color-7a Black, white, red, green, blue, yellow, orange Inkplate 6COLOR, Inky Impression 7.3
screen--color-full Whatever the display can show 12-bit and 24-bit displays: Onyx BOOX Nova Air C, Tidbyt
#

Full color

screen--color-full is a first-class mode, not a fallback. The CSS paints every framework color token at its actual hex, with no ink remap and no dithering.

  • color-24bit (16.7 million colors) covers LCD, OLED, browser, and virtual screens. The render ships as lossless sRGB: no remap, no dithering, no posterize.
  • color-12bit (4096 colors) covers Kaleido-class color e-paper. It shares the class, and the platform posterizes the render to those 4096 colors.

Both publish --framework-bit-depth: 12, the lower of the two, so nothing reading the depth over-promises what a Kaleido panel prints. Every color the framework paints is sRGB.

<div class="screen screen--generic_16_9 screen--color-full">
  <div class="view view--full">
    <!-- bg--red-60 is a solid red here, a dither on every limited palette -->
    <div class="layout bg--red-60">
      <span class="title">Delayed</span>
    </div>
  </div>
</div>
Palette Registry name Framework class Published depth
bw Black & White (1-bit) screen--1bit 1
gray-4 4 Grays (2-bit) screen--2bit 2
gray-16 16 Grays (4-bit) screen--4bit 4
gray-256 Smooth Grayscale (device-quantized) screen--4bit 4
color-3bwr Color (3 colors) screen--color-3bwr 4
color-3bwy Color (3 colors) screen--color-3bwy 4
color-4bwry Color (4 colors) screen--color-4bwry 4
color-6a Color (6 colors) screen--color-6a 4
color-7a Color (7 colors) screen--color-7a 4
color-12bit Color (4096 colors) screen--color-full 12
color-24bit Color (16777216 colors) screen--color-full 12

Depth describes the paint rail, not the panel's storage. The limited palettes print solid inks the way the 4-bit rail prints solid tokens, so they publish 4.

The numeric variants stop at 4bit:. Grayscale glass stops at 16 levels, so 1bit:, 2bit:, and 4bit: cover every grayscale palette. Color is a separate axis with its own classes, and no numeric variant matches it; the mode-by-mode story is Rendering Modes .

#

How tokens resolve

A limited palette prints solid inks and nothing in between, so the framework dithers every token in the Colors palette down to the inks that panel carries. Your markup does not change: the same bg-- and text-- utilities resolve differently per palette.

  • Grays dither in black and white. On every limited palette, bg--gray-50 is a 1-bit pattern rather than a solid gray.
  • Hues snap to the closest ink. On screen--color-3bwr every hue prints red, so blue and green stop reading as separate categories. screen--color-7a carries its own orange ink.
  • Shade steps dither the ink. bg--red-20 mixes red with black and bg--red-60 mixes red with white, which is how one ink covers a ladder of shades.
  • Full color skips dithering. screen--color-full paints every token as a solid color.

Device Preview tip: Pick a color device in the Device Preview (top right) to see the palette applied to every demo on this site.

#

Applying a palette

The palette class sits on the screen, next to the device class. Grayscale palettes use the same slot for their bit-depth class. Who puts it there depends on where the screen is rendered.

TRMNL Platform trmnl.com
Custom Stack BYOS, trmnlp, ...

You don't write the palette class. The platform renders your layout against the device's own profile, so one plugin covers 1-bit panels and 7-color panels alike.

You add the palette class to the screen yourself, next to the device class, and the framework repaints every token for that ink set.

<!-- Your layout; the platform supplies the screen and its classes -->
<div class="layout">
  <span class="title">Northbound</span>
  <span class="label label--primary">On time</span>
</div>
<div class="screen screen--inky_impression_7_3 screen--color-7a">
  <div class="view view--full">
    <div class="layout">
      <span class="title">Northbound</span>
      <span class="label label--primary">On time</span>
    </div>
  </div>
</div>
#

Preview modes

Panel inks are darker and flatter than the same hex on a monitor. Two modifiers repaint a limited palette with device-accurate values so a preview on a screen matches the print.

  • screen--preview-colors: swaps the full-bright inks for the muted ones the panel actually prints.
  • screen--preview-white-limited: mutes white to the panel's off-white. Add it alongside screen--preview-colors for panels whose white is not paper white.

The Device Preview's Raw Colors and Preview Colors toggle sets both for you. Rendered output on a device uses neither.

<!-- Device-accurate preview of a 6-color panel -->
<div class="screen screen--color-6a screen--preview-colors screen--preview-white-limited">
  ...
</div>
#

Targeting a palette in SCSS

Custom SCSS scopes rules to a palette with the same mixins the framework uses. The mixin ids drop the color- prefix the class carries: '3bwr', '3bwy', '4bwry', '6a', and '7a'.

  • for-color-palette($id): scopes to one limited palette.
  • for-color-full: scopes to full-color displays.
  • for-preview-color-palette($id): scopes to the device-accurate preview of one limited palette.
  • for-1bit, for-2bit, for-4bit: scope to a grayscale tier.
@use 'framework/mixins' as trmnl;

.legend-swatch {
    width: 12px;
    height: 12px;

    // Three-ink panels print every hue in the same accent, so carry the
    // distinction in shape instead of color.
    @include trmnl.for-color-palette('3bwr') {
        border-radius: 50%;
    }

    @include trmnl.for-color-full {
        border-radius: 0;
    }
}