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

@sorrell/color

v2.0.1

Published

Functional types and utilities for working with colors.

Readme

@sorrell/color

Immutable, structural RGB color types for effect: RgbColor (8-bit channels), RgbaColor (8-bit channels plus alpha), and LinearColor (normalized [0, 1] decimal channels, also with alpha). Every constructor clamps and truncates its input, so out-of-range or fractional channel values never throw or wrap. Mutators follow Effect's data-first/ data-last Function.dual convention, and every color type parses and formats the same set of CSS and ANSI representations. Contrast computes WCAG relative luminance and contrast ratio, and can adjust a color's lightness to guarantee a minimum contrast against a background.

RgbColor

import { RgbColor } from "@sorrell/color";

const Red = RgbColor.RgbColor(255, 0, 0);
const Clamped = RgbColor.RgbColor(-10, 300, 127.9); // { R: 0, G: 255, B: 127 }

const Lighter = RgbColor.Lighten(Red, 0.25);
const Darker = RgbColor.Darken(0.25)(Red);

RgbColor.Format.Hex(Red); // "#ff0000"
RgbColor.Format.Hsl(Red); // "hsl(0, 100%, 50%)"

Channels accept number, bigint, or an Effect BigDecimal, and are clamped to {0..255} and truncated toward zero. RgbColor.From parses Hex, Rgb, Hsl, Hsv, Hwb, Keyword, Ansi16, Ansi256, Tuple, and Record representations; the string parsers return an Effect Option, since the input may not match. RgbColor.Format renders every one of those representations in the other direction. SetRed, SetGreen, and SetBlue update one channel; Assign (aliased Patch) updates several at once from a Partial<RgbColor>.

RgbaColor

RgbaColor mirrors RgbColor exactly, with an additional 8-bit A channel:

import { RgbaColor, RgbColor } from "@sorrell/color";

const HalfRed = RgbaColor.RgbaColor(255, 0, 0, 128);
RgbaColor.SetAlpha(HalfRed, 64);

RgbaColor.To.RgbColor(HalfRed); // discards alpha
RgbaColor.From.RgbColor(RgbColor.RgbColor(0, 0, 0)); // alpha defaults to 255

Every From string parser (Hex, Rgb, Hsl, …) produces a fully opaque color, since none of those representations carry an alpha component in this package. RgbaColor.From.LinearColor and RgbaColor.To.LinearColor convert against LinearColor, scaling every channel, including alpha, between {0..255} and [0, 1].

LinearColor

import { BigDecimal } from "effect";
import { LinearColor } from "@sorrell/color";

const Opaque = LinearColor.LinearColor(1, 0, 0.5); // A defaults to 1
const HalfTransparent = LinearColor.LinearColor(1, 0, 0.5, 0.5);

LinearColor.Format.Tuple(Opaque).map(BigDecimal.toNumberUnsafe); // [1, 0, 0.5, 1]

Channels, including alpha, are Effect BigDecimal values clamped to [0, 1]. Unlike RgbaColor, every LinearColor constructor's Alpha argument is optional and defaults to 1 (fully opaque); From.Tuple and From.Record extend the same default when a tuple or record omits A. Lighten and Darken preserve the original alpha.

Contrast

import { Contrast, RgbColor } from "@sorrell/color";

const Background = RgbColor.RgbColor(255, 255, 255);
const Foreground = RgbColor.RgbColor(220, 220, 220);

Contrast.ContrastRatio(Foreground, Background); // ~1.3

const Accessible = Contrast.EnsureContrast(Foreground, Background, 4.5);
Contrast.ContrastRatio(Accessible, Background); // >= 4.5

RelativeLuminance and ContrastRatio implement the WCAG 2 formulas. EnsureContrast darkens or lightens Self along its HSL lightness — whichever direction has more contrast headroom against Background — using a bounded binary search, and returns Self unchanged when it already meets MinimumRatio. Contrast operates on RgbColor; convert an RgbaColor or LinearColor first when checking contrast on one of those.

Entrypoints

  • @sorrell/colorRgbColor, RgbaColor, LinearColor, and Contrast, each re-exported as a namespace.
  • @sorrell/color/RgbColor
  • @sorrell/color/RgbaColor
  • @sorrell/color/LinearColor
  • @sorrell/color/Contrast