Famiq - Getting start

Famiq is a UI library built on top of Bevy UI by providing default widgets and a simple way to manage styles. Instead of writing Rust code for styling, developers can define styles in a well known JSON file. These styles are then parsed into Bevy's native UI styles, significantly reducing boilerplate code. You can read introduction to Famiq here. Today we will create a simple UI app (Counter) in bevy engine using Famiq. The Final result will look like this Create project in your terminal, create new rust project using cargo cargo new counter navigate into counter directory, and install famiq cargo add famiq This will install the latest version of famiq which is v0.2.5. Noted that famiq supports only bevy 0.15.x onward. open the project in your favorite code editor and get ready to write some code! Coding time open main.rs inside src/ directory, paste code below into it use bevy::prelude::*; use famiq::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(FamiqPlugin) // required by Famiq .add_systems(Startup, setup) .run(); } fn setup() {} This is what we need to get started in every bevy project. Write setup system to spawn widgets // use this component to keep track of counter number #[derive(Component)] struct Count(i32); fn setup( mut commands: Commands, asset_server: ResMut, // required by Famiq mut famiq_res: ResMut, // required by Famiq ) { // spawn new 2d camera commands.spawn(Camera2d::default()); // create a widget builder with hot-reload feature on let mut builder = FamiqWidgetBuilder::new(&mut commands, &mut famiq_res, &asset_server) .hot_reload(); // Text widget let count_text = fa_text(&mut builder, "0").id("#count-text").build(); builder.insert_component(count_text, Count(0)); // Button widget let button = fa_button(&mut builder, "Press me").id("#button").build(); // Container widget fa_container(&mut builder) .id("#container") .children([count_text, button]) .build(); } What is FamiqWidgetBuilder? In simple terms, FamiqWidgetBuilder is the root UI node that acts as a starting point for building and managing widgets. All widgets are created and structured on top of this root. .hot_reload() is used to enable hot-reload feature. When we make changes to JSON file (style) it will reflect the running app without needing to re-compile. If you run the app cargo run, without any styles, you will see Give our widgets some styles inside root directory, create a folder called assets. Inside assets folder, create a file called styles.json. open styles.json, paste below code into it. { "#container": { "justify_content": "center", "align_items": "center", "width": "300px", "margin": "auto auto auto auto", "background_color": "grey", "padding": "35px 35px 25px 25px", "border": "2px 2px 2px 2px", "border_radius": "10px 10px 10px 10px" }, "#button": { "margin_top": "20px" }, "#count-text": { "font_size": "40", "color": "blue" } } now run the app again, you will see a better UI. By default, famiq will look for json file at assets/styles.json. If you want to use different file name or path, you can call method use_style_path(). let mut builder = FamiqWidgetBuilder::new(&mut commands, &mut famiq_res, &asset_server) .use_style_path("assets/some_name.json") .hot_reload(); Increase counter on button press in order to handle button press, you will to create a new system that run in Update schedule. fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(FamiqPlugin) .add_systems(Startup, setup) .add_systems(Update, handle_button_press) // add this .run(); } fn handle_button_press( mut events: EventReader, mut text_res: ResMut, mut count_query: Query ) { for e in events.read() { if e.is_button_pressed() { let mut count = count_query.get_single_mut().unwrap(); count.0 += 1; text_res.update_value_by_id("#count-text", &count.0.to_string()); } } } we need FaInteractionEvent to get the button press event. we need FaTextResource to get or update text widget's value. Now run the app again, you will be able to increase the counter! This post is just about getting start using famiq. For more info, please go to the documentation. Famiq's github: https://github.com/MuongKimhong/famiq Famiq's docs: https://muongkimhong.github.io/famiq/ Famiq's crate: https://crates.io/crates/famiq

Feb 9, 2025 - 04:06
 0
Famiq - Getting start

Famiq is a UI library built on top of Bevy UI by providing default widgets and a simple way to manage styles.

Instead of writing Rust code for styling, developers can define styles in a well known JSON file. These styles are then parsed into Bevy's native UI styles, significantly reducing boilerplate code.

You can read introduction to Famiq here.

Today we will create a simple UI app (Counter) in bevy engine using Famiq.

The Final result will look like this

Image description

Create project

  • in your terminal, create new rust project using cargo
cargo new counter
  • navigate into counter directory, and install famiq
cargo add famiq

This will install the latest version of famiq which is v0.2.5. Noted that famiq supports only bevy 0.15.x onward.

  • open the project in your favorite code editor and get ready to write some code!

Coding time

  • open main.rs inside src/ directory, paste code below into it
use bevy::prelude::*;
use famiq::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(FamiqPlugin) // required by Famiq
        .add_systems(Startup, setup)
        .run();
}

fn setup() {}

This is what we need to get started in every bevy project.

  • Write setup system to spawn widgets
// use this component to keep track of counter number
#[derive(Component)]
struct Count(i32);

fn setup(
    mut commands: Commands,
    asset_server: ResMut<AssetServer>, // required by Famiq
    mut famiq_res: ResMut<FamiqWidgetResource>, // required by Famiq
) {
    // spawn new 2d camera
    commands.spawn(Camera2d::default());

    // create a widget builder with hot-reload feature on
    let mut builder = FamiqWidgetBuilder::new(&mut commands, &mut famiq_res, &asset_server)
        .hot_reload();

    // Text widget
    let count_text = fa_text(&mut builder, "0").id("#count-text").build();
    builder.insert_component(count_text, Count(0));

    // Button widget
    let button = fa_button(&mut builder, "Press me").id("#button").build();

    // Container widget
    fa_container(&mut builder)
        .id("#container")
        .children([count_text, button])
        .build();
}

What is FamiqWidgetBuilder?

In simple terms, FamiqWidgetBuilder is the root UI node that acts as a starting point for building and managing widgets. All widgets are created and structured on top of this root.

.hot_reload() is used to enable hot-reload feature. When we make changes to JSON file (style) it will reflect the running app without needing to re-compile.

If you run the app cargo run, without any styles, you will see

Image description

Give our widgets some styles

  • inside root directory, create a folder called assets. Inside assets folder, create a file called styles.json.
  • open styles.json, paste below code into it.
{
  "#container": {
    "justify_content": "center",
    "align_items": "center",
    "width": "300px",
    "margin": "auto auto auto auto",
    "background_color": "grey",
    "padding": "35px 35px 25px 25px",
    "border": "2px 2px 2px 2px",
    "border_radius": "10px 10px 10px 10px"
  },
  "#button": {
    "margin_top": "20px"
  },
  "#count-text": {
    "font_size": "40",
    "color": "blue"
  }
}

now run the app again, you will see a better UI.
Image description

By default, famiq will look for json file at assets/styles.json. If you want to use different file name or path, you can call method use_style_path().

    let mut builder = FamiqWidgetBuilder::new(&mut commands, &mut famiq_res, &asset_server)
        .use_style_path("assets/some_name.json")
        .hot_reload();

Increase counter on button press

  • in order to handle button press, you will to create a new system that run in Update schedule.
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(FamiqPlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, handle_button_press) // add this
        .run();
}

fn handle_button_press(
    mut events: EventReader<FaInteractionEvent>,
    mut text_res: ResMut<FaTextResource>,
    mut count_query: Query<&mut Count>
) {
    for e in events.read() {
        if e.is_button_pressed() {
            let mut count = count_query.get_single_mut().unwrap();

            count.0 += 1;
            text_res.update_value_by_id("#count-text", &count.0.to_string());
        }
    }
}
  • we need FaInteractionEvent to get the button press event.
  • we need FaTextResource to get or update text widget's value.

Now run the app again, you will be able to increase the counter!

This post is just about getting start using famiq. For more info, please go to the documentation.

Famiq's github: https://github.com/MuongKimhong/famiq
Famiq's docs: https://muongkimhong.github.io/famiq/
Famiq's crate: https://crates.io/crates/famiq