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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@poupe/theme-builder

v0.10.1

Published

Design token management and theme generation system for Poupe UI framework

Downloads

189

Readme

@poupe/theme-builder

jsDocs.io npm version License: MIT

Design token management and theme generation system for Material Design 2025 themes with automatic dark mode, CSS variables, and image-based color extraction.

Table of Contents

Features

  • 🎨 Material Design 2025 color system with automatic dark themes
  • 🌓 Built-in dark mode support with CSS custom properties
  • 🖼️ Generate color palettes from images using Material algorithms
  • 🔧 Advanced color manipulation utilities (HCT, RGB, HSL, ARGB)
  • 📦 Lightweight, tree-shakable API with TypeScript support
  • 🧩 CSS variables generation for external customization
  • 🎭 Theme scheme variants (vibrant, expressive, content, etc.)
  • 🛠️ Server-side utilities for build-time theme generation
  • 🎯 Material Design 3 state layer colors for interactive states

Installation

# npm
npm install -D @poupe/theme-builder

# yarn
yarn add -D @poupe/theme-builder

# pnpm
pnpm add -D @poupe/theme-builder

Usage

Basic Theme Creation

import { makeTheme } from '@poupe/theme-builder'

// Create Material Design 2025 theme with color roles
const { dark, light } = makeTheme({
  primary: '#1976d2',
  secondary: '#9c27b0',
  tertiary: '#ff4081',
}, 'vibrant', 0.0)

// Access color roles
console.log(light.primary.value)    // Primary color in light theme
console.log(dark.onPrimary.value)   // Text on primary in dark theme

// Theme with state colors included by default
console.log(light['primary-hover'])  // Primary hover state
console.log(dark['on-primary-disabled']) // Disabled text on primary

// Use CSS color-mix() for runtime state color generation
// Fourth parameter accepts additional theme generation options
const runtimeTheme = makeTheme({
  primary: '#1976d2',
}, 'content', 0.0, { useColorMix: true })

CSS Theme Generation

import { makeCSSTheme } from '@poupe/theme-builder'

// Generate CSS variables for dark/light themes
const cssTheme = makeCSSTheme({
  primary: '#6750A4',
  secondary: '#958DA5',
  error: '#B3261E',
}, {
  scheme: 'content',
  contrastLevel: 0.5,
  prefix: 'md-',
  darkMode: ['.dark', 'media'],    // Multiple selectors + aliases
  lightMode: '.light',
})

// Built-in responsive aliases
makeCSSTheme(colors, {
  darkMode: ['dark', 'mobile'],    // Uses media queries
  lightMode: ['light', 'desktop']  // Now supports arrays too
})

// Advanced selector configuration
const advancedTheme = makeCSSTheme(colors, {
  darkMode: ['mobile', '.dark-mode'],    // Mobile + custom class
  lightMode: ['desktop', '.light-mode'],  // Desktop + custom class
})

// Use generated CSS variables
console.log(cssTheme.vars.primary)   // '--md-primary'
console.log(cssTheme.styles)         // CSS rule objects

Theme from Image

import { fromImageElement } from '@poupe/theme-builder'

// Extract color from image element
async function createImageTheme(imageElement: HTMLImageElement) {
  const seedColor = await fromImageElement(imageElement)

  const { dark, light } = makeTheme({
    primary: seedColor.toHex(),
  }, 'expressive')

  return { dark, light }
}

Color Manipulation

import {
  hct, colord, hexString, makeTonalPalette
} from '@poupe/theme-builder/core'

// HCT color space (Hue, Chroma, Tone)
const color = hct('#1976d2')
const lighter = color.withTone(80)   // Lighter variant
const muted = color.withChroma(30)   // Lower saturation

// Advanced color utilities
const c = colord('#1976d2')
console.log(c.toHsl())               // HSL representation
console.log(c.lighten(0.2).toHex())  // Lightened color

// Format colors
console.log(hexString(lighter))      // Convert to hex string

// Create tonal palette with full tone range (0-100)
const palette = makeTonalPalette('#1976d2')
console.log(palette.tone(50))        // Medium tone
console.log(palette.tone(90))        // Light tone
console.log(palette.tone(10))        // Dark tone

// Harmonize colors to create cohesive palettes
const primary = hct('#1976d2')
const harmonized = makeTonalPalette('#9c27b0', primary)

State Layer Colors

Material Design 3 interactive state support:

import {
  makeStandardStateVariants,
  getStateColorMixParams,
  stateLayerOpacities
} from '@poupe/theme-builder'

// Generate state variants for theme colors
const theme = makeTheme({ primary: '#6750A4' })
const stateColors = makeStandardStateVariants(theme.light)

// Access state colors
console.log(stateColors['primary-hover'])     // 8% opacity
console.log(stateColors['primary-focus'])     // 12% opacity
console.log(stateColors['primary-pressed'])   // 12% opacity
console.log(stateColors['on-primary-disabled']) // 38% opacity

// Get CSS color-mix parameters for dynamic theming
const params = getStateColorMixParams('primary', 'hover', '--md-')
// Returns: {
//   state: 'hover',
//   baseColor: '--md-primary',
//   onColor: '--md-on-primary',
//   opacityPercent: 8
// }

// Material Design 3 opacity values
console.log(stateLayerOpacities.hover)    // 0.08
console.log(stateLayerOpacities.focus)    // 0.12
console.log(stateLayerOpacities.pressed)  // 0.12
console.log(stateLayerOpacities.dragged)  // 0.16
console.log(stateLayerOpacities.disabled) // 0.12
console.log(stateLayerOpacities.onDisabled) // 0.38

API Reference

Main Exports

import {
  // Theme generation
  makeTheme,
  makeCSSTheme,

  // CSS utilities
  assembleCSSColors,
  defaultCSSThemeOptions,

  // Image extraction
  fromImageElement,

  // State layer colors
  makeStandardStateVariants,
  makeCustomStateVariants,

  // Color utilities (re-exported from core)
  hct,
  colord,
  hexString,
  rgbaString,
} from '@poupe/theme-builder'

Core Utilities

Color manipulation and formatting utilities:

import {
  // Color types and creation
  type Hct,
  type HexColor,
  hct,
  colord,

  // Color formatting
  hexString,
  rgbaString,

  // Color conversion
  argb,
  rgb,

  // State layer utilities
  stateLayerOpacities,
  makeStateLayerColors,
  makeStateVariants,
  getStateColorMixParams,

  // CSS utilities (re-exported)
  formatCSSRules,
} from '@poupe/theme-builder/core'

Server Utilities

Server-side color processing, validation, and CSS response utilities:

import {
  // Parameter processing
  getColorParam,
  getThemeSchemeParam,

  // CSS formatting utilities
  stringifyCSSRulesArray,
  stringifyCSSRulesArrayStream,
  stringifyCSSRulesArrayAsStream,
  stringifyCSSRulesArrayAsResponse,
  stringifyCSSRulesArrayAsStreamingResponse,

  // Color types (re-exported)
  type HexColor,
  hct,
  colord,
} from '@poupe/theme-builder/server'

// Convert to CSS string (no trailing newline)
const cssString = stringifyCSSRulesArray([
  { '.theme': { '--primary': '#6750A4' } }
])

// Convert with camelCase to kebab-case normalization
const normalizedCSS = stringifyCSSRulesArray([
  { fontSize: '16px', backgroundColor: 'blue' }
], { normalizeProperties: true })
// Result: 'font-size: 16px;\nbackground-color: blue;'

// Create ReadableStream (perfect for Cloudflare Workers)
const stream = stringifyCSSRulesArrayAsStream([
  { '.theme': { '--primary': '#6750A4' } }
])
const response = new Response(stream, {
  headers: { 'Content-Type': 'text/css' }
})

// Create Response object with headers
const response = stringifyCSSRulesArrayAsResponse([
  { '.theme': { '--primary': '#6750A4' } }
])

// Create streaming Response for large CSS files
const streamingResponse = stringifyCSSRulesArrayAsStreamingResponse([
  // Large array of CSS rules
])

Color System

Material Design 2025 color roles and theming:

  • Primary: Main brand color and variants (primary, primaryDim, onPrimary, primaryContainer, onPrimaryContainer)
  • Secondary: Supporting colors (secondary, secondaryDim, onSecondary, secondaryContainer, onSecondaryContainer)
  • Tertiary: Accent colors (tertiary, tertiaryDim, onTertiary, tertiaryContainer, onTertiaryContainer)
  • Error: Error states (error, onError, errorContainer, onErrorContainer)
  • Neutral: Surface and outline colors (surface, onSurface, outline, etc.)
const { dark, light } = makeTheme({
  primary: '#6750A4',
  secondary: '#958DA5',
  tertiary: '#B58392',
  neutral: '#938F94',
  neutralVariant: '#948F94',
  error: '#B3261E',
}, 'content', 0.0)

// Access all color roles
console.log(light.primaryContainer.value)  // Primary container color
console.log(dark.onSurfaceVariant.value)   // Text on surface variant

CSS Variables

Automatic CSS custom property generation:

const cssTheme = makeCSSTheme({
  primary: '#6750A4',
}, {
  prefix: 'md-',         // Variable prefix
  darkMode: '.dark',     // Dark mode selector
  lightMode: '.light',   // Light mode selector (optional)
  darkSuffix: '-dark',   // Dark variable suffix
  lightSuffix: '-light', // Light variable suffix
})

// Generated variables
cssTheme.vars.primary            // '--md-primary'
cssTheme.vars.onPrimary          // '--md-on-primary'
cssTheme.styles                  // CSS rule objects

Dark Mode

Built-in dark mode support with flexible selectors and aliases:

// Class-based dark mode (default)
makeCSSTheme(colors, { darkMode: '.dark' })

// Media query dark mode using built-in alias
makeCSSTheme(colors, { darkMode: 'media' })

// Multiple selectors
makeCSSTheme(colors, { darkMode: ['.dark', '.theme-dark'] })

// Built-in responsive aliases
makeCSSTheme(colors, {
  darkMode: ['dark', 'mobile'],  // Uses media queries
  lightMode: 'light'
})

// Custom selectors
makeCSSTheme(colors, {
  darkMode: '[data-theme="dark"]',
  lightMode: '[data-theme="light"]'
})

// Disable dark mode
makeCSSTheme(colors, { darkMode: false })

Built-in Selector Aliases

The theme builder includes convenient aliases for common media queries:

  • 'media' or 'dark''@media (prefers-color-scheme: dark)'
  • 'light''@media (prefers-color-scheme: light)'
  • 'mobile''@media (max-width: 768px)'
  • 'tablet''@media (min-width: 769px) and (max-width: 1024px)'
  • 'desktop''@media (min-width: 1025px)'
// Using aliases for responsive theming
const cssTheme = makeCSSTheme(colors, {
  darkMode: ['dark', 'tablet'],    // Dark mode + tablet screens
  lightMode: ['light', 'desktop'], // Light mode + desktop screens
})

Integration with Poupe Ecosystem

Requirements

  • Node.js >=20.19.1
  • TypeScript-friendly environment

License

MIT licensed.