Foundations

Colors

Colour roles, hue scopes, and intents

Colour comes in three layers. Ramps hold twenty steps per hue. A theme maps one hue onto the steps for a scope. Roles read the theme as light-dark() pairs, so a component names what a colour is for and the scheme picks the value.

import { role } from "@nyte-ai/ui/styles/vars.stylex";
import { intent, surfaceTheme } from "@nyte-ai/ui/surface-theme";

Rules

  • Components read a role. They never write a hex, rgb(), oklch(), or light-dark().
  • A new colour need is a new role in roles.stylex.ts with a handle in vars.stylex.ts.
  • Readable text uses contentPrimary or contentSecondary. contentTertiary is for placeholders, disabled hints, and decoration.
  • Glyphs use contentInteractiveTertiary or a stronger role.
  • Meaning picks a hue through an intent; a category picks one through a scope. Both reuse the same role names.
  • Nothing paints a page background in the desktop app; the window's material shows through.

Content

RoleLightDark
role.contentPrimary
--nyte-content-primary
#2c2c2b#e6e5e3
role.contentSecondary
--nyte-content-secondary
#5f5e59#a19e99
role.contentTertiary
--nyte-content-tertiary
#a19e99#5f5e59
role.contentDisabled
--nyte-content-disabled
#d4d3cf#383836
role.contentChrome
--nyte-content-chrome
#5f5e59#ada9a3
role.contentInteractivePrimary
--nyte-content-interactive-primary
#383836#f0efed
role.contentInteractiveSecondary
--nyte-content-interactive-secondary
#5f5e59#bcbab6
role.contentInteractiveTertiary
--nyte-content-interactive-tertiary
#8e8b86#7d7a75
role.contentOnInteractiveStrong
--nyte-content-on-interactive-strong
#ffffff#ffffff
role.contentOnControl
--nyte-content-on-control
#ffffff#ffffff

Border

RoleLightDark
role.borderPrimary
--nyte-border-primary
#e6e5e3#383836
role.borderSecondary
--nyte-border-secondary
#f0efed#262626
role.borderStrong
--nyte-border-strong
#d4d3cf#5f5e59
role.borderControl
--nyte-border-control
#8e8b86#8e8b86
role.borderInteractivePrimary
--nyte-border-interactive-primary
#8e8b86#8e8b86
role.borderPrimaryTranslucent
--nyte-border-primary-translucent
#1b12001c#fffff022
role.borderSecondaryTranslucent
--nyte-border-secondary-translucent
#2b1c0012#ffffff0f
role.borderStrongTranslucent
--nyte-border-strong-translucent
#1b150030#fffceb4e
role.borderControlTranslucent
--nyte-border-control-translucent
#110b0079#fff9ef82

Surface

RoleLightDark
role.bgBase
--nyte-bg-base
#ffffff#1b1b1b
role.bgChrome
--nyte-bg-chrome
#fbfbfa#191919
role.bgMuted
--nyte-bg-muted
#f9f8f7#202020
role.bgElevated
--nyte-bg-elevated
#ffffff#202020
role.bgMutedTranslucent
--nyte-bg-muted-translucent
#40200008#ffffff08
role.bgScrim
--nyte-bg-scrim
#00000026#000000bf
role.bgScrimTranslucent
--nyte-bg-scrim-translucent
#1b150030#fffceb4e
role.bgHover
--nyte-bg-hover
#3b14000d#ffffff0f
role.bgPressed
--nyte-bg-pressed
#3b140018#ffffff1a

Interactive

RoleLightDark
role.bgInteractivePrimary
--nyte-bg-interactive-primary
#e6e5e3#383836
role.bgInteractivePrimaryPressed
--nyte-bg-interactive-primary-pressed
#c2c1bf#434341
role.bgInteractiveSecondary
--nyte-bg-interactive-secondary
#f5f3f2#262626
role.bgInteractiveSecondaryHover
--nyte-bg-interactive-secondary-hover
#e5e3e2#292929
role.bgInteractiveSecondaryPressed
--nyte-bg-interactive-secondary-pressed
#cfcdcc#2e2e2e
role.bgInteractiveStrong
--nyte-bg-interactive-strong
#2c2c2b#5f5e59
role.bgInteractivePrimaryTranslucent
--nyte-bg-interactive-primary-translucent
#1b12001c#fffff022
role.bgInteractiveSecondaryTranslucent
--nyte-bg-interactive-secondary-translucent
#3b14000d#ffffff0f
role.buttonFill
--nyte-button-fill
#6b6864#6b6864
role.buttonFillHover
--nyte-button-fill-hover
#64615c#64615c
role.buttonFillPressed
--nyte-button-fill-pressed
#5a5752#5a5752

Control

RoleLightDark
role.bgControl
--nyte-bg-control
#8e8b86#5f5e59
role.bgControlHover
--nyte-bg-control-hover
#84817d#666560
role.bgControlPressed
--nyte-bg-control-pressed
#777470#6f6e69
role.bgControlSelected
--nyte-bg-control-selected
#2c2c2b#5f5e59
role.bgControlSelectedHover
--nyte-bg-control-selected-hover
#282827#666560
role.bgControlSelectedPressed
--nyte-bg-control-selected-pressed
#232322#6f6e69

Hue scopes

Pass a scope to props() and every role inside reads that hue. custom takes its hue from --nyte-custom-hue.

grayLabelAction
brownLabelAction
orangeLabelAction
yellowLabelAction
greenLabelAction
blueLabelAction
purpleLabelAction
pinkLabelAction
redLabelAction
tealLabelAction
customLabelAction
<span {...props(surfaceTheme.green, styles.badge)}>Added</span>

Intents

IntentHueTextUse
intent.primaryblue#3c5f85Filled actions, links, the current item
intent.successgreen#116d3eStatus text: done, passing
intent.warningyellow#955a14Status text: needs attention
intent.dangerred#a63536Status text, destructive menu items and alert actions

The focus ring ignores scopes. It reads appearance.focusRing, a fixed blue.