Crates.io | haalka |
lib.rs | haalka |
version | 0.5.1 |
created_at | 2024-06-13 05:43:43.581947+00 |
updated_at | 2025-07-06 03:12:40.811848+00 |
description | ergonomic reactive Bevy UI library powered by FRP signals |
homepage | |
repository | https://github.com/databasedav/haalka |
max_upload_size | |
id | 1270237 |
size | 968,661 |
in bengali, haalka means "light" (e.g. not heavy) and can also be used to mean "easy"
haalka is an ergonomic reactive Bevy UI library powered by the incredible FRP signals of futures-signals and the convenient async ECS of bevy-async-ecs with API ported from web UI libraries MoonZoon and Dominator.
While haalka is primarily targeted at UI and provides high level UI abstractions as such, its core abstraction can be used to manage signals-powered reactivity for any entity, not just bevy_ui
nodes.
MutableVec
and MutableBTreeMap
use bevy::prelude::*;
use haalka::prelude::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, HaalkaPlugin))
.add_systems(
Startup,
(
|world: &mut World| {
ui_root().spawn(world);
},
camera,
),
)
.run();
}
#[derive(Component)]
struct Counter(Mutable<i32>);
fn ui_root() -> impl Element {
let counter = Mutable::new(0);
El::<Node>::new()
.with_node(|mut node| {
node.height = Val::Percent(100.);
node.width = Val::Percent(100.);
})
.cursor(CursorIcon::default())
.align_content(Align::center())
.child(
Row::<Node>::new()
.with_node(|mut node| node.column_gap = Val::Px(15.0))
.item(counter_button(counter.clone(), "-", -1))
.item(
El::<Text>::new()
.text_font(TextFont::from_font_size(25.))
.text_signal(counter.signal_ref(ToString::to_string).map(Text)),
)
.item(counter_button(counter.clone(), "+", 1))
.update_raw_el(move |raw_el| raw_el.insert(Counter(counter))),
)
}
fn counter_button(counter: Mutable<i32>, label: &str, step: i32) -> impl Element {
let hovered = Mutable::new(false);
El::<Node>::new()
.with_node(|mut node| node.width = Val::Px(45.0))
.align_content(Align::center())
.border_radius(BorderRadius::MAX)
.cursor(CursorIcon::System(SystemCursorIcon::Pointer))
.background_color_signal(
hovered
.signal()
.map_bool(|| Color::hsl(300., 0.75, 0.85), || Color::hsl(300., 0.75, 0.75))
.map(BackgroundColor),
)
.hovered_sync(hovered)
.on_click(move || *counter.lock_mut() += step)
.child(
El::<Text>::new()
.text_font(TextFont::from_font_size(25.))
.text(Text::new(label)),
)
}
fn camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
All examples are compiled to wasm for both webgl2 and webgpu (check compatibility) and deployed to github pages.
the example above, a simple counter
a basic button, port of https://github.com/bevyengine/bevy/blob/main/examples/ui/button.rs
alignment API demo, port of https://github.com/MoonZoon/MoonZoon/tree/main/examples/align and https://github.com/MoonZoon/MoonZoon/tree/main/examples/align_content
scrollability API demo, inspired by https://github.com/mintlu8/bevy-rectray/blob/main/examples/scroll_discrete.rs
i can't believe it's not scrolling!
the classic, with adjustable grid size and tick rate
forward ecs changes to the ui, throttled button presses
key_values_sorted
webgl2 webgpu
text inputs, scrolling/viewport control, and reactive lists; promises made promises kept! https://discord.com/channels/691052431525675048/1192585689460658348/1193431789465776198 (yes I take requests)
simple calculator, spurred by https://discord.com/channels/691052431525675048/885021580353237032/1263661461364932639
nested dynamic lists, arbitrarily deeply nested retained reactivity, spurred by https://discord.com/channels/691052431525675048/885021580353237032/1356769984474517617
sub menus, sliders, dropdowns, reusable composable widgets, gamepad navigation
grid, icons, drag and drop, tooltips
3D character anchor, customizable widgets
nine-patch buttons, screen size reactivity
character_editor
webgl2 webgpu
scrollable buttons, mutable viewport, text input reactivity
Or run them locally with cargo
.
cargo run --example counter
cargo run --example button
cargo run --example align
cargo run --example scroll
cargo run --example scroll_grid
cargo run --example snake
cargo run --example dot_counter
cargo run --example key_values_sorted
cargo run --example calculator
cargo run --example nested_lists
# ui challenges from https://github.com/bevyengine/bevy/discussions/11100
cargo run --example main_menu
cargo run --example inventory
cargo run --example healthbar
cargo run --example responsive_menu
cargo run --example character_editor
Or with just
, e.g. just example snake -r
.
bevy | haalka |
---|---|
0.16 |
0.5 |
0.15 |
0.4 |
0.14 |
0.2 |
0.13 |
0.1 |
git clone --single-branch --branch main --recurse-submodules https://github.com/databasedav/haalka.git
nickel
must be in your PATH)All code in this repository is dual-licensed under either:
at your option.
Assets used in examples may be licensed under different terms, see the examples
README.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.