Open-source project
glennwilton/jsColorEngine avatar
glennwilton/jsColorEngine

jsColorEngine: A Pure-JavaScript ICC Engine That Claims LittleCMS Parity

jsColorEngine is a color management engine using ICC profiles in 100% JavaScript.

41 stars7 forksJavaScriptMPL-2.0

At a glance

What is it?
jsColorEngine is a 100% JavaScript color management engine with optional WASM acceleration, claiming sub-LSB accuracy against LittleCMS and 3x speed over lcms-wasm. This review examines its architecture, real-world usage, and the caveats behind those numbers.
Who is it for?
Adopt jsColorEngine if you need ICC v2/v4 profile handling in a Node.js, browser, or headless environment where WebGL shaders are unavailable, and if you value a small footprint (~115 KB gzip) with no native bindings. Do not adopt it if you require guaranteed bit-identical output to LittleCMS across all workflows, as the README only promises 1 LSB accuracy on image-path LUTs and notes content-dependent performance.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 27 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Problem It Solves and Who It Is For

jsColorEngine targets a specific gap: doing ICC profile transforms in pure JavaScript, without WebGL or WebGPU shaders. The README positions it for headless prepress servers, containers, CI steps, and any environment where GPU acceleration is a non-starter. It handles RGB, CMYK, Lab, XYZ, and N-channel device spaces (5CLR to 15CLR), which is rare among JS color libraries. The intended user is a developer building color-accurate image pipelines in Node.js or the browser, who needs ICC v2 and v4 support, DeviceLink profiles, and multiple rendering intents. The project claims to be the fastest full ICC implementation in JavaScript, comparing itself directly to lcms-wasm, the only other comparable full ICC engine available to JS.

How It Works: Architecture and Data Flow

The engine is built around a single Transform object that exposes three methods: transform for single colors (microsecond calls, always LUT-free), array for typed arrays of image data, and transformImages for a worker pool. The core pipeline uses trilinear and tetrahedral interpolation for LUT-based profiles, and a matrix-shaper path for profiles like sRGB and AdobeRGB. A key design choice is the LUT-free mode: when buildLut is false, it walks a full f64 pipeline without LUT quantization, which the README says is for prepress and measurement where precision matters more than speed. The WASM path is inlined into the UMD bundle, so there is no separate fetch or sync init. The pixel cache is on by default for WASM RGB to 6CLR transforms, giving a ~10% boost on clean photos and up to 3.94x on solid colors, but it should be disabled for grainy images. This shows the engine is tuned for photographic content, not synthetic graphics.

Getting It Running: Install and Quick Start

Installation follows standard npm practice, though the README does not show the exact npm install command. The quick start is implied through the examples. To build the browser bundle, you run `npm run browser` once, then `npm run serve` to launch a sample server on port 8080. The samples include a live benchmark at /samples/bench/ that runs every lutMode against lcms-wasm in your browser with zero upload or telemetry. For production, the README highlights portable LUTs: you can bake a small JSON at deploy time and reconstruct a Transform at runtime using Transform.fromJSON(json), without needing the ICC profiles or rebuilding the pipeline. This is a concrete workflow for shipping color transforms to clients without licensing or distribution issues.

The Accuracy and Speed Claims: What to Scrutinize

The headline claims are bold: 100% of samples within 1 LSB of LittleCMS on image-path LUT workflows, and 3.1 to 3.6 times faster than lcms-wasm on every LUT workflow, measured single-threaded on an AMD Ryzen 7 7700X. The README is careful to say that absolute MPx/s figures depend on content, and it provides a benchmark harness so you can verify on your own hardware. The benchmark uses a photo with 5% noise added to stabilize results, because clean photos and solids swing with cache locality. This is a smart methodology but also a caveat: the speed advantage may not hold on your specific images. The accuracy claim is limited to image-path LUTs; LUT-free mode walks the full f64 pipeline, which may differ from LittleCMS in edge cases. The README does not claim bit-identical output, only within 1 LSB on a tested set.

Key Features and Limitations

The feature list is comprehensive: ICC v2 and v4 loading, built-in virtual profiles, black-point compensation, ΔE76 and ΔE2000, spectral and illuminant math, and custom pipeline stages. The N-channel support (5CLR to 15CLR) is a standout, as most JS color libraries stop at CMYK. However, the README also lists limitations, though the truncated text cuts off before detailing them. Based on the visible material, one limitation is that the pixel cache is only beneficial for WASM RGB to 6CLR transforms; for other paths it may add overhead. Another is that the performance ratios travel better than absolute numbers, so you cannot assume 80 to 120 MPx/s on your machine. The project has no homepage and a single maintainer (glennwilton), which raises questions about long-term support. The license is MPL-2.0, which is permissive for source use but has copyleft implications for modified files.

Alternative Approaches: Comparing to lcms-wasm and WebGL

The primary alternative is lcms-wasm, a WebAssembly port of LittleCMS. The README directly compares against it and claims jsColorEngine is 3.1 to 3.6 times faster on LUT workflows. The difference in approach is that lcms-wasm is a port of a C library, while jsColorEngine is written from scratch for how a JIT compiler handles numeric typed-array loops. This is a real architectural difference: the pure-JS kernels are optimized for V8's JIT, not for C semantics. The other alternative is using WebGL or WebGPU shaders for image transforms, which is fast but requires GPU access. jsColorEngine's value proposition is that it works on headless servers and CI steps where shaders are impossible. However, if you are already in a browser with GPU access, a shader-based approach might be simpler and faster, provided you can live with the platform lock-in.

Maintenance, Licensing, and Upgrade Cost

The project is actively maintained, with the last push in August 2026 and a recent v1.6.0 release. The release cadence is brisk: v1.4.4 in May, v1.5.0 in August, and v1.6.0 in the same month. This suggests ongoing development, but also a moving target. The license is MPL-2.0, which means you can use the library in proprietary software without paying, but any modifications to the source files must be released under MPL-2.0. This is a middle ground between MIT and GPL. The upgrade cost is low because the library has zero dependencies and a single UMD file, so updating is a matter of swapping the file. However, the API may change between minor versions, as evidenced by the addition of kernel modules and DeviceLink in v1.5.0. You should pin the version and review the changelog before upgrading.

Editorial conclusion

Adopt jsColorEngine if you need ICC v2/v4 profile handling in a Node.js, browser, or headless environment where WebGL shaders are unavailable, and if you value a small footprint (~115 KB gzip) with no native bindings. Do not adopt it if you require guaranteed bit-identical output to LittleCMS across all workflows, as the README only promises 1 LSB accuracy on image-path LUTs and notes content-dependent performance. Before committing, verify the benchmark harness yourself by running `npm run browser` and `npm run serve`, and check docs/LcmsComparison.md for the exact conditions. The real decision hinges on whether you can tolerate a young project with a single maintainer and a benchmark methodology that uses noise-added content to stabilize results.

Frequently asked questions

Where can I find color profiles to use with jsColorEngine?

The repository ships profiles with its samples, under samples/profiles/, next to the sample images and other assets. For your own pipeline the documented route is to bake a small JSON at deploy time and rebuild it with Transform.fromJSON(json), so no ICC profile has to be shipped at all.

Does jsColorEngine need WebGL, WebGPU or a GPU?

No. It runs on Node.js, in browsers, in Electron, in web workers and under React Native, with no native bindings, no compile step and no platform-specific binaries. WASM SIMD is the acceleration path, using the same kernel anywhere a WebAssembly engine runs.

How accurate is jsColorEngine compared with LittleCMS?

The README states that 100 percent of samples land within 1 LSB of the LittleCMS oracle across four tested workflows, with the large majority bit-identical. The conditions are in docs/LcmsComparison.md, and the in-browser bench under samples/bench/ repeats the comparison against lcms-wasm on your own hardware.

Is jsColorEngine a port of LittleCMS?

No. The README says a lot of the core concepts are lifted from LittleCMS, the reference open-source ICC engine, but the implementation is independent and was written for how a JIT compiler sees numeric typed-array loops. The deep dive folder holds V8 assembly walkthroughs of the kernels.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/glennwilton-jscolorengine.svg)](https://hysenlabs.com/projects/glennwilton-jscolorengine)