Crates.io | bevy-ui-builders |
lib.rs | bevy-ui-builders |
version | 0.1.3 |
created_at | 2025-09-25 18:36:15.728459+00 |
updated_at | 2025-09-25 19:31:24.606479+00 |
description | Declarative UI builders for Bevy with consistent styling and interaction handling |
homepage | |
repository | https://github.com/noahsabaj/bevy-ui-builders |
max_upload_size | |
id | 1854967 |
size | 404,782 |
commands.spawn((
Button,
Node {
width: Val::Px(200.0),
height: Val::Px(65.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
border: UiRect::all(Val::Px(2.0)),
margin: UiRect::all(Val::Px(10.0)),
padding: UiRect::all(Val::Px(10.0)),
..default()
},
BackgroundColor(Color::srgb(0.15, 0.15, 0.15)),
BorderColor(Color::BLACK),
)).with_children(|parent| {
parent.spawn((
Text::new("Click Me"),
TextFont {
font_size: 40.0,
..default()
},
TextColor(Color::srgb(0.9, 0.9, 0.9)),
));
});
// Plus 30+ more lines for hover system...
use bevy_ui_builders::*;
ButtonBuilder::new("Click Me")
.style(ButtonStyle::Primary)
.build(parent);
That's it! Hover effects, styling, and interaction handling included.
Add to your Cargo.toml
:
[dependencies]
bevy = "0.16"
bevy-ui-builders = "0.1"
Add the plugin:
use bevy::prelude::*;
use bevy_ui_builders::UiBuilderPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UiBuilderPlugin)
.run();
}
// Simple button
ButtonBuilder::new("Click Me").build(parent);
// Styled button with size
ButtonBuilder::new("Submit")
.style(ButtonStyle::Primary) // Primary, Secondary, Success, Danger, Warning, Ghost
.size(ButtonSize::Large) // Small, Medium, Large, XLarge
.with_marker(SubmitButton) // Add your own marker component
.build(parent);
// Convenience functions
primary_button("Save").build(parent);
danger_button("Delete").build(parent);
ghost_button("Cancel").build(parent);
// Confirmation dialog
DialogBuilder::new(DialogType::Custom)
.title("Delete Item?")
.body("This action cannot be undone.")
.danger_button("Delete")
.cancel_button("Cancel")
.dismissible(false) // Can't click outside to close
.z_index(1000) // Layer above other UI
.build(commands);
// Preset dialogs
use bevy_ui_builders::dialog::presets;
presets::error(commands, "File not found!");
presets::unsaved_changes(commands);
// Text input with validation
TextInputBuilder::new()
.with_placeholder("Enter email...")
.with_filter(InputFilter::Alphanumeric) // Allow letters and numbers
.with_max_length(100)
.with_focus_group(FocusGroupId::LoginForm) // Focus management
.with_clear_button() // X button to clear
.with_marker(EmailInput)
.build(parent);
// Numeric input
text_input()
.numeric_only() // Only allows 0-9
.with_value("0")
.build(parent);
FormBuilder::new()
.title("User Registration")
.field(FieldType::Text, "username", "Username")
.field(FieldType::Email, "email", "Email Address")
.field(FieldType::Password, "password", "Password")
.field(FieldType::Checkbox, "terms", "I accept the terms")
.validation("username", ValidationRule::Required)
.validation("username", ValidationRule::MinLength(3))
.validation("email", ValidationRule::Required)
.validation("email", ValidationRule::Email)
.submit_button("Register")
.cancel_button("Cancel")
.build(parent);
// Percentage slider
SliderBuilder::new(0.5, 0.0..=1.0)
.width(Val::Px(200.0))
.with_label(ValueFormat::Percentage) // Shows "50%"
.with_marker(VolumeSlider)
.build(parent);
// Custom format
slider(75.0, 0.0..=100.0)
.with_label(ValueFormat::Custom(|v| format!("{:.0}°C", v)))
.build(parent);
// Basic progress bar
ProgressBarBuilder::new(0.75) // 75% complete
.style(ProgressBarStyle::Thick)
.with_label() // Shows "75%"
.animated() // Smooth transitions
.build(parent);
// Custom styled
progress(loading_progress)
.fill_color(Color::srgb(0.2, 0.8, 0.2))
.track_color(Color::srgb(0.1, 0.1, 0.1))
.with_label_text("Loading assets...")
.build(parent);
// Card panel with title
PanelBuilder::new()
.style(PanelStyle::Card)
.width(Val::Px(400.0))
.padding(UiRect::all(Val::Px(24.0)))
.with_title("Settings")
.build_with_children(parent, |panel| {
// Add any children here
LabelBuilder::new("Audio Settings").build(panel);
SeparatorBuilder::new().build(panel);
// More UI...
});
// Transparent overlay panel
panel()
.style(PanelStyle::Transparent)
.position_type(PositionType::Absolute)
.build(parent);
// Styled labels
LabelBuilder::new("Welcome!")
.style(LabelStyle::Title) // Title, Heading, Body, Caption
.text_align(JustifyContent::Center)
.margin(UiRect::bottom(Val::Px(20.0)))
.build(parent);
// Status labels
label("Error: File not found")
.style(LabelStyle::Error) // Error, Success, Warning, Muted
.build(parent);
// Horizontal separator
SeparatorBuilder::new()
.style(SeparatorStyle::Dashed)
.margin(UiRect::vertical(Val::Px(20.0)))
.build(parent);
// Vertical divider
separator_vertical()
.style(SeparatorStyle::Thick)
.length(Val::Percent(80.0))
.build(parent);
Generic cleanup system:
// Before: 15 lines of cleanup per UI system
fn cleanup_menu(mut commands: Commands, query: Query<Entity, With<MenuRoot>>) {
for entity in &query {
commands.entity(entity).despawn();
}
}
// After: One line, works for ANY component!
app.add_systems(OnExit(GameState::Menu), despawn_ui_entities::<MenuRoot>);
use bevy::prelude::*;
use bevy_ui_builders::*;
#[derive(Component)]
struct LoginForm;
#[derive(Component)]
struct SubmitButton;
fn setup_ui(mut commands: Commands) {
// Create a login form
commands.spawn(Camera2d);
commands
.spawn((Node::default(), LoginForm))
.with_children(|parent| {
PanelBuilder::new()
.style(PanelStyle::Card)
.width(Val::Px(400.0))
.padding(UiRect::all(Val::Px(32.0)))
.with_title("Login")
.build_with_children(parent, |panel| {
// Username input
LabelBuilder::new("Username")
.style(LabelStyle::Body)
.margin(UiRect::bottom(Val::Px(8.0)))
.build(panel);
TextInputBuilder::new()
.with_placeholder("Enter username...")
.with_focus_group(FocusGroupId::Custom(1))
.build(panel);
// Add spacing
SeparatorBuilder::new()
.style(SeparatorStyle::Invisible)
.margin(UiRect::vertical(Val::Px(16.0)))
.build(panel);
// Password input
LabelBuilder::new("Password")
.style(LabelStyle::Body)
.margin(UiRect::bottom(Val::Px(8.0)))
.build(panel);
TextInputBuilder::new()
.with_placeholder("Enter password...")
.with_focus_group(FocusGroupId::Custom(1))
.build(panel);
// Buttons
SeparatorBuilder::new()
.style(SeparatorStyle::Invisible)
.margin(UiRect::vertical(Val::Px(24.0)))
.build(panel);
ButtonBuilder::new("Login")
.style(ButtonStyle::Primary)
.size(ButtonSize::Large)
.with_marker(SubmitButton)
.build(panel);
});
});
}
Control which builders are included:
# Include everything (default)
bevy-ui-builders = "0.1"
# Or pick specific builders
bevy-ui-builders = { version = "0.1", default-features = false, features = ["button", "dialog"] }
Available features:
button
- ButtonBuilderdialog
- DialogBuildertext_input
- TextInputBuilderform
- FormBuilderslider
- SliderBuilderprogress
- ProgressBarBuilderpanel
- PanelBuilderlabel
- LabelBuilderseparator
- SeparatorBuilderCrate | Problem |
---|---|
bevy_ui_builder |
Too basic, no text inputs or forms |
sickle_ui |
Complex macro system, steep learning curve |
bevy_dioxus |
Requires React/web knowledge |
bevy_egui |
Immediate mode, not native Bevy |
bevy-ui-builders | Just right! Simple, powerful, pure Bevy |
despawn_ui_entities<T>
bevy-ui-builders | Bevy |
---|---|
0.1 | 0.16 |
Dual-licensed under either:
at your option.
Contributions welcome! Please check CONTRIBUTING.md for development setup, coding standards, and how to submit pull requests.
Created by Noah Sabaj, the creator of bevy-plugin-builder, and bevy-test-suite.
// From 45 lines to 3. That's the power of builders.
ButtonBuilder::new("Play Game")
.style(ButtonStyle::Primary)
.build(parent);
bevy-ui-builders/
├── .github/ # GitHub Actions workflows
│ └── workflows/
│ ├── ci.yml # CI pipeline (test, clippy, fmt)
│ └── release.yml # Automated release to crates.io
├── examples/ # Usage examples
│ ├── button_showcase.rs # Button styles and sizes demo
│ ├── dialog_examples.rs # Dialog types and interactions
│ ├── form_complete.rs # Form with validation
│ ├── kitchen_sink.rs # All builders combined
│ ├── labels_and_separators.rs # Label styles and dividers
│ ├── panel_layouts.rs # Panel configurations
│ ├── progress_bars.rs # Progress bar animations
│ ├── slider_demo.rs # Slider interactions
│ └── text_input_demo.rs # Text input with filters
├── src/
│ ├── button/ # ButtonBuilder module
│ │ ├── mod.rs # Gateway (exports only)
│ │ ├── builder.rs # ButtonBuilder implementation
│ │ ├── plugin.rs # ButtonPlugin
│ │ ├── systems.rs # Button interaction systems
│ │ └── types.rs # Component types (StyledButton, etc.)
│ ├── dialog/ # DialogBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # DialogBuilder implementation
│ │ ├── plugin.rs # DialogPlugin
│ │ ├── systems.rs # Dialog interaction (ESC, overlay clicks)
│ │ └── types.rs # DialogOverlay, DialogType, button markers
│ ├── form/ # FormBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # FormBuilder implementation
│ │ ├── field.rs # Form field implementations
│ │ └── types.rs # FieldType, ValidationRule
│ ├── label/ # LabelBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # LabelBuilder implementation
│ │ └── types.rs # Label, LabelStyle
│ ├── panel/ # PanelBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # PanelBuilder implementation
│ │ └── types.rs # Panel, PanelStyle
│ ├── progress/ # ProgressBarBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # ProgressBarBuilder implementation
│ │ ├── plugin.rs # ProgressBarPlugin
│ │ ├── systems.rs # Progress bar update systems
│ │ └── types.rs # ProgressBar, ProgressBarStyle
│ ├── relationships/ # Bevy 0.16 custom relationships
│ │ ├── mod.rs # Gateway (exports only)
│ │ ├── types.rs # All relationship component definitions
│ │ ├── systems.rs # Relationship systems (button groups, etc.)
│ │ └── plugin.rs # UIRelationshipsPlugin
│ ├── separator/ # SeparatorBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # SeparatorBuilder implementation
│ │ └── types.rs # Separator, SeparatorStyle, Orientation
│ ├── slider/ # SliderBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # SliderBuilder implementation
│ │ ├── plugin.rs # SliderPlugin
│ │ ├── systems.rs # Slider drag systems
│ │ └── types.rs # Slider, SliderHandle, SliderTrack
│ ├── styles/ # Centralized styling
│ │ ├── mod.rs # Gateway (exports colors & dimensions)
│ │ ├── button_styles.rs # ButtonStyle and ButtonSize enums
│ │ ├── colors.rs # Color constants (PRIMARY, SECONDARY, etc.)
│ │ └── dimensions.rs # Size constants (FONT_SIZE_*, PADDING_*, etc.)
│ ├── systems/ # Shared systems
│ │ ├── mod.rs # Gateway
│ │ ├── cleanup.rs # Generic despawn_entities<T> system
│ │ ├── hover.rs # HoverPlugin for button effects
│ │ └── interaction.rs # Generic interaction handling
│ ├── text_input/ # TextInputBuilder module
│ │ ├── mod.rs # Gateway
│ │ ├── builder.rs # TextInputBuilder implementation
│ │ ├── plugin.rs # TextInputPlugin
│ │ ├── systems.rs # Focus management, validation
│ │ └── types.rs # InputFilter, TextInputFocus, etc.
│ ├── utils/ # Utilities
│ │ ├── mod.rs # Gateway
│ │ └── intrinsic.rs # Intrinsic sizing utilities
│ └── lib.rs # Main library entry point
├── Cargo.lock # Dependency lock file
├── Cargo.toml # Package manifest
├── CHANGELOG.md # Version history
├── CONTRIBUTING.md # Contribution guidelines
├── LICENSE-APACHE # Apache License 2.0
├── LICENSE-MIT # MIT License
└── README.md # This file
Total: 72 files
Modules: 14 (13 builders/utilities + relationships with 4 files)