---
# System prepended metadata

title: 'Rust egui: A Step-by-Step Tutorial (Easy Reading Format)'

---


# Rust egui: A Step-by-Step Tutorial (Easy Reading Format)

Hello there! Welcome to GUI (Graphical User Interface) development with Rust and the `egui` library.

I'm Gemini, your guide. Think of me as a friendly teacher who's helped many beginners like you get started with Rust. We'll take it slow and steady.

Don't worry if things seem new – we'll break them down. Let's begin!

## I. Introduction to egui: Your Friendly GUI Toolkit

**What's a GUI?**
It's the visual part of an app – buttons, text boxes, sliders – things you click and interact with.

**What's `egui`?**
`egui` is a Rust library specifically made for building these GUIs.

**Why use `egui`?**

* **Simple & Fast:** It's designed to be easy to learn and quick to run [1, 2].
* **Portable:** Write your code once, run it on desktops (Windows, Mac, Linux) *and* in web browsers! [1, 3] This uses a technology called WebAssembly (WASM).
* **Immediate Mode:** This is `egui`'s special way of working. Let's explore it.

### Immediate Mode vs. Retained Mode (The `egui` Way)

Think of **Retained Mode** (common in other GUI toolkits) like building with LEGOs. You create objects (button, text box), and the library *remembers* them [1].

`egui` uses **Immediate Mode**. Imagine a whiteboard:

1.  Every fraction of a second (a "frame"), `egui` asks your code: "What should the UI look like *right now*?"
2.  Your code describes the *entire* UI based on the current situation (your app's data).
3.  `egui` draws it.
4.  `egui` then *forgets* the drawing, ready for the next frame [1, 2].

**Key Differences:**

| Feature             | Immediate Mode (`egui`)                 | Retained Mode (Other GUIs)              |
| :------------------ | :-------------------------------------- | :-------------------------------------- |
| **UI Definition** | Redrawn fresh **every frame** [1].      | UI objects **created & kept** in memory. |
| **State** | **Your app code** holds UI data [1, 2]. | GUI library often holds UI data.      |
| **Interactions** | Logic is **in your drawing code** [1].  | Separate "event handlers" attached.   |
| **Simplicity** | Often **simpler** to start with [1, 2]. | Can handle complex layouts easily.    |

**Why Immediate Mode is often simpler:** Your code directly controls what's shown based on your application's data *right now*. There's less complexity in syncing separate UI state [2].

## II. Essential Rust Fundamentals for egui

You don't need to be a Rust expert, but knowing these basic concepts will help you understand `egui` code [3].

* **Functions (`fn`):** Blocks of code that do specific tasks. You'll put your UI logic in functions.
* **Mutability (`mut`):** Allows variables to be changed. GUIs change constantly, so you'll see `mut` a lot, especially with `&mut` (mutable borrow) [3].
* **Structs (`struct`):** Let you create your own data types by grouping related variables. You'll use a struct to hold your application's state (data) [1].
* **Enums (`enum`):** Define a type that can have one of a few specific values (variants). Great for multiple-choice options [3].
* **Closures (`|args| { ... }`):** Mini, unnamed functions defined on the spot. `egui` uses them heavily for layout and defining UI sections [3].
* **Ownership & Borrowing (`&`, `&mut`):** Rust's safety feature! `&mut` lets `egui` safely *modify* your app's state without taking ownership [3].
* **Traits:** Define shared behaviour (like interfaces). You'll implement the `eframe::App` trait for your main app struct [3].
* **Modules & Crates (`use`, `::`):** How Rust organizes code and uses external libraries (`egui`, `eframe`). `use` brings items into scope; `::` separates parts of a path (like `eframe::egui`).

Don't worry if these seem abstract now. You'll see them in action soon!

## III. Setting Up a New Rust Project with eframe

Let's create our first project! We'll use `eframe`, which helps `egui` run as a standalone app [1].

**Steps:**

1.  **Open Terminal:** Go to your command prompt or terminal.
2.  **Navigate:** Go to the directory where you keep your code projects.
3.  **Create Project:** Run `cargo new egui_demo`
    ```bash
    cargo new egui_demo
    ```
4.  **Enter Directory:** Run `cd egui_demo`
    ```bash
    cd egui_demo
    ```
5.  **Add `eframe` Dependency:**
    * Open the `Cargo.toml` file in the `egui_demo` folder.
    * Find the `[dependencies]` section.
    * Add this line:
        ```toml
        [dependencies]
        eframe = "0.25" # Using version from example [1]. Check crates.io for latest!
        ```
6.  **Write Basic Code:**
    * Open the file `src/main.rs`.
    * **Delete everything** inside it.
    * Paste this starting code [1]:

        ```Rust
        // Import necessary stuff from the eframe crate
        use eframe::egui;

        // Main entry point of the program
        fn main() -> Result<(), eframe::Error> {
            // Default window settings
            let options = eframe::NativeOptions::default();

            // Start the egui application!
            eframe::run_native(
                "egui Demo", // Window title
                options,     // Window settings
                // This creates our app state. Don't worry too much about Box::new for now.
                Box::new(|_cc| Box::new(MyApp::default())),
            )
        }

        // This struct holds our application's data (state)
        // `#[derive(Default)]` makes it easy to create a starting instance
        #[derive(Default)]
        struct MyApp {
            label: String, // For a text input field
            value: f32,    // For a slider
            // We will add more fields here later!
        }

        // Implement the eframe::App trait for MyApp, telling eframe how to run it
        impl eframe::App for MyApp {
            // The `update` method is called every frame to draw the UI
            // `&mut self` allows this method to modify MyApp's fields
            fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
                // Show a central panel where we'll put our UI
                egui::CentralPanel::default().show(ctx, |ui| {
                    // `ui` is our tool to add widgets

                    // Add a heading
                    ui.heading("My egui Application");

                    // Arrange items horizontally
                    ui.horizontal(|ui| {
                        ui.label("Write something: ");
                        // Text input linked to `self.label`
                        // `&mut self.label` lets the widget change the `label` field
                        ui.text_edit_singleline(&mut self.label);
                    });

                    // Add a slider linked to `self.value`
                    ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0).text("value"));

                    // Add a button
                    if ui.button("Increment").clicked() {
                        // If clicked, increase `self.value`
                        self.value += 1.0;
                    }

                    // Display the current state in a label
                    ui.label(format!("Hello '{}', value: {}", self.label, self.value));
                });
            }
        }
        ```

7.  **Run the App:**
    * Go back to your terminal (still in the `egui_demo` folder).
    * Run `cargo run`
        ```bash
        cargo run
        ```
    * Cargo will build and run your code. A window should appear! [1]

You did it! You ran your first `egui` app.

## IV. Basic Structure of an egui Application (Enhanced Explanation)

Let's break down that starting code:

1.  **`main` Function:**
    * Starts the program.
    * Sets up `eframe` options.
    * Calls `eframe::run_native(...)`.
    * Tells `eframe` how to create your application's initial state (`Box::new(|_cc| Box::new(MyApp::default()))`).
        * **Syntax Note:** `Box::new()` puts data on the "heap" (a memory area). `eframe` uses it here for flexibility. You don't need to fully grasp `Box` yet. Just know this line creates your `MyApp` struct.
        * **Syntax Note:** `MyApp::default()` uses the `Default` trait (often auto-generated by `#[derive(Default)]`) to create a `MyApp` with starting values (empty `String`, `0.0` `f32`).

2.  **The State Struct (`struct MyApp`)**
    * Holds *all* the data your UI needs.
    * `label: String` holds text for the input box.
    * `value: f32` holds the number for the slider.

3.  **The `eframe::App` Trait Implementation (`impl eframe::App for MyApp`)**
    * This block tells `eframe` that `MyApp` knows how to be an application.
    * It requires the `update` method.

4.  **The `update` Method (`fn update(&mut self, ...)`):**
    * **The heart of `egui`!** Called every frame (many times per second).
    * **`&mut self`:** Gets *mutable access* to your `MyApp` instance. This is crucial! It means `update` can *change* the data (like `self.value += 1.0`).
    * **`ctx: &egui::Context`:** Provides access to `egui`'s context (input, style, etc.).
    * **`|ui| { ... }`:** A closure! An inline function where you define the UI for *this frame*. `egui` gives you the `ui` object to use inside it.
    * **`ui.heading(...)`, `ui.horizontal(...)`, etc.:** Methods called on the `ui` object add widgets (visual elements) to the screen.
    * **`&mut self.label`, `&mut self.value`:** Passing mutable borrows (`&mut`) links the widget directly to your state field. When the user interacts, the widget modifies your `MyApp` field.

**Key Idea:** The `update` function runs, reads the current state from `self`, draws the UI based on that state, checks for interactions, potentially modifies `self` based on interactions, and then finishes until the next frame.

## V. Adding Basic UI Widgets (Enhanced Explanation)

Widgets are the building blocks (buttons, labels, etc.). You add them using the `ui` object inside closures.

Let's enhance `MyApp` to hold more state for new widgets:

```Rust
// --- Add Enums (Specific choice types) ---
#[derive(Debug, PartialEq, Clone, Copy)] // Allow printing, comparing, copying
enum ColorChoice { Red, Green, Blue }

#[derive(PartialEq, Debug, Clone, Copy)] // Allow comparing, printing, copying
enum AppMode { View, Edit, Settings }

// --- Update MyApp Struct (holds ALL application state) ---
struct MyApp {
    label: String,
    value: f32,
    show_extra_info: bool, // For a checkbox (true/false)
    selected_color: ColorChoice, // For radio buttons
    counter: i32,          // Another piece of state
    current_mode: AppMode, // To control which view is shown
}

// --- Manually Implement `Default` (starting values) ---
// We do this manually because ColorChoice/AppMode don't have automatic defaults.
impl Default for MyApp {
    fn default() -> Self { // `Self` means `MyApp` here
        Self {
            label: "Initial Text".to_string(), // Create a String
            value: 5.0,
            show_extra_info: false, // Checkbox starts unchecked
            selected_color: ColorChoice::Red, // Default radio choice
            counter: 0,
            current_mode: AppMode::View, // Start in View mode
        }
    }
}
```

**Syntax Explained:**

* **`enum`:** Defines a type with specific variants (e.g., `ColorChoice` can *only* be `Red`, `Green`, or `Blue`).
* **`#[derive(...)]`:** Asks Rust to auto-generate common trait implementations (`Debug` for printing, `PartialEq` for `==`, `Clone`/`Copy` for duplicating).
* **`impl Default for MyApp`:** Provides a standard way (`MyApp::default()`) to create a starting instance.
* **`Self { ... }`:** Syntax to create an instance of the struct (`MyApp`) within its own `impl` block.
* **`.to_string()`:** Converts a basic string literal (`"..."`) into an owned `String`.

Now, let's see how to add Checkboxes and Radio Buttons in the `update` method (we'll integrate this into a fuller example later):

```Rust
// Inside the `update` method, within a panel's `.show(ctx, |ui| { ... })` block:

// --- Checkbox ---
// Links directly to the `show_extra_info` boolean field in `MyApp`.
// Clicking the box toggles `self.show_extra_info`.
ui.checkbox(&mut self.show_extra_info, "Show Advanced Options");

// You can then use this state to show/hide other things:
if self.show_extra_info {
    ui.label("Showing advanced info because the box is checked!");
    // ... add more widgets here ...
}

// --- Radio Buttons ---
ui.label("Choose a Color:");
// Arrange them horizontally
ui.horizontal(|ui| {
    // Each button represents one variant of the `ColorChoice` enum.
    // They are linked to the SAME state field: `self.selected_color`.
    // Clicking a button updates `self.selected_color` to *that button's* value.
    ui.radio_value(&mut self.selected_color, ColorChoice::Red, "Red");
    ui.radio_value(&mut self.selected_color, ColorChoice::Green, "Green");
    ui.radio_value(&mut self.selected_color, ColorChoice::Blue, "Blue");
});
// Display the currently selected choice
ui.label(format!("Selected: {:?}", self.selected_color)); // `{:?}` uses Debug format
```

**Key Idea:** Widgets like `checkbox` and `radio_value` use `&mut self.field_name` to directly read *and write* to your application's state struct (`MyApp`).

## VI. Handling User Interactions (Enhanced Explanation)

How does your app *react*? You check widget states during the `update` call [1, 4].

Most interactive widgets (like `button`, `slider`, `checkbox`) return a `Response` struct. This `Response` tells you what happened *in that specific frame*.

* **Button Clicks (`.clicked()`):**
    ```Rust
    // Store the response in a variable
    let save_button_response = ui.button("Save");

    // Check if it was clicked THIS frame
    if save_button_response.clicked() {
        println!("Save clicked!");
        // Update state or call a function here...
        self.label = "Saved!".to_string();
    }
    ```

* **Mouse Hover (`.hovered()`):**
    ```Rust
    if save_button_response.hovered() {
        // Show a helpful tooltip when the mouse is over the button
        save_button_response.on_hover_text("Click here to save your data");
    }
    ```

* **Right-Clicks (`.secondary_clicked()`):**
    ```Rust
    if save_button_response.secondary_clicked() {
        println!("Right-click detected!");
        // Maybe show a context menu here...
    }
    ```

* **Value Changes (`.changed()`):** Useful for sliders, text edits, etc.
    ```Rust
    let slider_response = ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0));
    // `changed()` is true in the frame the value *finished* changing (e.g., mouse release)
    if slider_response.changed() {
        println!("Slider value is now: {}", self.value);
        // Trigger saving the new value, perhaps?
    }
    ```

* **Dragging (`.dragged()`):**
    ```Rust
    if slider_response.dragged() {
        // Maybe show temporary feedback while dragging
        // ui.label("Dragging slider...");
    }
    ```

**Key Idea:** You don't wait for events. In each `update`, you *ask* the widgets (via their `Response`) if an interaction just happened, and react immediately by changing state or drawing something different.

## VII. Organizing UI Layout (Enhanced Explanation)

Arranging widgets makes your UI usable. `egui` offers simple tools [3]:

* **Basic Layouts (`horizontal`, `vertical`):**
    * `ui.horizontal(|ui| { ... });` - Widgets side-by-side [5].
    * `ui.vertical(|ui| { ... });` - Widgets top-to-bottom [5].
    * You can **nest** these (e.g., vertical list of horizontal rows).

* **Panels (`TopBottomPanel`, `SidePanel`, `CentralPanel`):**
    * Divide your window into fixed areas (top/bottom/left/right) or the main central area [1].
    * Define panels *before* `CentralPanel` in `update`.

* **Grouping (`ui.group`, `ui.collapsing`):**
    * `ui.group(|ui| { ... });` - Draws a box around items [5].
    * `ui.collapsing("Header", |ui| { ... });` - Clickable header to show/hide content [3].

* **Alignment (`ui.vertical_centered`, `Layout::right_to_left`):**
    * Helpers to center items or change layout direction.

* **Grids (`egui::Grid`):**
    * Perfect for forms! Aligns items in columns.
    * Use `ui.end_row()` after adding widgets for each row.

* **Menus (`egui::menu::bar`, `ui.menu_button`):**
    * Helpers for creating menu bars, usually in a `TopBottomPanel`.

Let's see a combined layout (using the full `MyApp` struct from Section V):

```Rust
// This replaces the `impl eframe::App for MyApp` block entirely

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {

        // --- Top Panel: Menu Bar ---
        egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
            egui::menu::bar(ui, |ui| { // Use the menu bar layout helper

                // File Menu
                ui.menu_button("File", |ui| { // Creates "File" button with dropdown
                    if ui.button("Reset Counter").clicked() { self.counter = 0; }
                    if ui.button("Quit").clicked() {
                        // Send command to close the window
                        ctx.send_viewport_cmd(egui::ViewportCommand::Close);
                    }
                }); // End File Menu dropdown

                // Mode Menu
                ui.menu_button("Mode", |ui| { // Creates "Mode" button with dropdown
                     // Use radio buttons to change mode, close menu on click
                     if ui.radio_value(&mut self.current_mode, AppMode::View, "View").clicked() { ui.close_menu(); }
                     if ui.radio_value(&mut self.current_mode, AppMode::Edit, "Edit").clicked() { ui.close_menu(); }
                     if ui.radio_value(&mut self.current_mode, AppMode::Settings, "Settings").clicked() { ui.close_menu(); }
                }); // End Mode Menu dropdown

                // Display state on the right side of the menu bar
                 ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
                     ui.label(format!("Counter: {}", self.counter)); // Show counter value
                 }); // End right-aligned section

            }); // End menu bar
        }); // End Top Panel

        // --- Left Panel: Info / Tools ---
        egui::SidePanel::left("info_panel")
            .default_width(150.0) // Set a default width
            .show(ctx, |ui| {
                ui.heading("Info Panel");
                 ui.separator(); // Visual dividing line
                 ui.label(format!("Selected: {:?}", self.selected_color));
                 ui.separator();
                if ui.button("Reset Label Text").clicked() {
                    self.label = String::default(); // Reset to empty string
                }
                 ui.separator();
                 // Add some spacing at the bottom
                 ui.allocate_space(ui.available_size());

        }); // End Side Panel

        // --- Central Panel: Main Content (Changes based on Mode) ---
        egui::CentralPanel::default().show(ctx, |ui| {
             ui.heading(format!("Current Mode: {:?}", self.current_mode));
             ui.separator();

            // Use `match` to show different UI based on `self.current_mode`
            match self.current_mode {

                // --- VIEW MODE UI ---
                AppMode::View => {
                    ui.heading("VIEW DATA");
                    // Use a group to visually contain the data
                    ui.group(|ui|{
                        ui.label(format!("Label: {}", self.label));
                        ui.label(format!("Value: {:.1}", self.value)); // Format float to 1 decimal place
                    }); // End group

                    // Show more details only if the checkbox in settings is ticked
                    if self.show_extra_info {
                        // Use a collapsing header for optional info
                         ui.collapsing("Show More Details", |ui| {
                             ui.label(format!("Counter: {}", self.counter));
                             ui.label(format!("Color Choice: {:?}", self.selected_color));
                         });
                    } else {
                         ui.label("(Enable 'Show Advanced Info' in Settings)");
                    }
                } // End View Mode Arm

                // --- EDIT MODE UI ---
                AppMode::Edit => {
                     ui.heading("EDIT DATA");
                    // Use a Grid for aligned form elements
                    egui::Grid::new("edit_grid")
                        .num_columns(2) // Define 2 columns
                        .spacing([20.0, 8.0]) // Horizonal & vertical spacing
                        .striped(true) // Alternating row backgrounds
                        .show(ui, |ui| { // Add content row by row

                            ui.label("Edit Label:"); // Column 1, Row 1
                            ui.text_edit_singleline(&mut self.label); // Column 2, Row 1
                            ui.end_row(); // MUST call end_row() to finish the row

                            ui.label("Adjust Value:"); // Column 1, Row 2
                            ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0)); // Column 2, Row 2
                            ui.end_row();

                            ui.label("Counter:"); // Column 1, Row 3
                            ui.horizontal(|ui|{ // Nested horizontal layout in Col 2, Row 3
                                if ui.button("+").clicked() { self.counter += 1; }
                                ui.label(format!("{}", self.counter)).highlight(); // Highlight the number
                                if ui.button("-").clicked() { self.counter -= 1; }
                            });
                            ui.end_row();
                        }); // End Grid
                } // End Edit Mode Arm

                // --- SETTINGS MODE UI ---
                AppMode::Settings => {
                     ui.heading("SETTINGS");
                    // Use a Group for visual structure
                    ui.group(|ui|{
                        ui.checkbox(&mut self.show_extra_info, "Show Advanced Info in View");
                         ui.separator(); // Line separator within the group
                        ui.label("Color Scheme:");
                         ui.horizontal(|ui| { // Radio buttons side-by-side
                            ui.radio_value(&mut self.selected_color, ColorChoice::Red, "Red");
                            ui.radio_value(&mut self.selected_color, ColorChoice::Green, "Green");
                            ui.radio_value(&mut self.selected_color, ColorChoice::Blue, "Blue");
                        }); // End horizontal layout
                    }); // End group

                     ui.separator(); // Separator between group and button
                     // Add a button to reset ALL state back to defaults
                     if ui.button("Reset All State").clicked() {
                        *self = MyApp::default(); // Replace current state with default values
                        // Optional: Stay in settings mode after reset
                        // self.current_mode = AppMode::Settings;
                    }
                } // End Settings Mode Arm

            } // End match self.current_mode

        }); // End CentralPanel

    } // End update fn
} // End impl eframe::App
```

**Key Layout Ideas:**

* Use Panels for overall structure (Menu, Side, Central).
* Use `horizontal`/`vertical` for basic flow inside panels/groups.
* Use `Grid` for forms needing aligned columns.
* Use `group`/`collapsing` to organize related items visually.
* Nest layouts as needed!

## VIII. State Management (Enhanced Explanation)

This is super important for `egui`!

* **Your `struct MyApp` is King:** It holds all the data (`label`, `value`, `counter`, `current_mode`, etc.) [1, 2]. This is the **single source of truth**.
* **`update` Reads State:** Each frame, `ui.label(format!("{}", self.counter))` reads the *current* `self.counter` value to display it [1, 4].
* **Interactions Write State:** `if ui.button("+").clicked() { self.counter += 1; }` *directly changes* `self.counter` when the button is clicked [4]. `ui.text_edit_singleline(&mut self.label)` *directly changes* `self.label` as you type.
* **UI Updates Automatically:** Because `update` runs every frame and always reads the *latest* state from `self`, the UI instantly reflects any changes made in the previous frame [4].

**Example: Changing Modes**

1.  `self.current_mode` holds the state (`View`, `Edit`, or `Settings`).
2.  The `match self.current_mode { ... }` block reads this state.
3.  Based on the state, *different UI code runs*, showing the View, Edit, or Settings widgets.
4.  Clicking a mode radio button (`ui.radio_value(&mut self.current_mode, ...`) *directly changes* the `self.current_mode` field.
5.  On the *very next frame*, the `match` expression reads the *new* mode and instantly shows the corresponding UI.

**Resetting State:**
The `*self = MyApp::default();` line is a simple way to reset everything.
* `MyApp::default()` creates a *brand new* struct instance with default values.
* `*self = ...` assigns this new instance over the memory of the old `self`, effectively replacing it.

**Slow Tasks (Reminder):** Don't do slow things (like file downloads) directly in `update`! Use threads and communicate back using channels or shared state, checking for results without blocking `update` [2].

## IX. Advanced Features

Once you master the basics, `egui` offers more [3]:

* **Custom Panels:** Design your own panel types [1, 3].
* **Game Engine Integration:** Use `egui` inside games (e.g., with `bevy_egui`) [1, 3].
* **Dynamic UI:** Use `if`, `match`, and loops (`for item in &self.items { ... }`) to build UI based on data.
* **More Widgets:** Explore `egui_extras` (tables, images) and other community crates [1].
* **Custom Widgets:** Build your own reusable UI elements.
* **Context Menus:** Add right-click menus easily (`response.context_menu(...)`).
* **Drag and Drop:** Handle file drops or item dragging.
* **Debugging Tools:**
    * `ctx.set_debug_on_hover(true);` - Hover to see widget bounds/IDs [1].
    * `egui::Window::new("Debug").show(ctx, |ui| { ctx.inspection_ui(ui); });` - Show detailed debug info window.

## X. Best Practices

Tips for good `egui` code [1]:

1.  **Keep Logic Out of `update`:** Put complex calculations in separate functions. Let `update` *call* those functions based on interactions, but keep `update` itself focused on drawing and simple state changes [1].
2.  **Organize State:** Keep your `MyApp` struct tidy. For very complex apps, group related state into smaller structs within `MyApp`.
3.  **Use Debug Tools:** They save *a lot* of time when layouts or interactions misbehave [1].
4.  **Think Readability:** Structure your `update` function clearly. Use comments. Break down very complex UI sections into helper functions if needed.
5.  **Accessibility:** Use clear labels. Check if `eframe` or your integration supports accessibility features like AccessKit [2].

## XI. Further Learning & Resources

Ready for more? Check these out [2, 5, 1, 3]:

* **Official Docs:** [docs.rs/egui](https://docs.rs/egui) [5]
* **Web Demo & Examples:** [www.egui.rs](https://www.egui.rs/) [2]
* **GitHub Repo:** [github.com/emilk/egui](https://github.com/emilk/egui) (Source code, discussions, more examples!) [2]
* **`eframe` Template:** [github.com/emilk/eframe_template](https://github.com/emilk/eframe_template) (Quick start project) [5]
* **Game Dev:** `bevy_egui` [github.com/mvlabat/bevy_egui](https://github.com/mvlabat/bevy_egui) [3]
* **Community:** GitHub Discussions, Discord servers.
* **Extra Widgets:** `egui_extras` [crates.io/crates/egui_extras](https://crates.io/crates/egui_extras) [1]
* **"Awesome egui" Lists:** Search for curated lists of helpful `egui` crates.

## XII. Conclusion

`egui` makes GUI development in Rust surprisingly simple and fun! Its immediate mode approach often leads to cleaner code by keeping state management straightforward [1, 2]. Plus, it runs everywhere (desktop and web) [1, 3].

You've learned the essentials: setup, the `update` loop, state handling (`MyApp`), adding widgets, responding to clicks/hovers, organizing layouts, and even switching UI views based on state.

The best way forward? **Build things!** Start simple, modify the examples, try adding features. `egui` gives fast feedback, making experimentation easy. Enjoy creating interactive Rust applications! Happy coding!

---
