# haalka [হালকা](https://translate.google.com/?sl=bn&tl=en&text=%E0%A6%B9%E0%A6%BE%E0%A6%B2%E0%A6%95%E0%A6%BE&op=translate) [![Crates.io Version](https://img.shields.io/crates/v/haalka?style=for-the-badge)](https://crates.io/crates/haalka) [![Docs.rs](https://img.shields.io/docsrs/haalka?style=for-the-badge)](https://docs.rs/haalka) [![Following released Bevy versions](https://img.shields.io/badge/Bevy%20tracking-0.18-lightblue?style=for-the-badge)](https://bevyengine.org/learn/quick-start/plugin-development/#main-branch-tracking) ```text in bengali, haalka means "light" (e.g. not heavy) and can also be used to mean "easy" ``` [haalka](https://github.com/databasedav/haalka) is an ergonomic reactive [Bevy](https://github.com/bevyengine/bevy) UI library powered by the [FRP](https://en.wikipedia.org/wiki/Functional_reactive_programming) signals of [jonmo](https://github.com/databasedav/jonmo) with API ported from web UI libraries [MoonZoon](https://github.com/MoonZoon/MoonZoon) and [Dominator](https://github.com/Pauan/rust-dominator). ## assorted features - simple high-level alignment semantics ported from MoonZoon (see [align example](https://databasedav.github.io/haalka/examples/webgl2/align/) below) - pointer event handling methods - hovered change methods (including web-style [`Enter`](https://docs.rs/haalka/latest/haalka/pointer_event_aware/struct.Enter.html) and [`Leave`](https://docs.rs/haalka/latest/haalka/pointer_event_aware/struct.Leave.html) events) - on click and on-click-outside methods - on pressed methods, with throttle-ability - cursor-on-hover management - global event handling methods - mouse wheel scroll handling methods - signals-integrated text input, a thin layer on top of [bevy_ui_text_input](https://github.com/ickshonpe/bevy_ui_text_input) - viewport mutation handling methods - simple grid layout model ported from MoonZoon - macro rules for adding signal helper methods to custom element structs ## [feature flags](https://docs.rs/haalka/latest/haalka/#feature-flags-1) ## examples

```rust no_run use bevy::prelude::*; use haalka::prelude::*; fn main() { App::new() .add_plugins((DefaultPlugins, HaalkaPlugin::new())) .add_systems( Startup, ( |world: &mut World| { ui_root().spawn(world); }, camera, ), ) .run(); } #[derive(Component, Clone, Deref, DerefMut)] struct Counter(i32); fn ui_root() -> impl Element { let counter_holder = LazyEntity::new(); El::::new() .with_node(|mut node| { node.height = Val::Percent(100.); node.width = Val::Percent(100.); }) .insert(Pickable::default()) .cursor(CursorIcon::default()) .align_content(Align::center()) .child( Row::::new() .with_node(|mut node| node.column_gap = Val::Px(15.0)) .insert(Counter(0)) .lazy_entity(counter_holder.clone()) .item(counter_button(counter_holder.clone(), "-", -1)) .item( El::::new() .text_font(TextFont::from_font_size(25.)) .text_signal( signal::from_component_changed::(counter_holder.clone()) .map_in(deref_copied) .map_in_ref(ToString::to_string) .map_in(Text) .map_in(Some), ), ) .item(counter_button(counter_holder.clone(), "+", 1)), ) } fn counter_button(counter_holder: LazyEntity, label: &'static str, step: i32) -> impl Element { let lazy_entity = LazyEntity::new(); El::::new() .with_node(|mut node| { node.width = Val::Px(45.0); node.border_radius = BorderRadius::MAX; }) .insert((Pickable::default(), Hoverable)) .align_content(Align::center()) .cursor(CursorIcon::System(SystemCursorIcon::Pointer)) .lazy_entity(lazy_entity.clone()) .background_color_signal( signal::from_entity(lazy_entity) .has_component::() .dedupe() .map_bool_in(|| Color::hsl(300., 0.75, 0.85), || Color::hsl(300., 0.75, 0.75)) .map_in(BackgroundColor) .map_in(Some), ) .on_click(move |_: In<_>, mut counters: Query<&mut Counter>| { if let Ok(mut counter) = counters.get_mut(*counter_holder) { **counter += step; } }) .child( El::::new() .text_font(TextFont::from_font_size(25.)) .text(Text::new(label)), ) } fn camera(mut commands: Commands) { commands.spawn(Camera2d); } ``` ### on the web All examples are compiled to wasm for both webgl2 and webgpu (check [compatibility]()) and deployed to github pages. - [**`counter`**](https://github.com/databasedav/haalka/blob/main/examples/counter.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/counter/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/counter/) the example above, a simple counter - [**`button`**](https://github.com/databasedav/haalka/blob/main/examples/button.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/button/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/button/) a basic button, port of - [**`align`**](https://github.com/databasedav/haalka/blob/main/examples/align.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/align/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/align/) alignment API demo, port of and - [**`scroll`**](https://github.com/databasedav/haalka/blob/main/examples/scroll.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/scroll/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/scroll/) scrollability API demo, inspired by - [**`scroll_grid`**](https://github.com/databasedav/haalka/blob/main/examples/scroll_grid.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/scroll_grid/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/scroll_grid/) i can't believe it's not scrolling! - [**`snake`**](https://github.com/databasedav/haalka/blob/main/examples/snake.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/snake/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/snake/) the classic, with adjustable grid size and tick rate - [**`dot_counter`**](https://github.com/databasedav/haalka/blob/main/examples/dot_counter.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/dot_counter/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/dot_counter/) forward ecs changes to the ui, throttled button presses - [**`dragging`**](https://github.com/databasedav/haalka/blob/main/examples/dragging.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/dragging/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/dragging/) dragging with z-index stacking - [**`key_values_sorted`**](https://github.com/databasedav/haalka/blob/main/examples/key_values_sorted.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/key_values_sorted/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/key_values_sorted/) text inputs, scrolling/viewport control, and reactive lists; promises made promises kept! (yes I take requests) - [**`calculator`**](https://github.com/databasedav/haalka/blob/main/examples/calculator.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/calculator/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/calculator/) simple calculator, spurred by - [**`nested_lists`**](https://github.com/databasedav/haalka/blob/main/examples/nested_lists.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/nested_lists/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/nested_lists/) nested dynamic lists, arbitrarily deeply nested retained reactivity, spurred by - [**`main_menu`**](https://github.com/databasedav/haalka/blob/main/examples/main_menu.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/main_menu/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/main_menu/) sub menus, sliders, dropdowns, reusable composable widgets, gamepad navigation - [**`inventory`**](https://github.com/databasedav/haalka/blob/main/examples/inventory.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/inventory/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/inventory/) grid, icons, drag and drop, tooltips - [**`healthbar`**](https://github.com/databasedav/haalka/blob/main/examples/healthbar.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/healthbar/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/healthbar/) 3D character anchor, customizable widgets - [**`responsive_menu`**](https://github.com/databasedav/haalka/blob/main/examples/responsive_menu.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/responsive_menu/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/responsive_menu/) nine-patch buttons, screen size reactivity - [**`character_editor`**](https://github.com/databasedav/haalka/blob/main/examples/character_editor.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/character_editor/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/character_editor/) scrollable buttons, mutable viewport, text input reactivity - [**`futures_signals_jonmo_compat`**](https://github.com/databasedav/haalka/blob/main/examples/futures_signals_jonmo_compat.rs) [webgl2](https://databasedav.github.io/haalka/examples/webgl2/futures_signals_jonmo_compat/) [webgpu](https://databasedav.github.io/haalka/examples/webgpu/futures_signals_jonmo_compat/) demonstrates that both futures-signals and jonmo signals backends can be used together Or run them locally with `cargo`. ```bash 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 cargo run --example futures_signals_jonmo_compat --features futures_signals_ui ``` Or with [`just`](https://github.com/casey/just), e.g. `just example snake -r`. ## Bevy compatibility |bevy|haalka| |-|-| |`0.18`|`0.7`| |`0.17`|`0.6`| |`0.16`|`0.5`| |`0.15`|`0.4`| |`0.14`|`0.2`| |`0.13`|`0.1`| ## development - avoid the gh-pages branch and include submodules when fetching the repo ```bash git clone --single-branch --branch main --recurse-submodules https://github.com/databasedav/haalka.git ``` - install [just](https://github.com/casey/just?tab=readme-ov-file#installation) - install [nickel](https://github.com/tweag/nickel?tab=readme-ov-file#run) for modifying CI configuration (`nickel` must be in your PATH) - install [File Watcher](https://marketplace.visualstudio.com/items?itemName=appulate.filewatcher) for automatically syncing nickels ## license All code in this repository is dual-licensed under either: - MIT License ([LICENSE-MIT](https://github.com/databasedav/haalka/blob/main/LICENSE-MIT) or ) - Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/databasedav/haalka/blob/main/LICENSE-APACHE) or ) at your option. Assets used in examples may be licensed under different terms, see the [`examples` README](https://github.com/databasedav/haalka/blob/main/examples/README.md). ### your contributions 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.