Oklab color spaces - #335
Open
smelfungus wants to merge 4 commits into
Open
Conversation
HSL lightness is not perceived lightness: blue and yellow at 0.5 differ by more than 0.3 in Oklab L, which is why an HSL lightness slider does something visibly different at every hue. Okhsl and Okhsv fix that, and their saturation is measured against the sRGB gamut, so full saturation is reachable at every hue instead of running off the end of what the screen can show. Oklab and OkLCh come along for interpolation and for moving values in and out of CSS. This is a breaking change. PickerColor is a public sealed interface, so four new implementations stop any consumer's exhaustive `when` from compiling — hence 2.0.0 rather than 1.2.0. The saved-state format keeps its existing space keys, so a state persisted by 1.x still restores. Out-of-gamut Oklab and OkLCh go through the CSS Color 4 algorithm rather than either obvious alternative. Clamping each RGB channel shifts lightness and hue as a side effect, which is what the LAB path already does. Reducing chroma alone holds both but over-corrects badly on yellows, where the gamut surface curves away from the search line. The spec's binary search with local-MINDE clipping keeps the chroma that pure reduction throws away. Eight spaces would have meant sixty-four hand-written branches in the derived-state matrix, so conversions now route through RGB instead of being spelled out pairwise.
computeMaxSaturation declared eight uninitialized vals and filled them from a three-way if chain, which is how the C++ reference has to do it and not how Kotlin does. The coefficients are now three named constants picked by a when, so the branch says which channel clips first instead of assigning to eight names. The two grays in each of toOkhsl and toOkhsv were built twice from the same arguments, once per guard. Hoisting the construction turns both guards into single lines. The hue sliders built a whole gradient per coloring mode when the modes differ only in the saturation and lightness the strip is drawn at. Choosing that pair first also tightens the remember keys: Independent no longer rebuilds the track when the color's own saturation changes.
The eight derived views were the same four lines eight times over, differing only in the target type and the conversion — which is exactly `as? T ?: convert(...)` behind a reified parameter. Naming that collapses the block to one line per space, and the branch now reads as the type test it always was rather than an if. The helper is private and inlined, so nothing moves in either API dump.
ExperimentalKotlinGradlePluginApi is no longer required to opt into the Android target's compilerOptions block, and OkConversionsTest names OklabColor nowhere — it only reaches the type through toOklab().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.