meowlynxsea/yororen-ui/yororen-ui-recipes
Claude Code and agent skill by meowlynxsea/yororen-ui
- community
Checking that the SKILL.md file is still in the repository.
End-to-end recipe patterns for end users building gpui apps with Yororen UI (yororen_ui). Use when the user asks for a complete working example, wants a screen layout pattern, or needs guidance composing components, modals, forms, list rendering, virtualized lists, notifications, theme switching, or i18n. Triggers include "show me a full example", "copy from the gallery", "how do I do theme switching", "how do I compose a modal + form", "how do I virtualize a long list". Not for contributing to yororen-ui itself.
Install
npx vskill@latest install meowlynxsea/yororen-ui/yororen-ui-recipesSKILL.md
Yororen UI Recipes
Prefer copying and adapting proven patterns from the demos rather than inventing new architectures. The five live demos converge on a small set of working patterns; this skill points to the right demo for each need and distills the cross-cutting composition rules.
1. The five demos
All five are under crates/yororen-ui-demos/. The first four are members of the workspace Cargo.toml; the fifth is excluded but still builds in isolation.
| Demo | What it shows | Copy from when you want… | |
|---|---|---|---|
counter | minimal bootstrap, single Entity<T> global, three buttons, cx.notify() | a starter template for any app | |
layers_demo | the 3 render pathways (headless / default-render / caller-custom Material ripple) side by side | to understand the visual flexibility of headless props | |
inputs_demo | all 7 text inputs wired with cx.entity().clone() on_change closures | an input form, a settings page, anything input-heavy | |
gallery_demo | the full 54-component showcase, theme switching, i18n, notification host, virtualized list | a kitchen-sink reference for any pattern | |
theme_showcase | per-render theme::install(cx, theme) for live theme switching | a "Next theme" toolbar, A/B theme testing |
The gallery is the most complete — start there if you're building a real app. The counter is the smallest — start there if you're new.
2. Counter — the minimal template
Files: crates/yororen-ui-demos/counter/src/.
Three takeaways from the counter:
- The state is one
Entity<Counter>inside aGlobalwrapper. The
global is registered with cx.set_global, read with cx.global::<AppState>().
- Each button's
moveclosure clones theEntity<Counter>once at
construction. The closure owns the clone.
- Mutate the value, then
cx.notify(). gpui-ce 0.3 does not auto-notify
on Entity::update.
3. Layers demo — the 3 render pathways
Files: crates/yororen-ui-demos/layers_demo/src/.
One window, three columns:
| Column | Render pathway | What it shows | |
|---|---|---|---|
| 1 | headless::button(id, cx).on_click(...).apply(div().bg(…).p_2().child("click me")) | A11y only — caller owns every visual. The button does not respond to hover/press; the cursor changes to a pointer. | |
| 2 | headless::button(id, cx).variant(ActionVariantKind::Neutral).on_click(...).render(cx).child("Click me") | The default renderer paints bg / border / padding / radius / hover / active from the theme JSON. | |
| 3 | material_button(id, "Click me".into(), cx, window) (a custom Material-ripple painter defined in material_button.rs) | Caller writes a bespoke gpui::Element for the ripple animation. Headless apply is still called for focus + click. |
Copy from this demo when you need to:
- Understand what
.applydoes and doesn't do (it doesn't paint). - See a hand-rolled
Element(the ripple) that uses
window.request_animation_frame to advance an f32 progress and PathBuilder to draw a true circle.
- See how a custom renderer is wired into the headless flow (the
material_button function calls headless::button(id, cx).on_click(...).apply(div()...) internally — the focus + click is the headless layer's job; the visual is the bespoke painter's job).
The demo also has a fourth panel: a text_input with .render(cx, window) to prove the headless / renderer split works the same for inputs, not just buttons.
4. Inputs demo — all 7 text inputs wired
Files: crates/yororen-ui-demos/inputs_demo/src/.
Seven panels, one per text input. The pattern is the same for all:
Plus a status line that reads the value back from state:
Two non-obvious things the demo shows:
- `number_input` has three callbacks —
on_change(f64, …)for
the typed value, on_increment(f64, …) and on_decrement(f64, …) for the stepper buttons. All three write to the same field.
- `keybinding_input` has its own `mode: KeybindingInputMode`
(Idle or Capturing). The renderer drives the mode transitions but you wire the on_start_capture / on_cancel_capture hooks to update your app state so the status line shows "Capturing…" vs "Idle".
5. Gallery demo — the kitchen sink
Files: crates/yororen-ui-demos/gallery_demo/src/.
By far the largest demo. It is the canonical reference for:
- The full component surface (54 components, all in one window).
cell()andinput_cell()helper functions that wrap a single
component in a labelled card with a status line — the fastest way to compose a "compare every variant" page.
- A working theme switcher in the toolbar (default vs brutalism, light
vs dark) using cx.renderer_arc and per-render theme::install(cx, theme).
- i18n with multiple locales + app-specific translations layered on
top of the framework strings, via locale::install_with_translations(cx, "en"|"zh-CN"|"ar", app_map).
- The
NotificationCenterhost rendered with
gpui::deferred(...).with_priority(3) so toasts float above modals.
- The modal scrim and Esc handling using
modal_state.set_on_close+
ModalCloseReason::Escape | ScrimClick | Programmatic.
- A virtualized list with infinite loading, using
on_visible_range_change to bump the controller's count.
When the user asks "how do I do X", the answer is almost always in the gallery. Open it before writing new code.
6. Theme showcase — live theme switching
Files: crates/yororen-ui-demos/theme_showcase/src/ (excluded from workspace but still builds; check the file before reaching for it).
Two-window pattern for theme switching:
The four themes are usually system-light, system-dark, and two inline const CATPPUCCIN: &str = r##"{...}"##; JSON strings. Bump self.current = (self.current + 1) % themes.len() in a click handler, cx.notify(), and the next render re-themes the window.
7. Composition rules
These are the rules the demos converge on. Violate them and the UI becomes hard to maintain or visibly broken.
- Stable identity. Every stateful child in a list, virtualized
view, or any tree that can be reordered needs .id(...). Use the row index as the id when the data is append-only; use the data's primary key when the data is mutable. Example: text_input(format!("row-email-{ix}")) in a virtual list.
- Render overlays at the scroll root, not inside a section. A
modal that lives inside a scrollable column will be clipped and won't receive Escape reliably. Build the scroll root, then .child(content).child(modal).child(toast_host) as siblings, with the modal and toast wrapped in gpui::deferred(...).with_priority(N).
- `&mut cx
for minting entities fromContext<T>`.**
cx.focus_handle() and XxxState::new(cx) need &mut App. Inside a Render::render closure you have &mut Context<MyApp>; Context<T>: DerefMut<Target = App>, so &mut **cx is a &mut App. Use it inline at the call site, never stored in a let.
- Stable identifier scope. Two inputs with the same
idshare
the same keyed state. If you render the same logical input twice (in a list of email rows, say), include the row index or some unique key in the id: format!("email-{row_id}").
- No `render()` side effects. Render closures must be pure with
respect to gpui's redraw cycle. Spawning tasks, calling cx.spawn, doing file I/O — all of these go in event handlers, not in Render::render.
- One renderer per `(Marker, dyn Trait)` slot. If you register
BrutalButtonRenderer for the Button marker, the previous TokenButtonRenderer is overwritten. There's no layering. If you want a hybrid, write a new renderer that does both.
8. Choosing a renderer
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingcodex-skills/yororen-ui-recipes/SKILL.md
Popularity
- Repository stars
- 331
- Repository forks
- 9
- 7-day trend score
- 29
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/meowlynxsea/yororen-ui/yororen-ui-recipes)