【Rust】Freya v0.3【ネイティブGUI】

**Freya**という新しいGUIライブラリのv0.3がリリースされました。注目すべきポイントがあるプロジェクトです。

## Freyaとは何か？

Freyaは、Rustで開発されたクロスプラットフォーム対応のネイティブGUIライブラリです。最大の特徴は、WebベースではなくSkiaグラフィックスライブラリを使用した **「真のネイティブ」な** GUIアプリケーションを作れることです。React風の宣言的なUIを書きながら、Web技術に一切依存しない点が大きな魅力となっています。

### 技術的な背景

FreyaはDioxusフレームワークの上に構築されており、RSX（React風のシンタックス）とフック（hook）を使って開発を行います。ただし、DioxusのWebviewベースのレンダラーとは異なり、FreyaはSkiaを使った独自のレンダラーを採用しています。これにより、全プラットフォームで一貫した見た目と動作を実現しています。

```rust
use freya::prelude::*;

fn main() {
    launch(app);
}

fn app() -> Element {
    let mut count = use_signal(|| 0);
    
    rsx!(
        rect {
            height: "100%",
            width: "100%",
            background: "rgb(35, 35, 35)",
            color: "white",
            padding: "12",
            onclick: move |_| count += 1,
            label {
                "Click to increase -> {count}"
            }
        }
    )
}
```

この例からも分かるように、FreyaではRustコードだけでUI全体を記述できます。JavaScript、HTML、CSSは一切必要ありません。

## v0.3の主要な新機能

約1年ぶりのメジャーリリースとなるv0.3では、数多くの機能強化が行われました。主な変更点を見ていきましょう。

### インクリメンタルレンダリングの実装

v0.3で最も大きな変更の一つが、インクリメンタルレンダリングの実装です。従来はUIの任意の変更で画面全体が再描画されていましたが、v0.3では変更された部分のみが再描画されるようになりました。これにより、特に大きなUIを持つアプリケーションでのパフォーマンスが大幅に向上しています。

開発時のデバッグ用に、`fade-cached-incremental-areas`という機能も追加されています。これにより、再描画されていない部分が徐々にフェードアウトして、インクリメンタルレンダリングの動作を視覚的に確認できます。

### Flexレイアウトのサポート

Web開発者には馴染み深いFlexレイアウトが、Freyaでも利用可能になりました。CSSのFlexboxに似た感覚で、柔軟なレイアウトを組むことができます。

```rust
fn app() -> Element {
    rsx!(
        rect {
            content: "flex",
            direction: "horizontal",
            rect {
                width: "flex(1)",  // 25%のスペースを使用
                height: "fill",
                background: "red"
            }
            label {
                "Some text here!"
            }
            rect {
                width: "flex(3)",  // 75%のスペースを使用
                height: "fill",
                background: "green"
            }
        }
    )
}
```

さらに、`space-between`、`space-around`、`space-evenly`といったCSS風の配置オプションも追加され、要素の配置がより細かく制御できるようになりました。

### 豊富な新コンポーネント

v0.3では多数の新しいコンポーネントが追加されました。特に注目すべきものをいくつか紹介します。

#### AnimatedPosition

要素の位置変化をアニメーション化するコンポーネントです。レイアウトの変更による要素の移動を自動的にアニメーション化してくれます。

```rust
fn app() -> Element {
    rsx!(
        AnimatedPosition {
            width: "110",
            height: "60",
            function: Function::Quad,
            duration: Duration::from_millis(250),
            rect {
                background: "red",
                width: "60",
                height: "110"
            }
        }
    )
}
```

#### ResizableContainer

分割されたパネルのサイズを動的に変更できるコンポーネントも追加されました。多くのIDEで見られるような、ドラッグでパネルサイズを調整する機能を簡単に実装できます。

```rust
fn app() -> Element {
    rsx!(
        ResizableContainer {
            ResizablePanel {
                initial_size: 50.,
                label { "Hello" }
            }
            ResizableHandle { }
            ResizablePanel {
                initial_size: 50.,
                label { "World" }
            }
        }
    )
}
```

### グラフィック機能の強化

#### グラデーション機能の拡張

v0.3では、線形グラデーションに加えて円形（radial）グラデーションと円錐形（conic）グラデーションもサポートされました。

```rust
let background = match gradient_type {
    GradientType::Linear => {
        "linear-gradient(250deg, orange 15%, rgb(255, 0, 0) 50%, rgb(255, 192, 203) 80%)"
    }
    GradientType::Radial => {
        "radial-gradient(orange 15%, rgb(255, 0, 0) 50%, rgb(255, 192, 203) 80%)"
    }
    GradientType::Conic => {
        "conic-gradient(250deg, orange 15%, rgb(255, 0, 0) 50%, rgb(255, 192, 203) 80%)"
    }
};
```

#### 画像処理の改善

`import_image`マクロの追加により、画像ファイルを簡単にコンポーネント化できるようになりました。また、`aspect_ratio`や`cover`属性により、画像の表示方法をより細かく制御できます。

```rust
import_image!(RustLogo, "./rust_logo.png", {
    width: "auto",
    height: "auto",
    sampling: "trilinear",
    aspect_ratio: "min",
});

fn app() -> Element {
    rsx!(RustLogo {})
}
```

### アクセシビリティの大幅改善

v0.3では、アクセシビリティ（a11y）のサポートが大幅に強化されました。これまではオプトイン方式でしたが、v0.3からは全ての要素が自動的にアクセシビリティIDを持つようになりました。

```rust
rect {
    a11y_role: "button",
    a11y_auto_focus: true,
    a11y_hidden: false,
    // その他のa11y属性...
}
```

キーボードナビゲーション（TabキーやShift+Tab）も改善されたそうです。

## 開発体験の向上

### ドキュメントの大刷新

v0.3のリリースに合わせて、ドキュメントが大幅に改善されました。[docs.rs](https://docs.rs/freya/0.3/freya/)では、主要なコンポーネントの埋め込みプレビューが提供されており、実際にコンポーネントがどのような見た目になるかを確認してから使用できます。

[例: ボタン](https://docs.rs/freya/0.3.3/freya/components/fn.Button.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79562/72619684-ed49-45cf-831f-2b4e871575e6.png)

すばらしいですね

### テスト機能の強化

ヘッドレステスト環境（`freya-testing`）では、UIキャンバスのスナップショットを保存できるようになりました。これにより、視覚的なテストやデバッグが格段に楽になります。

```rust
#[tokio::main]
async fn main() {
    let mut utils = launch_test(app);
    
    // 初期レンダリング
    utils.wait_for_update().await;
    utils.save_snapshot("./snapshot_before.png");
    
    // クリックイベント発火
    utils.click_cursor((100., 100.)).await;
    
    // クリック後のレンダリング
    utils.save_snapshot("./snapshot_after.png");
}
```

### 国際化（i18n）のサポート

Freyaアプリでの国際化には、`dioxus-i18n`クレートが推奨されています。`t!()`マクロを使って、簡単に多言語対応を実装できます。

```rust
fn Body() -> Element {
    let mut i18n = i18n();
    
    rsx!(
        rect {
            Button {
                onpress: move |_| i18n.set_language(langid!("en-US")),
                label { "English" }
            }
            Button {
                onpress: move |_| i18n.set_language(langid!("ja")),
                label { "日本語" }
            }
            label { {t!("hello", name: "Freya")} }
        }
    )
}
```

## 実際の使用例

公式ブログによると、開発者のMarc氏は自身のWebサイト（[https://freyaui.dev/](https://freyaui.dev/)）をFreya自体で構築しているそうです。また、作業中のクロスプラットフォームコードエディター「Valin」も、FreyaとRustで開発されています。



## 開発の現状と今後の展望

現在Freyaはまだ実験的な段階にあり、本格的なプロダクション利用には注意が必要です。

### 今後のロードマップ

公式ブログによると、開発者のMarc氏は今後はより高頻度なリリースサイクルに移行する予定とのことです。

## 始めてみよう

Freyaを試してみたい方は、以下の手順で簡単に始められます。

### 基本セットアップ

```toml
[dependencies]
freya = "0.3"
dioxus = { version = "0.6", features = ["macro", "hooks"], default-features = false }
```

### 最初のアプリケーション

```rust
use freya::prelude::*;

fn main() {
    launch(app);
}

fn app() -> Element {
    let mut name = use_signal(|| String::new());
    
    rsx!(
        rect {
            height: "100%",
            width: "100%",
            background: "rgb(35, 35, 35)",
            color: "white",
            padding: "50",
            Input {
                value: name.read().clone(),
                onchange: move |event| name.set(event),
                placeholder: "Enter your name..."
            }
            label {
                "Hello, {name.read()}!"
            }
        }
    )
}
```

### 開発者ツールの活用

Freyaには強力な開発者ツールが組み込まれています。`devtools`フィーチャーを有効にすることで、アプリケーションの構造やスタイル、レイアウトを視覚的に確認できます。

```toml
[dependencies]
freya = { version = "0.3", features = ["devtools"] }
```

## まとめ

Rust製のGUIは数々ありますが、Freya v0.3は大変使いやすそうで要注目です。まだ実験的な段階ですが、その可能性は非常に大きく、今後の発展が楽しみです。

興味を持たれた方は、ぜひ[公式ドキュメント](https://docs.rs/freya/0.3/freya/)や[GitHubリポジトリ](https://github.com/marc2332/freya)をチェックして、実際に触ってみてください。

### 参考リンク

- [Freya公式サイト](https://freyaui.dev/)
- [Freya v0.3リリースブログ](https://freyaui.dev/posts/0.3)
- [Dioxus公式サイト](https://dioxuslabs.com/)