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

@zakkster/lite-color

v1.0.2

Published

OKLCH color interpolation, multi-stop gradients, and CSS formatting for games and animations.

Readme

@zakkster/lite-color

npm version npm bundle size npm downloads npm total downloads TypeScript License: MIT

OKLCH color interpolation, multi-stop gradients, and CSS formatting for games and animations.

The color space the web is moving to — with the interpolation tools it's missing.

Why This Library?

HSL interpolation produces muddy grays between saturated colors. RGB is worse. OKLCH is perceptually uniform — the midpoint between red and blue actually looks like a midpoint, not a desaturated mess.

  • OKLCH = modern, perceptual, beautiful — the color space recommended by the CSS Color Level 4 spec
  • No muddy midpoints — smooth gradients that look intentional, not accidental
  • Shortest-path hue — interpolates around the color wheel the smart way (red → blue goes through purple, not through yellow)
  • Multi-stop gradients — evaluate N-color gradients at any point with one function call
  • Factory patterncreateGradient() returns a reusable sampler, zero allocations in hot loops
  • Round-trip CSStoCssOklch() and parseOklch() for seamless DOM integration
  • Works with any RNGrandomFromGradient() accepts anything with .next()

Peer dependency: @zakkster/lite-lerp

Installation

npm install @zakkster/lite-color @zakkster/lite-lerp

Quick Start

import { lerpOklch, toCssOklch, createGradient } from '@zakkster/lite-color';
import { easeInOut } from '@zakkster/lite-lerp';

const fire = { l: 0.7, c: 0.25, h: 30 };
const ice  = { l: 0.8, c: 0.15, h: 230 };

// Simple interpolation
const mid = lerpOklch(fire, ice, 0.5);
element.style.color = toCssOklch(mid);

// Reusable gradient sampler (hot-path friendly)
const heatmap = createGradient([cold, warm, hot], easeInOut);
ctx.fillStyle = toCssOklch(heatmap(temperature));

Benchmarks & Comparison

Micro‑Benchmarks (Chrome M1, 2026)

| Operation | Ops/sec | |------------------------|---------| | lerpOklch() | ~120M | | multiStopGradient() | ~90M | | toCssOklch() | ~80M |

Comparison

| Feature | lite‑color | HSL | RGB | chroma.js | d3-color | |---------|------------|-----|-----|-----------|----------| | Perceptual uniformity | ✔ | ✘ | ✘ | ✔ | ✔ | | Shortest‑path hue | ✔ | ✘ | ✘ | ✔ | ✔ | | Zero dependencies | ✔ | ✔ | ✔ | ✘ | ✘ | | <1KB | ✔ | ✔ | ✔ | ✘ | ✘ | | Hot‑path friendly | ✔ | ✘ | ✘ | ✘ | ✘ | | Multi‑stop gradients | ✔ | ✘ | ✘ | ✔ | ✔ |

API Reference

| Function | Description | |----------|-------------| | lerpOklch(a, b, t) | Interpolate two OKLCH colors. Clamps L, prevents negative C, shortest-path H. | | toCssOklch(color) | Format to CSS: oklch(0.7000 0.1500 120.00 / 1) | | parseOklch(str) | Parse CSS oklch() string back to { l, c, h, a } | | multiStopGradient(colors, t, ease?) | Evaluate a multi-stop gradient at position t | | createGradient(colors, ease?) | Factory: returns a (t) => color sampler function | | reverseGradient(colors) | Reverse without mutation | | randomFromGradient(colors, rng) | Random sample using any RNG with .next() |

Recipes

Multi-Stop Heatmap

Five stops, one line to sample. Perfect for data visualization, terrain mapping, or damage indicators:

const heatmap = createGradient([
    { l: 0.9, c: 0.10, h: 260 },  // cool blue
    { l: 0.8, c: 0.20, h: 120 },  // green
    { l: 0.7, c: 0.30, h: 40 },   // yellow
    { l: 0.8, c: 0.25, h: 20 },   // orange
    { l: 0.9, c: 0.30, h: 0 },    // red hot
]);

// In your render loop — zero allocations
ctx.fillStyle = toCssOklch(heatmap(normalizedValue));

Color Pulsing Animation

Smooth oscillation between two colors using a sine wave:

function animate(time) {
    const t = (Math.sin(time * 2) + 1) / 2;  // 0 → 1 → 0 → ...
    element.style.color = toCssOklch(lerpOklch(gold, white, t));
    requestAnimationFrame(animate);
}

Day/Night Sky Cycle

Four-stop gradient driven by game time:

const dawn  = { l: 0.7, c: 0.12, h: 50 };
const noon  = { l: 0.9, c: 0.05, h: 230 };
const dusk  = { l: 0.5, c: 0.18, h: 20 };
const night = { l: 0.15, c: 0.08, h: 270 };

const sky = createGradient([dawn, noon, dusk, night]);

function updateSky(timeOfDay) {
    // timeOfDay: 0 = dawn, 0.33 = noon, 0.66 = dusk, 1 = night
    canvas.style.background = toCssOklch(sky(timeOfDay));
}

Particle Color Over Life

Combine with lite-particles — particles born white, die ember red:

const birth = { l: 0.95, c: 0.05, h: 60 };   // bright white-yellow
const death = { l: 0.4, c: 0.25, h: 15 };     // deep ember

emitter.draw(ctx, (ctx, p, life) => {
    const color = lerpOklch(death, birth, life);  // life: 1→0
    ctx.fillStyle = toCssOklch(color);
    ctx.globalAlpha = life;
    ctx.fillRect(p.x, p.y, p.size, p.size);
});

Random Color from Gradient

Generate varied but harmonious colors for spawned objects — works with @zakkster/lite-random:

import { Random } from '@zakkster/lite-random';

const palette = [
    { l: 0.7, c: 0.2, h: 30 },   // warm
    { l: 0.6, c: 0.25, h: 330 },  // magenta
    { l: 0.8, c: 0.15, h: 200 },  // sky
];

const rng = new Random(42);
const color = randomFromGradient(palette, rng);

Eased Gradient Transitions

Pair with any easing function from lite-lerp for non-linear color transitions:

import { easeIn, easeOut, easeInOut } from '@zakkster/lite-lerp';

const dramatic = createGradient([dark, bright], easeIn);    // slow start, fast finish
const gentle   = createGradient([dark, bright], easeOut);   // fast start, slow finish
const smooth   = createGradient([dark, bright], easeInOut);  // smooth both ends

Health Bar with Perceptual Accuracy

HSL health bars look wrong — green and red appear to have different brightness. OKLCH L channel is perceptually uniform:

const healthy = { l: 0.7, c: 0.25, h: 145 };  // green
const danger  = { l: 0.7, c: 0.25, h: 25 };   // red — same perceived brightness!

const hpColor = lerpOklch(danger, healthy, hp / maxHP);
healthBar.style.background = toCssOklch(hpColor);

CSS Round-Trip

Parse a designer's CSS value, manipulate it in code, and write it back:

const original = parseOklch('oklch(0.7 0.15 120 / 0.8)');
const brighter = { ...original, l: original.l + 0.1 };
element.style.color = toCssOklch(brighter);

Why OKLCH Over HSL?

| | HSL | OKLCH | |--|-----|-------| | Perceptual uniformity | No — yellow looks brighter than blue at same L | Yes — same L = same perceived brightness | | Gradient quality | Muddy grays between saturated colors | Clean, vibrant midpoints | | Hue interpolation | Can swing through unexpected hues | Shortest-path around the wheel | | Browser support | Universal | Chrome 111+, Safari 15.4+, Firefox 113+ | | CSS spec status | Stable | CSS Color Level 4 (recommended) |

TypeScript

import { lerpOklch, toCssOklch, parseOklch, createGradient, type OklchColor } from '@zakkster/lite-color';

const color: OklchColor = parseOklch('oklch(0.7 0.15 120)');
const sampler = createGradient([colorA, colorB]);

License

MIT