Open source

Code themes

The four contrast themes from the Zacess reader, for code editors and terminals. Every text and syntax colour keeps at least 7:1 contrast.

We build the themes for VS Code, JetBrains IDEs, Obsidian, Neovim, Zed, Sublime Text, Helix, Emacs and five terminals. They are on the VS Code Marketplace and Open VSX and in the Obsidian community directory. Neovim installs them from zacess.nvim. The JetBrains Marketplace listing and the Zed extension are in review. Until they are live, install those from the releases page. Sublime Text, Helix, Emacs and the terminals install from the releases page or the themes repository.

Try a theme

// a reading profile, saved one file per profile
export interface Profile {
  name: string;
  fontSize: number;
  theme: "dark_on_light" | "yellow_on_black";
}

const AAA = 7;

/** WCAG relative luminance of a #rrggbb colour */
function luminance(hex: string): number {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
  const lin = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
}

export function passes(text: string, background: string): boolean {
  const [hi, lo] = [luminance(text), luminance(background)].sort((x, y) => y - x);
  const ratio = (hi + 0.05) / (lo + 0.05);
  if (ratio < AAA) {
    console.warn(`only ${ratio.toFixed(2)}:1`);
  }
  return ratio >= AAA;
}
Background
#ffffff
Text
#111111
Lowest measured contrast
7.2:1
Target
7:1 (WCAG AAA)

All four themes

The chosen language in every theme, so the four can be compared side by side. The lowest ratio is measured over the selection, the current line and the diff colours, where text is hardest to read.

Zacess Light
// a reading profile, saved one file per profile
export interface Profile {
  name: string;
  fontSize: number;
  theme: "dark_on_light" | "yellow_on_black";
}

const AAA = 7;

/** WCAG relative luminance of a #rrggbb colour */
function luminance(hex: string): number {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
  const lin = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
}

export function passes(text: string, background: string): boolean {
  const [hi, lo] = [luminance(text), luminance(background)].sort((x, y) => y - x);
  const ratio = (hi + 0.05) / (lo + 0.05);
  if (ratio < AAA) {
    console.warn(`only ${ratio.toFixed(2)}:1`);
  }
  return ratio >= AAA;
}

Everyday reading in a bright room. Lowest contrast 7.2:1.

Zacess Dark
// a reading profile, saved one file per profile
export interface Profile {
  name: string;
  fontSize: number;
  theme: "dark_on_light" | "yellow_on_black";
}

const AAA = 7;

/** WCAG relative luminance of a #rrggbb colour */
function luminance(hex: string): number {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
  const lin = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
}

export function passes(text: string, background: string): boolean {
  const [hi, lo] = [luminance(text), luminance(background)].sort((x, y) => y - x);
  const ratio = (hi + 0.05) / (lo + 0.05);
  if (ratio < AAA) {
    console.warn(`only ${ratio.toFixed(2)}:1`);
  }
  return ratio >= AAA;
}

Everyday reading in a dim room. Lowest contrast 7.1:1.

Zacess Yellow on Black
// a reading profile, saved one file per profile
export interface Profile {
  name: string;
  fontSize: number;
  theme: "dark_on_light" | "yellow_on_black";
}

const AAA = 7;

/** WCAG relative luminance of a #rrggbb colour */
function luminance(hex: string): number {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
  const lin = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
}

export function passes(text: string, background: string): boolean {
  const [hi, lo] = [luminance(text), luminance(background)].sort((x, y) => y - x);
  const ratio = (hi + 0.05) / (lo + 0.05);
  if (ratio < AAA) {
    console.warn(`only ${ratio.toFixed(2)}:1`);
  }
  return ratio >= AAA;
}

Low vision. Lowest contrast 8.0:1.

Zacess Cream
// a reading profile, saved one file per profile
export interface Profile {
  name: string;
  fontSize: number;
  theme: "dark_on_light" | "yellow_on_black";
}

const AAA = 7;

/** WCAG relative luminance of a #rrggbb colour */
function luminance(hex: string): number {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
  const lin = (c: number) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
}

export function passes(text: string, background: string): boolean {
  const [hi, lo] = [luminance(text), luminance(background)].sort((x, y) => y - x);
  const ratio = (hi + 0.05) / (lo + 0.05);
  if (ratio < AAA) {
    console.warn(`only ${ratio.toFixed(2)}:1`);
  }
  return ratio >= AAA;
}

Dyslexia friendly reading. Lowest contrast 7.3:1.

Install

Packaged files are attached to each release on the releases page. Every editor's files can also be taken straight from the themes repository.

Something hard to read?

A contrast or readability problem is a bug. Tell us with the readability form on GitHub or email contact@zacess.com. You never need to share a diagnosis.