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

ok-material-colors

v0.1.1

Published

OkLCH/OkHSL-based MD3 palette generator

Readme

ok-material-colors

OkLCH/OkHSL-based Material Design 3 palette generator. Produces the same 53 standard MD3 color tokens as Google's material-color-utilities, but built on Björn Ottosson's perceptually uniform color spaces instead of CAM16/HCT.

Built for use in @anoyomoose/q2-fresh-paint-md3e. This is primarily an internal package, but it's MIT-licensed — have at it.

Just wanted to see if using OkLAB based toning would look nicer, while using the same basic idea as Google's algorithm. Sometimes it does!

Install

pnpm install @anoyomoose/ok-material-colors

Usage

import { generatePalette, harmonize, vibrant } from 'ok-material-colors'

// Generate a full light + dark palette from a source color
const palette = generatePalette('#6750a4')
// palette.light['primary']    → '#615588'
// palette.dark['on-surface']  → '#e3e1ea'

// Pick a preset
const vib = generatePalette('#ff0000', { scheme: 'vibrant' })

// Tweak a preset
const custom = generatePalette('#ff0000', {
  scheme: { ...vibrant, neutralSaturation: 0.08 },
})

// Adjust contrast (-1 to 1)
const highContrast = generatePalette('#6750a4', { contrastLevel: 1 })

// Harmonize a custom color toward the theme source
const harmonized = harmonize('#21BA45', '#6750a4')
// Shifts green's hue toward purple by up to 15°

API

generatePalette(hex, options?)

Returns { light: Record<string, string>, dark: Record<string, string> } — 53 MD3 tokens per mode as sRGB hex values.

Options:

| Option | Type | Default | Description | |---|---|---|---| | scheme | string \| SchemeConfig | 'tonalSpot' | Preset name or custom config | | contrastLevel | number | 0 | -1 (reduced) to 1 (high) | | secondarySourceColor | string | — | Second source color for cmf preset |

harmonize(designColorHex, sourceColorHex)

Shifts the design color's hue toward the source by up to 15°, preserving saturation and lightness. Returns sRGB hex.

Presets

tonalSpot, vibrant, expressive, neutral, fidelity, content, monochrome, rainbow, fruitSalad, cmf

All exported individually and as presets (a Record<string, SchemeConfig>).

SchemeConfig

Every preset is a plain SchemeConfig object you can spread and override:

interface SchemeConfig {
  name: string
  primaryHueOffset: number          // -180 to 180
  primarySaturation: number | 'source'  // 0 to 1
  secondaryHueOffset: number
  secondarySaturation: number | 'source' | RelativeSaturation
  tertiaryHueOffset: number | 'complement' | 'analogous'
  tertiarySaturation: number | 'source' | RelativeSaturation
  neutralHueOffset: number
  neutralSaturation: number | RelativeSaturation
  neutralVariantHueOffset: number
  neutralVariantSaturation: number | RelativeSaturation
  errorHue: number                  // 0 to 360 (absolute)
  errorSaturation: number | RelativeSaturation
  darkSurfaceScale?: number         // 0.75 to 1.25, scales dark surface OkL. Default: 1.0
  darkLowestIsBlack?: boolean       // surface-container-lowest dark = pure black
}

interface RelativeSaturation {
  factor: number   // multiplied by source saturation
  offset?: number  // added after
  min?: number     // floor
}

How it works

  1. Source hex is parsed to OkHSL once
  2. Six tonal palettes are derived (primary, secondary, tertiary, neutral, neutralVariant, error) based on the scheme config's hue offsets and saturations
  3. Tonal ramps are generated in OkLCH with constant chroma and gamut clamping
  4. Token lightness values are converted from CIE L* to OkLab L for correct perceptual mapping
  5. Contrast targets are enforced via binary search on real WCAG 2.1 ratios
  6. sRGB hex conversion happens only at the final output boundary

Uses @texel/color for color space conversions and gamut mapping.

License

MIT