Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions src/color/p5.Color.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ class Color {
// where if we `import { Color }` directly, it will be a separate copy of the
// Color class from the one imported in the main p5.js bundle.
isColor = true;
#rgbaCache = new Map();

#invalidateRGBACache() {
this.#rgbaCache.clear();
}

// Used to add additional color modes to p5.js
// Uses underlying library's definition
Expand Down Expand Up @@ -241,6 +246,7 @@ class Color {
this._initialize();
this._initialize = undefined;
}
this.#invalidateRGBACache();
this._cachedColor = newColor;
}

Expand Down Expand Up @@ -559,6 +565,7 @@ class Color {

if(this.mode === RGB || this.mode === RGBP3){
this._color.coords[0] = newval;
this.#invalidateRGBACache();
}else{
// Will do an imprecise conversion to 'srgb', not recommended
const space = this._color.space.id;
Expand Down Expand Up @@ -611,6 +618,7 @@ class Color {

if(this.mode === RGB || this.mode === RGBP3){
this._color.coords[1] = newval;
this.#invalidateRGBACache();
}else{
// Will do an imprecise conversion to 'srgb', not recommended
const space = this._color.space.id;
Expand Down Expand Up @@ -663,6 +671,7 @@ class Color {

if(this.mode === RGB || this.mode === RGBP3){
this._color.coords[2] = newval;
this.#invalidateRGBACache();
}else{
// Will do an imprecise conversion to 'srgb', not recommended
const space = this._color.space.id;
Expand Down Expand Up @@ -715,33 +724,45 @@ class Color {
const newval = map(new_alpha, max[0], max[1], colorjsMax[0], colorjsMax[1]);

this._color.alpha = newval;
this.#invalidateRGBACache();
}

_getRGBA(maxes=[1, 1, 1, 1]) {
const cacheKey = maxes.join(',');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxes.join(',') allocates a new string on every call inside loops. Using a fast path key check for [255, 255, 255, 255] avoids string allocations during pixel loops.

if (this.#rgbaCache.has(cacheKey)) {
return [...this.#rgbaCache.get(cacheKey)];
}

// Get colorjs maxes
const colorjsMaxes = Color.#colorjsMaxes[RGB];

// Normalize everything to 0,1 or the provided range (map)
let coords = structuredClone(to(this._color, 'srgb').coords);
coords.push(this._color.alpha);

const rangeMaxes = maxes.map((v) => {
const rangeMaxes = maxes.map(v => {
if(!Array.isArray(v)){
return [0, v];
}else{
return v;
}
});

coords = coords.map((coord, i) => {
let coords;
if (this.mode === RGB) {

@Ayush4958 Ayush4958 Jul 27, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this._color.space.id === 'srgb' instead of this.mode === RGB makes the fast-path work for any color object backed by sRGB. It ensures that any color whose underlying color space is sRGB will bypass colorjs conversion and structuredClone, even if the color mode was initialized via another path.

coords = [...this._color.coords, this._color.alpha];
} else {
// Normalize everything to 0,1 or the provided range (map)
coords = structuredClone(to(this._color, 'srgb').coords);
coords.push(this._color.alpha);
}

const result = coords.map((coord, i) => {
return map(
coord,
colorjsMaxes[i][0], colorjsMaxes[i][1],
rangeMaxes[i][0], rangeMaxes[i][1]
);
});

return coords;
this.#rgbaCache.set(cacheKey, result);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this Map(). The only heavy step is the 'srgb' conversion you did above, so we can just cache that part, less complexity and cleaner code.

return result;
}

_getMode() {
Expand Down