Skip to content

#79 Color Mixer: all HSL bands per tab and a weighted image-drag pipette - #98

Merged
yojen7 merged 25 commits into
mainfrom
claude/hopeful-goodall-fncu51
Oct 4, 2026
Merged

yojen7 merged 25 commits into
mainfrom
claude/hopeful-goodall-fncu51

Conversation

@yojen7

@yojen7 yojen7 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Closes #79

Expanded Color Mixer provides Hue, Saturation and Luminance tabs with all eight bands. Its global pipette samples a 16-screen-pixel square and weights a vertical drag across the sampled bands; Alt gives fine steps. A changed drag creates one undo step, while a click writes nothing. Mask panels do not offer the pipette.

Local integration matches the current shader: linear RGB is used for the near-black/neutral gate, then encoded sRGB is used for perceptual HSV band weights. A yellow (255, 200, 0) sample now predominantly affects Yellows. Disabling the global Color panel or Color Mixer ends an active drag and clears the picker. WGPU/JPEG selection, image-switch cancellation, typed-field flushing and listener cleanup are retained. Native readback rejects an unrendered display instead of panicking. No shader or adjustment-default changes.

Integrated with current main and #128/#106/#98; merge preceding verified branches first.

Source

  • Original work for RapidRoom
  • Harvested from lalibertemarc/RapidRAW, by marclaliberte: b5475ad8, dffc46a1, 17173f28. Original authorship, source trailers and CREDITS.md retained. Author contact remains a maintainer decision.
  • rapidroom/changes.json and generated docs updated.
  • Also offered upstream.

How it was made

  • Written by an AI agent: original cloud integration by Claude; local integration, sampler/visibility fixes, tests and verification by Codex. Original fork authorship and Claude assistance trailers retained.
  • Mostly AI-generated, reviewed and edited by a human
  • Written by a human with AI help
  • Written without AI

Who answers review: Yojen with Codex; maintainers decide.

Testing

  • fmt, strict locked all-target/all-feature Clippy, 230 Rust tests (3 pre-existing ignored), 112 Vitest tests, generated-doc check and locked release build pass.
  • TypeScript: same 46 baseline errors; scoped ESLint: 179 to 177 findings. No new diagnostics; scoped Prettier passes.
  • Eleven focused HSL helper/gesture tests cover neutral rejection, perceptual weights, one-step undo, no-op clicks, Alt, image switching, picker cleanup and disabling either parent or mixer during a drag.
  • 60/60 default renders pixel-identical to approved baseline-int7, same Intel xe / Mesa 26.2.2 / Linux 7.2.5 environment. No baseline/tolerance change. Engine SHA-256 7b3f9aed0791bd129e56a4f38b891f0caa23d9f260e2a5cb6fd0877d91449bd8.
  • Tested by a human in the running app
  • Default rendering unchanged by full-corpus comparison.

Hosted checks must pass for this exact head before merge. Mouse/touch interaction, cropped/rotated/zoomed images, WGPU and JPEG fallback, typed number fields, one Ctrl+Z per drag, hidden tools and platform Alt behavior still need desktop checks in #63. Unit tests exercise mocked UI/readback behavior; no desktop screenshots or visual picker validation claimed.

Local logs, comparison JSON and manifest remain in /tmp/rapidroom-codex-98/; temporary corpus TIFFs removed.

lalibertemarc and others added 25 commits October 4, 2026 00:55
Add an expanded Color Mixer view with Hue / Saturation / Luminance tabs,
each showing all eight band sliders, plus a pipette for the global mixer.
Press on the photo and drag up or down: every band present in the sampled
area moves in proportion to its presence (dominant band 0.5 pt/px, Alt for
fine control), mirroring the shader's band weighting.

With the WGPU renderer the sample is read back from the displayed output
texture via a new sample_display_area command; otherwise the JPEG preview
is sampled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b5475ad8e3176386153d8c3a8fbdc7d21ba7c5a9)
Remove the accent ring on the bands driven by the mixer pipette to keep
the expanded view clean, along with the store state that fed it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dffc46a161f6a9c35037348d9d62b1a5267a99ac)
Mixer sliders eased every external value change over 300 ms, so while the
pipette drove them the thumbs trailed the mouse. Add an
animateValueChanges prop to Slider (reusing the wheel path that already
skips the easing) and turn it off for mixer sliders during a pipette
drag. Also apply pipette moves directly instead of deferring them to the
next animation frame, since mousemove is already frame-aligned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 17173f2873b44f4f7d5f219df1e5e744b3e0dfa9)
…ching (#79)

Adapts the harvested expanded Color Mixer and targeted pipette
(from lalibertemarc/RapidRAW@17173f2) to RapidRoom:

- Weight bands in linear RGB. RapidRoom's mixer derives hue and
  saturation from linear RGB (the fork's base also has the perceptual
  hue change, which RapidRoom doesn't), so the sRGB preview sample is
  linearised before it is weighted.
- Read the WGPU display texture only when the canvas is actually drawn
  by WGPU, and otherwise the JPEG preview, instead of deciding by
  whether a preview URL happens to be set.
- A drag is one undo step: moves update the editor state directly and
  history is recorded once on release, only if a value changed.
- The preview sample never writes edits by itself: nothing is applied
  until the drag moves a value.
- End the drag if the image changes or the window loses focus, and
  commit a slider number field still being typed in before the drag
  takes its starting values.
- Turn the pipette off when the global Color panel unmounts.
- Return an error instead of panicking when the display has no
  rendered image yet.

HSL math, adjustment defaults and the render path are unchanged.

Co-authored-by: marclaliberte <laliberte.marc1@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016CdHB9AnmKmLftMu3oha5D
The Color panel eye bypasses every color tool at once. Color Grading and
Color Mixer now get their own eye toggle, stored per image and per mask
as sectionVisibility.colorGrading / colorMixer (default on, so existing
sidecars render unchanged). The renderer applies each only when both
the Color panel and the tool are visible. Resetting or pasting a section
re-enables its tool toggles.

The eye button is extracted into a shared VisibilityToggle used by both
CollapsibleSection and AdjustmentSubSection, and the Rust section
visibility lookup is shared between the global and mask builders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 879b4146fa4d87ecfa3580261cfc0554ffb1555f)
A sectionVisibility object without the new colorGrading/colorMixer keys
(an older or partial one) made the first eye click a no-op, because
!undefined is true.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SHAmUdMPzKcgwDMEftFCrN
L cycles Normal -> Dim -> Black, Shift+L cycles backward (both
configurable). Escape restores normal lighting before its existing
action. Dim fades the surrounding chrome to black; Black hides it,
flattens the layout and puts the window in fullscreen until Lights Out
is turned off again. The photo, thumbnails and editing overlays are not
dimmed, and exports are unaffected.

(from zeromeridian/RapidRAW-Enhanced@69bdb28)

Adapted for RapidRoom's panel layout:
- Dim uses opacity on the chrome instead of a CSS filter, so fixed
  popovers inside panels keep their positioning.
- Backgrounds go black through the components and the wgpu clear
  colours, so the transparent wgpu preview area is never painted over.
- Toggle folder tree moves from L to N; RapidRoom already bound L to it.
- Lights Out only cycles in the library and editor views; the window
  fullscreen switch is skipped on Android.
- Catalan and Dutch strings added; tests for the cycle and for
  duplicate default shortcuts.
- Dropped the donor's FEATURES.md, RELEASE_NOTES.MD and tauri.conf.json
  version change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WKn2QWXeYf2rr2z39dZggU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WKn2QWXeYf2rr2z39dZggU
Absent or partial sectionVisibility must produce byte-identical uniforms
to an explicit all-on one, for global and mask adjustments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SHAmUdMPzKcgwDMEftFCrN
Retain all change/credit entries and both color-visibility and pixel-format conversion test modules.
Give the shared eye button a translated accessible label and pressed state; reveal focused eyes in subsection and section headers.

Co-authored-by: marclaliberte <laliberte.marc1@gmail.com>
Retain Reference View, pick/reject badges and shortcut tests, workspace migration coverage and all existing change/credit rows.
…lidation

Retain the read-only importer, all credits and change entries; validate the full stacked source before pushing or merging.
Complete restoration before capturing a new Black session; preserve existing fullscreen and recover from failed native requests. Add six asynchronous behavioral tests for cancelled entry, entry/restore races and failures.

Co-authored-by: Emil Zimmermann <emil@zeromeridian.biz>
Keep shared migration controls and regenerated status docs; validate the combined source before pushing.
Keep both photos visible while dimming or hiding reference labels, chooser controls and the active-image badge; use black around the reference photo when Lights Out is enabled.
Keep the shader linear-RGB neutral gate, then derive hue and saturation after sRGB encoding. Correct the yellow/orange sample case and cover nearly black neutral pixels. No shader or rendering defaults change.

Co-authored-by: marclaliberte <laliberte.marc1@gmail.com>
Co-Authored-By: marclaliberte <laliberte.marc1@gmail.com>
@yojen7

yojen7 commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

Verified and merged as e85f2000 by Yojen following the maintainer queue; local adaptation and verification by Codex.

  • 230 Rust tests pass (3 pre-existing ignored), 112 Vitest tests, fmt, strict locked all-target/all-feature Clippy, generated docs, scoped Prettier and locked release build pass. No new TypeScript or scoped ESLint diagnostics.
  • 60/60 default renders pixel-identical to approved baseline-int7, same environment, unchanged baseline/tolerance. Engine SHA-256 7b3f9aed0791bd129e56a4f38b891f0caa23d9f260e2a5cb6fd0877d91449bd8.
  • Exact-head hosted CI green, including build, headless exits and lavapipe regression.
  • Eleven targeted picker/gesture tests cover current perceptual HSL weighting, dark samples, bypass cancellation, typed fields and undo boundaries. Picker sampling now matches the current shader's perceptual HSL bands. Disabling Color or Mixer ends an active gesture.

Desktop mouse/touch, zoom/crop, WGPU/JPEG fallback, Alt precision, typed fields and undo still need #63 checks. Automated tests do not claim desktop interaction coverage. Logs/JSON retained in /tmp/rapidroom-codex-98/; temporary full-corpus TIFFs removed. Marc Laliberte source credits retained.

@yojen7
yojen7 merged commit e85f200 into main Oct 4, 2026
9 checks passed
@yojen7
yojen7 deleted the claude/hopeful-goodall-fncu51 branch October 26, 2026 18:38
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.

Color Mixer: expose all HSL bands and add weighted image-drag adjustment

3 participants