Documentation

Getting started with GPUI.

Installation

Add gpui-ce as a git dependency in your Cargo.toml. It uses wgpu for GPU abstraction and winit for windowing, so no platform-specific setup is required.

Cargo.toml
[dependencies] gpui-ce = { git = "https://github.com/Far-Beyond-Pulsar/WGPUI" }

Your First Window

Create a window with a basic element tree. The entry point is Application::new().run().

src/main.rs
use gpui::*; struct HelloApp; impl Render for HelloApp { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { cx.notify(); div() .flex() .size_full() .justify_center() .items_center() .bg(rgb(0x0c0c0c)) .text_color(rgb(0xffffff)) .child( div() .px_6() .py_3() .rounded_xl() .bg(rgb(0x0ea5e9)) .child("Hello, WGPUI!") ) } } fn main() { Application::new().run(|cx: &mut App| { cx.open_window(WindowOptions::default(), |_, cx| { cx.new(|_| HelloApp) }).unwrap(); }); }

Run with cargo run. The same code compiles on Windows, macOS, Linux, and WASM. On WASM, call cx.activate(true) after opening the window.

Element Tree

GPUI uses a builder pattern for constructing UI element trees. Every element returns impl IntoElement, enabling composition. Text is added via .child("text") — there are no span()or h1() element functions.

rust
use gpui::*; fn metric_card(label: &str, value: &str) -> impl IntoElement { div() .flex_1() .p_4() .rounded_lg() .bg(rgb(0x1a1a1a)) .child( div().flex().flex_col().gap_1() .child(div().text_xs().text_color(rgb(0x888888)).child(label.to_string())) .child(div().text_2xl().font_weight(FontWeight::BOLD).text_color(rgb(0xffffff)).child(value.to_string())) ) } fn dashboard() -> impl IntoElement { div() .flex() .flex_col() .gap_4() .p_6() .child(div().text_xl().font_weight(FontWeight::BOLD).child("Dashboard")) .child(div().flex().gap_3() .child(metric_card("Users", "1,234")) .child(metric_card("Revenue", "$8,910")) .child(metric_card("Active", "89%")) ) }

Style shortcuts: flex_1(), px_4(),py_2(), gap_4(),rounded_lg(), border_1(),w_full(), text_size(px(24.0)),hover(|s| s.bg(rgb(0x...)))

Interactivity & State

Elements need .id() for on_clickto work. Listeners receive (this, event, window, cx) — 4 arguments. Always call cx.notify() after state changes.

rust
use gpui::*; struct Counter { count: i32, } impl Render for Counter { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { cx.notify(); div() .flex() .size_full() .justify_center() .items_center() .gap_4() .bg(rgb(0x0c0c0c)) .text_color(rgb(0xffffff)) .child( div().flex().items_center().gap_4() .child( div() .id("dec") .px_4().py_2().rounded_lg() .bg(rgb(0x333333)) .hover(|s| s.bg(rgb(0x444444))) .on_click(cx.listener(|this, _event, _window, cx| { this.count -= 1; cx.notify(); })) .child("-") ) .child( div() .text_size(px(32.0)) .font_weight(FontWeight::BOLD) .child(self.count.to_string()) ) .child( div() .id("inc") .px_4().py_2().rounded_lg() .bg(rgb(0x0ea5e9)) .hover(|s| s.bg(rgb(0x0284c7))) .on_click(cx.listener(|this, _event, _window, cx| { this.count += 1; cx.notify(); })) .child("+") ) ) } } fn main() { Application::new().run(|cx: &mut App| { cx.open_window(WindowOptions::default(), |_, cx| { cx.new(|_| Counter { count: 0 }) }).unwrap(); }); }

Gotchas: on WASM, the render() method should callcx.notify() at the top to keep the frame loop running. Without it, events may not fire.

WASM Build

Compile GPUI apps to WebAssembly with wasm-pack. The entry point must use #[wasm_bindgen(start)] and call console_error_panic_hook::set_once().

Cargo.toml
[package] name = "my-app" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] gpui-ce = { git = "https://github.com/Far-Beyond-Pulsar/WGPUI" } wasm-bindgen = "0.2" console_error_panic_hook = "0.1" [package.metadata.wasm-pack.profile.release] wasm-opt = false
src/lib.rs
use gpui::*; use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn start() { console_error_panic_hook::set_once(); Application::new().run(|cx: &mut App| { // On WASM, winit throws for control flow — catch in JS cx.activate(true); cx.open_window(WindowOptions::default(), |_, cx| { cx.new(|_| MyView) }).unwrap(); }); }
index.html
<!DOCTYPE html> <html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; } html, body { width: 100%; height: 100%; background: #000; } canvas { display: block; width: 100%; height: 100%; } </style> </head> <body> <script type="module"> import init from "./pkg/my_app.js"; try { await init(); } catch (e) { if (!String(e).includes("exceptions for control flow")) throw e; } </script> </body> </html>

Build: wasm-pack build --target web --out-dir pkg