Painting primitives at non-integer pixel coordinates produces blurry output. Pixel snapping converts layout coordinates into integer device-pixel coordinates so painted edges land exactly on physical pixel boundaries. Non-integer coordinates can arise for several reasons, including: - flex distribution, percentages, centering, and text measurement can produce fractional element sizes and positions; - at fractional scale factors (for example 125% or 150%), integer logical-pixel values can map to non-integer device-pixel values. We pixel-snap by rounding in device-pixel space, after multiplying by `scale_factor`, so that snapping targets physical pixels. Bounds are divided by `scale_factor` before being returned to GPUI. Midpoints are rounded toward zero. This is a stylistic choice: a 1-logical-pixel line at 150% scale should render as 1 dp rather than 2 dp. Pixel snapping is done in two phases: 1. Pre-layout metric snapping. Before Taffy computes layout, all authored absolute lengths are rounded in `to_taffy`. This includes borders, padding, gaps, and explicit sizes. Custom-measured leaf nodes have their measured sizes rounded up to integer device-pixel lengths. 2. Post-layout edge snapping. After Taffy resolves the tree, layout relationships such as flex shares, grid tracks, percentages, and centering can produce new fractional edge positions. Boxes now have edges in absolute coordinates, and snapping must decide where those edges land on the device-pixel grid. Ideally, post-layout snapping would satisfy: - Edge closure. Two raw layout edges at the same absolute position should snap to the same pixel column. - Translation stability. A component's internal geometry should not change when it moves to a new absolute position. These goals are in tension because rounding is not associative. The simple local schemes make different tradeoffs: - Absolute edge rounding gives each window coordinate one answer, so coincident edges always close globally. But a span's snapped length is `round(far) - round(near)`, which may change by 1 dp as its absolute origin moves. - Parent-relative edge rounding rounds each child inside its parent's coordinate space. This guarantees translation stability, but a shared edge reached through different parents can accumulate different rounding, causing non-closure between cousins. - Length rounding rounds each width, height, and thickness independently and then places boxes from those rounded lengths. Sizes stay stable under translation, but neighboring boxes derive their shared boundary from different sources, so closure is not guaranteed. We apply absolute edge rounding for each element's outer box in post-layout rounding to preserve closure. Border and padding widths are not touched by post-layout rounding; they keep their pre-layout rounded value so that they remain stable under translation. This gives both closure and translation stability in the case that all local metrics are integer device-pixel lengths. Pre-layout rounding covers that in most cases. The exception is metrics resolved by layout relationships, such as percentages. Outer box edges will still close globally, and painted border widths are still snapped independently, but the raw content-box origin can carry a 1 dp residual into descendants. --- Fixes https://github.com/zed-industries/zed/issues/46360 Fixes https://github.com/zed-industries/zed/issues/44528 Fixes https://github.com/zed-industries/zed/issues/40282 Fixes https://github.com/zed-industries/zed/issues/42257 --- Release Notes: - Fixed potentially blurry appearance of UI elements when using fractional display scaling.
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.