Linear gradients in dark color ranges (5-15% lightness) show visible banding due to 8-bit quantization — only ~7 distinct values exist in that range, producing hard steps instead of smooth transitions. This affects every dark theme in Zed. ## What this does Adds triangular-distributed dithering after gradient interpolation in both the Metal and HLSL fragment shaders. The noise breaks up quantization steps at the sub-pixel level, producing perceptually smooth gradients. ## How it works Two hash-based pseudo-random values (seeded from fragment position x golden ratio) are summed to produce a triangular probability distribution. This is added to the RGB channels at +/-1/255 amplitude. - **Triangular PDF** — mean-zero, so no brightness shift across the gradient - **+/-1/255 amplitude** — below perceptual threshold, invisible on bright gradients where 8-bit precision is already sufficient - **Deterministic per-pixel** — seeded from position, no temporal flickering - **Zero-cost** — a couple of `fract`/`sin` per fragment, negligible vs. the existing gradient math ### Channel-specific amplitudes | Channel | Amplitude | Rationale | |---------|-----------|----------------------------------------------------------------------------------------------------| | RGB | ±2/255 | Breaks dark-on-dark banding where adjacent 8-bit values are perceptually close | | Alpha | ±3/255 | Alpha gradients over dark backgrounds need stronger noise — α × dark color = tiny composited steps | The higher alpha amplitude is necessary because when a semi-transparent gradient (e.g., 0.4 → 0.0 alpha) composites over a dark background, the effective visible difference per quantization step is smaller than the RGB case. ±3/255 is still well below the perceptual threshold on bright/opaque elements. ## Scope Two files changed, purely additive: | File | Change | |------|--------| | `crates/gpui_macos/src/shaders.metal` | 13 lines after `mix()` in `fill_color()` | | `crates/gpui_windows/src/shaders.hlsl` | 13 lines after `lerp()` in `gradient_color()` | No changes to Rust code, no API changes, no new dependencies. ## Screenshots <img width="1886" height="1003" alt="gradient_dithering_before" src="https://github.com/user-attachments/assets/f75ae93b-b142-4d0e-9b61-e08f30fe1758" /> _Before_ <img width="1902" height="1052" alt="gradient_dithering_after" src="https://github.com/user-attachments/assets/7aee9a36-f578-4e08-a846-44d092bcf043" /> _After_ ## Test plan This is a shader-level fix; no Rust test harness exists for visual output. Manual testing is appropriate here. Visual regression tests cover UI layout, not sub-pixel rendering quality. **Manual (macOS):** - [x] Dark gradients (5-13% lightness range) — banding eliminated - [x] Bright gradients — no visible difference (dither amplitude below precision threshold) - [x] Oklab and sRGB color spaces — both paths dithered - [x] Solid colours, pattern fills, checkerboard — unaffected (dither only applies to LinearGradient case) - [x] Alpha gradients (semi-transparent over dark bg) — banding eliminated with alpha dithering - [x] Path gradients (paint_path) — same fill_colour() function, dithering applies **Windows:** HLSL change is identical logic with HLSL built-ins (`frac`/`lerp` vs `fract`/`mix`) — not tested locally. Release Notes: - Improved linear gradient rendering by adding dithering to eliminate visible banding in dark color ranges Liam
Zed
Welcome to Zed, a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
Installation
On macOS, Linux, and Windows you can download Zed directly or install Zed via your local package manager (macOS/Linux/Windows).
Other platforms are not yet available:
- Web (tracking issue)
Developing Zed
Contributing
See CONTRIBUTING.md for ways you can contribute to Zed.
Also... we're hiring! Check out our jobs page for open roles.
Licensing
License information for third party dependencies must be correctly provided for CI to pass.
We use cargo-about to automatically comply with open source licenses. If CI is failing, check the following:
- Is it showing a
no license specifiederror for a crate you've created? If so, addpublish = falseunder[package]in your crate's Cargo.toml. - Is the error
failed to satisfy license requirementsfor a dependency? If so, first determine what license the project has and whether this system is sufficient to comply with this license's requirements. If you're unsure, ask a lawyer. Once you've verified that this system is acceptable add the license's SPDX identifier to theacceptedarray inscript/licenses/zed-licenses.toml. - Is
cargo-aboutunable to find the license for a dependency? If so, add a clarification field at the end ofscript/licenses/zed-licenses.toml, as specified in the cargo-about book.
Sponsorship
Zed is developed by Zed Industries, Inc., a for-profit company.
If you’d like to financially support the project, you can do so via GitHub Sponsors. Sponsorships go directly to Zed Industries and are used as general company revenue. There are no perks or entitlements associated with sponsorship.