Design system
Docs
Foundations

Tokens

The --nyte-* custom properties every primitive is built from, read live from @nyte-ai/ui

Tokens are the only values a primitive is allowed to paint with. They are declared once in packages/ui/src/platform-tokens.stylex.ts as stylex.defineVars groups, and every entry is a literal --nyte-* name so the same token can be read from StyleX, from Tailwind, and from plain CSS.

platform-tokens.stylex.ts    typed StyleX handles     tokens.color["--nyte-color-primary"]
  └─ sync-platform-tokens.mjs
       └─ platform-tokens.css   :root declarations     var(--nyte-color-primary)
            └─ tailwind.css     @theme inline mapping   bg-primary, text-body, rounded-lg

pnpm --dir packages/ui typecheck runs check:tokens and fails if the CSS is stale. The tables on this page are read from the generated CSS at build time, so they cannot disagree with the package.

Rules

  • A primitive must read colors, radii, sizes, and motion through tokens.*. Literal colors in packages/ui/src/components are a defect.
  • Colors are light-dark() pairs. The theme follows color-scheme on an ancestor, not a class. A host that wants dark mode sets color-scheme: dark; it does not restyle tokens.
  • Consumers override tokens on an ancestor, ideally the app root, and only the ones that carry the app's identity. See Theming.
  • --nyte-color-focus-ring is var(--nyte-color-ring) by default and is the one token a host is expected to zero out at runtime. See Focus.

Color

Semantic roles, not a palette. primary is the filled button; muted is the hover wash and the avatar background; border has four strengths; bubble-* and sidebar exist for the conversation surface.

TokenValue
--nyte-color-backgroundlight-dark(#fcfcfc, #181818)
--nyte-color-foregroundlight-dark(#141414, #fcfcfc)
--nyte-color-popoverlight-dark(#fcfcfc, #181818)
--nyte-color-popover-foregroundlight-dark(#141414, #fcfcfc)
--nyte-color-primarylight-dark(#070707, #fafafa)
--nyte-color-primary-hoverlight-dark(#2f2f2f, #d5d5d5)
--nyte-color-primary-foregroundlight-dark(#fcfcfc, #141414)
--nyte-color-mutedlight-dark(#77777717, #7777772c)
--nyte-color-muted-hoverlight-dark(#7777772b, #77777752)
--nyte-color-muted-foregroundlight-dark(#14141499, #fcfcfc99)
--nyte-color-tertiary-foregroundlight-dark(#14141466, #fcfcfc66)
--nyte-color-destructivelight-dark(#c21d2e, #ff5667)
--nyte-color-destructive-mutedlight-dark(#ff263c17, #ff263c2c)
--nyte-color-destructive-hoverlight-dark(#ff263c2b, #ff263c52)
--nyte-color-warninglight-dark(#c27400, #ffaf38)
--nyte-color-border-subtlelight-dark(#1414140d, #fcfcfc0d)
--nyte-color-border-weaklight-dark(#1414141a, #fcfcfc1a)
--nyte-color-borderlight-dark(#14141426, #fcfcfc26)
--nyte-color-border-stronglight-dark(#1414144d, #fcfcfc4d)
--nyte-color-field-backgroundlight-dark(#fcfcfc, #2f2f2f)
--nyte-color-ringlight-dark(#14141466, #fcfcfc66)
--nyte-color-focus-ringvar(--nyte-color-ring)
--nyte-color-scrimlight-dark(#14141480, #141414b2)
--nyte-color-sidebarlight-dark(#f7f7f7, #141414)
--nyte-color-bubble-agentlight-dark(#eeeeee, #262626)
--nyte-color-bubble-userlight-dark(#070707, #5a5a5a)
--nyte-color-bubble-user-foregroundlight-dark(#fcfcfc, #fcfcfc)
--nyte-color-avatar-backgroundlight-dark(#77777717, #7777772c)
--nyte-color-avatar-foregroundlight-dark(#3d3d3d, #b7b7b7)
--nyte-color-avatar-neutral-solidlight-dark(#777777, #777777)
--nyte-color-avatar-orange-backgroundlight-dark(#ff670017, #ff67002c)
--nyte-color-avatar-orange-foregroundlight-dark(#c24e00, #ff8838)
--nyte-color-avatar-orange-solidlight-dark(#ff6700, #ff6700)
--nyte-color-avatar-blue-backgroundlight-dark(#1084fe17, #1084fe2c)
--nyte-color-avatar-blue-foregroundlight-dark(#0c64c1, #459ffe)
--nyte-color-avatar-blue-solidlight-dark(#1084fe, #1084fe)
--nyte-color-avatar-violet-backgroundlight-dark(#9159fe17, #9159fe2c)
--nyte-color-avatar-violet-foregroundlight-dark(#6e44c1, #a97efe)
--nyte-color-avatar-violet-solidlight-dark(#9159fe, #9159fe)
--nyte-color-avatar-green-backgroundlight-dark(#00c97217, #00c9722c)
--nyte-color-avatar-green-foregroundlight-dark(#009957, #38d591)
--nyte-color-avatar-green-solidlight-dark(#00c972, #00c972)

Font

One UI family and a five-step type scale. label and body share a size and line height on purpose: labels sit beside fields, and mixed sizes on one row misalign.

TokenValue
--nyte-font-family-ui-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif
--nyte-font-size-caption11px
--nyte-font-size-detail12px
--nyte-font-size-label13px
--nyte-font-size-body13px
--nyte-font-size-title14px
--nyte-font-weight-regular400
--nyte-font-weight-medium500
--nyte-font-weight-semibold600
TokenValue
--nyte-leading-caption14px
--nyte-leading-detail16px
--nyte-leading-label18px
--nyte-leading-body18px
--nyte-leading-title22px

Radius

control and field are the same today and are separate tokens so they can diverge. avatar is a percentage so it scales with the size steps; pill is the circle.

TokenValue
--nyte-radius-control8px
--nyte-radius-field8px
--nyte-radius-menu10px
--nyte-radius-dialog14px
--nyte-radius-avatar42%
--nyte-radius-pill9999px

Control

The geometry of anything you press or type into. height-md (28px) is the default button and input height; height-sm (24px) is the compact button and the icon button. menu-inset is the left padding that leaves room for a radio or checkbox indicator.

TokenValue
--nyte-control-height-sm24px
--nyte-control-height-md28px
--nyte-control-textarea-min-height64px
--nyte-control-padding-xs6px
--nyte-control-padding-sm8px
--nyte-control-padding-lg12px
--nyte-control-menu-inset28px
--nyte-control-gap-sm4px
--nyte-control-disabled-opacity0.56
--nyte-control-focus-width1px
--nyte-control-focus-offset1px

Border

TokenValue
--nyte-border-control-width1px
--nyte-border-hairline-width.5px

Avatar

TokenValue
--nyte-avatar-size-xs20px
--nyte-avatar-size-sm24px
--nyte-avatar-size-md28px
--nyte-avatar-size-lg36px
--nyte-avatar-font-xs9px
--nyte-avatar-font-sm10px
--nyte-avatar-font-md11px
--nyte-avatar-font-lg14px
--nyte-avatar-ring-width.5px

Space

Only three steps ship; layout spacing belongs to the app.

TokenValue
--nyte-space-14px
--nyte-space-28px
--nyte-space-416px

Motion

fast for state changes on controls, normal for popups. Every primitive collapses its transition to 0s under prefers-reduced-motion: reduce.

TokenValue
--nyte-motion-fast100ms
--nyte-motion-normal160ms
--nyte-motion-ease-outcubic-bezier(.2,.8,.2,1)

Elevation

Shadows are light-dark() too: the dark values are transparent, because on a dark surface a border does the separating.

TokenValue
--nyte-elevation-field0 1px 3px 0 light-dark(#0000001f, #00000000)
--nyte-elevation-menu0 10px 20px -3px light-dark(#0000001a, #00000000), 0 4px 6px -4px light-dark(#0000001a, #00000000), 0 0 0 1px light-dark(#e4e4e40a, #e4e4e400)
--nyte-elevation-dialog0 22px 70px 4px light-dark(#0000008f, #00000000), 0 0 0 .5px light-dark(#0000001a, #00000000)

Overlay

Sizes and stacking for dialogs and menus. --nyte-menu-max-width and -max-height read Base UI's --available-width / --available-height, which the Positioner sets from the viewport.

TokenValue
--nyte-dialog-widthcalc(100% - 32px)
--nyte-dialog-max-width384px
--nyte-dialog-max-heightcalc(100dvh - 32px)
TokenValue
--nyte-menu-min-width160px
--nyte-menu-max-widthvar(--available-width)
--nyte-menu-max-heightvar(--available-height)
TokenValue
--nyte-layer-dialog50
--nyte-layer-menu60

Tailwind mapping

@nyte-ai/ui/tailwind.css maps tokens into Tailwind v4's @theme inline so utilities resolve to the same variables. Import @nyte-ai/ui/styles.css for the tokens plus the mapping, or @nyte-ai/ui/platform-tokens.css for tokens only.

Tailwind tokenReads
--font-sans--nyte-font-family-ui
--color-primary--nyte-color-primary
--color-muted--nyte-color-muted
--color-border--nyte-color-border
--color-ring--nyte-color-ring
--text-body--nyte-font-size-body
--text-body--line-height--nyte-leading-body
--radius-sm, --radius-md--nyte-radius-control
--radius-lg--nyte-radius-menu
--radius-xl--nyte-radius-dialog

The full list is the file itself: packages/ui/src/tailwind.css.

Desktop variables

The desktop app does not consume these tokens directly. It defines its own t.* constants in desktop/src/renderer/src/theme/vars.stylex.ts over a separate runtime palette. See Desktop › Theme variables.