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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ericrovell/blossom

v1.10.0

Published

Blossom is a JS library tool for colour manipulations and transformations.

Downloads

43

Readme

Blossom

Blossom is a JS library tool for color manipulations and transformations.

Features:

  • Chainable API;
  • Ummutable;
  • Written in Typescript;
  • Types included;
  • Dependency-free;

Getting started

npm i @ericrovell/blossom
import { blossom } from "@ericrovell/blossom";

blossom("#FF0000")
  .grayscale
  .setAlpha(0.25)
  .toStringRGB

// -> rgb(128 128 128 / 0.25)

Supported color models

  • Hexadecimal strings;
  • RGB (objects, strings);
  • HSL (objects, strings);
  • HSV (objects);
  • CMYK (objects);
  • XYZ (objects);
  • LAB (objects);
  • LCH (objects, strings);
  • HWB (objects, strings);
  • Named colors

API

Color parsing

Parses the given input and creates a new Blossom instance.

import { blossom } from "@ericrovell/blossom";

// string input
blossom("#ABC");
blossom("#AABBCC");
blossom("#ADCDEF12");
blossom("rgb(100, 200, 255)");
blossom("rgba(100, 200, 255, 0.5)");
blossom("rgba(10% 20% 30% / 35%)");
blossom("hsl(180, 78%, 87%)");
blossom("hsla(180, 78%, 87%, 0.5)");
blossom("hsla(180deg 78% 87% / 50%)");

// object input
blossom({ r: 12, g: 34, b: 56 });
blossom({ r: 12, g: 34, b: 56, a: 1 });
blossom({ h: 180, s: 50, l: 75 });
blossom({ h: 180, s: 50, l: 75, a: 1 });
blossom({ h: 180, s: 50, v: 65 });
blossom({ h: 180, s: 50, v: 65, a: 1 });
blossom({ c: 25, m: 50, k: 75, k: 100 });
blossom({ c: 25, m: 50, k: 75, k: 100, a: 1 });

Parses a color and returns a color model name of the given input.

  import { getModel } from "@ericrovell/blossom";

  getModel("#ADC123"); // -> "hex"
  getModel({ r: 13, g: 237, b: 162 }); // -> "rgb"
  getModel("hsl(180deg 50% 50%)"); // -> "hsl"
  getModel("Hi!"); // -> null

Color transformations

Returns the hexadecimal representation of a color. Outputs the modern #RRGGBBAA opacity syntax for transparent colors.

blossom("rgb(0, 255, 0)").hex; // -> "#00FF00"
blossom({ h: 300, s: 100, l: 50 }).hex; // -> "#FF00FF"
blossom({ r: 255, g: 255, b: 255, a: 0 }).hex; // -> "#FFFFFF00"

Returns the RGB color model object of a color.

blossom("#ff0000").rgb; // -> { r: 255, g: 0, b: 0, a: 1 }
blossom({ h: 180, s: 100, l: 50, a: 0.5 }).rgb; // -> { r: 0, g: 255, b: 255, a: 0.5 }

Returns the RGB color model string of a color. Outputs the modern whitespace syntax.

blossom("#ff0000").toStringRGB; // -> "rgb(255 0 0)"
blossom({ h: 180, s: 100, l: 50, a: 0.5 }).toStringRGB; // -> "rgb(0 255 255 / 0.5)"

Returns the HSL color space object of a color.

blossom("#ffff00").hsl; // -> { h: 60, s: 100, l: 50, a: 1 }
blossom("rgba(0, 0, 255, 0.5)").hsl; // -> { h: 240, s: 100, l: 50, a: 0.5 }

Returns the HSL color space string of a color. Outputs the modern whitespace syntax.

blossom("#ffff00").toStringHSL; // -> "hsl(60deg 100% 50%)"
blossom("rgba(0, 0, 255, 0.5)").toStringHSL; // -> "hsl(240deg 100% 50% / 0.5)"

Returns the HSV color space object of a color.

blossom("#ffff00").hsv; // -> { h: 60, s: 100, v: 100, a: 1 }
blossom("rgba(0, 255, 255, 0.5)").hsv; // -> { h: 180, s: 100, v: 100, a: 1 }

Returns the HSV color space string of a color. Outputs the modern whitespace syntax.

blossom("#FFFF00").toStringHSV; // -> "hsc(60deg 100% 100%)"
blossom("rgba(0, 0, 255, 0.5)").toStringHSV; // -> "hsc(240deg 100% 100% / 0.5)"

Returns the CMYK color space object of a color.

blossom("#FFFFFF").cmyk; // -> { c: 0, m: 0, y: 0, k: 0, a: 1 }
blossom("#555AAA").cmyk; // -> { c: 50, m: 47, y: 0, k: 33, a: 1 }

Returns the CMYK color space string of a color.

blossom("#FFFFFF").toStringCMYK; // -> device-cmyk(0% 0% 0% 0%){ c: 0, m: 0, y: 0, k: 0, a: 1 }
blossom("#555AAA80").toStringCMYK; // -> device-cmyk(50% 47% 0 33% / 0.5)

Returns the CIE XYZ color space object of a color.

blossom("#FFFFFF").xyz; // -> { x: 95.047, y: 100, z: 108.883 a: 1 }
blossom({ x: 0, y: 0, z: 0 }).hex; // -> "#000000"

Returns the CIE XYZ color space string of a color.

blossom("#FFFFFF").toStringXYZ; // -> color(xyz 96.42 100 82.52)
blossom("#555AAA80").toStringXYZ; // -> color(xyz 13.65 11.79 29.83 / 0.5)

Returns the CIE LAB color space object of a color.

blossom("#FFFFFF").lab; // -> { l: 100, a: 0, b: 0, alpha: 1 }
blossom("#123ABC").lab; // -> { l: 29.95, a: 29.48, b: -72.93, alpha: 1 }

Returns the CIE LAB color space string of a color.

blossom("#FFFFFF").toStringLAB; // -> lab(100% 0 0)
blossom("#555AAA80").toStringLAB; // -> lab(40.88% 15.43 -44.4)

Returns the CIE LCH color space object of a color.

blossom("#FFFFFF").lch; // -> { l: 100, c: 0, h: 0, a: 1 }
blossom("#123ABC").lch; // -> { l: 29.95, c: 78.66, c: 292.01, alpha: 1 }

Returns the CIE LCH color space string of a color.

blossom("#FFFFFF").toStringLCH; // -> lch(100% 0 0)
blossom("#555AAA80").toStringLCH; // -> lch(40.88% 47.01 289.16 / 0.5)

Returns the HWB color space object of a color.

blossom("#FFFFFF").hwb; // -> { h: 0, w: 100, b: 0, a: 1 }
blossom("#123ABC").hwb; // -> { h: 226, w: 7, b: 26, a: 1 }

Returns the HWB color space string of a color.

blossom("#FFFFFF").toStringHWB; // -> hwb(0 100% 0%)
blossom("#555AAA80").toStringHWB; // -> hwb(236 33% 33% / 0.5)

Returns the name of the color as exact match of browser supported list of 140 named colors. If the color has not an alias returns null instead.

blossom("#FF0000").name; // -> "red"
blossom("#123ABC").name; // -> null

Returns the closest named color from browser supported list of 140 named colors color.

blossom("#FF0001").closestName; // -> "red"
blossom("#66339A").closestName; // -> "rebeccapurple"

Color manipulation

Changes the alpha channel value and returns a new Blossom instance.

blossom("rgb(0, 0, 0)")
  .setAlpha(0.5)
  .toStringRGB; // -> "rgb(0 0 0 / 0.5)"

Creates a new Blossom instance with an inverted color.

blossom("#aabbcc")
  .inverted
  .hex; // -> "#554433"

Increases the HSL saturation of a color by the given amount.

blossom("#bf4040")
  .saturate(0.25)
  .hex; // -> "#df2020"

blossom("hsl(0, 50%, 50%)")
  .saturate(0.5)
  .toStringHSL; // -> "hsl(0deg 100% 50%)"

Decreases the HSL saturation of a color by the given amount.

blossom("#df2020")
  .saturate(0.25)
  .hex; // -> "#bf4040"

blossom("hsl(0, 100%, 50%)")
  .saturate(0.5)
  .toStringHSL; // -> "hsl(0deg 50% 50%)"  

Creates a gray color with the same lightness as a source color. Same result as .desaturate(1).

blossom("#bf4040")
  .grayscale
  .hex; // -> "#808080"

blossom("hsl(0, 100%, 50%)")
  .grayscale
  .toStringHSL; // -> "hsl(0deg 0% 50%)"

Increases the HSL lightness of a color by the given amount.

blossom("#000000")
  .lighten(0.5)
  .hex; // -> "#808080"

blossom("#223344")
  .lighten(0.3)
  .hex; // -> "#5580aa"

blossom("hsl(0, 50%, 50%)")
  .lighten(0.5)
  .toStringHSL; // -> "hsl(0deg 50% 100%)"

Decreases the HSL lightness of a color by the given amount.

blossom("#ffffff")
  .darken(0.5)
  .hex; // -> "#808080"

blossom("#5580aa")
  .darken(0.3)
  .hex; // -> "#223344"

blossom("hsl(0, 50%, 100%)")
  .lighten(0.5)
  .toStringHSL; // -> "hsl(0, 50%, 50%)"

Changes the hue value and returns a new Blossom instance.

blossom("hsl(90, 50%, 50%)")
  .setHue(180)
  .toStringHSL; // -> "hsl(180deg 50% 50%)"

blossom("hsl(90, 50%, 50%)")
  .setHue(370)
  .toStringHSL; // -> "hsl(10deg 50% 50%)"

Increases the HSL hue value of a color by the given amount.

blossom("hsl(90, 50%, 50%)")
  .rotate(90)
  .toStringHSL; // -> "hsl(180deg 50% 50%)"

blossom("hsl(90, 50%, 50%)")
  .rotate(-180)
  .toStringHSL; // -> "hsl(270deg 50% 50%)"

Color properties

Returns a boolean indicating whether or not an input has been parsed successfully. On unsuccess, color value defaults to black without error.

blossom("#FFF").valid; // -> true
blossom("#NaN").valid; // -> false
blossom("hello").valid; // -> false
blossom({ r: 0, g: 0, b: 0 }).valid; // -> true
blossom({ r: 0, g: 0, v: 0 }).valid; // -> false

Returns an alpha channel value of the color.

blossom("#FFFFFF").alpha; // -> 1
blossom("rgba(50 100 150 / 0.5)").alpha; // -> 0.5

Returns a boolean indicating whether or not a color is opaque.

blossom("#FFFFFF").opaque; // -> true
blossom("rgba(50 100 150 / 0.5)").opaque; // -> false

Returns a boolean indicating whether or not a color is transparent.

blossom("#FFFFFF").transparent; // -> false
blossom("rgba(50 100 150 / 0.5)").transparent; // -> true

Returns the Hue value of the number on the color wheel.

blossom("hsl(90deg 50% 50%)").hue; // -> 90
blossom("hsl(-10deg 50% 50%)").hue; // -> 350

Returns the saturation value of the number.

blossom("hsl(90deg 50% 50%)").saturation; // -> 0.5
blossom("hsl(-10deg 98% 50%)").saturation; // -> 0.98

Returns the lightness value of the number.

blossom("hsl(90deg 50% 50%)").lightness; // -> 0.5
blossom("hsl(-10deg 50% 46%)").lightness; // -> 0.46

Returns the brightness of a color in range [0; 1]. The calculation logic is modified from Web Content Accessibility Guidelines.

blossom("#000000").brightness; // -> 0
blossom("#808080").brightness; // -> 0.5
blossom("#FFFFFF").brightness; // -> 1

A Boolean indicator whether or not a color is light (brightness >= 0.5).

blossom("#000000").light; // -> false
blossom("#808080").light; // -> true
blossom("#FFFFFF").light; // -> true

A Boolean indicator whether or not a color is dark (brightness < 0.5).

blossom("#000000").dark; // -> true
blossom("#808080").dark; // -> false
blossom("#FFFFFF").dark; // -> false

Returns the relative luminance of a color, normalized to range [0, 1] as from pure black to pure white according to WCAG 2.0.

blossom("#000000").luminance; // 0
blossom("#808080").luminance; // 0.22
blossom("#ffffff").luminance; // 1

Calculates a contrast ratio for a pair of colors.

The luminance difference lies in range [1 (white on white), 21 (black on white)]. WCAG required a ratio at least 4.5 for normal text and 3:1 for large one.

blossom("#000000").contrast(); // 21 (black on white)
blossom("#ffffff").contrast("#000000"); // 21 (white on black)
blossom("#777777").contrast(); // 4.47 (gray on white)
blossom("#ff0000").contrast(); // 3.99 (red on white)
blossom("#0000ff").contrast("#ff000"); // 2.14 (blue on red)

Checks that a background and text color pair is readable according to WCAG 2.0 Contrast and Color Requirements.

blossom("#000000").isReadable(); // true (normal black text on white bg conforms to WCAG AA)
blossom("#777777").isReadable(); // false (normal gray text on white bg conforms to WCAG AA)
blossom("#ffffff").isReadable("#000000"); // true (normal white text on black bg conforms to WCAG AA)
blossom("#e60000").isReadable("#ffff47", { level: "AAA" }); // false (normal red text on yellow bg does not conform to WCAG AAA)
blossom("#e60000").isReadable("#ffff47", { level: "AAA", size: "large" }); // true (large red text on yellow bg conforms to WCAG AAA)

Produces a mixture of two colors and returns the result as new Blossom instance. Mix produced using CIE LAB color space.

import { colord, extend } from "blossom";
import pluginMix from "@ericrovell/blossom/plugins/mix";

extend([ mixPlugin ]);

blossom("#FFFFFF").mix("#000000").hex; // -> "#777777"
blossom("#800080").mix("#DDA0DD").hex; // -> "#AF5CAE"
blossom("#CD853F").mix("#EEE8AA", 0.6).hex; // -> "#E3C07E"
blossom("#008080").mix("#808000", 0.35).hex; // -> "#50805D"

Calculates the perceived color difference between two colors. The difference calculated according to Delta E2000.

Returns the normalized value in range from [0, 1], where 0 means the same colors and 1 are completely different ones.

colord("#3296fa").delta("#197dc8") // 0.099
colord("#faf0c8").delta("#fff") // 0.148
colord("#afafaf").delta("#b4b4b4") // 0.014
colord("#000").delta("#fff") // 1.0

Color Utilities

Creates new instance with a random color.

import { random } from "@ericrovell/blossom";

random().hex; // -> "#01C8EC"
random().setAlpha(0.5).rgb; // -> { r: 13, g: 237, b: 162, a: 0.5 }

Plugins

Usage

To extend the functionality using plugins, the extend function should be used:

import { blossom, extend } from "@ericrovell/blossom";
import { plugin1, plugin2 } from "plugin-path;

extend([
  plugin1,
  plugin2
]);

Included plugins

Provides functionatity to generate harmony colors.

Available harmony pallets:

  • analogous;
  • complimentary;
  • double-split-comlimentary;
  • rectangle;
  • tetradic;
  • triadic;
  • split-complimentary;
import { blossom, extends } from "@ericrovell/blossom";
import { pluginHarmonies } from "blossom/plugins/harmonies";

extend([ pluginHarmonies ]);

const color = blossom("FF0000");

color.harmonies("analogous")
  .map(color => color.hex); // -> [ "#FF0080", "#FF0000", "#FF8000"]
color.harmonies("complimentary")
  .map(color => color.hex); // -> [ "#FF0000", "#00FFFF" ]
color.harmonies("double-split-complimentary")
  .map(color => color.hex); // -> [ "#FF0080", "#FF0000", "#FF8000", "#00FF80", "#0080FF" ]
color.harmonies("rectangle")
  .map(color => color.hex); // -> [ "#FF0000", "#FFFF00", "#00FFFF", "#0000FF" ]
color.harmonies("tetradic")
  .map(color => color.hex); // -> [ "#FF0000", "#80FF00", "#00FFFF", "#8000FF" ]
color.harmonies("triadic"  )
  .map(color => color.hex); // -> [ "#FF0000", "#00FF00", "#0000FF" ]
color.harmonies("split-complimentary")
  .map(color => color.hex); // -> [ "#FF0000", "#00FF80", "#0080FF" ]

Harmony color schemes type is available for import:

import type { Harmony } from "@ericrovell/blossom/plugins/harmonies";

const harmony: Harmony = "analogous";
const notHarmony: Harmony = "round"; // TypeError

Provides functionatity to generate monochromatic colors as:

  • Tints;
  • Shades;
  • Tones.
import { blossom, extends } from "@ericrovell/blossom";
import { pluginMonochromatic } from "blossom/plugins/monochromatic";

extend([ pluginMonochromatic ]);

const color = blossom("FF0000");

color.tints(4).map(tint => tint.hex); // -> [ "#FF0000", "#FF4242", "#FF8585", "#FFC7C7", "#FFFFFF" ]
color.shades(4).map(shade => shade.hex); // -> [ "#FF0000", "#BD0000", "#7A0000", "#380000", "#000000" ]
color.tones(4).map(tone => tone.hex); // -> [ "#FF0000", "#DF2020", "#BF4040", "#9F6060", "#808080" ]

The original color is always included as first palette item.

If there is not enough space between colors to generate required number of colors, less number of colors will be generated. For example, generating 10 shades for #050505 is not practical as #000000 is too close and all shades will be indistinguishable:

import { blossom, extends } from "@ericrovell/blossom";
import { pluginMonochromatic } from "blossom/plugins/monochromatic";

extend([ pluginMonochromatic ]);

blossom("#FAFAFA").tints(10).map(tint => tint.hex); // -> [ "#FAFAFA", "#FDFDFD", "#FFFFFF" ]
blossom("#050505").shades(10).map(shade => shade.hex); // -> [ "#050505", "#020202", "#000000" ]
blossom("#827D7D").tones(10).map(tone => tone.hex); // -> [ "#827D7D", "#817E7E", "#808080" ]

Adds accessibility and color contrast utilities working according to Web Content Accessibility Guidelines 2.0.

import { blossom, extend } from "@ericrovell/blossom";
import { pluginA11Y } from "@ericrovell/blossom/plugins/a11y";

extend([ pluginA11Y ]);

blossom("#000000").luminance; // 0
blossom("#CCDDEE").luminance; // 0.71
blossom("#FFFFFF").luminance; // 1

blossom("#000000").contrast(); // 21 (black on white)
blossom("#FFFFFF").contrast("#000000"); // 21 (white on black)
blossom("#0000ff").contrast("#FF000"); // 2.14 (blue on red)

blossom("#000000").readable(); // true (black on white)
blossom("#FFFFFF").readable("#000000"); // true (white on black)
blossom("#777777").readable(); // false (gray on white)
blossom("#E60000").readable("#FFFF47"); // true (normal red text on yellow bg conforms to WCAG AA)
blossom("#E60000").readable("#FFFF47", { level: "AAA" }); // false (normal red text on yellow bg does not conform to WCAG AAA)
blossom("#E60000").readable("#FFFF47", { level: "AAA", size: "large" }); // true (large red text on yellow bg conforms to WCAG AAA)

Adds support of CIE XYZ color model.

import { blossom, extend } from "@ericrovell/blossom";
import { pluginXYZ } from "@ericrovell/blossom/plugins/xyz";

extend([ pluginXYZ ]);

blossom("#FFFFFF").xyz; // -> { x: 95.047, y: 100, z: 108.883, a: 1 }
blossom({ x: 0, y: 0, z: 0 }).hex; // -> "#000000"

Adds support of CIE LAB color model. Plugin provides .delta method for perceived color difference calculations: 0 for same colors, 1 for completely different ones.

import { blossom, extend } from "@ericrovell/blossom";
import { pluginLAB } from "@ericrovell/blossom/plugins/lab";

extend([ pluginLAB ]);

blossom({ l: 29.95, a: 29.48, b: -72.93 }).hex; // "#123ABC"
blossom("#FFFFFF").lab; // { l: 100, a: 0, b: 0, alpha: 1 }

blossom("#afafaf").delta("#b4b4b4") // 0.014
blossom("#000").delta("#fff") // 1.0

Adds support of CIE LCH color model.

import { blossom, extend } from "@ericrovell/blossom";
import { pluginLCH } from "@ericrovell/blossom/plugins/lch";

extend([ pluginLCH ]);

blossom({ l: 29.95, a: 29.48, b: 40.21 }).hex; // "#6B372A"
blossom("#FFFFFF").lab; // { l: 100, c: 0, h: 0, a: 1 }

Adds support of HWB color model.

import { blossom, extend } from "@ericrovell/blossom";
import { pluginHWB } from "@ericrovell/blossom/plugins/hwb";

extend([ pluginHWB ]);

blossom({h: 236, w: 33, b: 33 }).hex; // "#555AAA"
blossom("#FFFFFF").hwb; // { h: 0, w: 100, b: 0 }

Adds support for mixing colors. Mixture is produced using CIE LAB color space.

import { colord, extend } from "blossom";
import pluginMix from "@ericrovell/blossom/plugins/mix";

extend([ mixPlugin ]);

blossom("#FFFFFF").mix("#000000").hex; // -> "#777777"
blossom("#800080").mix("#DDA0DD").hex; // -> "#AF5CAE"
blossom("#CD853F").mix("#EEE8AA", 0.6).hex; // -> "#E3C07E"
blossom("#008080").mix("#808000", 0.35).hex; // -> "#50805D"

Adds support for a list of 140 named colors supported by all modern browsers.

import { colord, extend } from "blossom";
import pluginNames from "@ericrovell/blossom/plugins/names";

extend([ pluginNames ]);

blossom("white").hex           // -> "#FFFFFF"
blossom("red").hex             // -> "#FF0000"
blossom("#FF0000").name        // -> "red"
blossom("#ABC123").name        // -> null
blossom("#FF0101").closestName // -> "red"
blossom("#66339A").closestName // -> "rebeccapurple"

Types

Blossom is written in strict TypeScript and ships with types in the library itself.

While not only typing its own functions and variables, you can also type yours. Depending on the color space you are using, the types can be also imported and used to type the code.

import type { ColorRGB, ColorHSL } from "@ericrovell/blossom";

const foo: ColorHSL = { h: 0, s: 0, l: 0 };
const bar: ColorRGB = { r: 0, g: 0, v: 0 }; // type error!

Extending the functionality

To extend functionality for your needs, just extend the Blossom class:

import { Blossom } from "@ericrovell/blossom";

class BlossomExtended extends Blossom {
  constructor(input?) {
		super(input);
	}

  get red() {
    return this.color.r;
  }
}

const extended = new BlossomExtended("#FF0000");
extended.red // -> 255;

Inspiration

It was a long time I was thinking about this project. There were two unsuccessfull attemps, it was not thoughfull enough.

This project is inspired by fantastic colord project, that gave me the idea about architecture and implementation.