JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 7
  • Score
    100M100P100Q63185F
  • License MIT

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

Package Exports

  • @ericrovell/blossom
  • @ericrovell/blossom/plugins/harmonies
  • @ericrovell/blossom/plugins/monochromatic

Readme

Blossom

Flower

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 (strings, objects);
  • HSL (strings, objects);
  • HSV (objects);
  • CMYK (objects).

API

Color parsing

blossom

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 });
getModel

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

.hex

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"
.rgb

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 }
.toStringRGB

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)"
.hsl

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 }
.toStringHSL

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)"
.hsv

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 }
.cmyk

Returns the CMYK color space object of a color.

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

Color manipulation

.setAlpha(value)

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)"
.inverted

Creates a new Blossom instance with an inverted color.

blossom("#aabbcc")
  .inverted
  .hex; // -> "#554433"
.saturate(amount = 0.1)

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%)"
.desaturate(amount = 0.1)

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%)"  
.grayscale

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%)"
.lighten(amount = 0.1)

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%)"
.darken(amount = 0.1)

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%)"
.setHue(value)

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%)"
.rotate(amout = 15)

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 analysis

.valid

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
.alpha

Returns an alpha channel value of the color.

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

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

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

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

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

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
.saturation

Returns the saturation value of the number.

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

Returns the lightness value of the number.

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

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
.light

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
.dark

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

Color Utilities

random()

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
]);

Developing plugins

To develop a custom plugin and extend library's functionality, the function should be created which integrates methods using prototype chain.

export const plugin = (BaseClass) =>  {
  BaseClass.prototype.newMethod = function() {
    // ...
  }
}

After that it should be provided as the parameter for extend function.

Developing plugins with TypeScript

To develop a plugin with TypeScript, module blossom should be declared with the Blossom interface described.

import { Plugin } from "@blossom/types";

declare module "blossom" {
  interface Blossom {
    newMethod(): void;
  }
}

export const pluginHarmonyColors: Plugin = (BaseClass): void =>  {
  BaseClass.prototype.newMethod = function() {
    // ...
  }
}

Included plugins

Harmonies

Provides functionatity to generate harmony colors.

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

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("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("splitcomplimentary")
  .map(color => color.hex); // -> [ "#FF0000", "#00FF80", "#0080FF" ]

Harmony color schemes is available as type:

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

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

Provides functionatity to generate monochromatic colors as:

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

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 { monochromatic } from "blossom/plugins/monochromatic";

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" ]

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 "blossom/types";

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

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.