research/gpui.md
GPUI: Zed's framework
Use this file to understand the engine under GPUI Kit before you read the kit's docs: how state, views and elements fit together, what the GPU renderer does and does not do, what each OS gives the app, and what "native" means for the screens we will draw (D2). A builder reads the programming model and the platform layer; a designer reads the renderer, text and "native" sections. Companion: gpui-kit.md. Every source below was read on 2026-11-09.
What GPUI is
- "A fast, hybrid immediate and retained mode, GPU-accelerated UI framework for Rust", from the makers of Zed. It lives inside the Zed monorepo at
crates/gpui, and since February 2026 the platform code is split intogpui_platform,gpui_macos,gpui_windows,gpui_linux,gpui_wgpu,gpui_web,gpui_ios. — https://www.gpui.rs/, https://github.com/zed-industries/zed/pull/49277 - Pre-1.0 and honest about it: "There will often be breaking changes between versions." Zed itself reached 1.0 on 2026-04-29 (latest 1.27.0, 2026-11-04) on Mac, Windows and Linux. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/README.md, https://zed.dev/blog/zed-1-0, https://zed.dev/releases/stable
- Licence Apache-2.0. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/Cargo.toml
- Two version lines. crates.io
gpuistopped at 0.2.2 on 2025-10-22. Everyone outside Zed uses Longbridge's weekly snapshot familygpui-pre("snapshot of zed@d2a4fb6"), 0.3.0 on 2026-09-03 through 0.3.12 on 2026-11-09, published by the kit's author. The kit pins it exactly (see gpui-kit.md). An agent reading docs.rs forgpuireads an API a year behind. — https://crates.io/api/v1/crates/gpui, https://crates.io/api/v1/crates/gpui-pre - On use outside Zed: "For the near future, GPUI is tied to Zed"; contributions go to the Zed repo. Zed's blog nonetheless counts "A growing number of projects… building with the gpui/gpui-component combination" and names Longbridge's Electron-to-GPUI rewrite. — https://www.gpui.rs/, https://zed.dev/blog/community-champion-jason-lee
The programming model
Three "registers", in the README's words. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/README.md
| Register | What it is | What a builder does |
|---|---|---|
| State: entities | Every model and view is owned by one top-level App; cx.new(...) returns an Entity<T>, "an inert identifier plus a compile-time type tag". Context<T> is the App seen from one entity. | Keep state in entities; update / read; cx.notify() tells observers; emit / subscribe for events. Effects flush at the end of each update, so there is no re-entrancy. — https://zed.dev/blog/gpui-ownership |
| Declarative UI: views | "A view is simply an Entity that can be rendered, by implementing the Render trait." render(&mut self, window, cx) -> impl IntoElement builds a fresh element tree each pass. | Compose div() trees with the Tailwind-named Styled methods: flex(), flex_col(), gap_2(), p_4(), w_64(), bg(...), text_color(...), border_1(), rounded(...), text_sm(), .when(cond, ...), hover(...). Sizes are rem-based. — https://gpui-kit.com/docs/style |
| Imperative UI: elements | An Element is one node in the tree GPUI builds for a frame, with three phases: request_layout → prepaint → paint. Taffy (flexbox and grid) resolves bounds between the first two. | Write a custom element only when nothing composes; canvas(prepaint, paint) for short-lived drawing. — https://gpui-kit.com/docs/element |
- Hybrid, in practice. "Retained" describes the entity state and the caches; "immediate-style" describes how
renderrebuilds the description each time it is needed.RenderOnce"does not mean once per display frame." — https://gpui-kit.com/docs/fps - Redraw on demand. "An Entity mutation followed by
cx.notify()marks that Entity for rendering… A frame tick alone does not redraw an unchanged window." An unconditionalnotify()orrequest_animation_frame()insiderender"creates continuous work even when the UI is idle." This is the rule that keeps an idle app at zero CPU. — https://gpui-kit.com/docs/window, https://gpui-kit.com/docs/fps - Actions and keys.
actions!(ns, [Name])defines unit actions;KeyBinding::new("cmd-s", Save, Some("Editor"))binds them (static strings since gpui-pre 0.3.10); dispatch follows the focus path; the same action drives a button, a palette entry and a native menu item. — https://gpui-kit.com/docs/action, https://gpui-kit.com/docs/keybinding - Testing built in.
#[gpui::test],TestAppContext(add_window,dispatch_action,simulate_keystrokes,run_until_parked) andVisualTestContext(simulate_click,draw). The kit wraps these as headless UI tests. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/app/test_context.rs
The renderer
- GPU on every OS, a different API each. macOS and iOS: Metal. Windows: Direct3D 11 with DirectComposition. Linux: wgpu (Vulkan or GLES), which replaced blade in February 2026; "A headless shell or Vulkan loader without a driver is insufficient." Web: wgpu over WebGPU, then WebGL2. — https://github.com/zed-industries/zed/pull/46758, https://gpui-kit.com/docs/installation, https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui_wgpu/Cargo.toml
- Everything is a primitive. Shadows, quads, paths, underlines, monochrome sprites (glyphs, SVG icons as tintable alpha masks), polychrome sprites (images), surfaces. Rounded rectangles come from a signed-distance function in the fragment shader; glyphs are cached in an atlas on the GPU with 4 horizontal subpixel variants; one instanced draw call per primitive type per layer. — https://zed.dev/blog/videogame, https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/scene.rs
- 120 Hz is a budget, not a promise: about 8.3 ms per frame; several invalidations collapse into one draw. — https://gpui-kit.com/docs/fps
- GPUI Fast is Longbridge's fork with a retained mode that "reuses unchanged views, layout nodes and text measurements"; its own bench puts a spinner at 11 % of a core against upstream's 85 %. "The project remains experimental." The kit offers it as an optional feature. — https://raw.githubusercontent.com/longbridge/gpui-fast/main/README.md
The platform layer
One crate per OS; gpui_platform::application() "picks the windowing and text backends for the host OS". — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui_platform/src/gpui_platform.rs
| The OS gives | Through | Notes |
|---|---|---|
| The window | WindowOptions: bounds, titlebar (hidden for a custom-drawn one on macOS and Windows), kind (Normal, PopUp, Floating, Dialog, LayerShell), window_background (Opaque, Transparent, Blurred, Mica), window_decorations (Server or Client on Linux), app_id, min size | Methods: set_window_title, zoom_window, minimize_window, toggle_fullscreen, set_window_edited, appearance(), observe_window_appearance, set_rem_size. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/platform.rs |
| Menus | App::set_menus, set_dock_menu, add_recent_document, update_jump_list (Windows); Menu, MenuItem::{Separator, Submenu, SystemMenu, Action}, OsAction::{Cut, Copy, Paste, SelectAll, Undo, Redo} | The macOS menu bar is native. Windows and Linux have no global menu bar; the kit draws one. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/platform/app_menu.rs |
| Dialogs | prompt_for_paths, prompt_for_new_path; native alerts via Window::prompt(PromptLevel, …); set_prompt_builder to replace them | — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/app.rs |
| Clipboard | read_from_clipboard, write_to_clipboard | |
| URLs | Application::on_open_urls, App::open_url, App::register_url_scheme(scheme) | The hooks for a deep link in the Connect flow (platform.md). |
| Notifications | show_system_notification(SystemNotification { tag, title, body, actions }); gpui_macos links objc2-user-notifications, gpui_linux uses notify-rust | macOS requires a real signed .app bundle; Linux needs a session D-Bus and a notification daemon. — https://gpui-kit.com/docs/system-notification |
| Credentials | write_credentials / read_credentials / delete_credentials, keychain-backed | A home for the plane's connect token. |
| Other | reveal_path, open_with_system, on_quit, on_reopen, activate, hide, displays, keyboard layout, screen capture (feature) | |
| Not a tray | No tray or status-item API exists in GPUI. A 2024 PR to add Linux tray icons was closed unmerged. A third-party crate gpui-tray 0.3.0 exists (5 stars). | The spike's first platform question. — https://github.com/zed-industries/zed/pull/13098, https://crates.io/api/v1/crates/gpui-tray |
Windows has been a supported Zed platform since 2025-10-15 ("Windows is now a fully supported platform for Zed"); Linux since 2024-07-10. — https://zed.dev/blog/zed-for-windows-is-here, https://zed.dev/blog/zed-on-linux
Text rendering
- The OS shapes and rasterises on macOS and Windows; cosmic-text does on Linux and the web. macOS: CoreText through
font-kit(without thefont-kitfeature "GPUI falls back to a placeholder text system that lays text out but renders no glyphs"). Windows: DirectWrite. Linux and wasm:cosmic-text0.19 withswash, fontconfig for discovery. — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/README.md, https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui_wgpu/Cargo.toml - Bundling a font:
Application::with_assets(...)thencx.text_system().add_fonts(vec![include_bytes!("Inter.ttf").into()])at startup; set the family on the theme..SystemUIFontis the alias for the platform UI font. — https://gpui-kit.com/docs/fonts - Emoji render in colour; COLRv1 fixes were still landing in November 2026. RTL and bidi are unsupported: every RTL PR found was closed unmerged or is still open. CJK resolves against the OS font collection on desktop; on the web a font must be embedded. — https://github.com/zed-industries/zed/issues/31102, https://gpui-kit.com/docs/text-system
- Hinting and gamma policy per OS is not documented beyond a
TextRenderingMode { PlatformDefault, Subpixel, Grayscale }enum. Expect text to look slightly different on each OS; the spike should capture the same screen on all three.
What "native" means here (D2)
GPUI draws every control itself, on the GPU, the way Flutter does. There is no NSButton, no Win32 edit control, no GTK widget behind a kit button. The operating system provides the window and its chrome, the menu bar (macOS), dialogs, the clipboard, notifications, the keychain and URL handling; the app provides the pixels inside the window.
- Zed's own words: "Zed isn't an Electron app; we integrate directly with the underlying platform for maximal control", and the editor is organised "around feeding data to shaders running on the GPU." — https://zed.dev/blog/zed-for-windows-is-here, https://zed.dev/blog/zed-1-0
- GPUI's caveat on its web-like API: "while GPUI mimics web APIs, it doesn't necessarily behave exactly as a web browser would". — https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/src/_accessibility.rs
- The kit's framing: "Modern controls inspired by macOS and Windows"; "Respect platform differences that carry meaning: Command versus Control, native window decorations, system appearance, scrollbar behavior, menus, and notification capabilities." — https://github.com/longbridge/gpui-kit, https://gpui-kit.com/docs/design-guides
- Where the kit does reach for OS-drawn parts:
NativeMenuusesNSMenuon macOS andTrackPopupMenuExon Windows, and falls back to a GPUI-drawn menu on Linux. — https://gpui-kit.com/docs/native-extension
What follows for us:
- Stakeholders should expect a native binary and a native window, not OS-drawn buttons. Say so in the pitch. The upside is that the same screen looks the same on three OSes and every pixel can carry the brand (D5 keeps that subtle).
- Accessibility is published, not inherited. A custom-drawn control has no semantics unless the app reports them. GPUI publishes an AccessKit tree since 2026-05-27; a node is reported only when it has an
ElementIdand a role. Zed keeps it off by default and "doesn't support screen readers" today by a maintainer's own words. The kit reports roles on its components and tests them headlessly, but no screen-reader run is reported by anyone. Treat screen-reader usability as unproven and check it on each OS in c131 (D10 there). — https://github.com/zed-industries/zed/pull/56065, https://github.com/zed-industries/zed/issues/41138, https://gpui-kit.com/docs/accessibility - Platform conventions still matter. Command vs Control, the menu bar on macOS, window controls on Linux, system light/dark: the kit's design guide lists these as the places where "native" is earned.
Where to learn GPUI
- The README ("Intro to GPUI"),
docs/contexts.md,docs/key_dispatch.md, the module docs on ownership and on accessibility, and 46 examples (hello_world,data_table,uniform_list,set_menus,system_notifications,a11y,testing,drag_drop,window_positioning). — https://www.gpui.rs/, https://api.github.com/repos/zed-industries/zed/contents/crates/gpui/examples - Zed's posts, in reading order: "Leveraging Rust and the GPU to render user interfaces at 120 FPS" (2023-03-07), "Ownership and data flow in GPUI" (2024-01-25, updated 2025-12-12), "Optimizing the Metal pipeline to maintain 120 FPS" (2024-02-07). — https://zed.dev/blog
- The README's own advice: "the best way to learn about these APIs is to read the Zed source code or drop a question in the Zed Discord".
- The most complete GPUI manual today is GPUI Kit's docs, written against the snapshot the kit pins: Entity, Context, Render, Element, Window, Style, Action, KeyBinding, Focus, Task, Fonts, Animation, Accessibility, Testing, WebAssembly, FPS. — https://gpui-kit.com/docs, https://gpui-kit.com/llms-full.txt
- Community books exist (an "Unofficial GPUI Cheat Book", two
gpui-books); their currency is unverified.
Open questions
- Will Zed publish
gpuito crates.io again, or is Longbridge's weeklygpui-prethe distribution for everyone else? Nothing from Zed says. - Is any GPUI app usable with VoiceOver, NVDA or Orca today?
- RTL: no timeline.
- Hinting and subpixel policy per OS, and how the same text differs across them.
Sources
https://www.gpui.rs/ · https://raw.githubusercontent.com/zed-industries/zed/main/crates/gpui/README.md · https://zed.dev/blog/gpui-ownership · https://zed.dev/blog/videogame · https://zed.dev/blog/120fps · https://zed.dev/blog/zed-1-0 · https://zed.dev/blog/zed-for-windows-is-here · https://zed.dev/blog/zed-on-linux · https://zed.dev/blog/community-champion-jason-lee · https://zed.dev/faq · https://zed.dev/releases/stable · https://crates.io/api/v1/crates/gpui · https://crates.io/api/v1/crates/gpui-pre · https://crates.io/api/v1/crates/gpui-tray · https://github.com/zed-industries/zed/pull/13098 · https://github.com/zed-industries/zed/pull/46758 · https://github.com/zed-industries/zed/pull/49277 · https://github.com/zed-industries/zed/pull/56065 · https://github.com/zed-industries/zed/issues/41138 · https://github.com/zed-industries/zed/issues/31102 · the gpui crate sources under https://github.com/zed-industries/zed/tree/main/crates (gpui/src/platform.rs, app.rs, window.rs, scene.rs, text_system.rs, _accessibility.rs, _ownership_and_data_flow.rs, app/test_context.rs, platform/app_menu.rs; gpui_platform, gpui_wgpu, gpui_windows, gpui_macos, gpui_linux Cargo.toml) · https://gpui-kit.com/docs (element, window, fps, style, action, keybinding, fonts, text-system, accessibility, system-notification, native-extension, design-guides, installation) · https://raw.githubusercontent.com/longbridge/gpui-fast/main/README.md