color.whiten() not working #166
ageofabenius posted onGitHub
When I use color.whiten in-browser, I get no change to the color object. My test code below:
import Color from 'color';
let color = Color("#0099cc") console.log(color.hwb()) let newColor = Color(color).whiten(0.5) console.log(newColor.hwb()) let newColor2 = Color(color).blacken(0.5) console.log(newColor2.hwb())
I am seeing another issue where Color('#000000').whiten(anyValue)
is always returning absolute white instead of a shade of gray. Tested with 0, 0.01, 0.05, 0.1, 0.5, and 1.
Same issue here! @Qix- could you please look at https://github.com/Qix-/color/pull/167 ?
Quick note: Sorry for any spelling typos in this post. I'm in the process of learning German and it appears MacOS cannot handle two languages at once with spell check. This is what I see.
This has been my feedback for a number of "not working" issues, but I guess I'll re-form it here for the folks using the HWB color model and the associated methods (.whiten()
and .blacken()
).
Let me make it abundantly clear that .whiten()
and .blacken()
are working as intended. Please don't flame me before you read the rest of this comment, because it's starting to wear on me a bit as a maintainer.
HWB is a color model similar to HSV (the "H" means Hue, which is identical between the two cylindrical color models) with "whiten" and "blacken" channels. Basically, it takes a fully-saturated color (W=0, B=0
) and 'mixes' black and/or white to achieve varying degrees of lightness (W=0, B>0
or W>0, B=0
) or (de-)saturation (W>0, B>0
). A full grey (RGB 127, 127, 127
) is where W=100%, B=100%
; the Hue no longer has any significance in such a case.
Keep in mind, color
was designed to work with color models, and the methods exist to reflect that. The methods were not designed to reflect human-friendly operations per se. "Whiten" and "blacken" can mean very different things given the intended effect, color model and source color.
The problem here isn't with implementation, but with the intent of the API - color
is designed as a more "academic" library than a "end-user friendly" library; corrollary: color
's API is focused on manipulating color spaces in a mathematically correct way.
.whiten()
increases the white (W) channel of the HWB color by a ratio - that is, W += W * r
(where r
is the parameter to .whiten()
). Black does the same thing, just with the black channel. If you want to remove black from the black channel, you'd pass a negative parameter to the method.
If you check the source code, this is exactly what's happening. It is mathematically and academically correct behavior.
This is also why Color('#000000').whiten(n)
will still result in black - the White channel in the HWB color model is 0
for #000000
. Multiplying anything by zero is always zero, of course, and then adding zero to zero is - of course - zero, resulting in #000000
.
.whiten()
is working as intended.
If you print out the output from the OP, you'll see the White (W) channel of the color is 0
, but the Black (B) channel is not 0. This is why .blacken()
results in different color whereas .whiten()
does not.
These two methods are working entirely as intended.
Now, that's not to say something can't be improved here. I fully agree that the API methods are not intuitive to most people who do not care about the color theory behind the library (why else would you use this library instead of using color-convert
directly? 🙃)
However, the issue then becomes about the API naming conventions, not about the correctness of the mathematical methods. I'm very much open to having a discussion about the naming conventions used here because I fully understand there is some confusion with what this library does and what users are trying to do.
Please also keep in mind I'm not the original author of this library, and that even if I were, designing an API that is intuitive, just as powerful, mathematically sound and useful to a whole range of people (designers all the way to academics) is very, very difficult. It has been a problem with this library for a while and it's a problem I've been racking my brain on how to solve for years. Any input is appreciated.
As-is, this is a won't-fix. I know that's not the response you want to hear.
The two methods I would suggest looking into are .lighten()
, which works with the HSL model's Lightness (L) channel, or instead to color.mix()
the Color('white')
instead.
@Qix- Thanks for answer.
So, I see only one way to change brighteness independently current values - use lightness()
method.
let color = Color('rgb(255, 0, 0)');
color.lightness(); // 50
console.log(color.lightness(90).rgb().toString()) // rgb(255, 204, 204)
If your definition of "brightness" is the lightness channel in the HSL color model, then yes :) other people might think "brightness" means saturation.
Perhaps I should add a guide of common transformations to the readme.
Some more examples that demonstrate this were added to the readme.
You are indeed looking for lightness in this case. I'd also, again, recommend .mix()
as it might suit you as well.