home / skills / aprilnea / gpui-skills / gpui
This skill helps you apply GPUI best practices to desktop UI development, improving performance, reliability, and maintainability across views, state, events,
npx playbooks add skill aprilnea/gpui-skills --skill gpuiReview the files below or copy the command above to add this skill to your agents.
---
name: gpui
description: GPUI UI framework best practices for building desktop applications. Use when writing GPUI code, creating UI components, handling state/events, async tasks, animations, lists, forms, testing, or working with Zed-style Rust GUI code.
license: MIT
metadata:
author: AprilNEA
version: "1.0.0"
---
# GPUI Best Practices
Comprehensive guide for building desktop applications with GPUI, the UI framework powering Zed editor. Contains 40+ rules across 8 categories, prioritized by impact.
## When to Apply
Reference these guidelines when:
- Writing new GPUI views or components
- Implementing state management with Entity
- Handling events and keyboard shortcuts
- Working with async tasks and background work
- Building forms, lists, or dialogs
- Styling components with Tailwind-like API
- Testing GPUI applications
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Core Concepts | CRITICAL | `core-` |
| 2 | Rendering | CRITICAL | `render-` |
| 3 | State Management | HIGH | `state-` |
| 4 | Event Handling | HIGH | `event-` |
| 5 | Async & Concurrency | MEDIUM-HIGH | `async-` |
| 6 | Styling | MEDIUM | `style-` |
| 7 | Components | MEDIUM | `comp-` |
| 8 | Anti-patterns | CRITICAL | `anti-` |
## Quick Reference
### 1. Core Concepts (CRITICAL)
- `core-ownership-model` - Understand GPUI's single ownership model
- `core-entity-operations` - Use read/update/observe/subscribe correctly
- `core-weak-entity` - Use WeakEntity to break circular references
- `core-context-types` - Know when to use App, Context<T>, AsyncApp
### 2. Rendering (CRITICAL)
- `render-render-vs-renderonce` - Choose Render for stateful, RenderOnce for components
- `render-element-composition` - Build element trees with div() and method chaining
- `render-conditional` - Use .when() and .when_some() for conditional styling
- `render-shared-string` - Use SharedString to avoid string copying
- `render-builder-pattern` - Design components with builder pattern
### 3. State Management (HIGH)
- `state-notify` - Always call cx.notify() after state changes
- `state-observe` - Use cx.observe() to react to Entity changes
- `state-subscribe` - Use cx.subscribe() for typed events
- `state-global` - Use Global trait for app-wide state
- `state-keyed-state` - Use window.use_keyed_state() for persistent state
### 4. Event Handling (HIGH)
- `event-actions` - Define and register actions for keyboard shortcuts
- `event-listener` - Use cx.listener() for view-bound event handlers
- `event-focus` - Manage focus with FocusHandle and key_context
- `event-propagation` - Understand event bubbling and stop_propagation
### 5. Async & Concurrency (MEDIUM-HIGH)
- `async-task-lifecycle` - Store or detach tasks to prevent cancellation
- `async-debounce` - Implement debounce with timer + task replacement
- `async-background-spawn` - Use background_spawn for CPU-intensive work
- `async-weak-entity` - Use WeakEntity for safe cross-await access
- `async-error-handling` - Use .log_err() and .detach_and_log_err()
### 6. Styling (MEDIUM)
- `style-flexbox` - Use h_flex() and v_flex() for layouts
- `style-theme-colors` - Always use cx.theme() for colors
- `style-spacing` - Use DynamicSpacing for responsive spacing
- `style-elevation` - Use elevation system for layered surfaces
### 7. Components (MEDIUM)
- `comp-stateless` - Prefer RenderOnce with #[derive(IntoElement)]
- `comp-traits` - Implement Disableable, Selectable, Sizable traits
- `comp-focus-ring` - Add focus ring for accessibility
- `comp-dialog` - Use WindowExt for dialog management
- `comp-variant` - Use variant enums for component styles
### 8. Anti-patterns (CRITICAL)
- `anti-silent-error` - Never silently discard errors with let _ =
- `anti-drop-task` - Never drop Task without storing or detaching
- `anti-drop-subscription` - Always detach or store subscriptions
- `anti-circular-reference` - Avoid Entity cycles, use WeakEntity
- `anti-missing-notify` - Never forget cx.notify() after state changes
- `anti-unwrap` - Avoid unwrap(), use ? or explicit handling
## Architecture Overview
```
┌─────────────────────────────────────────────────────────┐
│ Application (App) │
│ (Single owner of all Entities) │
└─────────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────────┐ ┌───────────┐ ┌──────────┐
│ Entity<A> │ │ Entity<B> │ │ Global<C>│
└───────────┘ └───────────┘ └──────────┘
│ │ │
│ read/update │ read/update │ via App
│ via Context<A> │ via Context<B> │
│
┌─────────────────────────────────────────────────┐
│ UI Rendering (Render trait) │
│ Each frame: fn render(&mut self, ...) │
│ Returns: impl IntoElement (Element tree) │
└─────────────────────────────────────────────────┘
│
├─ observe() → changes trigger render
├─ subscribe() → events trigger reactions
├─ notify() → signal changes
└─ emit() → send typed events
```
## How to Use
Read individual rule files for detailed explanations and code examples:
```
rules/core-ownership-model.md
rules/render-render-vs-renderonce.md
rules/anti-silent-error.md
```
Each rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
This skill captures GPUI UI framework best practices for building robust desktop applications. It condenses 40+ prioritized rules across core concepts, rendering, state, events, async, styling, components, and anti-patterns into a practical reference. Use it to speed development, avoid common pitfalls, and ensure consistent, maintainable GPUI code.
The skill inspects common GPUI patterns and prescribes clear, actionable rules for component design, state management, event handling, async tasks, styling, and testing. Each rule highlights the problem, shows incorrect and correct approaches, and recommends concrete APIs (Entity, Context, Render/RenderOnce, WeakEntity, background_spawn, cx.notify(), etc.). Follow the rules while writing views, components, or background tasks to reduce bugs and improve UX.
When should I use Render vs RenderOnce?
Use Render for components that need internal state, observe Entities, or re-render frequently. Use RenderOnce (IntoElement) for stateless, composition-only widgets to reduce overhead.
How do I avoid dropped background work?
Store tasks on the owning Entity or explicitly detach them. Use background_spawn for CPU-intensive jobs and WeakEntity to access state safely across awaits.