npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dispersa

v1.4.0

Published

Core library for processing DTCG design tokens

Readme

Dispersa

A TypeScript build system for processing DTCG 2025.10 design tokens. Dispersa loads resolver documents, resolves references and modifiers, applies filters and transforms, then renders output to CSS, JSON, JS/TS or custom modules.

Features

  • DTCG 2025.10 compliant -- full support for the resolver and token format specifications
  • Multiple outputs -- CSS custom properties, JSON, JS/TS modules
  • Extensible pipeline -- custom preprocessors, filters, transforms, and renderers
  • Schema validation -- AJV runtime validation with schema-generated TypeScript types
  • Linting -- Plugin-based lint rules for design token validation
  • In-memory mode -- use without the filesystem for build tools, APIs, and testing
  • CLI -- config-first workflow with auto-discovery

Token types

Standard DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number

Composite types: shadow, typography, border, strokeStyle, transition, gradient

Linting

Dispersa includes a plugin-based linting system to validate design tokens against semantic rules. Linting can run standalone or as part of the build pipeline.

import { lint } from 'dispersa'
import { dispersaPlugin, recommendedConfig } from 'dispersa/lint'

const result = await lint({
  resolver: './tokens.resolver.json',
  ...recommendedConfig,
})
console.log(`Found ${result.errorCount} errors, ${result.warningCount} warnings`)

Built-in rules include require-description, case-check, no-deprecated-usage, no-duplicate-values, and path-schema. Create custom rules with the createRule() factory or build reusable plugins.

Getting started

New project

pnpm create dispersa

The scaffold prompts for a project directory, lets you pick a template (programmatic or CLI-based), and optionally installs dependencies.

Add to an existing project

pnpm add dispersa

Quick start

Define tokens inline and build CSS -- no files needed:

import type { ResolverDocument } from 'dispersa'
import { build, css } from 'dispersa'
import { colorToHex } from 'dispersa/transforms'

const resolver: ResolverDocument = {
  version: '2025.10',
  sets: {
    base: {
      sources: [
        {
          color: {
            brand: {
              primary: {
                $type: 'color',
                $value: { colorSpace: 'srgb', components: [0, 0.4, 0.8] },
              },
            },
            neutral: {
              white: {
                $type: 'color',
                $value: { colorSpace: 'srgb', components: [1, 1, 1] },
              },
              black: {
                $type: 'color',
                $value: { colorSpace: 'srgb', components: [0, 0, 0] },
              },
            },
          },
          spacing: {
            small: { $type: 'dimension', $value: { value: 8, unit: 'px' } },
            medium: { $type: 'dimension', $value: { value: 16, unit: 'px' } },
          },
        },
      ],
    },
  },
  modifiers: {
    theme: {
      default: 'light',
      contexts: {
        light: [
          {
            semantic: {
              background: { $type: 'color', $value: '{color.neutral.white}' },
              text: { $type: 'color', $value: '{color.neutral.black}' },
            },
          },
        ],
        dark: [
          {
            semantic: {
              background: { $type: 'color', $value: '{color.neutral.black}' },
              text: { $type: 'color', $value: '{color.neutral.white}' },
            },
          },
        ],
      },
    },
  },
  resolutionOrder: [{ $ref: '#/sets/base' }, { $ref: '#/modifiers/theme' }],
}

import { build, css } from 'dispersa'
import { colorToHex } from 'dispersa/transforms'

const result = await build({
  resolver,
  outputs: [
    css({
      name: 'css',
      preset: 'bundle',
      selector: ':root',
      transforms: [colorToHex()],
    }),
  ],
})

for (const output of result.outputs) {
  console.log(output.content)
}

For file-based tokens, define JSON files and reference them with $ref in your resolver document. See the typescript-starter example for a complete setup.

Output formats

Dispersa ships five builder functions. Each returns an OutputConfig that can be passed to build().

css(config)

Renders CSS custom properties.

| Option | Type | Default | Description | | -------------------- | ---------------------------------------- | ---------- | -------------------------------------------- | | name | string | -- | Unique output identifier | | file | string \| function | -- | Output path (supports {modifier} patterns) | | preset | 'bundle' \| 'standalone' \| 'modifier' | 'bundle' | Output preset | | selector | string \| SelectorFunction | ':root' | CSS selector | | mediaQuery | string \| MediaQueryFunction | -- | Media query wrapper | | preserveReferences | boolean | false | Emit var() references for aliases | | minify | boolean | false | Minify output | | transforms | Transform[] | -- | Per-output transforms | | filters | Filter[] | -- | Per-output filters | | hooks | LifecycleHooks | -- | Per-output lifecycle hooks |

json(config)

Renders JSON output.

| Option | Type | Default | Description | | ----------------- | -------------------------- | -------------- | -------------------------------------------- | | name | string | -- | Unique output identifier | | file | string \| function | -- | Output path (supports {modifier} patterns) | | preset | 'bundle' \| 'standalone' | 'standalone' | Output preset | | structure | 'flat' \| 'nested' | -- | Token structure in output | | includeMetadata | boolean | -- | Include DTCG metadata fields | | minify | boolean | -- | Minify output | | transforms | Transform[] | -- | Per-output transforms | | filters | Filter[] | -- | Per-output filters | | hooks | LifecycleHooks | -- | Per-output lifecycle hooks |

js(config)

Renders JavaScript/TypeScript modules.

| Option | Type | Default | Description | | ---------------- | -------------------------- | -------------- | -------------------------------------------- | | name | string | -- | Unique output identifier | | file | string \| function | -- | Output path (supports {modifier} patterns) | | preset | 'bundle' \| 'standalone' | 'standalone' | Output preset | | structure | 'flat' \| 'nested' | -- | Token structure in output | | moduleName | string | -- | Module name for exports | | generateHelper | boolean | -- | Generate token lookup helper (bundle mode) | | minify | boolean | -- | Minify output | | transforms | Transform[] | -- | Per-output transforms | | filters | Filter[] | -- | Per-output filters | | hooks | LifecycleHooks | -- | Per-output lifecycle hooks |

tailwind(config)

Renders Tailwind CSS v4 @theme blocks.

| Option | Type | Default | Description | | --------------- | ------------------------------ | ---------- | -------------------------------------------- | | name | string | -- | Unique output identifier | | file | string \| function | -- | Output path (supports {modifier} patterns) | | preset | 'bundle' \| 'standalone' | 'bundle' | Output preset | | includeImport | boolean | -- | Include @import "tailwindcss" directive | | namespace | string | -- | Prefix for CSS variable names | | selector | string \| SelectorFunction | ':root' | CSS selector | | mediaQuery | string \| MediaQueryFunction | -- | Media query wrapper | | minify | boolean | false | Minify output | | transforms | Transform[] | -- | Per-output transforms | | filters | Filter[] | -- | Per-output filters | | hooks | LifecycleHooks | -- | Per-output lifecycle hooks |

Experimental: native platform outputs

Dispersa also ships ios() and android() builders for Swift/SwiftUI and Kotlin/Jetpack Compose. These are experimental -- APIs and generated code may change.

See the multi-platform example for a complete setup.

Output presets

Presets control how modifier permutations are packaged into files.

standalone -- each permutation produces its own complete file. Use pattern-based filenames to distinguish them:

css({
  name: 'css',
  file: 'tokens-{theme}.css',
  preset: 'standalone',
  selector: ':root',
})
// -> tokens-light.css, tokens-dark.css (each with all tokens)

bundle -- all permutations are bundled into a single file with format-specific grouping (CSS selectors, JSON keys, JS named exports):

css({
  name: 'css',
  file: 'tokens.css',
  preset: 'bundle',
  selector: ':root',
})
// -> tokens.css with :root { ... } and [data-theme="dark"] { ... }

modifier -- CSS-only preset that emits only the tokens that differ per modifier context, not the full set:

css({
  name: 'css',
  file: 'tokens.css',
  preset: 'modifier',
  selector: (modifierName, context, isBase) => {
    if (isBase) return ':root'
    return `[data-${modifierName}="${context}"]`
  },
})

Built-in transforms

Import from dispersa/transforms. All transforms are factory functions that return a Transform object.

Color

| Factory | Output | | ------------------------ | ----------------------- | | colorToHex() | #rrggbb / #rrggbbaa | | colorToRgb() | rgb() / rgba() | | colorToHsl() | hsl() / hsla() | | colorToOklch() | oklch() | | colorToOklab() | oklab() | | colorToLch() | lch() | | colorToLab() | lab() | | colorToHwb() | hwb() | | colorToColorFunction() | CSS color() function |

Dimension

| Factory | Output | | ----------------------- | -------------- | | dimensionToPx() | "16px" | | dimensionToRem() | "1rem" | | dimensionToUnitless() | 16 (numeric) |

Name

| Factory | Output | | -------------------- | --------------------------- | | nameKebabCase() | color-brand-primary | | nameCamelCase() | colorBrandPrimary | | nameSnakeCase() | color_brand_primary | | namePascalCase() | ColorBrandPrimary | | nameConstantCase() | COLOR_BRAND_PRIMARY | | namePrefix(prefix) | ds-color-brand-primary | | nameSuffix(suffix) | color-brand-primary-token |

Other

| Factory | Output | | ---------------------- | ------------------ | | fontWeightToNumber() | 400, 700, etc. | | durationToMs() | "200ms" | | durationToSeconds() | "0.2s" |

Built-in filters

Import from dispersa/filters. All filters are factory functions that return a Filter object.

| Factory | Description | | ----------------- | ----------------------------------------------------------- | | byType(type) | Include tokens matching the given $type | | byPath(pattern) | Include tokens whose path matches a string or RegExp | | isAlias() | Include only alias tokens (tokens referencing other tokens) | | isBase() | Include only base tokens (tokens with direct values) |

import { byType, isAlias } from 'dispersa/filters'

css({
  name: 'colors-only',
  file: 'colors.css',
  preset: 'bundle',
  filters: [byType('color')],
  transforms: [colorToHex()],
})

css({
  name: 'semantic-only',
  file: 'semantic.css',
  preset: 'modifier',
  filters: [isAlias()],
  transforms: [colorToHex()],
})

Extending the pipeline

Custom transforms

A Transform has an optional matcher (to scope which tokens it applies to) and a transform function:

import type { Transform } from 'dispersa'

const addPrefix: Transform = {
  matcher: (token) => token.$type === 'color',
  transform: (token) => ({
    ...token,
    name: `brand-${token.name}`,
  }),
}

Custom filters

A Filter has a single filter function that returns true to keep a token:

import type { Filter } from 'dispersa'

const excludeDeprecated: Filter = {
  filter: (token) => !token.$deprecated,
}

Custom preprocessors

A Preprocessor transforms raw token objects before parsing:

import type { Preprocessor } from 'dispersa'

const stripMetadata: Preprocessor = {
  name: 'strip-metadata',
  preprocess: (rawTokens) => {
    const { _metadata, ...tokens } = rawTokens
    return tokens
  },
}

await dispersa.build({
  preprocessors: [stripMetadata],
  outputs: [
    /* ... */
  ],
})

Custom renderers

Use defineRenderer<T>() to create type-safe custom renderers. The generic parameter gives you autocomplete and type-checking on both context and options inside format():

import { defineRenderer, outputTree } from 'dispersa'
import type { RenderContext } from 'dispersa'

// 1. Define your renderer-specific options
type SwiftUIOptions = {
  structName?: string
  accessLevel?: 'public' | 'internal'
}

// 2. Create the renderer with defineRenderer<T>()
const swiftUIRenderer = defineRenderer<SwiftUIOptions>({
  format(context, options) {
    const structName = options?.structName ?? 'DesignTokens'
    const access = options?.accessLevel ?? 'public'
    const tokens = context.permutations[0]?.tokens ?? {}

    const props = Object.entries(tokens)
      .map(([name, token]) => `    ${access} static let ${name} = ${JSON.stringify(token.$value)}`)
      .join('\n')

    return `import SwiftUI\n\n${access} struct ${structName} {\n${props}\n}\n`
  },
})

// 3. Use it in your build config
await dispersa.build({
  outputs: [
    {
      name: 'swift',
      renderer: swiftUIRenderer,
      file: 'DesignTokens.swift',
      options: { structName: 'AppTokens', accessLevel: 'public' },
      transforms: [nameCamelCase()],
    },
  ],
})

RenderContext

Every renderer receives a RenderContext with these fields:

| Field | Type | Description | | -------------- | ------------------------------ | --------------------------------------------------------------------------------------------- | | permutations | { tokens, modifierInputs }[] | Resolved tokens for each permutation (theme/platform combo) | | output | OutputConfig | The current output configuration (name, file, options, transforms, filters) | | resolver | ResolverDocument | The resolved DTCG resolver document | | meta | RenderMeta | Modifier metadata: dimensions (e.g. ['theme', 'platform']), defaults, basePermutation | | buildPath | string \| undefined | Output directory (undefined in in-memory mode) |

Multi-file output with outputTree

When your renderer needs to produce multiple files, return an OutputTree instead of a string:

import { defineRenderer, outputTree } from 'dispersa'

const multiFileRenderer = defineRenderer({
  format(context) {
    const files: Record<string, string> = {}

    for (const { tokens, modifierInputs } of context.permutations) {
      const content = Object.entries(tokens)
        .map(([name, token]) => `${name}: ${JSON.stringify(token.$value)}`)
        .join('\n')

      const key = Object.values(modifierInputs).join('-') || 'default'
      files[`tokens-${key}.yaml`] = content
    }

    return outputTree(files)
  },
})

Presets: bundle, standalone, modifier

The built-in renderers support three presets that control how permutations are handled:

| Preset | Behavior | Use case | | ------------ | ----------------------------------------------------------------------------- | ------------------------ | | bundle | All permutations in one file (e.g. CSS cascade with :root + [data-theme]) | Single-file delivery | | standalone | One file per permutation (e.g. tokens-light.css, tokens-dark.css) | Platform-specific builds | | modifier | Only the diff between a permutation and the base | Overlay/patch files |

Custom renderers can use context.meta.basePermutation to determine which permutation is the base.

Composing transforms and filters with renderers

Each OutputConfig (returned by builders like css() or constructed manually) bundles transforms, filters, and a renderer together. Global transforms/filters from BuildConfig are applied first, then per-output transforms/filters:

await dispersa.build({
  // Global: applied to ALL outputs
  transforms: [nameKebabCase()],
  filters: [byType('color')],

  outputs: [
    css({
      name: 'css',
      preset: 'bundle',
      // Per-output: applied AFTER global transforms
      transforms: [colorToHex()],
    }),
    {
      name: 'swift',
      renderer: swiftUIRenderer,
      // Per-output: applied AFTER global transforms
      transforms: [nameCamelCase()],
    },
  ],
})

Dynamic selectors and media queries

The CSS builder accepts functions for selector and mediaQuery, giving full control over how rules are generated per modifier context:

css({
  name: 'css',
  file: 'tokens.css',
  preset: 'bundle',
  selector: (modifierName, context, isBase, allInputs) => {
    if (isBase) return ':root'
    return `[data-${modifierName}="${context}"]`
  },
  mediaQuery: (modifierName, context, isBase) => {
    if (modifierName === 'platform' && context === 'mobile') {
      return '(max-width: 768px)'
    }
    return ''
  },
})

The function signature for both is:

;(
  modifierName: string,
  context: string,
  isBase: boolean,
  allModifierInputs: Record<string, string>,
) => string

Token references

Dispersa supports two reference mechanisms:

Aliases ({token.name}) reference another token's value within $value:

{
  "color": {
    "primary": {
      "$type": "color",
      "$value": { "colorSpace": "srgb", "components": [0, 0.4, 0.8] }
    },
    "action": {
      "$type": "color",
      "$value": "{color.primary}"
    }
  }
}

JSON Pointer $ref references files, resolver sets, or property-level values:

{
  "colors": {
    "blue": {
      "$type": "color",
      "$value": { "colorSpace": "srgb", "components": [0.2, 0.4, 0.9] }
    },
    "primary": {
      "$type": "color",
      "$ref": "#/colors/blue/$value"
    }
  }
}

Token-level $ref preserves the token shape and resolves into $value. When $type is missing on an alias or $ref token, it is inferred from the referenced token.

In-memory mode

Dispersa can run entirely without the filesystem. Pass a ResolverDocument object directly and omit buildPath to get output content in memory:

import type { ResolverDocument } from 'dispersa'
import { build, css } from 'dispersa'
import { colorToHex } from 'dispersa/transforms'

const resolver: ResolverDocument = {
  version: '2025.10',
  sets: {
    base: {
      sources: [
        {
          color: {
            primary: {
              $type: 'color',
              $value: { colorSpace: 'srgb', components: [0, 0.4, 0.8] },
            },
          },
        },
      ],
    },
  },
  resolutionOrder: [{ $ref: '#/sets/base' }],
}

const result = await build({
  resolver,
  outputs: [
    css({
      name: 'css',
      preset: 'bundle',
      selector: ':root',
      transforms: [colorToHex()],
    }),
  ],
})

// Access generated content directly
for (const output of result.outputs) {
  console.log(output.content)
}

Error handling

  • build() returns a BuildResult object. It never throws.
  • buildOrThrow() is the fail-fast variant that throws on invalid config, resolver errors, or build failures.
type BuildResult = {
  success: boolean
  outputs: { name: string; path?: string; content: string }[]
  errors?: BuildError[]
}

type BuildError = {
  message: string
  code: ErrorCode
  path?: string // file path (for FILE_OPERATION errors)
  tokenPath?: string // token path (for TOKEN_REFERENCE, CIRCULAR_REFERENCE errors)
  severity: 'error' | 'warning'
  suggestions?: string[] // e.g. similar token names for TOKEN_REFERENCE errors
}

ErrorCode is a union of all failure types:

| Code | Description | | -------------------- | ------------------------------------------- | | TOKEN_REFERENCE | Unresolved alias reference ({token.name}) | | CIRCULAR_REFERENCE | Circular alias chain detected | | VALIDATION | Schema or structural validation failure | | FILE_OPERATION | File read/write failure | | CONFIGURATION | Invalid build or renderer configuration | | BASE_PERMUTATION | Missing base permutation for bundle mode | | MODIFIER | Invalid modifier input or context | | UNKNOWN | Catch-all for unexpected errors |

Lifecycle hooks

Both BuildConfig.hooks (global) and OutputConfig.hooks (per-output) accept the same LifecycleHooks type. Global hooks fire once per build; per-output hooks fire in the context of each output.

await dispersa.build({
  outputs: [
    css({
      name: 'css',
      preset: 'bundle',
      hooks: {
        onBuildStart: ({ config }) => {
          console.log(`[css] starting...`)
        },
        onBuildEnd: (result) => {
          console.log(`[css] ${result.success ? 'done' : 'failed'}`)
        },
      },
    }),
  ],
  hooks: {
    onBuildStart: ({ config }) => {
      console.log(`Building ${config.outputs.length} output(s)...`)
    },
    onBuildEnd: (result) => {
      if (result.success) {
        console.log(`Build succeeded: ${result.outputs.length} file(s)`)
      } else {
        console.error(`Build failed: ${result.errors?.length} error(s)`)
      }
    },
  },
})

Execution order:

| # | Hook | Scope | When it fires | | --- | -------------- | ---------- | ----------------------------------------------- | | 1 | onBuildStart | Global | Before permutation resolution | | 2 | onBuildStart | Per-output | Before each output is processed | | 3 | onBuildEnd | Per-output | After each output finishes (success or failure) | | 4 | onBuildEnd | Global | After all outputs complete (success or failure) |

All hooks support both sync and async functions.

CLI

Dispersa includes a CLI for a config-first workflow.

pnpm add dispersa
dispersa build
dispersa build --config ./dispersa.config.ts

The CLI auto-discovers config files named dispersa.config.(ts|js|mts|mjs|cts|cjs). Use defineConfig for type safety:

// dispersa.config.ts
import { defineConfig } from 'dispersa/config'
import { css, json } from 'dispersa'
import { colorToHex } from 'dispersa/transforms'

export default defineConfig({
  resolver: './tokens.resolver.json',
  buildPath: './dist',
  outputs: [
    css({
      name: 'css',
      file: 'tokens.css',
      preset: 'bundle',
      selector: ':root',
      transforms: [colorToHex()],
    }),
    json({
      name: 'json',
      file: 'tokens-{theme}.json',
      preset: 'standalone',
      structure: 'flat',
    }),
  ],
})

API reference

Core functions

Dispersa provides standalone functions for all operations:

import {
  build,
  buildOrThrow,
  buildPermutation,
  resolveTokens,
  lint,
  resolveAllPermutations,
  generateTypes,
} from 'dispersa'

| Function | Description | | ------------------------------------------- | ----------------------------------------------------- | | build(config) | Build tokens. Returns BuildResult (never throws). | | buildOrThrow(config) | Build tokens. Throws on failure. | | buildPermutation(config, modifierInputs?) | Build a single permutation. | | resolveTokens(resolver, modifierInputs?) | Resolve tokens for one permutation without rendering. | | lint(options) | Run lint rules on resolved tokens. | | resolveAllPermutations(resolver) | Resolve tokens for every permutation. | | generateTypes(tokens, fileName, options?) | Generate a .d.ts file from resolved tokens. |

BuildConfig

When calling build() or buildOrThrow(), pass a BuildConfig object:

| Option | Type | Description | | ------------ | --------------------------------------- | ------------------------------------- | | resolver | string \| ResolverDocument | Resolver (file path or inline object) | | buildPath | string | Output directory | | outputs | OutputConfig[] | Array of output configurations | | validation | { mode?: 'error' \| 'warn' \| 'off' } | Validation behavior | | filters | Filter[] | Global filters | | transforms | Transform[] | Global transforms | | lint | LintBuildConfig | Lint configuration |

Subpath exports

| Export | Description | | ------------------------ | ---------------------------------------------------------------------- | | dispersa | Core functions (build, lint, etc.), builder functions, types | | dispersa/transforms | Built-in transform factories | | dispersa/filters | Built-in filter factories | | dispersa/outputs | Renderer types, builder functions, defineRenderer, and outputTree | | dispersa/preprocessors | Preprocessor type | | dispersa/errors | Error classes (DispersaError, TokenReferenceError, etc.) | | dispersa/config | defineConfig helper for CLI config files | | dispersa/lint | Linting system: LintRunner, built-in rules, createRule, formatters |

Everything outside these entry points is internal and not a stable API contract.

Pipeline overview

Resolver -> Preprocessors -> $ref resolution -> Parse/flatten -> Alias resolution -> Filters -> Transforms -> Renderers
  1. Resolver -- loads sets and applies modifier contexts per the DTCG resolver spec
  2. Preprocessors -- transform raw token objects before parsing
  3. $ref resolution -- resolves JSON Pointer references within token documents
  4. Parse/flatten -- resolves group extensions, validates names, flattens to dot-path keys
  5. Alias resolution -- resolves {token.name} references with cycle detection
  6. Filters -- removes tokens (global filters first, then per-output)
  7. Transforms -- mutates token values and names (global first, then per-output)
  8. Renderers -- formats tokens into the target output (CSS, JSON, JS, or custom)

Examples

See examples/ for complete working projects. Suggested learning path:

| Example | Focus | | ------------------------------------------------------ | --------------------------------------------------------- | | typescript-starter | Programmatic build script with themed CSS | | cli-starter | Config-file workflow using the dispersa CLI | | in-memory | In-memory mode with inline tokens | | custom-plugins | Custom transforms, filters, and renderers | | multi-format | Multi-modifier system with all output formats | | multi-brand | Multi-brand, multi-platform at scale | | multi-platform | CSS, Tailwind, iOS, and Android from one set | | split-by-type | Filtered outputs split by token category | | atlassian-semantic | Semantic tokens with density, motion, and theme modifiers |

License

MIT