Skip to content

Building with Terrazzo

Terrazzo reads Scalar’s scalar.resolver.json directly, so it builds every mode from one input with no extra scripts.

The config below is tested automatically with @terrazzo/cli and @terrazzo/plugin-css 2.10.0, against Scalar’s sample export (two multi-mode collections, every token and style type).

Give it the resolver, and only the resolver

Section titled “Give it the resolver, and only the resolver”
terrazzo.config.mjs
import css from '@terrazzo/plugin-css';
export default {
tokens: ['./tokens/scalar.resolver.json'], // the resolver alone
outDir: './build',
plugins: [
css({
filename: 'tokens.css',
permutations: [
{ input: { theme: 'Light' }, prepare: (css) => `:root {\n${css}\n}` },
{ input: { theme: 'Dark' }, prepare: (css) => `:root[data-theme="dark"] {\n${css}\n}` },
],
}),
],
};
Terminal window
npx terrazzo build

This writes one tokens.css with a :root block for Light and a [data-theme="dark"] block for Dark. References between tokens, across files, become var() chains.

Don’t list the token files next to the resolver. Terrazzo only reads modes when the resolver is its only input. With other files beside it, it errors with Resolver must be the only input; a glob that happens to match the resolver and the token files does the same.

Each entry in permutations picks one context per modifier in the resolver. A modifier is one multi-mode Figma collection, named after it; its contexts are the mode names, exactly as in Figma. Open scalar.resolver.json and look under modifiers to see yours:

"modifiers": {
"theme": {
"contexts": { "Dark": [ … ], "Light": [ … ] },
"default": "Light"
}
}
  • One multi-mode collection: one permutation per mode, as above.
  • Several: each permutation names a context for every modifier, for example { theme: 'Dark', density: 'Compact' }, with a selector to match.
  • No multi-mode collections: there are no modifiers, so use a single permutation with input: {} and a :root selector.

Terrazzo’s linter warns about token names that aren’t kebab-case. Scalar keeps your Figma names’ casing, and style names are often capitalized (Heading/Large), so expect these warnings. The build still succeeds; to silence them, turn the rule off:

lint: { rules: { 'core/consistent-naming': 'off' } },
  • $root tokens (a token with tokens nested under it) are named after their group (--text-warning), and references to them work. Nothing to set up.
  • Gradients come out as their color stops (var(--color-red-500) 0%, rgb(96% 62% 4%) 100%). The format doesn’t carry the direction, so wrap them in linear-gradient(<angle>, …) where you use them.
  • Typography extras (italic, text case, decoration) live in $extensions, which the CSS plugin doesn’t read. See Known limitations.
  • A number token that points to a size token stops Terrazzo with a type error. This happens when an unscoped number variable aliases a size variable; give the number variable a size scope in Figma.