mcpField
B
bevy-ui

bevy-ui

github.com/chrisgliddonDevelopment2687 installsUpdated 9w ago
Repository

About bevy-ui

A reference skill for building user interfaces with Bevy 0.19, aimed at developers working on game UI. It covers layout, interaction, text styling, focus management, accessibility labels, and static or dynamic child trees.

Key features

  1. 01Build Node-based UI layouts
  2. 02Handle button interaction states
  3. 03Style text with 0.19 APIs
  4. 04Manage input focus and accessible names
  5. 05Create static and dynamic child trees

Use cases

  1. 01Implement menus, panels, and overlays
  2. 02Style text in Bevy 0.19 interfaces
  3. 03Add keyboard focus and accessible labels

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/chrisgliddon/bevy-skills --skill bevy-ui

After installing, type/bevy-uiin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
accessibility.md
children-macro.md
colors-and-borders.md
gotchas.md
interaction.md
layout.md
palettes.md
text.md

Details

From the project README

Bevy 0.19 — UI

When to use this skill

  • Spawn Node-based panels, buttons, labels, overlays, or menus.
  • Handle Interaction::{None, Hovered, Pressed} and visual states.
  • Style text after the 0.19 Parley migration.
  • Manage pointer-acquired InputFocus or accessible names.
  • Build static trees with children![] or dynamic trees with with_children.

Canonical pattern

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

fn main() {
    App::new()
        .add_plugins(DefaultPlugins) // includes InputFocusPlugin in 0.19
        .add_systems(Startup, setup)
        .add_systems(Update, style_button)
        .run();
}

fn setup(mut commands: Commands, assets: Res<AssetServer>) {
    commands.spawn(Camera2d);
    commands.spawn((
        Node {
            width: percent(100),
            height: percent(100),
            align_items: AlignItems::Center,
            justify_content: JustifyContent::Center,
            ..default()
        },
        children![(
            Button,
            AccessibleLabel::new("Start game"),
            Node {
                width: px(180),
                height: px(64),
                border: UiRect::all(px(3)),
                border_radius: BorderRadius::MAX,
                align_items: AlignItems::Center,
                justify_content: JustifyContent::Center,
                ..default()
            },
            BackgroundColor(Color::srgb(0.12, 0.12, 0.15)),
            BorderColor::all(Color::WHITE),
            children![(
                Text::new("Start game"),
                TextFont {
                    font: assets.load("fonts/FiraSans-Bold.ttf").into(),
                    font_size: FontSize::Px(32.0),
                    ..default()
                },
                TextColor(Color::WHITE),
            )],
        )],
    ));
}

fn style_button(
    mut focus: ResMut<InputFocus>,
    mut buttons: Query<
        (Entity, &Interaction, &mut BackgroundColor),
        (Changed<Interaction>, With<Button>),
    >,
) {
    for (entity, interaction, mut background) in &mut buttons {
        *background = match interaction {
            Interaction::Pressed => {
                focus.set(entity, FocusCause::Pressed);
                BackgroundColor(Color::srgb(0.15, 0.55, 0.25))
            }
            Interaction::Hovered => BackgroundColor(Color::srgb(0.22, 0.22, 0.28)),
            Interaction::None => BackgroundColor(Color::srgb(0.12, 0.12, 0.15)),
        };
    }
}

Topics

TopicReference
Node, Val, flex/grid layoutLayout
FontSource, FontSize, TextLayoutText
Button, Interaction, ChangedInteraction
Colors, borders, and radiiColors and borders
Palette constantsPalettes
InputFocus, semantics, accessible labelsAccessibility
Static and dynamic childrenChildren
Cross-cutting trapsGotchas

Gotchas

  • A newly inserted component satisfies Changed<T>. The interaction system normally visits a new button on its first Update; use Ref<T>::is_added() when insertion and later mutation must be distinguished.
  • Pointer hover and input focus are different. Do not move or clear keyboard / assistive-technology focus merely because the cursor entered or left.
  • TextFont.font is FontSource; convert a Handle<Font> with .into(). font_size is FontSize, such as FontSize::Px(32.0).
  • InputFocus fields are private. Use get, set(entity, FocusCause), and clear. DefaultPlugins initializes it.
  • A visible text child gives a Button an inferred name, but use AccessibleLabel when the visual text is absent, decorative, or ambiguous.

See also

Comments

Markdown supported