skills/material-theme-builder/SKILL.md
Generate Material Design 3 color themes programmatically from a source color using @material/material-color-utilities, the same engine that powers the Material Theme Builder. Use this when the user asks to generate an M3 color palette, create a custom theme from a brand color, or export M3 tokens to CSS, JSON, or framework configs.
npx skillsauth add shelbeely/shelbeely-agent-skills material-theme-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate complete Material Design 3 color themes programmatically from any source color. This skill uses @material/material-color-utilities — the same color algorithm library that powers Google's Material Theme Builder — to produce accessible light/dark palettes, tonal ranges, and design tokens ready for CSS, JSON, or any framework.
Keywords: Material Theme Builder, color generation, dynamic color, theme export, @material/material-color-utilities, HCT, tonal palette, source color, brand color, CSS tokens, JSON export
Material Color Utilities uses the HCT color space (Hue, Chroma, Tone) — a perceptually uniform color model built on CAM16 and L* — to generate five tonal palettes from a single source color:
Each palette contains tones 0–100. Specific tones are mapped to semantic color roles (e.g., primary = tone 40 in light, tone 80 in dark).
npm install @material/material-color-utilities
Use the generate-theme.mjs script in this skill's directory:
node generate-theme.mjs "#FF9800" # CSS output (default tonal-spot)
node generate-theme.mjs "#FF9800" --json # JSON output
node generate-theme.mjs "#FF9800" --scheme expressive # Expressive scheme variant
The --scheme flag selects from 9 dynamic color strategies defined in material-color-utilities:
| Scheme | Description |
|--------|-------------|
| tonal-spot | Default — balanced, versatile (used by Android Material You) |
| content | Colors derived with fidelity to the source, good for photo-based themes |
| expressive | Intentionally detached from source for bold, playful palettes |
| fidelity | High fidelity to source hue, chroma-capped for accessibility |
| fruit-salad | Vibrant, playful secondary and tertiary from offset hues |
| monochrome | Achromatic — all palettes have zero chroma |
| neutral | Near-achromatic — very low chroma for subtle, muted themes |
| rainbow | Wide hue spread across primary, secondary, and tertiary |
| vibrant | Saturated, colorful variant of tonal-spot |
import {
argbFromHex,
hexFromArgb,
themeFromSourceColor,
} from "@material/material-color-utilities";
// Generate from any hex source color
const theme = themeFromSourceColor(argbFromHex("#FF9800"));
// Extract light scheme
const light = theme.schemes.light.toJSON();
for (const [role, argb] of Object.entries(light)) {
console.log(`${role}: ${hexFromArgb(argb)}`);
}
The base themeFromSourceColor provides core roles. Surface container tones are derived from the neutral palette at specific tones:
import {
argbFromHex,
hexFromArgb,
themeFromSourceColor,
} from "@material/material-color-utilities";
const theme = themeFromSourceColor(argbFromHex("#FF9800"));
const neutral = theme.palettes.neutral;
const primary = theme.palettes.primary;
const secondary = theme.palettes.secondary;
const tertiary = theme.palettes.tertiary;
// Light surface containers (tone values per M3 spec)
const lightSurfaces = {
surface: neutral.tone(98),
surfaceDim: neutral.tone(87),
surfaceBright: neutral.tone(98),
surfaceContainerLowest: neutral.tone(100),
surfaceContainerLow: neutral.tone(96),
surfaceContainer: neutral.tone(94),
surfaceContainerHigh: neutral.tone(92),
surfaceContainerHighest: neutral.tone(90),
};
// Dark surface containers
const darkSurfaces = {
surface: neutral.tone(6),
surfaceDim: neutral.tone(6),
surfaceBright: neutral.tone(24),
surfaceContainerLowest: neutral.tone(4),
surfaceContainerLow: neutral.tone(10),
surfaceContainer: neutral.tone(12),
surfaceContainerHigh: neutral.tone(17),
surfaceContainerHighest: neutral.tone(22),
};
// Fixed colors (consistent across light and dark)
const fixed = {
primaryFixed: primary.tone(90),
onPrimaryFixed: primary.tone(10),
primaryFixedDim: primary.tone(80),
onPrimaryFixedVariant: primary.tone(30),
secondaryFixed: secondary.tone(90),
onSecondaryFixed: secondary.tone(10),
secondaryFixedDim: secondary.tone(80),
onSecondaryFixedVariant: secondary.tone(30),
tertiaryFixed: tertiary.tone(90),
onTertiaryFixed: tertiary.tone(10),
tertiaryFixedDim: tertiary.tone(80),
onTertiaryFixedVariant: tertiary.tone(30),
};
function schemeToCss(scheme, selector = ":root") {
const entries = Object.entries(scheme.toJSON());
const props = entries
.map(([key, argb]) => {
const token = key.replace(/([A-Z])/g, "-$1").toLowerCase();
return ` --md-sys-color-${token}: ${hexFromArgb(argb)};`;
})
.join("\n");
return `${selector} {\n${props}\n}`;
}
console.log(schemeToCss(theme.schemes.light));
console.log(schemeToCss(theme.schemes.dark, '[data-theme="dark"]'));
function schemeToJson(scheme) {
const result = {};
for (const [key, argb] of Object.entries(scheme.toJSON())) {
result[key] = hexFromArgb(argb);
}
return result;
}
const output = {
source: "#FF9800",
light: schemeToJson(theme.schemes.light),
dark: schemeToJson(theme.schemes.dark),
};
console.log(JSON.stringify(output, null, 2));
import { applyTheme } from "@material/material-color-utilities";
const systemDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
applyTheme(theme, { target: document.body, dark: systemDark });
Add brand-specific colors that harmonize with the generated theme:
const theme = themeFromSourceColor(argbFromHex("#FF9800"), [
{
name: "brand-green",
value: argbFromHex("#4CAF50"),
blend: true, // harmonize with the source color
},
{
name: "warning",
value: argbFromHex("#FFC107"),
blend: false, // keep exact hue
},
]);
// Access custom colors
for (const custom of theme.customColors) {
console.log(`${custom.color.name}:`);
console.log(` light: ${hexFromArgb(custom.light.color)}`);
console.log(` dark: ${hexFromArgb(custom.dark.color)}`);
}
| Platform | Package |
|-------------|---------|
| TypeScript | @material/material-color-utilities (npm) |
| Dart | material_color_utilities (pub.dev) |
| Java/Kotlin | Built into MDC-Android |
| Swift | Source in material-color-utilities repo |
| C++ | Source in material-color-utilities repo |
@material/material-color-utilities installedthemeFromSourceColortools
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
testing
Applies Material Design 3 Expressive typography principles including variable fonts, type scales, and hierarchy. Use this when working on text styling, type hierarchy, readable interfaces, or when the user asks to apply Material Design 3 typography guidelines.
testing
Applies Material Design 3 Expressive shape and containment principles including rounded corners, morphing shapes, and container design. Use this when working on component shapes, borders, containment, or when the user asks to apply Material Design 3 shape guidelines.
testing
Applies Material Design 3 Expressive motion and animation principles to create natural, intuitive, and engaging user experiences. Use this when implementing animations, transitions, micro-interactions, or when the user asks to apply Material Design 3 motion guidelines.