HelixOverviewComponentsMapsGraphIntroductionInstallationDeriving a themeSandboxTheme builderVisual testingCortexDocsEngramBuildingTraceBuildingRecallDeclaredServicesInsightsGet in touchSource on GitHub
Theming
Intent referenceDeriving a theme explains how the engine works. This page lists
every field ThemeIntent accepts and what changes when you set it.import{initTheme}from'@fusion.dev/helix-theme'constengine=awaitinitTheme('/theme.wasm')consttheme=engine.derive({brand:'#2563eb'})Deriving a theme shows how Node loads the engine.Every input is optional. With no brand, the theme is ink: the primary
color is near-black in light mode and near-white in dark mode. Every other field
has a default, computed from brand or from the Helix design language, so an
empty intent, {}, is a valid theme.ColorFieldWhat it controlsbrandYour main brand color, or { light, dark } for a different one in each mode. Without one, the theme is ink, and so is a mode the pair leaves outaccentThe second emphasis color. Defaults to the brand color, or to ink with no brand. { from: 'brand', rotate: 180 } gives the complementary color, and needs a brandbackgroundThe page's color, { light, dark }, for a page that is not pure white or pure black. The surfaces keep their contrast with it, and the grays take its tint. A page no text color can reach the contrast target on is refusedneutralThe gray ramp, which can be tinted toward the brand. With background, it takes the page's tintstatusinfo, success, warning, and danger. A color pins one. { hue } moves its hue within the band that keeps its meaningchromaHow saturated the palette is, independent of huescheme'light' or 'dark', for a theme that has only one modetokensLiteral overrides by token name, for values no other field setsA brand color that already meets the contrast target is used as it is.
Where it clears every surface it lands on, it is the primary color, and where
its label clears on it, it is the fill. A navy brand stays navy on a light page.
A color that does not meet the target keeps its hue and chroma, and its
lightness moves only as far as the target needs.accent can be defined relative to the brand. status colors cannot. If
danger rotated with the brand, your users would have to learn a new warning
color for each product.A status hue stays in its band. Each band, in OKLCH degrees, covers the
colors that still read as that status. A hue outside its band is refused, and
the error names the band.StatusHue bandColorsdanger15 to 40The reds, from crimson to red-orangewarning45 to 105Orange and amber to yellowsuccess125 to 180The greens, from yellow-green to teal-greeninfo200 to 280Cyan and blue to indigochroma sets how saturated the theme feels. Monotone, muted, restrained, and
vivid all describe chroma, and none of them describes a hue. chroma has two
settings:ceiling caps chroma. 0 is monotone, and about 0.10 is muted.scale multiplies the chroma the brand color supplies.Both apply to every derived color, including the brand color, because in a
monotone theme the brand is gray too. A gray brand is solved like any other, to
the gray nearest the page that meets the contrast target, which is a mid gray.
For black and white, leave out brand. Neither applies to a color you pinned. A
pinned color is used exactly as you set it.tokens sets each value after the engine has solved the rest, so no other color
is solved against it. Each pair that names the token measures it, and a value
that misses its target is reported in violations. A name the engine does not
emit is added as a token of your own. No default pair names it, so only a pair
you list in pairings measures it. A value the engine cannot read is skipped: a
token the engine emits keeps its derived value, and a name it does not emit is
left out.ContrastFieldWhat it controlscontrastTargetTarget contrast for body text. 4.5 is WCAG AA, and 7 is AAApairingsThe foreground and background pairs to measure, by token name. A background of color-well over color-surface is a field's well over that surface, and color-hover over color-surface is a lit row over it. The list replaces the pairs from the engine's surface model. The engine measures each pair and solves none of them, and a pair that names a token the engine does not emit is reported as unverifiableThe default is 4.5, the WCAG 2.1 AA figure. The European Accessibility Act
refers to WCAG 2.1 AA, so 4.5 is the figure with legal weight.Shape and spaceFieldWhat it controlsradiusCorner rounding across the systemdensityScales spacing and control heights. 1 is the default, and 0.875 is compactseparationWhether a surface is set apart by an edge or by a liftseparation chooses between the two policies described in Surfaces and
separation.Type and motionFieldWhat it controlsfontThe font families and the type scalemotioncharacter and scalemotion.character sets the easing curve that every component uses, along with
a duration multiplier. The curve and the duration are set together because they
depend on each other. A spring over 120ms looks like a twitch, and a soft curve
over 120ms looks like a fade. scale multiplies the durations again, so you can
keep a character and change its speed.The instant character is 0, which means "do not animate". scale does not
change it. It outputs none of the three easing curves, because a transition of
zero length has no curve to follow.precise is the only character that does not imitate physical motion. The
other three accelerate, settle, or overshoot. precise is linear, so movement
looks driven by a mechanism. It is also the only curve that is easy to see over
a short distance. Constant speed shows in the timing, and an overshoot needs
distance to show.MaterialFieldWhat it controlsmaterialblur in pixels and opacity from 0 to 1material is the one field that can break the contrast guarantee. The
engine measures contrast against a known ground. A translucent surface has no
known ground, so a pair over it is reported as unverifiable. The report shows
you the trade-off that a theme with heavy material makes.OutputFieldWhat it controlsnamespaceThe token prefix. Defaults to helix. acme emits --acme-color-primaryUse namespace when your product ships its own token layer built on the
engine. The rest of the library still reads --helix-*, so a new namespace
changes only your own tokens.A namespace is ASCII letters, digits, hyphens, and underscores, with no
hyphen at either end. The engine writes the hyphens around it. Any other
namespace is refused with the value it received, such as an empty one, --acme,
or acme tokens.