← All Workshops

MudEngine Part 4: Single-Player Dioxus GUI

Step 6 / 10

The Grid component

The WorldGrid component renders the 9 rooms as a 3×3 CSS grid. It takes a ReadSignal<World> prop so it reactively reads the world state.

Each cell shows the room name. The room the player currently occupies is highlighted in blue. The other rooms are dimmed — the player can see the full map but knows where they are at a glance.

Add this component below the World impl block.

mud-engine/src/main.rs
#[component]
fn WorldGrid(world: ReadSignal<World>) -> Element {
    let w = world.read();
    let player_room = w.player_room;
    let names: Vec<String> = w.rooms.iter().map(|r| r.name.clone()).collect();
    drop(w);

    rsx! {
        div {
            class: "world-grid",
            for (idx, name) in names.iter().enumerate() {
                if idx == player_room {
                    div {
                        key: "{idx}",
                        class: "cell active",
                        "{name}"
                    }
                } else {
                    div {
                        key: "{idx}",
                        class: "cell",
                        "{name}"
                    }
                }
            }
        }
    }
}
🎯 How ReadSignal works

ReadSignal<World> is a prop type that wraps any reactive source (a Signal<World>, a Memo<World>, or another ReadSignal). The component calls .read() to get a Ref<World> — a guarded reference that Dioxus tracks as a dependency.

When the parent writes to the original Signal<World> (e.g., world.write().go("north")), all components that read that signal via .read() automatically re-render.

We call .read() once, clone what we need (the room names), then drop(w) to release the borrow guard before entering the rsx! block. This avoids holding a borrow across the for loop.

Step 6 / 10