whoshue
A pixel-art color analyzer for KDE/Wayland. Capture a game/application window, select part of its preview, and inspect the captured colors. The analyzer is a normal desktop window; it does not flash calibration colors or hide itself.
Run
On CachyOS/Arch with KDE, the capture backend uses xdg-desktop-portal,
xdg-desktop-portal-kde, and PipeWire. Building needs Rust, a C toolchain,
pkgconf, Clang/libclang, and PipeWire development libraries (libpipewire).
cargo run --release
# Or start with a local image, without requesting screen sharing:
cargo run --release -- /path/to/screenshot.png
- Click Choose source…. KDE handles selecting a window, screen, or region. Click it again to choose a different source.
- Drag a rectangle in the source preview. Capture display pauses during the drag, then returns to its previous live/frozen state. The crop is stored in source pixels and resets if the source dimensions change.
- Freeze holds the displayed frame and analysis; Resume takes the newest available frame. Stop sharing closes capture and keeps the last image.
- Inspect the nearest-neighbor zoomed crop. Zoom ranges from 0.1× to 16×, starting at 1×. Hover for source coordinates, RGB/hex and HSV; click to copy hex. Click palette swatches to copy them too.
- Save crop PNG writes a uniquely named PNG in the system temporary directory and displays its path. Drop an image or click Open image… to browse for a file in KDE's file picker.
Color grouping and mapping
Group similar colors is enabled by default in the Palette. The default Edited view shows the resulting colors. Switch to Source / map to select original colors for replacement. Nearby shades from scaling or compression share a row showing their combined percentage and shade count. Adjust Tolerance (default 8, range 0–32) to control the maximum difference in each RGB channel from the group's most frequent color. Groups do not chain together through intermediate shades. Turn grouping off or set tolerance to zero for the exact palette. Hover a row to highlight its pixels in magenta in the crop preview; this temporary highlight is never exported.
Freeze a capture or import an image, choose Source / map, then click Map beside a palette row. In Color mapping, click its replacement swatch to choose another color or enter RGB values. Every original shade in that group maps to the chosen replacement. Add multiple mappings to try a new palette. Each mapping keeps its original group members even if you later change tolerance or crop. If a new mapping overlaps an older one, the new mapping owns those shades; the older mapping keeps any others. Replacements are simultaneous, so swapping two colors works without cascading. Alpha is preserved and fully transparent pixels are left untouched.
Toggle Preview mappings to compare with the original palette. Remove an individual mapping with × or use Reset mappings. Mappings survive crop changes, pause during live capture, and return when frozen again. Opening a new image or choosing a new capture source clears them.
Mappings apply before the preview adjustments or vision filter. Source preview, copied pixel values, and Save crop PNG still use the original. Color analysis and the vision check use the edited selection. Save mapped crop PNG exports the crop with replacements, preserving alpha and excluding preview adjustments and filters.
Automatic harmony
Freeze a capture or import an image, open Harmonize, and enable Preview harmony. Choose Monochromatic, Analogous, Complementary, Split-Complementary, or Triadic. The app fits that rule to the crop automatically, then moves its hue families toward the chosen harmony while preserving shading. Strength blends from the input at 0% to the full transformation at 100%. Rotation, or dragging the color wheel, changes the palette's direction. White dots on the wheel mark input hue families; colored spokes mark target hues. The wheel shows targets at full strength. Auto fit resets rotation and fits the current crop again.
Protect neutrals is enabled by default: gray and near-gray colors stay unchanged, with a gradual transition into chromatic colors. Reset harmony turns harmony off and restores its defaults. Disabling Preview harmony lets you compare with the input (including any enabled manual mappings). Settings pause during live capture, resume when frozen, and reset for a new image or capture source. Changing the crop or manual mappings refits the harmony while retaining your rotation and strength.
Harmony works in OKLCH: it holds perceptual lightness and chroma while shifting hue, reducing chroma when needed to fit sRGB. It retains small hue variations within a family and compresses broad families into bands around target hues. Monochromatic instead converges to a single hue at full strength, retaining lightness and chroma variations (with neutral protection still applied). The offsets are 0° for monochromatic, −30°/0°/+30° for analogous, 0°/180° for complementary, 0°/150°/210° for split-complementary, and 0°/120°/240° for triadic, on the OKLCH wheel. These angles do not produce identical color pairs to HSV or traditional artist color wheels.
The fit uses a circular hue histogram, finds hue families, and searches for the orientation requiring the least weighted squared hue movement. Counts are square-root weighted after hue binning so a large background has less influence and compression-generated near-duplicates don't each get a separate vote. This is an experimental palette heuristic: it does not recognize objects, protect skin or gameplay indicators automatically, or guarantee that every target hue is used. Families may merge, and family boundaries can still affect subtle hue ramps. Start with moderate strength and compare the result in context.
The processing order is source → manual mappings → harmony → preview filter or adjustments. The source preview and copied pixel values remain original; color analysis and the vision check use the edited selection. Save harmonized crop PNG includes enabled mappings and harmony, preserving transparency, without hover highlights, preview filters, or adjustments. Save mapped crop PNG still saves only manual replacements; Save crop PNG still saves the original.
The conversion uses Björn Ottosson's Oklab transforms.
Color analysis and vision checks
The Color analysis tab uses the edited selection after active mappings, harmony, and the selected filter or adjustments. Histograms, means, neutral counts, distinct-color weighting, and the Edited palette all update together. Merged colors count once for distinct-color weighting. Diagnostic simulation previews and hover highlights are excluded, just as in the vision check. Source / map keeps the original palette available for choosing replacements.
The tab has four distributions:
- Hue: HSV hue in 36 ten-degree bins; saturation below 5% counts as neutral.
- Saturation: HSV saturation, from neutral to fully saturated.
- Brightness (V): HSV value, the maximum RGB channel. This is not perceived lightness: fully saturated red and green both have 100% value.
- Luminance: relative luminance in linear sRGB, weighted for contrast.
Saturation, value, and luminance use 20 five-percentage-point bins, including 100% in the final bin. Each has a mean. Switch between pixel frequency and equal weight per distinct RGB color; hover bars for counts and percentages. The exact palette is ordered by count, then RGB for deterministic ties. Fully transparent pixels are excluded; partially transparent pixels retain their stored RGB values and count once. Pixel inspection includes HSV and relative luminance.
Use Filter below the selection to apply protanopia, deuteranopia, tritanopia, or grayscale directly to the crop preview, or select Original to use the live color adjustment sliders. The first three use the Machado–Oliveira–Fernandes full-severity model, applied in linear RGB and then encoded back to sRGB. Grayscale uses relative luminance and tests removal of color cues; it does not model all aspects of achromatopsia. The selected filter updates color analysis and the vision check. Copied pixel values and Save crop PNG still use the original.
Invert replaces each RGB channel with its complement (255 minus the channel). With Original selected, adjust Hue shift (−180° to +180°), Saturation (−100% to +100% relative change), and Brightness (V) (−100 to +100 percentage points of HSV value). Changes update the crop preview immediately, including live captures. Saturation keeps neutral colors neutral; saturation and value clamp to their valid ranges. Brightness adjusts HSV value, not relative luminance. Reset adjustments restores the unmodified preview. Adjustments are remembered while another filter is selected and applied again when returning to Original. Filters preserve alpha and always start from source pixels, so edits do not accumulate rounding errors.
Vision check automatically checks all four scenarios against the edited selection, after enabled group/manual mappings, harmony, and the selected filter or adjustments. It updates when these edits or the crop change. Palette grouping alone only organizes colors; mapping a group changes the checked pixels. Colors that merge through editing count as one color, and opaque-pixel coverage is recalculated from the result. Color distributions and the edited palette use those same pixels; Source / map remains available for mapping input colors.
The report's Preview buttons add a separate simulation of those edited pixels. They do not change the selected filter or feed simulated pixels back into the report. Use Return to edited preview to remove this simulation. Temporary palette hover highlights are also excluded from the check.
The check flags pairs whose OKLab distance falls from at least 0.08 to at most 0.04, losing at least 50% of the separation in the edited image. These are project-specific screening heuristics, not validated visibility thresholds or WCAG criteria. Each scenario shows edited and simulated swatches, numeric hex values, and up to six closest candidate pairs. The preview button opens the corresponding simulation for the edited crop.
The check is bounded to the 64 most frequent opaque colors and reports both color and pixel coverage. Partially/fully transparent pixels have no known backdrop and are excluded from this check. No findings does not establish accessibility. The check cannot infer adjacency, text/background relationships, or the gameplay meaning of a color. Review important cues in context and combine color with shapes, labels, or differences in lightness. Select a smaller region when an important detail is outside the reported palette coverage.
References:
- Chrome's contrast audits and vision simulations
- Machado, Oliveira & Fernandes simulation model
- Published matrix coefficients in QGIS
- OKLab color space
- W3C: use of color
Choosing a source always opens KDE's picker. The last portal token is saved at
$XDG_CONFIG_HOME/whoshue/config.toml (normally ~/.config/whoshue/config.toml)
for the command-line capture diagnostic. No capture starts until Choose source…
is clicked. Cancelling the file picker leaves the current image/capture unchanged.
Portal requests share one application-lifetime async runtime. PipeWire runs on a separate blocking worker so restarting capture or opening another portal dialog cannot strand the cached D-Bus connection on a stopped executor.
Limits and next work
- Window capture is preferred: screen/region capture includes overlapping windows, including whoshue if placed inside the captured area.
- Selection follows coordinates within the source, not a moving sprite.
- Analysis uses source pixels before preview scaling, but these are rendered colors, not necessarily original game-asset colors. HDR and color-profile conversion have not been validated; the current path assumes ordinary SDR RGB.
- Live analysis refreshes at most five times per second. Large selections with many unique colors are more expensive; release builds are recommended.
- Game-specific behavior on focus loss/minimization needs desktop testing.
- Perceptual OKLCH views, color/hue highlighting, and comparing saved selections are future features; the distributions currently use HSV and relative luminance.
Validation
cargo test --offline --locked
cargo clippy --offline --locked --all-targets -- -D warnings
cargo fmt --check
Tests cover hue boundaries, neutral/transparent pixel handling, weighting,
cropping, selection coordinates, pixel-format conversion, frozen-frame behavior,
resize handling, all histogram/vision UI views, file-picker cancellation/reopening, and
repeated portal requests during/after capture. The portal regression test requires
dbus-run-session and permission to create a local socket; it uses its own private
bus and does not open desktop dialogs. Color tests cover histogram endpoints and
weighting, sRGB gamma, simulation reference colors, alpha handling, warning
positives/negatives, palette coverage, and preserving source pixels.
Harmony tests cover color-space reference values, gamut reduction, circular hue
fitting, neutral protection, shading, alpha, preset rendering, crop and capture
lifecycle, and exported PNG pixels.
Actual portal capture requires a running
Wayland desktop and permission through KDE's picker.
For a capture-only diagnostic (saves the first full source frame):
cargo run -- --selftest /tmp/whoshue-selftest.png