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

@sandlada/material-theme-cli

v1.0.0-20260525.a

Published

Material Design CLI for generating theme tokens and serialized color outputs from a source color.

Readme

@sandlada/material-theme-cli

npm version GitHub License

A CLI based on the Material Design dynamic color system. Given a source color, it generates theme data and palette tokens that can be used directly in front-end projects, design tokens, script integrations, and bulk exports.

Runtime requirements: Node.js 22+ and ESM.

For the Simplified Chinese version, see README.zh-CN.md.

Installation

Global install

npm i -g @sandlada/material-theme-cli

Run locally in the repository

npm install
npm start -- "#0f774a"

npm start runs the build first and then launches the CLI entry point. For local development and verification, this is the most direct workflow.

Quick Start

  1. Pass a color directly to the CLI. By default, it prints CSS theme and palette tokens to the terminal:
material-theme-cli "#0f774a"

If you want a random theme, you can also use random-color:

material-theme-cli random-color
  1. If you want to write the output to a file, switch to file output and specify a path:
material-theme-cli "#0f774a" --format css --output file --path ./theme.css
  1. If the color is already stored in a text file, use --input to read it:
# color.txt
#0f774a
material-theme-cli --input ./color.txt --format json --output file --path ./theme.json

Usage Guide

The recommended flow is simple: choose the input color, then the output format, then decide whether you want a preview or a file.

  1. Choose the input method.

You can pass [color] directly, or use --input <file-path> to read from a file. If both are provided, --input takes precedence.

  1. Choose the output method.

The default is terminal output. To generate a file, use --output file and set the destination with --path. If --path is omitted, the CLI writes to ./output.<format> in the current working directory.

  1. Choose the format and theme parameters.

If you just want a quick preview, keep the defaults. If you are integrating with a design system or multi-platform theme, adjust --variant, --contrast-level, --spec-version, and --platform, override palettes with --primary, --secondary, and similar options, or control palette output with --no-palette, --palette-tones, and token selectors such as palette-primary-50.

  1. Use a whitelist or blacklist when you need to filter tokens.

--token is a whitelist, and --exclude is a blacklist. The CLI normalizes names to kebab-case before matching, and the two options are mutually exclusive.

Command Usage

material-theme-cli [color] \
  [--input <file-path>] \
  [--format <css|json|xml|yaml|js|ts|csv>] \
  [--output <console|file>] \
  [--path <output-file-path>] \
  [--make-js <output-js-file-path>] \
  [--no-palette] \
  [--palette-only] \
  [--palette-tones <tone-list>] \
  [--variant <0-8|MONOCHROME|NEUTRAL|TONAL_SPOT|TONALSPOT|VIBRANT|EXPRESSIVE|FIDELITY|CONTENT|RAINBOW|FRUIT_SALAD|FRUITSALAD>] \
  [--contrast-level <-1|0|1>] \
  [--spec-version <2021|2025>] \
  [--platform <phone|watch>] \
  [--primary <color>] \
  [--secondary <color>] \
  [--tertiary <color>] \
  [--error <color>] \
  [--neutral <color>] \
  [--neutral-variant <color>] \
  [--token <token-name...>] \
  [--exclude <token-name...>] \
  [--help]

Default behavior:

  • --format css
  • --output console
  • palette output enabled by default
  • --palette-tones 0..100
  • --variant TONAL_SPOT
  • --contrast-level 0
  • --spec-version 2025
  • --platform phone

Color Input Formats

The CLI accepts the following color syntaxes:

| Syntax | Example | Description | | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | Hex | #0f774a | Supports #RGB, #RRGGBB, #RGBA, and #RRGGBBAA. Pure hexadecimal values must keep the leading #, or they may be parsed as integers. | | RGB | rgb(15, 119, 74) | Channels can be integers in the range 0-255, or percentages from 0%-100%. | | RGBA | rgba(15, 119, 74, 1) | Only fully opaque alpha is accepted, meaning 1 or 100%. | | LAB | lab(44.3, -15.2, 18.6) | Converted directly from LAB values. | | HCT | hct(270, 75, 50) | Useful when you want to provide Material color model values directly. | | ARGB fn | argb(0xff0f774a) | Accepts a single ARGB integer. | | ARGB int | 0xff0f774a or 4278851722 | Supports decimal and 0x-prefixed integers. | | Random | random-color | Generates an opaque random color. |

If the input is empty or unsupported, the CLI exits with an error.

random-color can be used in the positional argument, in --input file contents, and in the palette override options --primary, --secondary, --tertiary, --error, --neutral, and --neutral-variant.

Command Options

Input and Output

| Option | Default | Description | | --------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [color] | none | Positional argument for passing the color value directly. | | --input <file-path> | none | Reads the source color text from a file, trimming leading and trailing whitespace. The path is resolved relative to the current working directory. | | --format <format> | css | Output format. Supported values: css, json, xml, yaml, js, ts, and csv. | | --output <target> | console | console prints to the terminal; file writes to disk. | | --path <output-file-path> | ./output.<format> | Used when --output file is selected. The path is resolved relative to the current working directory. | | --make-js <output-js-file-path> | none | Generates a reusable ESM wrapper script. It captures the current CLI configuration and calls dist/index.js at runtime. If the input uses random-color, the generated script re-randomizes at runtime. This is different from --format js. | | --help | none | Displays help information. |

Theme and Palette

| Option | Default | Description | | ----------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --variant <variant> | TONAL_SPOT | Dynamic scheme variant. Available values include: 0 = MONOCHROME, 1 = NEUTRAL, 2 = TONAL_SPOT / TONALSPOT, 3 = VIBRANT, 4 = EXPRESSIVE, 5 = FIDELITY, 6 = CONTENT, 7 = RAINBOW, 8 = FRUIT_SALAD / FRUITSALAD. | | --contrast-level <contrast-level> | 1 | Contrast level. Only -1, 0, and 1 are accepted. | | --spec-version <spec-version> | 2025 | Design specification version. Only 2021 and 2025 are accepted. | | --platform <platform> | phone | Target platform. Only phone and watch are accepted. | | --primary <color> | none | Overrides the primary palette. | | --secondary <color> | none | Overrides the secondary palette. | | --tertiary <color> | none | Overrides the tertiary palette. | | --error <color> | none | Overrides the error palette. | | --neutral <color> | none | Overrides the neutral palette. | | --neutral-variant <color> | none | Overrides the neutral-variant palette. | | --no-palette | enabled | Disables palette token output. Theme tokens still render normally. | | --palette-only | off | Emits palette tokens only and skips theme token output. | | --palette-tones <tone-list> | 0..100 | Limits palette output to the selected tones. Accepts comma- or space-separated integers from 0 to 100, such as 0, 1. |

These palette override options accept the same syntax as the source color: Hex, RGB, RGBA, LAB, HCT, ARGB function, and ARGB integer.

Filtering

| Option | Default | Description | | --------------------------- | ------- | ------------------------------------------------------------- | | --token <token-name...> | none | Whitelist. Keeps only these tokens. Supports multiple values. | | --exclude <token-name...> | none | Blacklist. Removes these tokens. Supports multiple values. |

Notes:

  • --token and --exclude are mutually exclusive.
  • Names are normalized to kebab-case before matching, so primaryContainer, PRIMARY_CONTAINER, and primary-container are treated as the same token.
  • Palette selectors use the palette- prefix. Use palette-primary or palette-neutral-variant to keep an entire family, or palette-primary-50 to keep a single tone.
  • Palette selectors can be combined with --palette-only and --palette-tones to narrow output to specific palette tokens.
  • Unknown names are reported as warnings and ignored.

Examples

1. Terminal preview with the default CSS output

material-theme-cli "#0f774a"

2. Write CSS to a file

material-theme-cli "#0f774a" --format css --output file --path ./theme.css

3. Write JSON to a file

material-theme-cli "#0f774a" --format json --output file --path ./theme.json

4. Read a color from a file

material-theme-cli --input ./color.txt --format yaml --output file --path ./theme.yaml

5. Generate a TypeScript module

js and ts produce the same serialized content, both generating module source like export const MdSysColor = { ... }.

material-theme-cli "#0f774a" --format ts --output file --path ./theme.ts

6. Use a token whitelist

material-theme-cli "#0f774a" --token primary surface-tint on-primary

7. Use a token blacklist

material-theme-cli "#0f774a" --exclude surface-tint outline shadow

8. Override palettes

material-theme-cli "#0f774a" --primary "#1d4ed8" --secondary "#14b8a6" --neutral "#111827"

9. Adjust variant, contrast, and platform

material-theme-cli "#0f774a" --variant FRUIT_SALAD --contrast-level 0 --spec-version 2025 --platform watch

10. Generate a reusable script

material-theme-cli "#0f774a" --make-js ./scripts/theme-generator.js --format css --output file --path ./theme.css

--make-js generates a runtime script that captures the current parameters. The script depends on the built artifact dist/index.js, so run it only after the repository has been built.

11. Skip palette output

material-theme-cli "#0f774a" --no-palette

12. Limit palette tones

material-theme-cli "#0f774a" --palette-tones "0, 1"

13. Keep a single palette tone

material-theme-cli "#0f774a" --palette-only --token palette-primary-50

Protocol

Output Protocol

The CLI first generates a pair of lightObject and darkObject values, then serializes them into the chosen format. To keep output stable, keys are normalized to kebab-case and sorted alphabetically.

  • css: emits :root and --md-sys-color-* custom properties using light-dark(light, dark) values.
  • json / yaml: emits a theme object with top-level light, dark, and scheme nodes.
  • xml: emits a resources node, with color names using md_sys_color_*_light and md_sys_color_*_dark.
  • js / ts: emits module source like export const MdSysColor = { ... }, where Light, Dark, and Scheme suffixes represent the light, dark, and combined values.
  • csv: uses the fixed header scheme,token-name,color-value, and expands each token into three rows for light, dark, and scheme.

Palette output is included by default.

  • css: adds --md-sys-palette-* custom properties with fixed hex values and no light-dark() wrapper.
  • json / yaml: adds a top-level palette node with md-sys-palette-* keys.
  • xml: adds md_sys_palette_* color entries under resources.
  • js / ts: adds an export const MdSysPalette = { ... } object with fixed palette token values.
  • csv: adds palette rows for each palette token tone.

If the normalized keys in light and dark do not match, serialization fails. This prevents incomplete theme files from being generated.

License

This project is released under the MIT License. See LICENSE for details. Third-party dependencies are governed by their own license terms.