Skip to content

Saturation/lightness plane - #334

Open
smelfungus wants to merge 2 commits into
masterfrom
feat/saturation-lightness-plane
Open

Saturation/lightness plane#334
smelfungus wants to merge 2 commits into
masterfrom
feat/saturation-lightness-plane

Conversation

@smelfungus

Copy link
Copy Markdown
Member

No description provided.

Every input in the library was a slider, so picking two channels took two gestures and there was no surface to drag across. This is the S+L plane from the #49 roadmap.

The surface is a horizontal grey-to-hue ramp under a white/transparent/black overlay rather than a computed bitmap, and that pair is exact rather than approximate: HSL at lightness L is the mid-lightness colour blended toward white by 2L-1 above the middle and toward black by 1-2L below it, which is what compositing the overlay does. Zero error across 43911 sampled points, and a rendering test pins the four corners in a real composition.

It does not mirror in right-to-left layouts, where every slider does. Saturation would grow leftwards on the plane while still growing rightwards on the hue slider beside it.

Both channels go through a single updateFromHsl, so a drag cannot disturb hue or alpha.

A two-dimensional drag has no linear screen-reader equivalent; the surface carries a label and both values, and the sliders remain the accessible path to the same channels.
The indicator was the one part of the plane that mirrored. `Modifier.offset` places relatively, so in a right-to-left layout the ring sat over grey at saturation 0.9 while the gradient and the pointer mapping stayed where they were, and tapping the ring threw the value to the far side. `absoluteOffset` alone does not settle it: the wrapping `Box` aligns to `TopStart`, which mirrors too and pushes the indicator clean off the surface. Placing from a `Layout` with `place` handles both, and drops the `onSizeChanged` state the offset needed to know how big the plane was.

The `thumb` slot sat in a wrapper fixed at `PlaneThumbSize`, so a larger replacement was squeezed back to 24dp and a smaller one was stranded in that wrapper's corner, 8dp off the value it marks. The wrapper now takes its size from what it holds.

The shape clipped the whole plane, indicator included. At a corner the rounding left about an eighth of the ring — the position where a picker most has to show where the colour came from. It clips the surface alone now, so the ring overflows the edge the way a slider thumb overflows its track.

The golden shifts by a few pixels of anti-aliasing around the ring. The placement arithmetic is the same; the indicator reaches it as a measured child rather than through an offset modifier.
@smelfungus smelfungus self-assigned this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant