Generate perceptually uniform color scales from any CSS color — like Tailwind's palette, for any color you choose.
npm install hueforge
# or
yarn add hueforge
# or
pnpm add hueforgeimport { colorScale } from "hueforge";
colorScale("#3b82f6");
// {
// 50: "#f0f6ff",
// 100: "#dbeafe",
// 200: "#bfdbfe",
// 300: "#93c5fd",
// 400: "#60a5fa",
// 500: "#3b82f6", ← your color
// 600: "#2563eb",
// 700: "#1d4ed8",
// 800: "#1e40af",
// 900: "#1e3a8a",
// 950: "#172554"
// }colorScale("#e11d48") // hex
colorScale("#f43") // shorthand hex
colorScale("rgb(225, 29, 72)") // rgb
colorScale("rgba(225, 29, 72, 1)") // rgba
colorScale("hsl(346, 77%, 50%)") // hsl
colorScale("hsla(346, 77%, 50%, 1)") // hsla
colorScale("oklch(0.55 0.22 15)") // oklch
colorScale("red") // named CSS color (browser only)By default colorScale returns hex strings. Pass a second argument to change the format:
colorScale("#e11d48", "hex") // → "#f43f6e"
colorScale("#e11d48", "rgb") // → "rgb(244, 63, 110)"
colorScale("#e11d48", "hsl") // → "hsl(346, 89%, 60%)"
colorScale("#e11d48", "oklch") // → "oklch(0.6463 0.2043 14.87)"Pass a third argument to control which steps are generated. Steps are numbers in the range 50–950 and map to positions on the light-to-dark scale (50 = lightest, 950 = darkest).
// Only generate a few steps
colorScale("#3b82f6", "hex", [100, 500, 900]);
// { 100: "#dbeafe", 500: "#3b82f6", 900: "#1e3a8a" }
// Denser scale
colorScale("#3b82f6", "hex", [50, 100, 150, 200, 300, 400, 500]);
// Single step
colorScale("#3b82f6", "hex", [500]);
// { 500: "#3b82f6" }Duplicate steps are silently deduplicated. Steps outside 50–950 are clamped to the nearest end of the scale.
export type ColorFormat = "hex" | "rgb" | "hsl" | "oklch";
export type ColorScale = {
50: string; 100: string; 200: string; 300: string;
400: string; 500: string; 600: string; 700: string;
800: string; 900: string; 950: string;
};
// Default steps → fully typed ColorScale
function colorScale(input: string, returnFormat?: ColorFormat): ColorScale;
// Custom steps → Record keyed by the step numbers you passed
function colorScale(input: string, returnFormat: ColorFormat, steps: readonly number[]): Record<number, string>;All conversion helpers are exported for direct use.
Parses any supported CSS color string into an [r, g, b] tuple (0–255).
import { parseColor } from "hueforge";
parseColor("#3b82f6") // [59, 130, 246]
parseColor("rgb(59, 130, 246)") // [59, 130, 246]
parseColor("hsl(217, 91%, 60%)") // [59, 130, 246]Converts a hex color string (#rrggbb or #rgb) to an [r, g, b] tuple.
import { hexToRgb } from "hueforge";
hexToRgb("#3b82f6") // [59, 130, 246]
hexToRgb("#f00") // [255, 0, 0]Converts HSL values to an [r, g, b] tuple. h is 0–360, s and l are 0–100.
import { hslToRgb } from "hueforge";
hslToRgb(217, 91, 60) // [59, 130, 246]Converts OKLCH values to an [r, g, b] tuple. l is 0–1, c is chroma (typically 0–0.4), h is 0–360.
import { oklchToRgb } from "hueforge";
oklchToRgb(0.6239, 0.1752, 255.4) // [59, 130, 246]Converts an [r, g, b] tuple (0–255) to OKLCH.
import { rgbToOklch } from "hueforge";
rgbToOklch(59, 130, 246) // [0.6239, 0.1752, 255.4]Converts an [r, g, b] tuple (0–255) to a hex color string.
import { rgbToHex } from "hueforge";
rgbToHex(59, 130, 246) // "#3b82f6"Converts an [r, g, b] tuple (0–255) to an HSL color string.
import { rgbToHslString } from "hueforge";
rgbToHslString(59, 130, 246) // "hsl(217, 91%, 60%)"Formats an [r, g, b] tuple into any supported output format.
import { formatColor } from "hueforge";
formatColor(59, 130, 246, "hex") // "#3b82f6"
formatColor(59, 130, 246, "rgb") // "rgb(59, 130, 246)"
formatColor(59, 130, 246, "hsl") // "hsl(217, 91%, 60%)"
formatColor(59, 130, 246, "oklch") // "oklch(0.6239 0.1752 255.40)"Scales are generated in the OKLCH color space — the same perceptually uniform space used by Tailwind CSS v4 and Radix UI. This means:
- Step 50 is pure white with the barest hint of hue
- Step 500 matches your input color
- Step 950 is a very dark shade
- Lightness and chroma follow independent power curves so each step feels evenly spaced to the human eye — no muddy mid-tones or grey-ish extremes
MIT © Naxrul Ahmed