Gesso
Theming

Chrome & temperature

The neutral room of surfaces, ink, and borders, and the three knobs that tint it warm or cool.

Chrome is the neutral room that every component sits in, and this page shows how to leave it gray, tint it warm or cool, and see what the tint does to each surface. Brand color (--brand-primary, --brand-secondary, and the status colors) sits on top of the room, and paper temperature changes only the room.

What chrome is

The room is a set of roles, each with a utility.

RoleTokensUtilities
Surfaces--sys-bg, --sys-surface, --sys-surface-raised, --sys-surface-sunkenbg-background, bg-surface, bg-surface-raised, bg-surface-sunken
Ink--sys-fg, --sys-fg-muted, --sys-fg-subtletext-fg, text-fg-muted, text-fg-subtle
Lines--sys-border, --sys-border-strongborder-border, border-border-strong
Effect ink--sys-contrastbg-contrast, and the focus ring

Each --sys-* role takes its lightness from a --chrome-* token, which holds the light value at :root and the inverted value under .dark, and adds chroma and hue on top. The neutral ramp (--neutral-*) has no chroma, so with no knobs set the room is gray.

Gray, warm, and cool

A look tints the room by setting three knobs. The chroma knob takes the curve described below for surfaces, ink, and lines. The tag knob is a flat value for the categorical tag colors (--sys-cat-*), and the hue knob is shared.

PaperKnobs a look setsResult
GraynoneThe room is achromatic.
Warm--chrome-chroma: var(--warm-chroma), --chrome-chroma-tag: var(--warm-chroma-tag), --chrome-hue: var(--warm-hue)A warm tint at hue 72.
Cool--chrome-chroma: var(--cool-chroma), --chrome-chroma-tag: var(--cool-chroma-tag), --chrome-hue: var(--cool-hue)A blue-gray tint at hue 230.

Washi, ICS, and Ramson all set the warm knobs, and no prefab is cool. To use cool paper, or warm paper under your own colors, set the knobs on your own [data-theme].

[data-theme="acme"] {
  --chrome-chroma: var(--cool-chroma);
  --chrome-chroma-tag: var(--cool-chroma-tag);
  --chrome-hue: var(--cool-hue);
}

system.css repaints every --sys-* surface from these knobs wherever a [data-theme] is set, so the three lines above are all a look has to say. The sidebar paper picker in these docs is a docs-only axis, and app/global.css maps its data-chrome attribute to the same knobs. An installed kit responds to [data-theme] and ships no values for data-chrome.

The curve

Warm and cool share one curve and differ in hue and peak. In the formula, l is the lightness of the underlying --chrome-* role, taken from the neutral ramp.

chroma(l) = base + peak × (1 − l) × l
--sys-role = oklch(from var(--chrome-role) l chroma(l) hue)
HueBasePeakTag chroma
Warm720.00420.050.012
Cool2300.00420.0480.012

The curve falls to the 0.0042 base at the lightest and darkest steps and reaches about 0.017 at mid lightness, so mid-lightness roles such as borders and muted ink carry more tint than the near-white surfaces do. The tag chroma (--warm-chroma-tag and --cool-chroma-tag) is one flat value, because a categorical chip wants the same warmth at every lightness. The curves and tag values live in registry/dry/tokens/system.css.

Dark paper

.dark swaps the lightness on each --chrome-* role, and the same knobs tint the result, so a warm look is warm in both modes. Put .dark on the same element as data-theme.

What is guaranteed

These hold on gray, warm, and cool paper in light and dark. Paper changes chroma and hue and never lightness, so a paper never moves them.

  • text-fg and text-fg-muted pass AA text contrast on bg-background, bg-surface, bg-surface-raised, and bg-surface-sunken.
  • The unfilled edge of a control (--sys-track, used by the switch rail and the checkbox and radio border) is a light edge by choice, under the WCAG 1.4.11 line, so the control's shape and label carry its state.
  • The focus ring is --sys-contrast, a solid ink opposite the surfaces, so it flips with light and dark and does not depend on the brand.

text-fg-subtle is the faintest ink, and it does not reliably pass AA, more so in dark. Use it for text a reader does not depend on.

Try it

The cards below pin the room to cool, base, and warm paper, in light and dark. They keep the brand that the sidebar has selected, so only the room changes between cards. The ramp strips set the paper curve against a reference palette on the same lightness ramp.

Warm ramp (50 → 950)

Figma Vellum reference vs warm chrome on the dry achromatic L ramp.

Figma Vellum (reference)
Warm — C 0.0042 + 0.05(1−l)l, H 72
Cool ramp (50 → 950)

Slate blue-gray reference vs cool chrome on the same L ramp.

Slate (reference)
Cool — C 0.0042 + 0.048(1−l)l, H 230
Cooltag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Basetag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Warmtag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Cool · darktag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Base · darktag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Warm · darktag C — · H —

—

Body ink on canvas. Muted sits lower. Subtle is the faintest.

Surface
Raised + strong line
Sunken well
Field

—

Next

Set the brand on top of the room on Retune, or start from a whole look on Prefabs. Specimens for each surface and ink are on Color.

On this page