Rust の GUI フレームワーク Makepad


Makepad とは

Makepad は、Rust で書かれたクロスプラットフォーム(ネイティブおよびWeb)な UIフレームワークです。

2019年から開発が始まり、2025年5月15日に 1.0.0 版がリリースされました。

特徴としては、シェーダーベースのUIレンダリングを行う点、UIを独自のDSLで定義する点、Liveシステムによるホットリロードにより、再コンパイルすることなく、リアルタイムにUIを更新できる点、といったところでしょうか。

リポジトリは以下です。

github.com


サンプルの実行

Makepad のリポジトリには、makepad-studio という IDE が含まれています。

以下のように実行できます。

git clone https://github.com/makepad/makepad.git
cd makepad
cargo run -p makepad-studio --release

IDE っぽいものが起動します。

Makepad の開発者は、Cloud9 IDE の開発者でもる Rik Arends であり、最終的には Makepad で ライブコーディングとデザインのハイブリッドIDEを構築することが目的のようです。


簡単なアプリケーションの作成

少し触ってみましょう。

以下でプロジェクトを作成します。

cargo new makepad_example
cd makepad_example
cargo add [email protected]

src/main.rs を以下のように編集します。

// Import Makepad Widgets package
use makepad_widgets::*;

// Define live_design macro for declaring UI components and layout
live_design! {
    use link::widgets::*;
    App = {{App}} {
        ui: <Root> {
            <Window> {
                body = <View> {}
            }
        }
    }
}

// Define App struct containing UI and counter
#[derive(Live, LiveHook)]
pub struct App {
    #[live]
    ui: WidgetRef // UI component reference
}

// Implement LiveRegister trait for registering live design
impl LiveRegister for App {
    fn live_register(cx: &mut Cx) {
        // Register Makepad Widgets' live design
        makepad_widgets::live_design(cx);
    }
}

// Implement AppMain trait for handling events
impl AppMain for App {
    fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
        let scope = &mut Scope::empty();
        // Handle UI events
        self.ui.handle_event(cx, event, scope);
    }
}

// Define application entry point
app_main!(App);

fn main() {
    app_main()
}

以下で実行します。

cargo run

空のウインドウが表示されます。

簡単にコードを見ていきましょう。

live_design! マクロでUIを定義しています。

live_design! {
    use link::widgets::*;
    App = {{App}} {
        ui: <Root> {
            <Window> {
                body = <View> {}
            }
        }
    }
}

例えば、以下のように変更して保存してみます。

live_design! {
    use link::widgets::*;
    App = {{App}} {
        ui: <Root> {
            <Window> {
                show_bg: true,
                draw_bg: {
                    color: #000
                },
                body = <View> {}
            }
        }
    }
}

ウインドウの背景を黒で表示するように指定しました。 ファイルを保存すれば、ホットリロードされて、即座に変更が反映されます。

ウインドウのボディ内に Label コンポーネントを配備してみます。

live_design! {
    use link::widgets::*;
    App = {{App}} {
        ui: <Root> {
            <Window> {
                show_bg: true,
                draw_bg: {
                    color: #000
                },
                body = <View> {
                    <Label> {
                        margin: 40,
                        text: "Hello World!"
                        draw_text: {
                            color: #FFFFFF
                        }
                    }

                }
            }
        }
    }
}

またも即座に UI が更新されます。

このようにMakepad では live_design! マクロにより、UIを定義していきます。


イベント処理

ボタンとラベルを追加します。

live_design! {
    use link::widgets::*;
    App = {{App}} {
        ui: <Root> {
            <Window> {
                show_bg: true,
                draw_bg: {
                    color: #000
                },
                body = <View> {

                    button = <Button> {
                        margin: 30,
                        text: "Click Me",
                    }

                    msg = <Label> {
                        margin: 15,
                        draw_text: {
                            color: #FFFFFF
                        }
                    }
                }
            }
        }
    }
}

handle_event() 内に以下を追加します。

impl AppMain for App {
    fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
        self.match_event(cx, event); // <- 追加
        let scope = &mut Scope::empty();
        // Handle UI events
        self.ui.handle_event(cx, event, scope);
    }
}

MatchEvent の実装を以下のように追加します。

impl MatchEvent for App {

    fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions){
        if self.ui.button(id!(button)).clicked(&actions) {
            self.ui.label(id!(msg)).set_text(cx, "Hello world!");
            self.ui.redraw(cx);
        }

    }
}

UI 上の button という名前のボタンがクリックされた場合に、msg というラベルのテキストを変更するだけの処理です。

ボタンをクリックすると、以下のようにメッセージが表示されます。


まとめ

Rust の GUI フレームワーク Makepad を簡単に触ってみました。

基本的なウィジェットも揃っていますし、ホットリロードがなかなかステキです。

ドキュメントも最近公開されたので、興味のある方は触ってみてはいかがでしょうか。

book.makepad.rs