Facetreference

@facet-ui/theme

facetTheme(), the nineteen tokens, and the exact ramp step each one resolves to.

@facet-ui/themeStable directionimport facetTheme

Facet’s semantic tokens, shaped as a Vela config preset. A Node package — only vela.config.ts imports it, so it is a dev dependency and never reaches the Roblox runtime.

Installed by facet init. Currently 0.4.0, versioned in lockstep with the CLI and @facet-ui/react-variants.

facetTheme(options?)

import { facetTheme } from "@facet-ui/theme";
facetTheme({ base: "zinc", mode: "dark", radius: "new UDim(0, 8)" });

Returns a ThemeExtend — a plain object with colors and radius — for spreading into theme.extend:

vela.config.ts
export default defineConfig({
theme: { extend: { ...facetTheme({ base: "zinc", mode: "dark" }) } },
});

extend rather than colors, because Vela’s theme.colors replaces the family set — which would strip the ramps (zinc-500, red-400, …) you reach for outside Facet components.

OptionTypeDefault
base"zinc" | "slate" | "stone" | "neutral""zinc"Neutral ramp the tokens derive from
mode"light" | "dark""dark"Which side of the ramp they resolve to
radiusstring"new UDim(0, 8)"What rounded-*’s DEFAULT resolves to

radius is a string because it is a Luau expression Vela emits verbatim, not a number it interprets.

Other exports

Export
FACET_TOKENSThe nineteen token names as a const tuple. This is what facet doctor checks a registry item’s declared tokens against.
FacetTokenUnion of those names.
buildTokens(options?)The token → colour-expression map, without the radius wrapper.
buildColors(options?)Same map, typed as Vela’s ColorInputMap.
RAMPS, RampThe four neutral ramps, 50 through 950.
DESTRUCTIVE, WHITEThe red that is not part of any ramp, and white.
FacetBase, FacetMode, FacetThemeOptionsOption types.
ThemeExtend, ThemeScale, ColorExpression, ColorInputMap, ColorPaletteStructural mirrors of the slice of Vela’s config surface this package writes into.

Those Vela-shaped types are kept local rather than imported so that @facet-ui/theme type-checks without resolving vela-rbxts. They are checked against Vela in the CLI’s doctor command instead.

The tokens

background foreground
card card-foreground
popover popover-foreground
primary primary-foreground
secondary secondary-foreground
muted muted-foreground
accent accent-foreground
destructive destructive-foreground
border input ring

Every Facet component names only these. Nothing in the registry says zinc-800, which is what lets base: "slate" retheme a project without touching a single copied-in component.

What each token resolves to

Dark

TokenRamp stepTokenRamp step
background950primary50
foreground50primary-foreground900
card900secondary800
card-foreground50secondary-foreground50
popover900muted800
popover-foreground50muted-foreground400
accent800border700
accent-foreground50input700
destructivergb(220, 38, 38)ring300
destructive-foreground50

border and input sit one step lighter than the dark surfaces they are drawn on. At 800 an outline button was almost indistinguishable from a ghost one — a rendered-in-Studio finding, not a taste call.

Light

TokenValueTokenValue
backgroundwhiteprimary900
foreground950primary-foreground50
cardwhitesecondary100
card-foreground950secondary-foreground900
popoverwhitemuted100
popover-foreground950muted-foreground500
accent100border200
accent-foreground900input200
destructivergb(239, 68, 68)ring950
destructive-foreground50

The ramps

Standard Tailwind neutrals, as Luau Color3.fromRGB(…) expressions:

50500950
zinc250, 250, 250113, 113, 1229, 9, 11
slate248, 250, 252100, 116, 1392, 6, 23
stone250, 250, 249120, 113, 10812, 10, 9
neutral250, 250, 250115, 115, 11510, 10, 10

Each is a full 50/100/200/300/400/500/600/700/800/900/950 scale; only the ends and midpoint are shown here.

One mode per build

Vela resolves classes at compile time, so mode is a build-time choice and a build carries exactly one theme. There is no runtime toggle. What the alternatives would cost is in Theming.