mrkeyoor.com_
Tue 22 Sept 22:36 UTC
npmUtilsupdated 22 Sept 2026

@colordx/core review

@colordx/core 5.6.0 parses, converts, compares, mixes, and maps web colors, with OKLab and OKLCH available in the base package. Version 5.6 replaces regex-heavy parsing with character-code scanners and changes malformed-input rejection from quadratic to linear work. The base API also covers hex, RGB, HSL, gamut checks, immutable adjustments, and low-allocation channel converters. Less common formats and features, including named colors, Display-P3, Rec.2020, CIE Lab, CMYK, palettes, and contrast checks, live behind explicit plugin imports. Our browser build measured 29.8 KB minified and 8.9 KB gzipped when importing the whole package namespace.

Verdict

@colordx/core 5.6.0 installed in 1.4 seconds with 0 dependencies and gave our full-namespace browser build an 8.9 KB gzip cost, making it a credible pick for OKLCH authoring and gamut-aware UI tools. Use a narrower library for routine hex and RGB work, and pin the major while this young API keeps changing.

We installed it

Lab card: what happened when we installed @colordx/coreScreenshot of @colordx/core documentation
Install✓ · 1.4s1 package on disk · 2 MB
ImportESM import works · require() works · ESM package with exports map
Browser8.9 KBgzipped (29.8 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @colordx/core install cleanly?

Yes. In a fresh container with an empty cache, npm install @colordx/core finished in 1 seconds, leaving 1 package and 2 MB on disk. npm audit reported no known vulnerabilities.

How much does @colordx/core add to a browser bundle?

8.9 KB gzipped (29.8 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @colordx/core work with both ESM and CommonJS?

Yes. Both import '@colordx/core' and require('@colordx/core') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does @colordx/core include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@colordx/core or colord: which should you use?

colord: Choose it for common web-color work with a smaller core and a mature opt-in plugin API. @colordx/core 5.6.0 installed in 1.4 seconds with 0 dependencies and gave our full-namespace browser build an 8.9 KB gzip cost, making it a credible pick for OKLCH authoring and gamut-aware UI tools.

When should you not use @colordx/core?

You only parse hex and RGB or make an occasional lightness change. The plugin registration model, gamut choices, and broad conversion API add concepts that colord or tinycolor2 can avoid.

API stability2/5The current factory, immutable instance methods, plugin entry points, and conversion names form a consistent 5.x API, and the package exposes separate import and require targets. Its release record is much less settled: npm shows major versions 2.0.0 through 5.0.0 arriving between March 26 and March 29, 2026. Version 5.6.0 then rewrote parser internals in August. Semantic releases identify the breaks, but a broad major upgrade deserves a changelog review and conversion snapshots.
Docs4/5The README gives executable examples for parsing, precision, immutable edits, every bundled plugin, sRGB versus wide-gamut output, and buffer-reusing conversion functions. It also documents the important distinction between clipping and CSS Color 4 gamut mapping with concrete outputs. The weak spot is drift inside the same document: the roadmap still lists some A98 and ProPhoto string support even though plugin sections describe parts of those spaces, so edge syntax should be checked against tests or release notes.
Maintenance5/5GitHub reports an unarchived repository pushed on August 21, 2026, with 117 stars and 0 open issues or pull requests. Release 5.6.0 shipped that day and contains a specific parser-throughput change plus a linear-time fix for malformed strings. Releases in April and June added precision fixes and A98/ProPhoto plugins, showing regular work across correctness and features. The activity is strong, though the repository's small issue count should not be read as proof of a large maintainer bench.
Ecosystem4/5npm counted 4,665,948 downloads in the latest completed week, while GitHub reports 117 stars. The package serves ESM, CommonJS, and TypeScript consumers, and its own subpath plugins cover accessibility, names, mixing, minification, harmonies, CMYK, and several wide-gamut spaces. That is a wide first-party surface. Third-party extensions are not the center of the design, and the shared extend() mechanism means integrations generally follow the repository's plugin catalogue rather than an independent ecosystem.

Use it if

  • You author design tokens or color pickers in OKLCH and need a stated choice between sRGB clipping and chroma-reducing gamut mapping.
  • A canvas, gradient editor, or chart processes enough pixels to benefit from the documented channel converters and caller-owned *Into buffers.
  • Your application needs one typed API for sRGB plus optional Display-P3, Rec.2020, A98 RGB, ProPhoto RGB, Lab, LCH, HSV, HWB, or CMYK support.
  • You want immutable color objects, zero direct dependencies, bundled declarations, and entry points that load through both import and require.
Skip it if

Setup reality

We installed @colordx/core 5.6.0 in a fresh Node 22 Bookworm sandbox. npm finished in 1.4 seconds and left one package using 2 MB on disk. The published package is 1228 KB unpacked, declares 0 direct and 0 peer dependencies, and produced 0 npm audit findings. It ships TypeScript declarations and an exports map; both require() and ESM import worked in our checks. A namespace browser build measured 29.8 KB minified and 8.9 KB gzipped.

Core parsing needs no credentials or config file. Hex, RGB, HSL, OKLab, and OKLCH work after importing colordx. Named colors and the other optional spaces require importing their subpath plugin and calling extend([plugin]) before any dependent parsing or instance method. Put that registration in one bootstrap module. If two test files load different plugin sets into the same process, they share the extended class surface.

Channel scales are easy to cross: RGB objects use 0 to 255, alpha uses 0 to 1, HSL percentages use 0 to 100, and OKLCH lightness uses 0 to 1. Lab and OKLab objects also have similar field names. The Lab and LCH plugins require their documented colorSpace discriminator where shapes would otherwise collide. Check isValid() before converting user input because unsupported CSS syntax does not become valid merely because a browser accepts it.

OKLCH values remain available outside sRGB until serialization. toHex() and toRgbString() clip to screen bytes, mapSrgb() reduces chroma to hold lightness and hue more closely, and clampSrgb() returns an object describing the clipped result. In pixel loops, *Into functions reuse a Float64Array(3); functions returning linear and gamma output require 2 different buffers. Version 5.6.0 speeds parser dispatch and makes rejection of long malformed strings linear, which matters most at untrusted-input boundaries.

Patterns

Reject an unsupported color before conversion validate-and-normalize

import { colordx } from '@colordx/core';

const color = colordx(input);
if (!color.isValid()) throw new TypeError('Unsupported color');
const hex = color.toHex();

isValid() catches input outside the registered parsers. Version 5.6.0 makes rejection of long malformed strings linear rather than quadratic.

Read one color in several base formats convert-core-formats

const color = colordx('#3d7a9f');

const rgb = color.toRgb();
const hsl = color.toHslString();
const oklch = color.toOklch();

toRgb() returns 0 to 255 channels, while OKLCH lightness and alpha use 0 to 1. Keep those scales explicit at API boundaries.

Serialize RGB for an older consumer format-legacy-rgb

const color = colordx({ r: 255, g: 0, b: 0, alpha: 0.5 });
const modern = color.toRgbString();
const legacy = color.toRgbString({ legacy: true });

legacy: true emits comma syntax and rgba() when alpha is below 1. The default uses current CSS space and slash syntax.

Keep the source color while deriving a variant chain-immutable-edits

const source = colordx('#3d7a9f');
const variant = source.lighten(0.08).rotate(18).alpha(0.85);

console.log(source.toHex(), variant.toHex());

Adjustment methods return a new instance. Ignoring the returned value leaves source unchanged.

Compare absolute and proportional lightening choose-relative-lightness

const dark = colordx('#1a0000');
const absolute = dark.lighten(0.1);
const proportional = dark.lighten(0.1, { relative: true });

Absolute mode adds 10 percentage points. relative: true adds 10 percent of the current lightness, which is a smaller change on dark colors.

Preserve hue when reducing an OKLCH color map-oklch-to-srgb

import { colordx, inGamutSrgb } from '@colordx/core';

const color = colordx('oklch(0.5 0.4 180)');
const output = inGamutSrgb(color.toOklchString())
  ? color
  : color.mapSrgb();
console.log(output.toHex());

toHex() clips out-of-gamut channels. mapSrgb() reduces chroma to keep lightness and hue closer to the authored OKLCH value.

Register Display-P3 parsing once enable-display-p3

import { colordx, extend } from '@colordx/core';
import p3 from '@colordx/core/plugins/p3';

extend([p3]);
const css = colordx('color(display-p3 0.92 0.2 0.14)').toP3String();

P3 instance methods and P3 string parsing appear only after extend([p3]) runs. Registration affects the shared Colordx surface for that process.

Interpolate a midpoint in Oklab mix-in-oklab

import { colordx, extend } from '@colordx/core';
import mix from '@colordx/core/plugins/mix';

extend([mix]);
const midpoint = colordx('#000').mixOklab('#fff', 0.5).toHex();

mix() uses sRGB interpolation. Call mixOklab() when the midpoint should follow a perceptually uniform space.

Evaluate text contrast with the accessibility plugin check-wcag-contrast

import { colordx, extend } from '@colordx/core';
import a11y from '@colordx/core/plugins/a11y';

extend([a11y]);
const passes = colordx('#333').isReadable('#fff');

The default checks AA normal text. Pass the documented level and size options when your policy uses a different WCAG 2.x threshold.

Add named-color parsing parse-css-color-name

import { colordx, extend } from '@colordx/core';
import names from '@colordx/core/plugins/names';

extend([names]);
const hex = colordx('rebeccapurple').toHex();

CSS names are absent from the base parser. Load the names plugin before parsing them or asking an instance for toName().

Minify a color with optional names pick-shortest-css-color

import { colordx, extend } from '@colordx/core';
import minify from '@colordx/core/plugins/minify';
import names from '@colordx/core/plugins/names';

extend([minify, names]);
const css = colordx('#ff0000').minify({ name: true });

name: true depends on the names plugin. The minifier compares valid representations and uses a name only when it is shorter.

Convert pixels without allocating each tuple reuse-pixel-buffer

import { oklchToRgbChannelsInto } from '@colordx/core';

const rgb = new Float64Array(3);
for (const [l, c, h] of pixels) {
  oklchToRgbChannelsInto(rgb, l, c, h);
  writePixel(rgb);
}

The function may return channels outside 0 to 1 for an out-of-gamut color. Clamp before byte encoding, and reuse a Float64Array(3) only where profiling justifies the lower allocation rate.

Alternatives

PackageRegistryPick it when
colordnpmChoose it for common web-color work with a smaller core and a mature opt-in plugin API.
culorinpmChoose it when functional composition, many color spaces, interpolation modes, and color-science transforms matter more than a chainable object.
chroma-jsnpmChoose it for established data-visualization scales, domains, bezier palettes, and class breaks.
tinycolor2npmChoose it for older applications that need familiar RGB, HSL, HSV, and named-color handling without modern gamut tooling.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.