Install
Two crates: exponential-ui (the core) and exponential-ui-gpui (the painter and host runtime). The painter depends on gpui and gpui-component as git dependencies, which crates.io refuses, so it stays a git or path dependency until both are published there. gpui needs Rust 1.96: pin it in rust-toolchain.toml.
ui-v* tag. Until then, depend on both crates by path or git, as below.[package]
name = "exponential-ui-guide-gpui"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
publish = false
# A third-party app: its own workspace, outside apps/desktop's build graph.
[workspace]
[dependencies]
# The SDK. Path dependencies stand in for crates.io (`exponential-ui = "0.1"`,
# `exponential-ui-gpui = "0.1"`) until gpui + gpui-component publish there;
# a git dependency on github.com/Niach/exponential works the same way.
exponential-ui = { path = "../../../../apps/desktop/crates/exponential-ui" }
exponential-ui-gpui = { path = "../../../../apps/desktop/crates/exponential-ui-gpui" }
# gpui + gpui-component at the SDK's revisions (Cargo.lock pins zed's commit).
gpui = { version = "0.2.2", git = "https://github.com/zed-industries/zed" }
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit", "x11", "wayland", "runtime_shaders"] }
gpui-component = { git = "https://github.com/longbridge/gpui-component", rev = "da4f93696dc2b2b4d91bcc42412b9053a3d24de8" }
gpui-component-assets = { git = "https://github.com/longbridge/gpui-component", rev = "da4f93696dc2b2b4d91bcc42412b9053a3d24de8" }
# zed's ztracing is GPL-3.0-or-later; any app linking gpui at this revision
# swaps in the SDK's no-op shims.
[patch."https://github.com/zed-industries/zed"]
ztracing = { path = "../../../../apps/desktop/crates/ztracing" }
ztracing_macro = { path = "../../../../apps/desktop/crates/ztracing_macro" }
[profile.dev.package."*"]
debug = falsePaint a surface
The host is a gpui entity. host.surface(id) returns the surface's view once the agent has created it; it is full width and as tall as its content, so wrap it in your own scroller.
use exponential_ui::theme::Mode;
use exponential_ui_gpui::runtime::{ExponentialHost, HostOptions};
use exponential_ui_gpui::transport::{HttpTransportOptions, JsonlStreamTransport};
use gpui::{div, prelude::*, px, size, App, Bounds, Context, Entity, Window, WindowBounds, WindowOptions};
struct Main {
host: Entity<ExponentialHost>,
}
impl Render for Main {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
// The surface the agent creates, once it exists; you own the scroller.
div().id("main").size_full().overflow_y_scroll().p(px(16.0)).children(self.host.read(cx).surface("main"))
}
}
fn main() {
gpui_platform::application().with_assets(gpui_component_assets::Assets).run(|cx: &mut App| {
gpui_component::init(cx);
// One host per app: A2UI messages in over a transport, actions back out.
let transport = JsonlStreamTransport::new(HttpTransportOptions::new("http://localhost:4300/a2ui.jsonl").post_url("http://localhost:4300/action"));
let options = HostOptions { transport: Some(Box::new(transport)), theme: exponential_ui::themes::builtin_theme("exponential"), mode: Mode::Dark, ..Default::default() };
let host = cx.new(|cx| ExponentialHost::new(options, cx));
host.update(cx, |host, cx| host.connect(cx));
let window = WindowOptions { window_bounds: Some(WindowBounds::Windowed(Bounds::centered(None, size(px(540.0), px(640.0)), cx))), ..Default::default() };
cx.open_window(window, |_, cx| cx.new(|cx| {
cx.observe(&host, |_, _, cx| cx.notify()).detach();
Main { host: host.clone() }
}))
.expect("a window");
});
}Host plugin
Underneath, a SurfaceView takes a HostPlugin implementation: catalog icon names to SVG asset paths, font families, actions and input. Register the theme's fonts with the text system before the first frame, and extension natives with register_painter. Details in the gpui painter's README.
Compiled in CI
Every file on this page is a real file in apps/ui-site/guides/gpui. CI copies it into an empty directory and builds it from scratch, the way you would, so the example cannot drift from the SDK:
bun apps/ui-site/guides/check.ts gpuiFor a complete app on this platform, see the samples: four hosts rendering the same surface from a local A2UI server, in a third-party theme, with a custom extension component.