GPUI

Native desktop applications in Elixir, rendered by GPUI.

GPUI keeps application state, window topology, UI declarations, and event handling in Elixir. Rust owns the native event loop, windows, rendering, focus, IME, accessibility, and latency-sensitive interaction. Conventional controls are provided separately by gpui_components and rendered with gpui-component.

Elixir owns the application. GPUI owns the native interaction. Snapshots connect them.

One declarative application can run against a local native display, a deterministic test display, or a native display on another machine.

GPUI supports precompiled Linux, Apple silicon macOS, and x86-64 Windows hosts. See Platform support and development status.

Write native UI like Elixir

defmodule CounterView do
use GPUI.View
alias GPUI.UI
def render(assigns) do
~GPUI"""
<div class="flex grow flex-col items-center justify-center w-full gap-4 bg-slate-950">
<text class="text-3xl font-semibold text-white">Count: {assigns.count}</text>
<UI.button id="increment" label="Increment" variant="primary" phx-click="increment" />
</div>
"""
end
def handle_event("increment", _event, assigns) do
{:noreply, %{assigns | count: assigns.count + 1}}
end
end
defmodule CounterApp do
use GPUI.Application
def mount(_args) do
{:ok,
[
window "Counter" do
size(420, 280)
root(CounterView, count: 0)
end
]}
end
end

assigns remains authoritative Elixir state. Pointer, keyboard, and accessible activation return through the same typed event path; Rust does not become a second application state system.

Run the progressive examples from the repository:

RUST_FONTCONFIG_DLOPEN=1 mix run apps/gpui/examples/getting_started/01_hello_window.exs
RUST_FONTCONFIG_DLOPEN=1 mix run apps/gpui/examples/getting_started/02_events.exs
RUST_FONTCONFIG_DLOPEN=1 mix run apps/gpui/examples/getting_started/03_supervised_updates.exs
RUST_FONTCONFIG_DLOPEN=1 mix run apps/gpui/examples/getting_started/04_controlled_form.exs
RUST_FONTCONFIG_DLOPEN=1 mix run apps/gpui/examples/getting_started/05_multiple_windows.exs

See Your first application for supervision, controlled components, event handling, and native prerequisites.

Why GPUI

One application, multiple displays

GPUI.Application
GPUI.WindowSpec
GPUI.Session ──────► GPUI.Snapshot
┌────────────┼────────────┐
▼ ▼ ▼
Native display Test display Remote display

A native display presents real windows. A test display makes view behavior deterministic without Rust or a display server. The remote protocol can keep the authoritative session on one machine while another presents its native windows. Dynamic multi-window topology remains snapshot-driven in every mode.

See Sessions, snapshots, and displays, Remote displays, and Testing GPUI applications.

Highlights

Read more in Editable text internals, Accessibility internals, and UI components.

Examples

Example What it demonstrates
Rich transcript Variable-height virtualization, selectable rich text, links, and a native composer
BEAM Control Room Supervised runtime sampling driving controlled native views
Image Lab Display-side file reads, image decoding, and bounded raster resources
Component Gallery Canonical component states, combinations, and accessibility behavior

Run the gpui.dev Mix task with the larger examples for state-preserving Elixir source reload through GPUI.Dev.Reload. See the examples index for the complete catalog.

Packages

The repository is a Mix umbrella with three independently publishable packages and one private maintainer application:

Package Purpose
gpui Renderer-independent applications, sessions, snapshots, schemas, remote displays, and test APIs
gpui_components Conventional declarative controls backed by gpui-component
gpui_native RustlerPrecompiled vanilla and gpui-component native hosts
Root tooling Private RustQ generation, repository checks, native testing, and release validation

RustQ runs only in the source umbrella. Generated Elixir and Rust are committed, and supported consumer targets download checksum-verified NIF archives through RustlerPrecompiled; consumer compilation does not run RustQ.

Installation

For a renderer-independent application or remote server:

def deps do
[
{:gpui, "== 0.2.0"}
]
end

For a native application using conventional controls, gpui_native brings the matching gpui and gpui_components versions transitively:

def deps do
[
{:gpui_native, "== 0.2.0"}
]
end

Select the gpui-component host when component elements are used:

# config/config.exs
config :gpui_native, GPUI.Native, host: :gpui_component

Use host: :vanilla for the complete vanilla-GPUI host. Exactly one host artifact is loaded; the component-capable artifact statically links its renderer rather than attaching a second native library at runtime. Renderer-independent sessions, remote servers, and GPUI.Test require neither Rust nor a native library or display server. See Native builds and deployment.

Documentation

Development

mix deps.get
mix gpui.test.packages
mix ci
MIX_ENV=e2e xvfb-run -a dbus-run-session -- mix test --only e2e apps/gpui_native/test/e2e

mix gpui.test.packages builds the three public Hex payloads and compiles their exact unpacked contents in clean downstream consumers, with repository-only tooling and Cargo unavailable. mix ci includes this package-isolation gate and covers Elixir, generated Rust freshness, Cargo feature matrices, Clippy, native unit tests, Dialyzer, Credo, duplication, and architecture checks. Hosted push validation splits the renderer-independent and native checks; the full native interaction and release-package suite is an explicit Release candidate workflow rather than a scheduled or per-push job. See Testing GPUI applications for native Xvfb/Lavapipe interaction coverage.

License

MIT