# WarpUI Framework: The Entity-Handle Pattern

> How does Warp draw its screens? Instead of standard UI toolkits, it uses a custom UI framework built on the Entity-Component-Handle pattern. Think of it like a puppet show where a global App puppeteer owns all the puppets (views and models), and views talk to each other only by holding safe references (ViewHandle). It is Flutter-inspired, uses an Actions system for events, and requires creating a MouseStateHandle exactly once during construction to track mouse inputs—otherwise, clicking won't work!

- Repository: warpdotdev/warp
- GitHub: https://github.com/warpdotdev/warp
- Human wiki: https://grok-wiki.com/public/wiki/warpdotdev-warp-a2a3b9202160
- Complete Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a2a3b9202160/llms-full.txt

## Source Files

- `crates/warpui_core/src/core/app.rs`
- `crates/warpui_core/src/core/entity.rs`
- `crates/warpui_core/src/core/view/mod.rs`
- `crates/warpui_core/src/core/view/handle.rs`
- `crates/warpui_core/src/core/view/context.rs`
- `crates/warpui_core/src/presenter.rs`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/warpui_core/src/core/app.rs](crates/warpui_core/src/core/app.rs)
- [crates/warpui_core/src/core/entity.rs](crates/warpui_core/src/core/entity.rs)
- [crates/warpui_core/src/core/view/mod.rs](crates/warpui_core/src/core/view/mod.rs)
- [crates/warpui_core/src/core/view/handle.rs](crates/warpui_core/src/core/view/handle.rs)
- [crates/warpui_core/src/core/view/context.rs](crates/warpui_core/src/core/view/context.rs)
- [crates/warpui_core/src/presenter.rs](crates/warpui_core/src/presenter.rs)
- [crates/warpui_core/src/elements/hoverable.rs](crates/warpui_core/src/elements/hoverable.rs)
- [WARP.md](WARP.md)
</details>

# WarpUI Framework: The Entity-Handle Pattern

How does Warp draw its screens? Instead of using standard native or web UI toolkits, the Warp terminal emulator utilizes a custom UI framework named **WarpUI** built entirely on a specialized **Entity-Component-Handle** pattern. 

In a traditional application framework, visual UI elements hold direct references to their siblings, parent components, or underlying models. In Rust, this layout immediately triggers complex borrow checker conflicts and reference cycles. To solve this, WarpUI models its layout like a puppet show. A central orchestrator, `AppContext` (the puppeteer), retains full, exclusive ownership of all active UI views and models (the puppets). Views interact and talk to each other only by holding lightweight, type-safe references called handles (`ViewHandle`). When views need to render or modify state, they temporarily borrow access from the global puppeteer.

---

## The Global Puppeteer: App & AppContext

At the heart of the application is the `App` and its underlying `AppContext`. These structures act as the single source of truth for the entire application state.

`AppContext` retains exclusive ownership of all active models and views:
- **Models**: Stored within a central map of generic trait objects: `models: HashMap<EntityId, Box<dyn AnyModel>>`.
- **Windows & Views**: Windows are mapped by their ID: `windows: HashMap<WindowId, Window>`. The views are held inside the `Window` struct itself.

Because the puppeteer owns all state, views and models cannot store pointers to each other. Instead, they reference each other via globally-unique `EntityId` tokens wrapped inside handles.

```text
  +-------------------------------------------------------------+
  |                      AppContext (Puppeteer)                 |
  |  Owns all View instances in memory.                         |
  |  Provides raw access via read_view() & update_view()        |
  +-------------------------------------+-----------------------+
                                        |
                 Stores Views         | Creates Handles
                 in a HashMap          v
  +-------------------------------------+-----------------------+
  |  ViewInstance A                     |  ViewHandle<ViewA>    |
  |                                     |                       |
  |  Holds reference to:                |  Safe reference held  |
  |  ViewHandle<ViewB> <----------------+  by other views.      |
  +-------------------------------------+-----------------------+
```

Sources: [crates/warpui_core/src/core/app.rs:71-115](), [crates/warpui_core/src/core/app.rs:569-684](), [WARP.md:55-68]()

---

## Entities, Views, and Handles

To support this puppeteer model, WarpUI defines several base primitives:

### EntityId and Entity
An `EntityId` is a thread-safe, globally unique `usize` identifier used to refer to any View or Model interchangeably. An `Entity` is a trait that exposes an associated event type:
```rust
pub trait Entity: 'static {
    type Event;
}
```

### View
A `View` represents an interactive, renderable UI component (similar to a React component or a Flutter widget). It holds instance state and produces an `Element` tree to draw itself:
```rust
pub trait View: Entity {
    fn ui_name() -> &'static str;
    fn render(&self, app: &AppContext) -> Box<dyn Element>;
    fn on_focus(&mut self, _focus_ctx: &FocusContext, _ctx: &mut ViewContext<Self>) {}
    fn on_blur(&mut self, _blur_ctx: &BlurContext, _ctx: &mut ViewContext<Self>) {}
}
```

### ViewHandle & WeakViewHandle
Views interact with other views via handles:
- **`ViewHandle<T>`**: A strong reference containing the `WindowId` and the `EntityId` of the view. Dropping a `ViewHandle` decrements the internal reference count.
- **`WeakViewHandle<T>`**: A weak reference that prevents circular reference cycles. It must be upgraded back to a strong `ViewHandle` via the `AppContext` before use:
```rust
pub fn upgrade(&self, app: &AppContext) -> Option<ViewHandle<T>> {
    let window_id = app.view_to_window.get(&self.view_id).copied()?;
    if app.windows.get(&window_id).and_then(|w| w.views.get(&self.view_id)).is_some() {
        Some(ViewHandle::new(window_id, self.view_id, &app.ref_counts))
    } else {
        None
    }
}
```

Sources: [crates/warpui_core/src/core/entity.rs:8-33](), [crates/warpui_core/src/core/view/mod.rs:32-70](), [crates/warpui_core/src/core/view/handle.rs:20-56](), [crates/warpui_core/src/core/view/handle.rs:233-275]()

---

## Context-Bound Execution: ViewContext

Since raw views are owned inside `AppContext`, you cannot directly call methods on them. Instead, you interact with views inside scope-restricted callbacks using a `ViewContext<'a, T>`.

`ViewContext` wraps a mutable reference to `AppContext` and implements `Deref` / `DerefMut` to it. This allows components to seamlessly request global resources (such as fonts or windows) while executing code scoped to a specific view.

```rust
pub struct ViewContext<'a, T: ?Sized> {
    app: &'a mut AppContext,
    window_id: WindowId,
    view_id: EntityId,
    view_type: PhantomData<T>,
}
```

Through the `ViewContext`, views can:
- Spawn background async tasks (`ctx.spawn(...)`) that return results to the main thread.
- Establish observations (`ctx.observe(...)`) to track changes in models.
- Subscribe to view events (`ctx.subscribe_to_view(...)`) emitted by child components.

Sources: [crates/warpui_core/src/core/view/context.rs:30-49](), [crates/warpui_core/src/core/view/context.rs:800-813]()

---

## The Render Pipeline: Elements and the Presenter

WarpUI is a Flutter-inspired declarative framework. Instead of updating pixels or native buttons directly, a view's `render()` method outputs a visual description called an `Element` tree.

The `Presenter` orchestrates the conversion of these visual descriptions into pixels on a screen. Every frame, the presenter executes a multi-step pipeline:

```mermaid
classDiagram
    class AppContext {
        -models: HashMap~EntityId, Box~dyn AnyModel~~
        -windows: HashMap~WindowId, Window~
        +add_view() ViewHandle
        +add_model() ModelHandle
    }
    class View {
        <<interface>>
        +ui_name() str
        +render(app) Element
        +on_focus(focus_ctx, ctx)
        +on_blur(blur_ctx, ctx)
    }
    class ViewHandle {
        -view_id: EntityId
        -window_id: WindowId
        +id() EntityId
        +downgrade() WeakViewHandle
        +read(app, read)
        +update(app, update)
    }
    class WeakViewHandle {
        -view_id: EntityId
        +upgrade(app) ViewHandle
    }
    class ViewContext {
        -app: AppContext
        -window_id: WindowId
        -view_id: EntityId
        +handle() WeakViewHandle
        +emit(event)
        +subscribe_to_view(handle, callback)
        +dispatch_typed_action(action)
    }
    class Presenter {
        -rendered_views: HashMap~EntityId, Box~dyn Element~~
        +build_scene(window_size, scale_factor, ctx) Scene
        +dispatch_event(event, app) DispatchResult
    }
    AppContext "1" *-- "many" View : owns
    ViewHandle --> AppContext : reads/updates via
    ViewContext "1" o-- "1" AppContext : derefs to
    Presenter --> AppContext : renders views from
```

1. **`layout`**: The presenter traverses the tree, computing bounds and applying size constraints (`SizeConstraint`) from top to bottom.
2. **`after_layout`**: A secondary hook letting elements adjust their internals after dimensions are calculated.
3. **`paint`**: The elements are drawn into a vector-graphics `Scene`, converting shapes, text layouts, and styles into render commands.
4. **`dispatch_event`**: When the operating system fires events (e.g., keyboard input, mouse scroll), the presenter routes them down the cached visual element tree.

Sources: [crates/warpui_core/src/presenter.rs:25-35](), [crates/warpui_core/src/presenter.rs:301-330]()

---

## UI Communication and Event Dispatching

Unlike the DOM in web browsers, elements in WarpUI do not automatically bubble up arbitrary events. Instead, communication happens through two distinct patterns:

### 1. Emitters and Subscriptions (Down-to-Up)
When a view emits a change, it uses `ctx.emit(payload)`. For another view to react, it must explicitly subscribe to that exact child's handle:
```rust
ctx.subscribe_to_view(&child_handle, |parent, child_handle, event, ctx| {
    // React to the child view's event
});
```

### 2. The Actions System (Up-to-Down / Focused Routing)
Keyboard and mouse events are dispatched using **Actions**. Views implement `TypedActionView` to handle actions of a specific type.
When an action is triggered:
1. WarpUI retrieves the **responder chain** (the currently focused view, followed by all its parent views up to the root).
2. The framework bubbles the action up the responder chain, querying `handle_action` on each view until one returns `true` to signal it handled the event.
3. Legacy global action handlers are fallback targets if nothing in the focused chain captures the action.

Sources: [crates/warpui_core/src/core/view/context.rs:187-212](), [crates/warpui_core/src/core/view/context.rs:350-365](), [crates/warpui_core/src/core/view/context.rs:400-417]()

---

## Crucial Developer Gotcha: The MouseStateHandle Lifecycle

When writing views that support hovering or clicking, developers use a `MouseStateHandle` (defined as `Arc<Mutex<MouseState>>`). 

> [!WARNING]
> **The MouseStateHandle Lifecycle Rule**
> You must instantiate `MouseStateHandle` **exactly once** during the view's construction and store it as a field on the `View` struct itself. You must **never** create a `MouseStateHandle` inline inside the `render()` function.

### The Catastrophic Failure Mode
If you write code that instantiates the handle inside a view's `render()` method:
```rust
// CATASTROPHIC BUG: Recreates the state handle on every render pass!
impl View for MyButton {
    fn render(&self, app: &AppContext) -> Box<dyn Element> {
        let mouse_state = MouseStateHandle::default(); // Created inline
        Hoverable::new(mouse_state, |state| {
            // Draw button based on state.is_hovered
        })
    }
}
```

This code compiles but breaks clicking and hovering entirely:
1. When the mouse moves over the button, `Hoverable` receives the event and updates `is_hovered` to `true` on the passed `MouseStateHandle`.
2. This state change triggers a repaint and forces the parent view to call `render()`.
3. The inline instantiation runs again, creating a **brand-new** `MouseStateHandle` initialized to `false` (default state).
4. The active hover state is thrown away immediately, making it impossible to detect clicks or show hover states.

To prevent this, instantiate the handle once in your constructor and reference it:
```rust
struct MyButton {
    mouse_state: MouseStateHandle, // Stored persistently on the struct
}

impl View for MyButton {
    fn render(&self, app: &AppContext) -> Box<dyn Element> {
        Hoverable::new(self.mouse_state.clone(), |state| {
            // Safe: State persists across render cycles!
        })
    }
}
```

Sources: [crates/warpui_core/src/elements/hoverable.rs:159-210](), [WARP.md:68-68]()

---

## Summary

The Entity-Component-Handle pattern solves Rust's ownership and lifetime challenges by consolidating all view ownership into a global puppeteer (`AppContext`). This architecture allows developers to build complex terminal application screens safely through simple references (`ViewHandle`), declarative tree rendering (`Element`), and targeted events subscription. By respecting key rules like the single-instantiation lifecycle of `MouseStateHandle`, developers can successfully tap into the high-performance drawing capability of the WarpUI platform.

Sources: [crates/warpui_core/src/core/app.rs:71-115]()
