DEV Community

Cover image for Famiq - Getting start
Kim Hong Muong
Kim Hong Muong

Posted on

1 1 1

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
Enter fullscreen mode Exit fullscreen mode
  • navigate into counter directory, and install famiq
cargo add famiq
Enter fullscreen mode Exit fullscreen mode

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() {}
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • 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

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo 📊✨

Top comments (0)

PulumiUP 2025 image

PulumiUP 2025: Cloud Innovation Starts Here

Get inspired by experts at PulumiUP. Discover the latest in platform engineering, IaC, and DevOps. Keynote, demos, panel, and Q&A with Pulumi engineers.

Register Now

👋 Kindness is contagious

Please show some love ❤️ or share a kind word in the comments if you found this useful!

Got it!