Skip to content

Color Wheel: OKLCH Sliders edit a color by lightness, chroma and hue - #7632

Open
dotCooCoo wants to merge 3 commits into
storytold:mainfrom
dotCooCoo:feat/color-wheel-oklch-sliders-v2
Open

dotCooCoo wants to merge 3 commits into
storytold:mainfrom
dotCooCoo:feat/color-wheel-oklch-sliders-v2

Conversation

@dotCooCoo

@dotCooCoo dotCooCoo commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #7602. Until #7602 merges, this diff also shows its commit; this pull request's own commits are f763b86fdc and 3608506214.

What and why

The Color Wheel panel menu gets OKLCH Sliders. Turning it on adds L, C and H rows under the wheel or the box. They edit the current color by the OKLCH lightness (0 to 100 %), chroma (0 to 100 % of 0.4) and hue (0 to 360°) of its display sRGB, with the percent references CSS Color 4 gives for oklch() (https://www.w3.org/TR/css-color-4/#specifying-oklab-oklch). The rows themselves are VectorCraft's own design.

  • Each track shows a color outside sRGB at the largest chroma that fits (the color a pick there stores) and dims it. A tick on the C track marks the largest chroma that fits at the current lightness and hue, and its tooltip says so.
  • A color outside sRGB keeps its L and H and takes that largest chroma.
  • A click gives a row the keyboard focus, and the arrow keys then step it; the rows report their names and values to screen readers.
  • A CMYK fill shows the OKLCH of its display color.
  • While the working RGB space is not sRGB, the rows are gray, the menu item cannot turn them on and its tooltip gives the reason, and ui.colorWheel {sliders: "oklch"} returns an error. The rows are also gray when there is no color to edit.

ui.colorWheel takes a sliders key (none or oklch) next to view and channel and returns all three. The choice is kept with the preferences, and a saved value this build cannot read falls back to the default without changing the other settings. color.convert {to: "oklch"} answers [L %, C, H°] of the color's display sRGB; a color outside sRGB (Lab, CMYK, or RGB in a wider working RGB space) is clipped to sRGB first. vectorcraft-color gets oklab.rs with the OKLCH conversions and max_chroma. It reuses srgb_to_oklab and oklab_to_srgb from crates/color/src/libraries.rs, and max_chroma bisects the sRGB edge as that file's oklch does (libraries.rs:138). The new strings have rows in every catalog, and crates/mcp/src/ui_catalog.rs is regenerated. docs/mcp.md, docs/control-protocol.md and docs/target-app-parity.md describe the option.

How it was tested

New tests: 6 in crates/color/src/oklab.rs (red against the OKLab matrices and back, the CSS examples, the 216 web colors round trip, grays, a chroma past the gamut, black, white and bad numbers), convert_to_oklch_answers_lightness_chroma_and_hue in the engine (red, a gray, a CMYK color and a Lab color outside sRGB), and 11 in crates/ui-egui/src/panels/tests_color_wheel.rs (the rows' values, a drag on L, keys and screen-reader actions, the dimmed tracks and the tick, a change of working space, a CMYK fill, the panel menu, the sRGB check, lenient reading of saved settings, and ui.colorWheel's sliders key). Each test was shown failing with the code under test broken. #7602's settings tests in tests_color_wheel_box.rs now expect the sliders key too.

  • cargo fmt --all -- --check
  • cargo clippy -p vectorcraft-color -p vectorcraft-engine -p vectorcraft-ui-egui -p vectorcraft-mcp --all-targets -- -D warnings
  • cargo test -p vectorcraft-color -p vectorcraft-engine -p vectorcraft-ui-egui -p vectorcraft-mcp: 12313 passed, 0 failed, 5 ignored
  • cargo xtask brands, cargo xtask layers, cargo xtask assets and cargo xtask ui-commands --check

The branch merges cleanly with main at 460d211995, and cargo check --tests of the four crates, the engine's colormgmt tests and cargo xtask ui-commands --check pass on the merged tree. With #7617, #7629 and #7630, which also build on #7602, it conflicts at the lines they all add to: the ui.colorWheel description (ui_commands.rs, the regenerated ui_catalog.rs and the docs), the panel menu and the box settings tests; with #7617 and #7630 also in state.rs, with #7629 and #7630 at the docs/target-app-parity.md line after #7602's, and with #7630 at the widgets.rs export list. Each resolution combines both sides.

Checklist

  • cargo xtask ci passes (fmt, clippy, tests, assets, brands, layers, wasm).
  • No panics in shipped code: no unwrap(), expect(), panic!, unreachable!, todo! or
    unimplemented! outside tests, and no unchecked indexing on data from files, parameters or
    messages. Errors are returned as Result and shown to the user
    (why and how).
  • Clean-room: nothing copied from Adobe products or GPL/AGPL code (AGENTS.md).
  • Every new asset has a row in ASSETS.md.

… color field and a channel strip

The Color Wheel panel's menu gains Wheel View and Box View, and Box
Channel with Hue, Saturation, Brightness, Red, Green and Blue while the
box shows. The box takes the wheel's place: a color field with a 22 pt
channel strip at its right. The field shows the other two components on
the Color Picker's axes (Hue: saturation across and brightness up; Red:
blue across and green up). A click or drag in the field sets those two,
and the strip sets the channel; a drag is one undo step, and picks go
through the same paint commands and color model rules as the wheel's.
With no color to edit, the field and the strip show no markers and read
0 to screen readers, as the wheel does.

ui.colorWheel {view?, channel?} sets the view and the channel and
returns them. Params that are not an object, another key or a value off
the list are an error and change nothing. Both settings are kept with
the preferences, and a saved value the build does not know reads as
that key's default without losing the other preferences.

The strip takes the arrow keys after a click and offers screen readers
its increment, decrement and set-value actions. The Color Picker's
channel slider uses the same widget, so it now takes the arrow keys and
offers those actions too. New strings have rows in the complete
catalogs, and docs/mcp.md and docs/control-protocol.md describe the
command.
The Color Wheel panel's menu gets OKLCH Sliders: L, C and H rows under the
wheel or the box that edit the color by the OKLCH lightness (0 to 100 %),
chroma (0 to 100 % of 0.4) and hue of its display sRGB, as CSS Color 4
defines them. Each track dims the colors outside sRGB, and a tick on the C
track marks the largest chroma that fits; a color outside sRGB keeps L and H
and takes that chroma. The rows are gray, and the menu item and
ui.colorWheel {sliders: "oklch"} are refused, while the working RGB space is
not sRGB. The choice is kept with the preferences.

- vectorcraft-color: oklab.rs with OKLCH conversions and max_chroma.
- color.convert {to: "oklch"} answers [L %, C, H°].
- ui.colorWheel takes sliders next to view and channel.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 26 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 676f052 and 3608506.

Files ignored due to path filters: 28

  • crates/ui-egui/src/i18n/bg.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/bs.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/ca.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/cs.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/da.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/de.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/el.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/es.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/fi.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/fr.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/gu.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/hi.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/hu.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/id.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/it.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/ja.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/ka.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/ko.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/nl.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/pl.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/pt-br.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/ru.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/sv.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/tr.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/uk.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/vi.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/zh-hans.tsv is excluded by !**/*.tsv
  • crates/ui-egui/src/i18n/zh-hant.tsv is excluded by !**/*.tsv
Files selected for processing: 20

  • crates/color/src/lib.rs
  • crates/color/src/oklab.rs
  • crates/engine/src/cmd/colormgmt.rs
  • crates/engine/src/tests/colormgmt.rs
  • crates/mcp/src/ui_catalog.rs
  • crates/ui-egui/src/dialogs.rs
  • crates/ui-egui/src/dialogs/color_picker.rs
  • crates/ui-egui/src/menus/run.rs
  • crates/ui-egui/src/menus/ui_commands.rs
  • crates/ui-egui/src/panels.rs
  • crates/ui-egui/src/panels/color_wheel.rs
  • crates/ui-egui/src/panels/tests_color_wheel.rs
  • crates/ui-egui/src/panels/tests_color_wheel_box.rs
  • crates/ui-egui/src/state.rs
  • crates/ui-egui/src/widgets.rs
  • crates/ui-egui/src/widgets/buttons.rs
  • crates/ui-egui/src/widgets/color.rs
  • docs/control-protocol.md
  • docs/mcp.md
  • docs/target-app-parity.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

- The C row's tick reads the slider's own rect, so it stays on the bar
  when the row is taller than the rail. `color_rail_bar` gives the bar
  for both the rail and the tick.
- The L and H tracks show a color outside sRGB at the largest chroma
  that fits, the color a pick there stores, instead of clamping each
  channel.
- The menu item uses `menu_item_hint`, which translates like
  `menu_item`, and `menu_item_name` is unchanged.
- `color.convert {to: "oklch"}` says that any color outside sRGB (Lab,
  CMYK, or RGB in a wider working RGB space) is clipped to sRGB first,
  with a test for a Lab color.
- docs/mcp.md wraps the new paragraph; gu.tsv puts the new rows where
  the other catalogs put them.

This branch has not been deployed

No deployments
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