lush.nvim icon indicating copy to clipboard operation
lush.nvim copied to clipboard

Add oklab and/or oklch functions

Open rmunn opened this issue 1 year ago • 2 comments

It would be nice to have oklab and/or oklch functions available, so that (for example) lightening a blue color doesn't automatically turn it purple. In https://github.com/rktjmp/lush.nvim/issues/154#issuecomment-2481905872 @rktjmp mentioned not being able to find a good Oklab Lua library last year, but that appears to have changed in the past year. Here are several projects that I found, all of which are relatively recent and didn't exist 12 months ago (I haven't used any of them so I can't comment on their suitability as libraries):

  • https://github.com/vgskye/oklua - brand new, 2 weeks old, just one commit, MIT license in files but no LICENSE.md file in repo
  • https://github.com/loganswartz/polychrome.nvim - MIT license, not a library but https://github.com/loganswartz/polychrome.nvim/tree/main/lua/polychrome/color has oklab.lua and oklch.lua files which could be extracted?
  • https://github.com/behreajj/AsepriteOkHsl - MIT license, also not a library but https://github.com/behreajj/AsepriteOkHsl/blob/main/ok_color.lua and https://github.com/behreajj/AsepriteOkHsl/blob/main/ok_hue_adj.lua could probably be extracted

None of these appear to be complete, just-use-this-library-and-you're-done solutions, but all three of them have enough pure-Lua functions in them that you might be able to just extract and use some of their code and get 80-90% of the way there.

rmunn avatar Nov 18 '24 06:11 rmunn

An implementation of this should include the color operations, or similar to, as defined in https://github.com/rktjmp/lush.nvim/blob/main/lua/lush/vivid/hsl_like.lua,

  • rotate
  • saturate (+ desaturate, impl -saturate)
  • lighten (+ darken, impl -lighten)
  • mix
  • to_rgb

When using oklch we have,

  • l for lightness, actually measuring perceived lightness/"brightness", which is explicitly called out as "not being the same as hsl's lightness on the mdn docs, but I don't think that matters for practical use as long as 0% is black and 100% is white.

  • c for chroma, which would reasonably map to saturation amount, 0 is gray and 0.4+ is near enough to "saturated".

  • h for hue, which maps conceptually 1:1 to the existing "rotate" in HSL.

oklab has less obvious mapping, and potentially might be simpler to just convert oklab -> oklch -> oklab to perform any operations, or just use oklch internally always.

  • l has the same lightness definition
  • a is a mix point between green and red
  • b is a mix point between yellow and blue

It's rotate could probably be figured by some vectors for a b + theta and saturation is I guess shifting both a, b values towards 0.

Other questions

  • Is it worth supporting oklab? To me oklch is more intuitively understandable with a lightness, chroma and hue value vs a and b mix points.
  • Probably it would also stand to have at least an explicit absolute chroma setter, like the hue setter for HSL.
  • Probably values should only be given as 0-100% (+ 0-360deg) to avoid the awkward -0.4 -> 0.4 a, b, c values unless its super common express colors in that format.
    • This implies we cap 100% at (-)0.4 when the colorspaces actually support greater values, but in practice I dont think this matters.

https://bottosson.github.io/posts/gamutclipping/, https://bottosson.github.io/posts/colorpicker/

rktjmp avatar Nov 18 '24 11:11 rktjmp

Yeah, oklch has obvious meanings for all three components (luminance, chroma, hue) whereas the A and B in oklab are pretty arbitrary. You will often want to make a color brighter or darker (change L), make it more saturated or move it towards gray (change chroma), or say "same brightness and saturation but rotate the hue by 15° to get a reddish-orange instead of red". So it's not worth implementing oklab, at least until/unless someone actually needs it. Operations in the oklch space are definitely more obvious.

I agree with expressing the numbers as 0-100%, probably as floats because you might want to, say, divide by 3 and you'd want 33.333(etc)% rather than rounding to 33%. That would mean it would be difficult to express absolute values in the ±0.4 range, but the documentation could say "If you are trying to copy a color that someone else has written in the -0.4 to 0.4 format, write it as (value / 0.4 * 100.0)" if someone really wants to do that.

But most people are probably going to want to express L and c as 0-100% values.

rmunn avatar Nov 18 '24 16:11 rmunn