Figmaの生成AIプラグインでWebデザインを作ってSTUDIOで公開してみた

はじめに

こんにちは、フロントエンドエンジニアの堀江(@nandemo_3_)です。

最近、Figmaに生成AIプラグインが多くあることを知り、デザイン制作からサイト公開まで生成AIにやらせることができるのでは?と思い、

さらに、ノーコードでWebサイトが制作できるSTUDIOというサービスがあるのですが、

これもFigmaからSTUDIOに移行が行えるプラグインがあるということで、

生成AIで作成したデザインをSTUDIOに乗せ替え、公開までしてみようと思います。

使用したプラグイン

Builder.io

www.builder.io

Magician

magician.design

AI image generator

www.freepik.com

Figma To STUDIO

studio.design

デザイン作成

Figmaのデザインを生成するAIはいくつかあります。(ワイヤーフレーム、アイコンやライティング、画像など)

その中でも、Webサイトでも使えるようなデザインを生成して欲しいので、

Builder.ioというプラグインを使用することにしました。

このプラグインのすごいところは、Figmaのデザインをコードに変換できる点です。

React、Next.js、Vue、Svelte、Angularなどの多様なフレームワークを選択でき、HTMLにも変換可能です。

さらに、CSSライブラリも選ぶことができるというので驚きです。(Tailwind CSS、Material UI、Emotion、Styled Componentsなど)

これがどれくらいの精度で出力されるのか試してみたいところですが、今回はSTUDIO上で公開をするので、コードに変換するのはまた今度。

さて、Builder.ioを実際に使っていきます。

今回は、バーチャルアバターやモーションデータのサブスクサービスを仮定してランディングページを作ります。

FigmaのプラグインでBuilder.ioと検索し表示されたビューにて、Prompt、OpenAI Keyを入力すると、このように4パターンのデザインが生成されます。

例を入れる欄があったので、VRoid Hubを入れてみました。

お好みのデザインをクリックするとFigmaへのImportが始まります。

ライティングは英語ではあるものの、それっぽい見出しになっています。

しかし、Vroid Hubのまんまになっているので、ライティングを変える必要があります。

アイコン、画像の作成

続いて、サイトアイコンとページ内画像を作成するために、

Magicianというプラグインを使いたいと思います。

Magicianはフリートライアルがあるので、アカウント登録をしてAccess Keyをゲットしましょう。

アイコン

Magic Iconで作成ができます。

Text to Imageの機能でプロンプトを入れると4つのアイコンを生成してくれます。

適当なサイトであればこれくらいのロゴで良さそうです。

しかし、これをFigmaにインポートすると、黒塗りになったり欠けたりしたので、なかなか実用にはまだ厳しい印象を受けました。

Vector形式で出力されるので、Figma上で色の変更などを行う前提なのかもしれません。

今回は画像にて出力して利用しました。

画像

続いて、Magic Imageで画像の生成を行います。

こちらも、Text to Imageの機能でプロンプトを入れると4つの画像を生成してくれます。

出力サイズが512×512固定で、キービジュアルというよりは商品画像のようなものに使える機能かなという印象でした。

オプションもあったのですが、Comming soonとなってました。

プロンプトが微妙でイメージとは違う画像になってしまいましたが、デモなのでよしとします。

(おまけ)コピーライティング

Magicianにはライティングを生成する機能Magic Copyもあります。

本当はこの機能を使おうと思っていたのですが、あまり使えなかったので、取りやめました。。。素直にChatGPTを使うのが良さそうです。

また、翻訳機能はあるものの、2024年2月5日時点では日本語対応はしていませんでした。

STUDIOに移行

前述の通り、Figma To STUDIOを使い、FigmaのデザインをSTUDIOに移行させていきます。

Figmaのプラグインで「Figma To STUDIO」と検索すると出てきます。

STUDIOにログインするためアカウント作成をしてください。

続いて、フレームまたはレイヤーを選択し、「クリップボードにコピー」をクリックします。

が、コピー中が終了しません。

案の定、フレームが大きすぎるため、コピーできないようです。

今回モックアップに使用したBuilder.ioは、すべての要素が1フレームに集約されているため、Figma To STUDIOを使う場合はフレームを分割する必要があります。

TOPを1つのフレームにするとコピーができるようになりました。

そして、コピーしたフレームをSTUDIO側でペースト(Ctrl + V)すると、このような画面が表示されます。

「デザインをインポート」ボタンをクリックするとこのようにFigmaで作成したデザインを移動することができます。

キービジュアル画像の作成

やはり、トップページのデザインが物足りないので、キービジュアル的な画像を作りたいと思います。

Magicianではなく、AI image generatorを使ってみます。

このプラグインは、Freepikが運営するFigmaプラグインで、1日16回まで無料で利用できます。

1回につき4枚生成してくれるので、最大64枚まで画像生成ができます。

プラグインを開くとこのようにプロンプトを入力する画面が表示されます。

お好きなプロンプトを入力して、「Make magic」をクリックすると以下のように4つの画像が生成されます。

イメージ通りのプロンプトが考えられず難しいなという感じる今日この頃ですが、

ちょっとトリミングして、グレーアウトさせてあげたらちょっとマシになりましたね。

完成したサイト

そんなこんなでSTUDIOで公開した雑なサイトがこちらです。

orange262703.studio.site

Figma To STUDIOの感想

ここからは、Figma To STUDIOを使った感想をまとめていきたいと思います。

フレームやレイヤー単位でコピペができるので、サクサク作業が進んでいきます。

STUDIOに移行するのを想定してFigmaのフレームを作成すれば、ものの数分でSTUDIOに移し替えられると思いました。

PC、スマホ、ミニの3つの画面サイズに対応しているので、FigmaでPCとスマホのデザインを作成しておけば問題なく使えそうです。

しかし、STUDIO側で調整が必要だなというところもありました。

まず、画像のコピーが難しい点。

フレームを細かく分割しても、中に画像があった場合はコピーが難しいようです。(コピー中でずっと止まっている。。。)

画像はFigmaで書き出しをして、別途インポートする必要があります。

そのほかにも、微調整が必要なポイントがありました。

まずは、横幅の指定。

Figmaで横幅をpx指定しても、STUDIOでは100%に変換されてしまうパターンがありました。

おそらくFrameがdivタグに変換されるのですが、この時横幅が100%になってしまうようです。

これのよくない点は、Figma上で横幅を1280pxにしていた場合、それよりも大きい画面でデザイン崩れが起きてしまうことが考えられます。

今回は、max-widthを1280pxにしたかったため、別途、横幅を修正しました。

一方、テキストに関してはpxがそのまま引き継がれます。

それにより画面サイズによってはおかしな位置で改行されるため、横幅をpxからautoに修正しました。

続いて、配置の調整です。

Figma To STUDIOの問題というよりは、Builder.ioの問題ですが、

テキストやボタンの位置を絶対値(座標)で指定しています。

パッと見は中央揃えになっていても、STUDIO側ではなっておらず、画面サイズが変わるとデザイン崩れが起きてしまいました。

これと同じ事例で、マージンやパディングで位置が調整されているものもあるため、

STUDIO側で配置やマージン、パディングの値を修正する必要があります。

以上が、Figma To STUDIOを使ってみた感想でした。

正直、微調整レベルの内容なので許容範囲かもしれません。

とはいえ、その微調整の時間を含めてもおおよそ1、2時間で終わるくらい、簡単に移行が行えました。

FigmaのデザインをSTUDIOで公開したいというパターンだったら使わない手はないかなと思いました。

まとめ

今回は、Figmaの生成AIプラグインを使い、Webデザインを生成し、それをSTUDIOに公開するまでやってみました。

生成AIやプロンプト初心者なので、微妙な部分はありましたが、プロンプトの指定を極めればかなりいいものができるレベル感でした。

Figmaでは他にも多くの生成AIを搭載したプラグインがあるため、簡単なWebデザインなら非デザイナーでも作れる時代になったなと思いました。

また、最近社内でよくSTUDIOを使うことがあり、Figma To STUDIOは制作期間短縮につながるいいプラグインだなと思いました。

最後まで読んでくださりありがとうございました。

UnityでOpenPose風のアバタースケルトンを表示するライブラリを作ってみた

はじめに

エンジニアの松原です。前回こちらの記事で扱った、UnityでOpenPose風のアバタースケルトンを表示する仕組みを、Unityのライブラリとして開発、公開しました。この記事に実際の使い方を書きました。

synamon.hatenablog.com

今回の記事で使用しているライブラリ本体は以下のGitHubに公開しています。

github.com

英語の写植になりますが、Youtubeでも使い方の方法を公開しています。

www.youtube.com

今回説明用のアバターにユニティちゃん 3Dモデルデータを利用しました。

unity-chan.com

必要環境・必要条件

  • Unity 2021.3以降
  • URP
  • アバターのRigがHumanoidであること (※Humanoid経由でボーンを参照しているため、他のタイプだと正常に動作しません)

インストール方法

このライブラリはPackageManager経由でインストールできるようにしています。下記URLをPackageManager経由でインストールします。

https://github.com/blkcatman/LikeOpenPoseAvatar.git?path=/Packages/jp.blkcatman.like-openpose-avatar

描画用カメラのセットアップ

まずはスケルトン描画用のカメラのセットアップを行います。Unityのメニューバーから以下のメニューを選んでウィンドウを開きます。

[Window] > [LikeOpenPose] > [CameraSetup]

Target Camera の箇所にMain Camera(またはCamera Componentを持つ)のGameObjectをドラッグ&ドロップします。

出力先のディスプレイを選択します。

Create を選択します。

Hierarchyにスケルトン描画用のカメラと必要コンポーネントが追加されます。これで基本的なカメラのセットアップは終わりです。

アバターからスケルトンを生成する

対象のアバターからスケルトンを表示するためのコンポーネントを生成します。Unityのメニューバーから以下のメニューを選んでウィンドウを開きます。

[Window] > [LikeOpenPose] > [AvatarGenerator]

Animator の箇所にスケルトンを表示したいアバターの、Animatorをを持っているGameObjectをドラッグ&ドロップします。

Generate を選択します。

Hierarchyにアバター毎のスケルトン描画を行うGameObjectが追加されます。この後キーポイントの調整が必要になるため、次の手順を行います。

アバターの各キーポイントの位置を調整する

一部アバターでは以下の図のように、初回セットアップ時に目の位置のキーポイントがズレることがあります。これは Humanoid のボーン構造が参照できなかった際に起こりやすいです。

だいたい毎回調整が必要になるのは鼻(Noze)、右目(RightEye)、左目(LeftEye)、右耳(RightEar)、左耳(LeftEar)あたりのキーポイントになるかと思います。

Editor上から手動で位置調整を行います。

ギズモのサイズが大きすぎてキーポイントの位置調整が難しい場合、LikeOpenPoseAvatarのGameObjectにギズモサイズを変更するパラメータがあるので変更してみてください。

[:400]

描画用のGame Viewを表示する

デフォルト設定では、アバターのスケルトン描画用のディスプレイはDisplay 2になっているので、確認用のGameViewを追加します。Game ViewはSceceかGameタブを右クリックして追加します。

[Add Tab] > [Game]

表示するディスプレイを変更します。

Gameのタブを並べたものが以下のようになります。

他、細かいトピック

LikeOpenPoseGraph コンポーネントについて

追加したカメラのGameObjectの中にあるLikeOpenPoseGraphのコンポーネントにアバター表示周りの詳細設定が含まれています。

  • Target Avatars : 表示する対象アバターのスケルトンを設定する
    • ※ここにLikeOpenPoseAvatarコンポーネントが追加されていない場合、対象アバターのスケルトンが表示されないので注意が必要です。
  • KeyPoint Thickness : GameView上に表示する各キーポイントの大きさ
  • Joint Tickness : GameView上に表示する各ジョイントの大きさ

終わりに

前回こちらの記事時点でライブラリの根本の部分はできていたのですが、使い勝手などをよくするためのスクリプトの追加に時間がかかりました。他にもYoutubeで使い方の説明動画も作っていたので、前回から結構間が空いてしまいました。

ただ、今後のアップデートのための下準備ができたので、次の対応はあまり時間がかからずに済みそうです。

Unityの-nographicsオプションの影響について

Unity Editorは、コマンドラインで実行することが可能です。

docs.unity3d.com

コマンドライン引数に与えるオプションによって、プロジェクトの作成、ライセンス認証(オンライン認証及びオフライン認証)、テストやビルド、C#スクリプトの実行まで、実に様々な動作が出来るようになっています。

その中に、グラフィック機能を持たない環境で動作する為の-nographicsオプションが存在します。

私はCIを触る事がよくあるのですが、CI用に用意されているマシンはグラフィック性能が抑えられている事がよくある為、このオプションをたまに使っているのですが、とある作業で、GPUが使えない環境での処理に失敗することがあった為、原因の調査を行いました。

結局のところ、そこで起きていた問題は-nographics起因の問題ではなかったのですが、せっかくなので纏めておきます。

続きを読む

Rust/DioxusでWebフロントエンド入門してみる

こんにちは、エンジニアの渡辺(@mochi_neko_7)です。

先週の記事

synamon.hatenablog.com

では Rust の Web バックエンドのフレームワークを紹介してもらいました。

本記事ではそれに続く形で、Rust で使用できる Web フロントエンドのフレームワークで、React 風の API が使用できる Dioxus に入門してみたいと思います。

  • Rust v1.75.0
  • Dioxus v0.4.3

Dioxus Hello, world

Dioxus は Rust 向けの GUI ライブラリで、主な特徴は下記になります。

  • Web / Desktop / Mobile / Terminal のクロスプラットフォーム対応
  • React 風の宣言的な記述で UI を構築できる
  • 非同期処理をサポートしている
  • Hot Reload の機能がある

dioxuslabs.com

現在は v0.x 系でベータバージョンな点にご注意ください。

Web 向けには3種類の実装が提供されています。

  1. dioxus-web : クライアント側で WASM(WebAssembly)でレンダリングする
  2. dioxus-liveview : サーバー側でレンダリングした結果を WebSocket でクライアント側に送信して表示する
  3. dioxus-fullstack : 最初はサーバー側でレンダリングして、それ以降はクライアント側で更新する

dioxuslabs.com

今回は一番シンプルそうな dioxus-web を選んで触ってみます。

公式のインストール手順に従ってセットアップをします。

1. ツールのセットアップ

開発時のローカルサーバーを立てたりするために使用する CLI ツールをインストールします。

$ cargo install dioxus-cli

dioxus-web では WASM でビルドをするため、rustup に WASM のターゲットを追加します。

$ rustup target add wasm32-unknown-unknown

もしくは rust-toolchain.toml を作成して、toolchain.target を下記のように指定する形でも構いません。

[toolchain]
targets = ["wasm32-unknown-unknown"]

2. プロジェクトのセットアップ

cargo で作成したプロジェクトに、dioxusdioxus-web の2つの crate の依存関係を追加します。

$ cargo add dioxus
$ cargo add dioxus-web

3. Hello, world

src/main.rs にアプリケーションを起動するコードを書きます。

use dioxus::prelude::*;

fn main() {
    dioxus_web::launch(app);
}

fn app(cx: Scope) -> Element {
    render! {
        div {
            "Hello, world!"
        }
    }
}

dioxus-cli の下記のコマンドでビルドと起動を行い、http://127.0.0.1:8080 をブラウザで開いて「Hello, world!」が表示されたら成功です。

$ dx serve

ちなみに Hot Reload を使いたい場合は代わりに下記コマンドで起動します。

$ dx serve --hot-reload

Dioxus 入門

基本的な解説は公式の Guide

dioxuslabs.com

を参照していただくとして、ここではいくつかの取っ掛かりのポイントに絞って紹介します。

  1. Rendering
  2. Hooks
  3. Async
  4. Routing
  5. Design

1. Rendering

Hello world でも書いているように、Dioxus のレンダリングは render! マクロ*1を使用して記述をします。

dioxuslabs.com

HTML タグ風の記述もできます。

use dioxus::prelude::*;

fn app(cx: Scope) -> Element {
    render! {
        h1 { "Title" }

        div {
            "Hello, world!"
        }

         br {}    
    }
}

app 関数自身もそうですが、別で #[component] マクロを使って Component に切り出してレンダリングの要素を定義をすることもできます。

dioxuslabs.com

2. Hooks

Dioxus には React の Hooks 風の状態管理の仕組みが実装されています。

  • use_state
  • use_ref
  • use_future
  • use_coroutine
  • use_callback
  • etc...

dioxuslabs.com

docs.rs

名前も基本的には似ていますし、Rules of hooks も同様に存在します。

dioxuslabs.com

use_state を使ったシンプルな例が下記です。

use dioxus::prelude::*;

fn app(cx: Scope) -> Element {
    let mut count = use_state(cx, || 0);

    render! {
        h1 { "Counter: {count}" }

        button {
            onclick: move |_| {
                count += 1
            },
            "+"
        }

        button {
            onclick: move |_| {
                count -= 1
            },
            "-"
        }
    }
}

3. Async

Dioxus の Components の API は同期処理で書かれていますが、非同期処理を利用したい場合には下記を使用します。

  1. use_future : データの Fetch 系の処理など
  2. use_coroutine : 無限ループ系のタスク処理など
  3. cx.spawn() : 単発の非同期処理の実行など

それぞれ振る舞いが異なりますので場面に応じて使い分けます。

ちなみに tokiort-multi-thread は WASM をサポートしていないため使用できず、Mutex<T> などを使用したい場合は async-std などを使用することになります。

Rust で非同期処理中で共有するオブジェクトを実装する際にお馴染みの Arc<Mutex<T>> パターンを使用するときにはご注意ください。

doc.rust-jp.rs

4. Routing

Routing の機能は dioxus-router という dioxus 本体とは別の crate で提供されています。

dioxuslabs.com

dioxuslabs.com

リファレンスの

// All of our routes will be a variant of this Route enum
enum Route {
    // if the current location is "/home", render the Home component
    #[route("/home")]
    Home {},
    // if the current location is "/blog", render the Blog component
    #[route("/blog")]
    Blog {},
}

のように、enum で Route を定義して、それぞれの Component (例だと HomeBlog)を定義してレンダリングを切り替えます。

#[component]
fn Home(cx: Scope) -> Element {
    render! {
        h1 { "Welcome to the Dioxus Blog!" }
    }
}

main.rsapp 関数の render! { } マクロ内で Router::<Route> {} のように呼び出して利用します。

Route を明示的に切り替える方法には二種類あります。

  1. dioxus_router::components::Link を使ってリンクを埋め込む
  2. use dioxus_router::hooks::use_navigator を使って取得した navigatornavigator.push(Route::XXX {}) のように明示的に遷移する

上記の「sign up」「reset password」は Link で、「BACK TO HOME」 は Navigator で画面遷移を実装しています。

5. Design

公式では Tailwind をサポートしています。

dioxuslabs.com

OSS で Material UI を Dioxus 向けに実装しているものも利用できます。

github.com

Dioxus × WASM のハマりどころ

dioxus-web を触っていると WASM 由来と思しきハマりポイントが見えてきましたのでいくつか紹介します。

  1. 環境変数や I/O に制限がある
  2. style.css の読み込みがうまく動かない

1. 環境変数や I/O に制限がある

WASM はサンドボックス環境で動作するため、デフォルトでは環境変数や OS の I/O は使用できず、通常は WASI を通して限定的に許可したものにアクセスし利用します。

dioxus-web ではその辺りをどう扱うのかドキュメントに記載がなく、デフォルトでは環境変数もファイル I/O も使用できませんでした。

dioxuslabs.com

上記のドキュメントを見ながら asset_dir を設定してもファイルはコピーされてもブラウザ側の Resources では確認できず。

環境変数は直接アプリに埋め込んでも問題ないなら .env などから build.rs でソースコードを自動生成して利用するという力業もありますが...

2. style.css の読み込みがうまく動かない

自分のプロジェクトではリファレンスのプロジェクトと同様に style.css を配置したり、Dioxus.tomlweb.resources.style で設定してみても反映されませんでした。

こちらも力業ですが

render! {
    style {
        dangerous_inner_html: r#"body { ... } "
    }
}

のようにソースコードに文字列として埋め込んだ CSS を直接指定するという方法ではうまく動きました。

Dioxus × Rust のハマりどころ

同様に Rust との兼ね合いでハマりやすいポイントも紹介します。

  1. 借用やライフタイムよるコンパイルエラーが出やすい
  2. 実行時 panic が発生する場合がある
  3. マクロが多いので馴れないとソースコードが読みづらい

1. 借用やライフタイムよるコンパイルエラーが出やすい

Context (cx: Scope)や UseState などの Hooks、非同期処理関連などで借用やライフタイム関係で意図せずコンパイルエラーを出してしまう、rust-analyzer を使いながらでも慣れないと修正に時間がかかるということが起こりがちでした。

この手のコンパイルエラーはエラーメッセージを見ても解決方法が分かりづらいですが、Hooks のインスタンスは適度に .clone() を挟むと解決できる場合があります。

これは Rust の仕様上避けられない部分なので仕方ありませんが、Rust に慣れていない方だとハマる可能性は高いので注意が必要です。

2. 実行時 panic が発生する場合がある

Hooks の制約 の違反はコンパイルエラーにはならないため、実行時に panic を出すケースがあります。

また、UseSharedState も write の操作を同時に行うと panic を出しますので、Arc<Mutex<T>> パターンを使用するなどの工夫をした方が良いです。

doc.rust-jp.rs

Result ベースの API にはなっていないこともありエラーハンドリング自体も少し複雑になりやすい印象です。

dioxuslabs.com

仕様の問題ではあるものの、Rust の「コンパイルが通れば基本的に動く」性質を弱めてしまいデバッグのコストが少し高いのが少しもったいないポイントです。

3. マクロが多いので馴れないとソースコードが読みづらい

render!#[component] などマクロがコアな API になっていることもあり、ぱっと見で挙動が分かりづらかったり、エディターの補完が効きづらかったりして少し扱いが難しい印象を受けました。

ただしこれは React 風の宣言的 UI の実装のための副作用のようなものなので一定仕方がないかとは思います。

ひょっとしたらより Rust フレンドリーな実装方法も別であるのかもしれません。

Rust × Web フロントエンドの良いところ

これまでデメリットの側面ばかり挙げていますが、もちろん良い側面も多いです。

  • cargo、rustfmt、clippy をはじめとした周辺ツールが充実していて使いやすい
  • Rust の強い型制約や trait/enum/Option/Result/macro などの柔軟な表現を Web フロントエンドでも活かせる
  • バイナリサイズやメモリ使用量を抑えやすい

私に本家 React の知見がないためちゃんとした比較はできませんが、やはり Rust の恩恵を受けつつ快適な環境で開発ができるメリットは大きいと感じます。

まとめ

  1. Dioxus の導入や使用するにあたってのコアな機能を簡単に紹介しました
  2. dioxus-web を使用する際にハマりやすいポイントをいくつか紹介しました
  3. Rust × Web フロントエンドの良い側面にも少し触れました

全体の所感としては実戦投入するには WASM 周辺の事情をちゃんと把握しないと難しそうかなという印象です。

Rust もしくは React に慣れている方がもう一方の技術の勉強がでら試しに触ってみる分には面白いのではないかと思います。

サンプル

今回紹介した内容を勉強する目的で作成した Dioxus 上で Firebase Auth を触る Repository を公開しています。

github.com

Rust / Dioxus の dioxus-web をベースに、Firebase Auth の API を利用したログインフローと Material UI によるデザインの実装をしています。

Web Frontend 初心者で拙い部分も多いことを前提に参考にしていただければと思います。

おわりに

個人的にはついでに React の勉強にもなったのは良かったですし、Rust で Web フロントエンドが書けるのは楽しかったのですが、 慣れが必要な点も多く初心者のハードルは少し高めかなと思いました。

Dioxus は公式のドキュメントも充実しているので情報は探しやすいですが、逆にドキュメントに書かれていない落とし穴もありましたので補足しました。

Rust × Web フロントエンドはまだまだ未成熟な分野ではありますが、Rust ユーザーが増えてエコシステムが発達していくとより快適になっていくことを期待したいです。

*1:render! {...} と csx.render( rsx!(...) ) はほぼ同じのようです。

(2024年1月時点)RustのWebフレームワークの簡単な比較

はじめに

こんにちは、エンジニアのクロ(@kro96_xr)です。

エンジニアと言いながら最近コードを書く機会が減っていたので、年末年始にRustにチャレンジしていました。
まだ全然理解しきれていないという自覚はありつつ、今回はRustの主要なWebフレームワークについて簡単に調査、比較していきたいと思います。 間違いなどありましたらDM等でご指摘いただけると幸いです。

なお、情報は全て調査時点(2024/1/8)のものとなります。

Frameworkの候補

フレームワークの比較をしてくれているリポジトリがあるので、この情報を元にピックアップしてみます。

github.com

人気のフレームワーク

名称 Repos Docs スター数 最新バージョン Activity
actix-web Repo Doc 19.4k 4.4.1 181/year
axum Repo Doc 14.3k 0.7.3 307/year
Rocket Repo Doc 22.5k 0.5.0 176/year

Githubのスター数も多く、調査中によく名前を見かけました。
ただ、actix-web以外はバージョン1.0.0以下であることを考えるとプロダクトに使用するのは躊躇われるかもしれません。

中堅フレームワーク

名称 Repos Docs スター数 最新バージョン Activity
warp Repo Doc 8.8k 0.3.6 27/year
poem Repo Doc 3k 2.0.0 154/year
salvo Repo Doc 2.5k 0.63.1 660/year

先程の3つほどスター数は多くないですが、それぞれ独自の特徴や強みからスター数を伸ばしています。
warpは最新のリリースが2023/9/27でActivityも少ないのが気になりますね。一方でsalvoはActivityだけの判断になりますが勢いが凄いなという印象です。

これから期待のフレームワーク

名称 Repos Docs スター数 最新バージョン Activity
pavex Repo Doc 1.2k 0.1.0 -

Pavexは先ほどのリポジトリの表には載っていませんが、他のフレームワークとは異なるアプローチをしているとのことでこれからに期待です。
以下のような日本語記事もありますので参考にしてみてください。今回の記事では詳細については触れません。

Pavex – Rust API構築のための新しいWebフレームワーク | DevelopersIO

GithubリポジトリのStar数の推移

続いて、以下のサイトからStar数の推移を見てみます。

GitHub Star History

歴史としてはRocketがいちばん長く、次に出てきたactix-webとともに継続して人気なようです。
warpはこの中では3番目に古いですが、後続のaxumに抜かれています。
axumがこの勢いで伸びていくとactix-webやRocketに追いつくことになりそうですね。

各フレームワークの特徴とコードサンプル

続いて各フレームワークの特徴を簡単にまとめつつ、HTTPサーバを立ち上げて"Hello, world!"を返すエンドポイントを実装する簡単なサンプルコードを記載します。
エラーハンドリング等未考慮なのであくまで参考程度にご覧ください。

actix-web

axumやRocketと違いメジャーバージョンになっており、安定性を担保していると言えます。 技術的には、Tokioを基盤にしつつも独自の抽象化とクレートを持つことで結合を弱めているとのことです。 書き心地に関しては、HelloWorldレベルでは他のフレームワークと大きな差は感じられませんでした。 歴史も長く様々なクレートやドキュメント、サンプルがあり、第一の選択肢となりそうです。

use actix_web::{get, App, HttpResponse, HttpServer, Responder};
use serde_json::json;

#[actix_web::main]
pub async fn main() -> std::io::Result<()> {
    println!("launching server...");
    http_start("0.0.0.0", 8080).await
}

async fn http_start(addr: &str, port: u16) -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(hello)
    })
    .bind((addr, port))?
    .run()
    .await
}

#[get("/hello")]
async fn hello() -> impl Responder {
    HttpResponse::Ok().json(json!({"message": "Hello, world!"}))
}

axum

axumは前述の通り、近年伸びているフレームワークです。 特徴としては、Tokioプロジェクトの一部としてエコシステムに組み込まれていることがあります。 また、他のフレームワークではマクロが出てくるのに対し、axumはマクロを使用せずに実装することができ、初学者でも理解しやすいと思いました。

現時点でバージョン1未満ということで破壊的変更などがあるかもしれないのが少々不安ですが、今後も継続して伸びていくと思われます。

use axum::{routing::get, Router, response::{IntoResponse, Json}, http::StatusCode};
use tokio::net::TcpListener;
use serde_json::json;

#[tokio::main]
async fn main() {
    let app = router();

    let listener = listener("0.0.0.0", 8081);
    axum::serve(listener.await, app).await.unwrap();
}

fn router() -> Router {
    Router::new().
        route("/hello", get(hello))
}

async fn listener(addr: &str, port: u16) -> TcpListener {
    let addr_port = format!("{}:{}", addr, port);
    TcpListener::bind(addr_port).await.unwrap()
}

async fn hello() -> impl IntoResponse {
    (StatusCode::OK, Json(json!({"message": "Hello, world!"})))
}

Rocket

Rocketは前述の通り古くから存在するフレームワークですが、近年ではactix-webやaxumに遅れを取っているようです。思想として「全てを含む」ことがあるようで必要な機能を全てRocketの管理下においています。 結果として、リリースサイクルが他フレームワークと比較して遅くなることがあるようで、そのあたりが遅れをとっている要因かもしれません。実際にバージョン0.5の開発に2年以上かかっていたようです。

一方で必要な機能が一通りRocket側で用意されているので手軽にWebアプリケーションを開発したい場合にはいいかもしれません。以下のサンプルコードでもrocketのみに依存しています。

use rocket::*;
use rocket::serde::{Serialize, json::Json};
use rocket::http::Status;

#[derive(Serialize)]
struct Message {
    message: String,
}

#[rocket::main]
async fn main() {
    println!("launching server...");
    let config = configure("0.0.0.0", 8082);
    rocket::build()
        .configure(config)
        .mount("/", routes![hello])
        .launch()
        .await
        .unwrap();
}


fn configure(addr: &str, port: u16) -> rocket::Config {
    rocket::Config {
        address: addr.parse().unwrap(),
        port: port,
        ..rocket::Config::default()
    }
}

#[get("/hello")]
fn hello() -> (Status, Json<Message>) {
    let data = Message {
        message: "Rocket: Hello, world!".to_string(),
    };
    (Status::Ok, Json(data))
}

warp

warpに関しては他のフレームワークと書き心地が全く違いました。「フィルター」を用いてリクエストを処理するアプローチで、そのコンセプトを理解して実装する必要があります。

The main concept in warp is the Filter, which allows composition to describe various endpoints in your web service. Besides this powerful trait, warp comes with several built in filters, which can be combined for your specific needs.

個人的にはHelloWorldを実装する時点で一番混乱したフレームワークです。関数型のアプローチは面白いと思うのですが、自分が不慣れなこともあり正直理解しきれていません。前述の通り直近のActivityも少なく今後が少し心配です。

use std::convert::Infallible;
use warp::{Filter, Reply};
use serde::Serialize;

#[derive(Serialize)]
struct Message {
    message: String,
}


async fn hello() -> Result<impl warp::Reply, Infallible> {
    let message = "warp: Hello, world!".to_string();
    Ok(warp::reply::json(&message))
}

fn routes() -> impl Filter<Extract = impl Reply, Error = warp::Rejection> + Clone {
    warp::path!("hello")
        .and(warp::get())
        .and_then(hello)
}

#[tokio::main]
async fn main() {
    println!("launching server...");
    let routes = routes();
    warp::serve(routes)
        .run(([0, 0, 0, 0], 8085))
        .await;
}

poem

書き心地自体は他のフレームワークと大差ないと感じましたが、poemエコシステム内でgRPCやLambda、OpenAPIに対応したクレートを実装しており、Web開発のニーズを満たそうという意識を感じました。 同時期に出たaxumにスター数でも差が開けられていたり日本語記事が全然見つからなかったりと存在感はまだまだかもしれませんが、このまま開発が続いていけば非常に面白そうです。

poem/poem-openapi/README.md at master · poem-web/poem · GitHub

use poem::{get, handler, listener::TcpListener, web::Path, web::Json, IntoResponse, Route, Server};
use serde::Serialize;

#[derive(Serialize)]
struct Message {
    message: String,
}

#[handler]
fn hello() -> Json<Message> {
    Json(Message {
        message: "poem: Hello, world!".to_string(),
    })
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    let app = Route::new().at("/hello", get(hello));
    Server::new(TcpListener::bind("0.0.0.0:8084"))
        .run(app)
        .await
}

salvo

salvoはシンプルながらパワフルな特徴を持つと謳っており、実際にベンチマークでは上位につけています。

TechEmpower Framework Benchmarks

HelloWorldでの比較なので他のフレームワークと比べてどれほどシンプルかしづらいく、機能を持たせたWebアプリケーションで比較してみたいですね。別の機会があれば踏み込んでみたいと思います。

use salvo::prelude::*;
use serde::Serialize;

#[derive(Serialize)]
struct Message {
    message: String,
}

#[tokio::main]
async fn main() {
    println!("launching server...");
    tracing_subscriber::fmt().init();

    let router = Router::new()
        .push(Router::new().path("hello").get(hello));
    let acceptor = TcpListener::new("0.0.0.0:8083").bind().await;
    Server::new(acceptor).serve(router).await;
}

#[handler]
async fn hello(res: &mut Response) {
    let data = Message {
        message: "Salvo: Hello, world!".to_string(),
    };
    res.render(Json(data));
}

おわりに

以上、簡単にではありますがRustのWebフレームワークについて調査、比較してきました。何かの参考になれば幸いです。 Rustはライブラリの整備状況などまだ不十分な部分もありますが、トレンドとして注目されてきており(遅いですが)私自身継続してRustについて学んでいきたいと思います。

参考

Rust で Web バックエンド開発をはじめる | CyberAgent Developers Blog

Best Rust Web Frameworks to Use in 2023

GitHub - flosse/rust-web-framework-comparison: A comparison of some web frameworks and libs written in Rust

Pavex – Rust API構築のための新しいWebフレームワーク | DevelopersIO

async対応版Rocket、v0.5を試してみる - paild tech blog

RustでWebアプリケーションを作る - CADDi Tech Blog

Bunで構築したNext.jsをVercelに一瞬でデプロイしてみた

はじめに

こんにちは、フロントエンドエンジニアの堀江(@nandemo_3_)です。

先日、JavaScriptランタイム最新動向という記事を書いたのですが、

synamon.hatenablog.com

Bunが非常に興味深く、TypeScript、Next.jsに標準対応しているということで、Vercelにデプロイできるか調べてみたところ、Bunをサポートしたというアップデート記事が見つかりました。

vercel.com

記事を見る限り、bun.lockbファイルをプロジェクトに入れて、VercelのInstall Commandにbun installを設定するだけで良さそうです。

早速、試していこうと思います。

プロジェクト作成

まず、BunでNext.jsプロジェクトを作成します。

bun create next-appでプロジェクトを作成し、bun --bun run devで開発用サーバを立ち上げます。

bunx create-next-appでもできます)

$ bun create next-app
✔ What is your project named? … bun-nextjs
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
$ cd bun-nextjs
$ bun --bun run dev

サーバを立ち上げると、以下のようなログが出力されるので、http://localhost:3000にアクセスします。

$ next dev
   ▲ Next.js 14.0.4
   - Local:        http://localhost:3000

 ✓ Ready in NaNms
 ○ Compiling / ...
 ✓ Compiled / in 1502ms (480 modules)
 ✓ Compiled /favicon.ico in 475ms (285 modules)

Next.jsのデフォルトページが表示されます。

Vercelにデプロイ

Vercelにデプロイするために、作成したプロジェクトをGitHubのリポジトリと紐付けます。

そして、Vercelにてプロジェクトを新規作成すると、

以下のように作成したGitHubのリポジトリが表示されるので、「Import」を選択します。

続いて、「Configure Project」にて、「Build and Output Settings」を開きます。

「Install Command」の「OVERRIDE」をONにして、bun installを入力します。

Vercelの設定は以上です! めちゃめちゃ簡単です。

ちなみに「Build Command」にbun run buildを設定しないとエラーになりそうですが、不要でした。

(設定しても問題なくデプロイできました)

最後に、「Deploy」ボタンを入力するとデプロイが完了します。

デプロイ時間

ちなみに、デプロイ時間をNode.jsとBunで比較してみたいと思います。

デフォルトページ

コードはデフォルトページのままでデプロイしました。

Node.jsの場合

Bunの場合

Bunのデプロイ時間が31秒の時もあったので、おおよそ10秒ほどの時間差がありますね。

若干ですがBunの方が早くデプロイできました。

もう1パターン

もう少し大きなプロジェクトでも試してみます。

以前、ヘッドレスCMS「microCMS」を試した際のフロントエンドを使いました。

github.com

Node.jsの場合

Bunの場合

これも若干ですがBunの方が早くデプロイできました。

もう少し早くデプロイできるかなと期待しましたが、そこまで大きな差はないという結果になりました。(もっと巨大なプロジェクトだと差が顕著になるかもしれません)

ちなみに、Node.jsのプロジェクトをBunに切り替えるのは、node_modulesとlockファイルを削除したのちに、bun installをするだけで完了します。

ビルドに失敗する可能性もあるので、ローカルでビルドするのをお勧めします。

最後に

今回は、Bunで構築したNext.jsプロジェクトをVercelにデプロイしてみました。

Vercelのプロジェクト設定を1箇所変更するだけで、Bunのプロジェクトが一瞬でデプロイできてました。

もう少し設定が必要なのかなと思っていたので、驚きました。

また、VercelがBunをサポートしているのにも驚きましたし、

Next.jsもドキュメントでBunでのcreate-next-appのコマンドを記載していることから

Bunの利用範囲が広がっていることを感じました。

今回は、かなり簡単な内容でしたが、引き続きフロントエンド関連の記事を作成していこうと思います。

最後まで、読んでくださりありがとうございました。

UnityでOpenPose風のアバタースケルトンを表示する仕組みを作ってみた

はじめに

エンジニアの松原です。近年生成系AI、特にStableDiffusionの仕組みをベースとした生成系AIが目まぐるしい速度で進化しており、2023年の年間を通しても取り沙汰されない日のほうが少ないのでは、と思えるぐらい連日SNSでのニュースで見かけていました。
私自身も長いことAIのニュースを追いかけていなかったので、改めて追っていったところ、StableDiffusionの拡張機能として利用できる ControlNet の仕組みが面白く、2023年の夏ぐらいから調べていました。
今回は ControlNet でポーズの指示を扱うためのスケルトン情報(または Keypoints )を生成できるよう、Unity上でOpenPose風のアバターを表示するスクリプトを作ったことについて取り上げたいと思います。

本記事に入る前に

今回の記事は「生成系AIを使ってみた」、という内容ではなく、その前段階として、プロンプト指示に利用できるデータをUnityから生成できるようにするというのが記事の内容になります。
本記事に含まれる用語が分かっていると本記事の目的が分かりやすいので、超ざっくりですが以下に取り上げました。

ControlNetについて

StableDiffusion自体の基本的な解説に関しては、Qiitaでわかりやすくまとめてくださっている記事がありますので、そちらをご参考ください。

qiita.com

また、StableDiffusionの基本的な機能として、テキストを使ったプロンプト指示によって任意の生成画像を得られる仕組みが主な機能になっていますが、ControlNetを利用することにより、テキスト以外の情報をプロンプト指示に追加できるようになります。
ControlNetで利用できるバリエーションはいくつかありますが、今回はOpenPoseに着目しました。

github.com

OpenPoseについて

OpenPoseは人物を含む画像から抽象化されたボーン構造ベースの人体モデルを推定し、その人体モデルに含まれる各関節の情報を画像中の特徴点として書き出せるシステムです。この特徴点は三次元座標としても取り出せるため、他の目的にも利用できる技術になっています。

github.com

本記事の目的

今回はStableDiffusionの拡張機能であるControlNetを使ったプロンプト指示向けに、Unity上で表示するアバターに対してOpenPoseのボーン構造(18特徴点)を表示するスクリプトを作ってみました。
このスクリプトは近いうちに公開予定ですが、使い勝手を良くするために現在スクリプトの内容を整理しています。公開可能になったタイミングで記事に差し込みたいと思います。モデルはユニティちゃん 3Dモデルデータをお借りしております。

unity-chan.com

OpenPose風のアバタースケルトンを表示する仕組みの解説

以下今回作ったスクリプトについて解説していきます。

ボーン構造の対応付け

Unityには、モデリングソフトで作成したアバターに含まれるボーン構造を、Unity側のアバターシステムと紐づけを行う機能として、Humanoid というシステムがあります。この仕組みを応用して、OpenPoseのボーン構造に近い状態にマッピングします。
首から下ぐらいまでボーン構造が一致する箇所が多くあるため、Humanoidの関節情報をベースに親となるTransformを割り出しています。対応関係は以下のようになります。


上記画像はOpenPose公式から

index OpenPoseキーポイント名 Humanoidボーン名
0 Nose HumanBodyBones.Head
1 Neck HumanBodyBones.Neck
2 Right Shoulder HumanBodyBones.RightUpperArm
3 Right Elbow HumanBodyBones.RightLowerArm
4 Right Wrist HumanBodyBones.RightHand
5 Left Shoulder HumanBodyBones.LeftUpperArm
6 Left Elbow HumanBodyBones.LeftLowerArm
7 Left Wrist HumanBodyBones.LeftHand
8 Right Hip HumanBodyBones.RightUpperLeg
9 Right Knee HumanBodyBones.RightLowerLeg
10 Right Ankle HumanBodyBones.RightFoot
11 Left Hip HumanBodyBones.LeftUpperLeg
12 Left Knee HumanBodyBones.LeftLowerLeg
13 Left Ankle HumanBodyBones.LeftFoot
14 Right Eye HumanBodyBones.RightEye
15 Left Eye HumanBodyBones.LeftEye
16 Right Ear HumanBodyBones.RightEye
17 Left Ear HumanBodyBones.LeftEye

Unityの HumanBodyBones はこちらで定義されています。

docs.unity3d.com

耳のTransformはUnity側のHumanoidにはないため、大まかな位置を仮決めします。また、モデルによっては目のTransform(RightEye、LeftEye)が無いケースがあり、その場合は頭のTransform(Head)から大まかな位置を割り当てます。

スクリーンへのボーン構造を投影して描画

OpenPoseの特徴点とボーンの線分を一種のアバターとして描画する方法もありますが、その場合はカメラ位置との関係によって特徴点が小さく描画する可能性があります。
特徴点が小さく書かれることを回避するため、特徴点を一度スクリーン(Canvas)上の座標系に変換し、キャンバス上のグラフィックとして特徴点と線分を描画します。

できたもの

終わりに

今回はControlNetで利用すること前提でOpenPose風のアバタースケルトンをUnity上で表示する仕組みを作りました。OpenPose以外にも画像生成系AIで利用するために、Unityから出力できるデータ表現について考えていければと思います。