### Run the hello_world example Source: https://gpui-kit.com/docs/installation Run the existing example from the repository root to verify the installation. The first build may take several minutes as dependencies are downloaded and compiled. ```bash cargo run -p hello_world ``` -------------------------------- ### Run the example-stream-markdown example Source: https://gpui-kit.com/docs/task Run this command from the repository root after installing platform prerequisites. It launches the example window with a Replay button and a Fade in streamed text switch. ```bash cargo run -p example-stream-markdown ``` -------------------------------- ### Run the WebView example Source: https://gpui-kit.com/docs/webview Command to execute the WebView example from the repository root. ```bash cargo run -p webview ``` -------------------------------- ### Complete example: one model, one observing View Source: https://gpui-kit.com/docs/entity Runnable example for examples/hello_world. Replaces main.rs and runs with cargo run -p hello_world. The window starts at Messages: 0; each click increments the count via store.update and notify. The model has no Render implementation and is never added to the element tree. ```rust use gpui_kit::base::StyledExt; use gpui_kit::component::button::Button; use gpui_kit::*; struct MessageStore { count: usize, } struct MessagePanel { store: Entity, _subscription: Subscription, } impl MessagePanel { fn new(cx: &mut Context) -> Self { let store = cx.new(|_| MessageStore { count: 0 }); let _subscription = cx.observe(&store, |_, _, cx| cx.notify()); Self { store, _subscription, } } } impl Render for MessagePanel { fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { let count = self.store.read(cx).count; div() .v_flex() .gap_2() .size_full() .items_center() .justify_center() .child(format!("Messages: {count}")) .child( Button::new("add-message") .label("Add message") .on_click(cx.listener(|this, _, _, cx| { this.store.update(cx, |store, cx| { store.count += 1; cx.notify(); }); })), ) } } fn main() { gpui_kit::application().run(|cx| { gpui_kit::init(cx); gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| { cx.new(MessagePanel::new) }) .expect("failed to open window"); }); } ``` -------------------------------- ### Run native examples Source: https://gpui-kit.com/base/getting-started Execute the shared examples as a native GPUI application using cargo run. ```bash cargo run -p gpui-base-examples -- button ``` -------------------------------- ### Run the js_dock workspace example Source: https://gpui-kit.com/shell/examples Command to run the dockable workspace example from the shell. The workspace has a file list on the left, documents in the center, and persists its layout. ```bash cargo run -p gpui-shell -- examples/js_dock ``` -------------------------------- ### Context.bind_keys(bindings) Source: https://gpui-kit.com/shell/api Installs key bindings and returns the number of bindings installed. Mirrors App::bind_keys. ```APIDOC ## bind_keys(bindings) ### Description Installs key bindings and answers how many. Mirrors `App::bind_keys`. ### Method bind_keys ### Parameters - **bindings** (unknown) - Required - The key bindings to install. ### Returns number - The number of bindings installed. ``` -------------------------------- ### Run JavaScript Todolist Example Source: https://gpui-kit.com/shell/engine Command to run the JavaScript todolist example using the gpui-shell package. The script engine is behind a QuickJS-based seam, and this command launches the application. ```shell cargo run -p gpui-shell -- examples/js_todolist ``` -------------------------------- ### Multi-step Form Example Source: https://gpui-kit.com/component/stepper Example of a multi-step form using a stepper with icons and a click listener to update the form step. ```rust Stepper::new("form-stepper") .w_full() .selected_index(form_step) .items([ StepperItem::new() .icon(IconName::User) .child("Personal Info"), StepperItem::new() .icon(IconName::CreditCard) .child("Payment"), StepperItem::new() .icon(IconName::CircleCheck) .child("Confirmation"), ]) .on_click(cx.listener(|this, step, _, cx| { this.form_step = *step; cx.notify(); })) ``` -------------------------------- ### js_dock example file listing Source: https://gpui-kit.com/shell/examples The two files that make up the js_dock example: main.js contains the workspace, panels, dock, and persistence; ui.js contains the chrome such as tabs, dock frame, and drop hint. ```text main.js the workspace: panels, the dock, and persistence ui.js the chrome: tabs, the dock frame, the drop hint ``` -------------------------------- ### Create Hello World application in src/main.rs Source: https://gpui-kit.com/docs A complete example of a GPUI Kit application that renders a label and a button. Clicking the button triggers a print statement in the terminal. ```rust use gpui_kit::component::button::{Button, ButtonVariants}; use gpui_kit::*; struct HelloWorld; impl Render for HelloWorld { fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { div() .flex() .flex_col() .size_full() .items_center() .justify_center() .gap_2() .child("Hello, World!") .child( Button::new("hello") .primary() .label("Click me") .on_click(|_, _, _| println!("Clicked!")), ) } } fn main() { application() .with_assets(assets::Assets) .run(|cx| { init(cx); open_window(WindowOptions::default(), cx, |_, cx| { cx.new(|_| HelloWorld) }) .expect("Failed to open window"); }); } ``` -------------------------------- ### History navigation trail example Source: https://gpui-kit.com/base/history Example showing how to push locations into a History and use back() and current() to navigate the trail. After pushing A, B, C, back() returns B and current() returns a reference to B. ```rust let mut history = History::new(); history.push("A"); history.push("B"); history.push("C"); assert_eq!(history.back(), Some("B")); assert_eq!(history.current(), Some(&"B")); ``` -------------------------------- ### Install gpui-base dependencies Source: https://gpui-kit.com/base/getting-started Add the required gpui-base, gpui, and gpui_platform dependencies to your Cargo.toml file. ```toml [dependencies] gpui-base = { git = "https://github.com/longbridge/gpui-kit" } gpui = { git = "https://github.com/zed-industries/zed" } gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit"] } ``` -------------------------------- ### Initialize GPUI Kit application Source: https://gpui-kit.com/releases Use the gpui-kit facade to initialize and run a GPUI application. The example shows importing the facade and component root, then calling application().run() and init() to set up the environment. ```rust use gpui_kit::*; use gpui_kit::component::Root; fn main() { gpui_kit::application().run(|cx| { gpui_kit::init(cx); // Open windows and build the application here. }); } ``` -------------------------------- ### Install Linux development packages on Ubuntu 24.04 Source: https://gpui-kit.com/docs/installation Install the required development packages for Ubuntu 24.04. This matches the repository's script/install-linux.sh. libasound2-dev is needed only by the speech feature. A working Vulkan driver is required for displaying a window. ```bash sudo apt update sudo apt install -y gcc g++ clang libfontconfig-dev libwayland-dev \ libwebkit2gtk-4.1-dev libxkbcommon-x11-dev libx11-xcb-dev \ libssl-dev libzstd-dev libasound2-dev vulkan-validationlayers libvulkan1 ``` -------------------------------- ### package.json entry configuration Source: https://gpui-kit.com/shell/dependencies Example package.json showing the main and types fields used by gpui-shell to resolve the package entry. The runtime reads main, while an editor reads types. ```json { "type": "module", "main": "src/index.js", "types": "src/index.d.ts" } ``` -------------------------------- ### Manifest: gpui-shell.json structure Source: https://gpui-kit.com/shell/capabilities Example of a complete gpui-shell.json manifest file defining metadata, dependencies, and capabilities. ```json { "id": "com.example.quotes", "name": "Quotes", "version": "1.0.0", "shell-version": "0.7.1", "entry": "main.js", "dependencies": { "omarchy-ui": "huacnlee/omarchy-ui" }, "capabilities": { "fs": { "read": ["${pluginDir}"], "write": ["${dataDir}"] }, "network": { "hosts": ["stream.example.com"], "http": [ { "scheme": "https", "host": "api.example.com", "methods": ["GET"], "path_prefixes": ["/v1/"] } ] }, "storage": true, "clipboard": { "read": false, "write": true }, "process": { "exit": false } } } ``` -------------------------------- ### Run the quote board shell example Source: https://gpui-kit.com/shell/examples Command to run the gallery's Shell story, which displays two panels side by side: one drawn in Rust and one in JavaScript, both reading the same data. ```bash cargo run -- shell ``` -------------------------------- ### ShellRuntime::new Source: https://gpui-kit.com/shell/hosting Creates a new ShellRuntime, installing it as the default runtime for the App. This runtime owns one VM and is used for loading and instantiating script views. ```APIDOC ## ShellRuntime::new ### Description Creates a new ShellRuntime, installing it as the default runtime for the App. This runtime owns one VM and is used for loading and instantiating script views. ### Method new ### Signature `ShellRuntime::new(cx) -> Result` ### Parameters - **cx** (Context) - Required - The GPUI context. ### Returns - **ShellRuntime** - The new runtime instance. ### Errors - Returns an error if the runtime cannot be created. ``` -------------------------------- ### Dependency version selection example Source: https://gpui-kit.com/shell/dependencies Shows the JSON structure for specifying dependencies with different ref types: default-main, named-ref, commit, and remote-head. The shorthand is strict and any deviation results in a manifest error. ```json { "dependencies": { "default-main": "huacnlee/omarchy-ui", "named-ref": "huacnlee/omarchy-ui#v1.2.0", "commit": "https://github.com/huacnlee/omarchy-ui#0123456789abcdef0123456789abcdef01234567", "remote-head": "https://github.com/huacnlee/omarchy-ui" } } ``` -------------------------------- ### Loading Form Fields example Source: https://gpui-kit.com/component/skeleton Creates skeleton placeholders for form fields, each with a label and an input or textarea. The first field uses a 40px height input, and the second uses a 120px height textarea. ```rust v_flex() .gap_4() .child( v_flex() .gap_1() .child(Skeleton::new().w(px(60.)).h_4().rounded_md()) // Label .child(Skeleton::new().w_full().h(px(40.)).rounded_md()) // Input ) .child( v_flex() .gap_1() .child(Skeleton::new().w(px(80.)).h_4().rounded_md()) // Label .child(Skeleton::new().w_full().h(px(120.)).rounded_md()) // Textarea ) ``` -------------------------------- ### Conditional Loading example Source: https://gpui-kit.com/component/skeleton Shows how to conditionally render a Skeleton placeholder or actual content based on a loading flag. When loading is true, a skeleton is shown; otherwise, the real content is displayed. ```rust if loading { Skeleton::new().w(px(200.)).h_4().rounded_md() } else { div().child("Actual content here") } ``` -------------------------------- ### Initialize ShellRuntime and create default runtime Source: https://gpui-kit.com/shell/hosting Initializes the gpui-kit shell and creates a ShellRuntime, which is installed as the App's default. The runtime is an Rc with interior mutability, so it must live on the thread owning the App. ```rust gpui_kit::shell::init(cx); // gpui-base, the token palette, the style table let runtime = ShellRuntime::new(cx)?; // one VM, installed as this App's default ``` -------------------------------- ### Loading Article List example Source: https://gpui-kit.com/component/skeleton Renders a list of three article placeholders using a map over a range. Each item includes a thumbnail, title, excerpt lines, and a date, all represented by Skeleton components. ```rust v_flex() .gap_6() .children((0..3).map(|_| { h_flex() .gap_4() .child(Skeleton::new().w(px(120.)).h(px(80.)).rounded_md()) // Thumbnail .child( v_flex() .gap_2() .flex_1() .child(Skeleton::new().w_full().h_5().rounded_md()) // Title .child(Skeleton::new().w(px(300.)).h_4().rounded_md()) // Excerpt line 1 .child(Skeleton::new().w(px(250.)).h_4().rounded_md()) // Excerpt line 2 .child(Skeleton::new().w(px(100.)).h_3().rounded_md()) // Date ) })) ``` -------------------------------- ### Simplified window startup with gpui_kit::init and open_window Source: https://gpui-kit.com/releases Use this snippet to start a gpui-kit application. Call gpui_kit::init(cx) first, then open a window with gpui_kit::open_window, returning a window handle and content entity. The builder creates application content, and Kit supplies the Root and automatically hosts dialogs, sheets, and notifications. ```rust gpui_kit::init(cx); let (window_handle, content) = gpui_kit::open_window(options, cx, |window, cx| { build_content(window, cx) })?; ``` -------------------------------- ### Initialize and render a WebView Source: https://gpui-kit.com/docs/webview Demonstrates creating a WebView entity, loading a URL, and rendering it within a GPUI view. Ensure the native view is created after obtaining a live window handle. ```rust use gpui_kit::*; use gpui_wry::WebView; let webview = cx.new(|cx| { use raw_window_handle::HasWindowHandle; let handle = window.window_handle().expect("No window handle"); let native = wry::WebViewBuilder::new() .build_as_child(&handle) .expect("Failed to create WebView"); WebView::new(native, window, cx) }); webview.update(cx, |view, _| view.load_url("https://gpui-kit.com")); // In the owning View's render method: div().flex_1().child(webview.clone()) ``` -------------------------------- ### Migration: Replace cx.open_window with gpui_kit::open_window Source: https://gpui-kit.com/releases Shows the diff for migrating from the old window-opening pattern to the simplified gpui_kit::open_window call. The old code manually created a Root; the new code returns the window handle and content directly. ```rust - cx.open_window(options, |window, cx| { - let content = build_content(window, cx); - cx.new(|cx| Root::new(content, window, cx)) - }) + let (window_handle, content) = + gpui_kit::open_window(options, cx, |window, cx| { + build_content(window, cx) + })?; ``` -------------------------------- ### Initialize GPUI Kit and open a window with Root Source: https://gpui-kit.com/component/root Initializes GPUI Kit and opens a window whose root view is a `Root` wrapping the application view. Call `gpui_kit::init` before creating windows; it registers the styled window extension. The window's root view must be a `Root` for dialogs, sheets, notifications, focus traversal, and text selection to work. ```rust use gpui_kit::{ AppContext as _, Context, IntoElement, ParentElement as _, Render, Styled as _, Window, WindowOptions, div, }; pub fn run() { gpui_kit::application() .with_assets(gpui_kit::assets::Assets) .run(|cx| { gpui_kit::init(cx); // The window's root view is a `Root` wrapping the view, which // renders dialogs, sheets and notifications above it. gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| { cx.new(|_| BootstrapView) }) .expect("failed to open window"); }); } struct BootstrapView; impl Render for BootstrapView { fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { div().size_full().child("My application") } } ``` -------------------------------- ### Initialize gpui_kit::base Source: https://gpui-kit.com/base/getting-started Call gpui_kit::base::init once before opening windows to initialize the base framework. ```rust use gpui_kit::AppContext as _; fn main() { gpui_platform::application().run(|cx| { gpui_kit::base::init(cx); // Open your application window here. }); } ``` -------------------------------- ### Start hot-reload with runtime.watch Source: https://gpui-kit.com/shell/hosting Starts the hot-reload loop for a loaded root. The returned Watcher owns the watch; dropping it stops the loop, while .forget() lets it run for the View's lifetime. The loop ends when the View, runtime, or window goes away. ```rust runtime.watch(&root, window, cx)?.forget(); ``` -------------------------------- ### Context.spawn(body, opts?) Source: https://gpui-kit.com/shell/api Runs body(cx) and adopts the promise it returns, so a rejection is reported. Mirrors App::spawn. ```APIDOC ## spawn(body, opts?) ### Description Runs `body(cx)` and adopts the promise it returns, so a rejection is reported. Mirrors `App::spawn`. ### Method spawn ### Parameters - **body** (function) - Required - The async function to run. - **opts** (TaskOptions?) - Optional - Options for the task, including the owner View. ### Returns void ``` -------------------------------- ### TaskLab app with start, cancel, and fail Source: https://gpui-kit.com/docs/task Complete GPUI application that spawns a background task, tracks request IDs to ignore stale results, and provides buttons to start, fail, or cancel. Run with cargo run -p hello_world --bin task_lab from the repository root. ```rust use gpui_kit::component::button::{Button, ButtonVariants}; use gpui_kit::*; use std::time::Duration; struct TaskLab { status: String, request_id: u64, task: Option>, } impl TaskLab { fn start(&mut self, fail: bool, cx: &mut Context) { self.request_id = self.request_id.wrapping_add(1); let request_id = self.request_id; self.task = None; // Drop the previous handle before starting again. self.status = format!("Loading request {request_id}..."); cx.notify(); self.task = Some(cx.spawn(async move |this, cx| { let result: Result = cx .background_spawn(async move { // Stand in for expensive work; this blocks a worker, not the UI thread. std::thread::sleep(Duration::from_millis(800)); if fail { Err("Simulated failure".into()) } else { Ok(format!("Completed request {request_id}")) } }) .await; _ = this.update(cx, |view, cx| { if view.request_id != request_id { return; // A newer start or cancel owns the displayed state. } view.status = match result { Ok(value) => value, Err(error) => format!("Failed: {error}"), }; cx.notify(); }); })); } fn cancel(&mut self, cx: &mut Context) { self.request_id = self.request_id.wrapping_add(1); self.task = None; // Dropping the handle prevents future polls. self.status = "Cancelled".into(); cx.notify(); } } impl Render for TaskLab { fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { div() .flex() .flex_col() .size_full() .items_center() .justify_center() .gap_2() .child(self.status.clone()) .child( Button::new("start") .primary() .label("Start") .on_click(cx.listener(|view, _, _, cx| view.start(false, cx))), ) .child( Button::new("fail") .label("Fail") .on_click(cx.listener(|view, _, _, cx| view.start(true, cx))), ) .child( Button::new("cancel") .label("Cancel") .on_click(cx.listener(|view, _, _, cx| view.cancel(cx))), ) } } fn main() { application().with_assets(assets::Assets).run(|cx| { init(cx); open_window(WindowOptions::default(), cx, |_, cx| { cx.new(|_| TaskLab { status: "Idle".into(), request_id: 0, task: None, }) }) .expect("Failed to open window"); }); } ``` -------------------------------- ### Log message for unwired on_key_down on Select Source: https://gpui-kit.com/shell/elements Log message shown when a handler is written on a component that does not install GPUI's input listeners, such as Select. It explains that the shell installs listeners on the element it owns (a plain div, h_flex, or v_flex) and advises wrapping the component and writing the handler on the wrapper. ```text `on_key_down` is not wired on a Select: the shell installs GPUI's input listeners on the element it owns outright, which is a plain `div`, `h_flex` or `v_flex`. Wrap it and write `on_key_down` on the wrapper ``` -------------------------------- ### Set up and run the standalone test project (shell commands) Source: https://gpui-kit.com/docs/test These commands copy the required test files from the GPUI Kit checkout into a standalone project, generate a lockfile, and run the test with `cargo test --test ui --locked`. The `ui.rs` file alone will fail at `mod common;` without the companion `tests/common/mod.rs` fixture. ```shell mkdir -p tests/common cp ../gpui-kit/crates/kit/tests/ui.rs tests/ui.rs cp ../gpui-kit/crates/kit/tests/common/mod.rs tests/common/mod.rs cargo generate-lockfile cargo test --test ui --locked ``` -------------------------------- ### Shell document image permissions: Add HTTP request grants for remote images Source: https://gpui-kit.com/releases Remote document images now require explicit GET grants for their URL and every redirect target. Non-HTTP(S) sources, including data URLs, are refused. This diff shows adding an HttpRequestGrant for images.example with GET on /image.png. ```rust - Policy::new() + Policy::new().with_capabilities(Capabilities::new().http_requests([ + HttpRequestGrant::new("images.example", ["GET"], ["/image.png"], [] as [&str; 0]), + ])) ``` -------------------------------- ### Call an async function from script Source: https://gpui-kit.com/shell/host-module Example of how the script consumes the asynchronous function defined in the host module. ```typescript import { query } from "db"; const rows = await query("select 1"); ``` -------------------------------- ### Read and write files Source: https://gpui-kit.com/shell/capabilities Example of reading a file as a UTF-8 string and writing it back with an appended newline. ```typescript const source = await fs.readFile("notes.md", "utf8"); await fs.writeFile("notes.md", source + "\n"); ``` -------------------------------- ### Hello World GPUI View with click counter Source: https://gpui-kit.com/shell/getting-started A minimal GPUI application: a View class with an init method and a render method that builds a flex layout with a click counter and a button. The render method uses snake_case style methods from the host surface and calls cx.notify() to trigger repaints. Run it with the cargo command shown. ```javascript // hello/main.js import { View } from "gpui-kit"; import { v_flex, Button } from "gpui-base"; export default class Hello extends View { init() { this.clicks = 0; } render(cx) { return v_flex() .size_full() .items_center() .justify_center() .gap(12) .bg(cx.theme().colors.background) .child( div() .text_color(cx.theme().colors.foreground) .child(`Clicked ${this.clicks} times`), ) .child( Button.new("click") .h(28) .px(12) .items_center() .justify_center() .border(1) .border_color(cx.theme().colors.border) .bg(cx.theme().colors.surface) .text_color(cx.theme().colors.foreground) .on_click((_event, cx) => { this.clicks += 1; cx.notify(); }) .child("Click me"), ); } } ``` ```bash cargo run -p gpui-shell -- hello ``` -------------------------------- ### Run gpui-shell benchmark in release mode Source: https://gpui-kit.com/shell/engine Run the timing benchmark in release mode; the second invocation includes the largest test behind --ignored that scales the panel to 8,403 nodes and takes seconds. Both commands must run with --nocapture to view output. ```bash cargo test -p gpui-shell --release --lib benchmark -- --nocapture ``` ```bash cargo test -p gpui-shell --release --lib benchmark -- --ignored --nocapture ``` -------------------------------- ### Different Loading Icons Source: https://gpui-kit.com/component/spinner Examples using the default loader icon and the LoaderCircle icon with various colors and sizes. ```rust // Default loader (line spinner) Spinner::new() .color(cx.theme().muted_foreground) // Circle loader Spinner::new() .icon(IconName::LoaderCircle) .color(cx.theme().blue) // Large circle loader with custom color Spinner::new() .icon(IconName::LoaderCircle) .large() .color(cx.theme().green) ``` -------------------------------- ### Storing Structured Data with JSON Source: https://gpui-kit.com/shell/capabilities Example of storing and retrieving structured objects by serializing them to strings using JSON.stringify and JSON.parse. ```javascript localStorage.setItem( "window", JSON.stringify({ title: "Notes", size: [640, 480] }), ); const window = JSON.parse(localStorage.getItem("window") ?? "{}"); ``` -------------------------------- ### Loading Profile Card example Source: https://gpui-kit.com/component/skeleton Builds a profile card layout with skeleton placeholders for the avatar, name, email, and bio lines. Uses v_flex and h_flex with gap, padding, border, and rounded utilities to structure the card. ```rust v_flex() .gap_4() .p_4() .border_1() .border_color(cx.theme().border) .rounded(cx.theme().radius_lg) .child( h_flex() .gap_3() .items_center() .child(Skeleton::new().size_12().rounded_full()) // Avatar .child( v_flex() .gap_2() .child(Skeleton::new().w(px(120.)).h_4().rounded_md()) // Name .child(Skeleton::new().w(px(100.)).h_3().rounded_md()) // Email ) ) .child( v_flex() .gap_2() .child(Skeleton::new().w_full().h_4().rounded_md()) // Bio line 1 .child(Skeleton::new().w(px(200.)).h_4().rounded_md()) // Bio line 2 ) ``` -------------------------------- ### ShellRuntime::new_isolated Source: https://gpui-kit.com/shell/hosting Creates an additional ShellRuntime that is not installed as the default. The host must retain the handle to manage multiple VMs. ```APIDOC ## ShellRuntime::new_isolated ### Description Creates an additional ShellRuntime that is not installed as the default. The host must retain the handle to manage multiple VMs. ### Method new_isolated ### Signature `ShellRuntime::new_isolated() -> ShellRuntime` ### Parameters None. ### Returns - **ShellRuntime** - The new isolated runtime instance. ``` -------------------------------- ### ShellRuntime::watch Source: https://gpui-kit.com/shell/hosting Starts watching the loaded root for changes. Returns an error if the root is a failure root (no application to watch). ```APIDOC ## ShellRuntime::watch ### Description Starts watching the loaded root for changes. Returns an error if the root is a failure root (no application to watch). ### Method watch ### Signature `runtime.watch(&root, window, cx) -> Result` ### Parameters - **root** (ShellRoot) - Required - The root to watch. - **window** (Window) - Required - The window. - **cx** (Context) - Required - The GPUI context. ### Returns - **WatchHandle** - A handle to the watch. ### Errors - Returns an error if the root is a failure root. ``` -------------------------------- ### Basic localStorage API Usage Source: https://gpui-kit.com/shell/capabilities Standard operations for interacting with localStorage, including setting, getting, removing, and clearing items. ```javascript localStorage.setItem("todolist.items", JSON.stringify(items)); const saved = localStorage.getItem("todolist.items"); // null when the key is unset localStorage.removeItem("todolist.items"); localStorage.length; localStorage.key(0); localStorage.clear(); ``` -------------------------------- ### Open window and load ShellRoot Source: https://gpui-kit.com/shell/hosting Opens a window and loads the application root, returning a ShellRoot. In debug builds, it also sets up a watcher for hot reload. If loading fails, the error surface is rendered instead of panicking. ```rust cx.open_window(options, move |window, cx| { let root = runtime.load(&app_root, window, cx); #[cfg(debug_assertions)] if let Ok(watch) = runtime.watch(&root, window, cx) { watch.forget(); } root })?; ```