AgentStack
SKILL verified MIT Self-run

Bevy Ui

skill-chrisgliddon-bevy-skills-bevy-ui · by chrisgliddon

Use when building UI with `Node`, `Button`, `children![]`, `TextFont`, `InputFocus`, `BackgroundColor`, `BorderColor`, or `BorderRadius` in Bevy 0.18. Covers layout, text styling, interaction handling, colors, palettes, accessibility, and the frame-0 `Changed<Interaction>` invariant.

No reviews yet
0 installs
8 views
0.0% view→install

Install

$ agentstack add skill-chrisgliddon-bevy-skills-bevy-ui

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Bevy Ui? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Bevy 0.18 — UI

When to use this skill

  • Spawning any Node-based UI element (panels, buttons, text labels, overlays).
  • Handling Button interaction states (Hovered, Pressed, None).
  • Styling text with TextFont, TextColor, TextShadow.
  • Setting BackgroundColor, BorderColor, BorderRadius on a widget.
  • Using palette constants from bevy::color::palettes.
  • Wiring up InputFocus for accessibility / screen-reader integration.
  • Nesting child entities with children![] or .with_children(...).
  • Debugging a button that shows the wrong color at frame 0 or frame 120.

Canonical pattern

Centered button — full-screen flex container, rounded pill button, text child.

use bevy::{input_focus::InputFocus, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_resource::()
        .add_systems(Startup, setup)
        .add_systems(Update, button_system)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res) {
    commands.spawn(Camera2d);
    commands.spawn((
        // Full-screen flex container — centres the button.
        Node {
            width: percent(100),
            height: percent(100),
            align_items: AlignItems::Center,
            justify_content: JustifyContent::Center,
            ..default()
        },
        children![(
            Button,
            Node {
                width: px(150),
                height: px(65),
                border: UiRect::all(px(5)),
                justify_content: JustifyContent::Center,
                align_items: AlignItems::Center,
                border_radius: BorderRadius::MAX,
                ..default()
            },
            // Spawn-time border is what appears at frame 0 — `Changed`
            // does NOT fire on startup, so the `Interaction::None` arm below
            // (which sets the border to BLACK) only runs after the first mouse
            // event. This is the frame-0 invariant: see Gotchas #1 + references/gotchas.md.
            BorderColor::all(Color::WHITE),
            BackgroundColor(Color::BLACK),
            children![(
                Text::new("Button"),
                TextFont {
                    font: asset_server.load("fonts/FiraSans-Bold.ttf"),
                    font_size: 33.0,
                    ..default()
                },
                TextColor(Color::srgb(0.9, 0.9, 0.9)),
                TextShadow::default(),
            )]
        )],
    ));
}

fn button_system(
    mut input_focus: ResMut,
    mut query: Query,
    >,
) {
    for (entity, interaction, mut bg, mut border, mut button) in &mut query {
        match *interaction {
            Interaction::Pressed => {
                input_focus.set(entity);
                *bg = BackgroundColor(Color::srgb(0.35, 0.75, 0.35));
                *border = BorderColor::all(Color::srgb(1.0, 0.0, 0.0));
                button.set_changed(); // signal accessibility system
            }
            Interaction::Hovered => {
                input_focus.set(entity);
                *bg = BackgroundColor(Color::srgb(0.25, 0.25, 0.25));
                *border = BorderColor::all(Color::WHITE);
                button.set_changed();
            }
            Interaction::None => {
                input_focus.clear();
                *bg = BackgroundColor(Color::BLACK);
                *border = BorderColor::all(Color::BLACK);
                // No set_changed() for None — not required by the a11y system.
            }
        }
    }
}

Topics

| Topic | Reference | |---|---| | Node, Val, FlexDirection, AlignItems, layout recipes | [references/layout.md](references/layout.md) | | Text::new, TextFont, TextColor, TextShadow, default font swap | [references/text.md](references/text.md) | | Button, Interaction, Changed, footguns | [references/interaction.md](references/interaction.md) | | BackgroundColor, BorderColor, BorderRadius constructors | [references/colors-and-borders.md](references/colors-and-borders.md) | | bevy::color::palettes::{basic,css,tailwind} | [references/palettes.md](references/palettes.md) | | InputFocus, init_resource, set / clear | [references/accessibility.md](references/accessibility.md) | | children![] vs .with_children(...) | [references/children-macro.md](references/children-macro.md) | | Cross-cutting invariants, frame-0 trap, black-border bug | [references/gotchas.md](references/gotchas.md) |

Gotchas

  1. Changed does NOT fire at frame 0. The button shows its

spawn-time components (e.g. BorderColor::all(Color::WHITE)) on the first frame, not the output of button_system. Screenshot-based parity tests taken at frame 0 must account for this. See [references/gotchas.md](references/gotchas.md).

  1. Call button.set_changed() in Hovered and Pressed arms. This is a

manual dirty-marker required so the accessibility system re-processes the button. Omitting it causes screen readers to miss focus changes. See [references/interaction.md](references/interaction.md).

See also

  • bevy-cameras — spawn a Camera2d alongside any UI scene.
  • bevy-ecs-queriesChanged, Added, query filters used in button_system.
  • bevy-fluent — localized UI text via FluentText.
  • bevy-cargo-features — feature flags; the ui collection enables all UI crates.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.