🐶

UnityYAML Assets を GitHub 上でレビュー可能にする OSS「PrefabLens」を作った

に公開

PrefabLens を Pre-release しました

https://github.com/hashiiiii/PrefabLens

まずは見たほうが早いと思うので、各ツールのデモを置いておきます。

Chrome Extension

Unity Plugin

CLI

Prefab を含む Unity の多くのアセットは UnityYAML (YAML のサブセット) で記述されています。PrefabLens はその差分を、人間が読める形で表示するためのツール群です。名前に Prefab とついていますが、.prefab に限らず UnityYAML アセット全般に対応しています。

また UnityYAML はオブジェクト参照を fileID / guid で持ちます。これを GitHub Trees APIGitHub GraphQL API などで解決したうえで表示できるのも、個人的に推したいポイントです。

Demo もあるので、気軽に触ってみてください。

正式版のリリースはもう少し先です。Fable 5 のフィーバータイム中にゴリっと進めたのもあり、設計のリファクタやパフォーマンスチューニングなどを経てから正式リリースします。残課題のうち影響が大きいものとして GHES 対応があり、現時点では github.com のみ対応です。

動機

.prefab や .unity ファイルのレビューは辛い

GitHub の Files changed タブを開いた瞬間、UnityYAML が目に入ってそっ閉じした経験はないでしょうか。

GitHub 上ではこのフォーマットのまま差分が出るので、レビューコストが非常に高いです。.asset など重要なファイルも同様で、差分を見逃して頭を抱えた経験がある人も多いと思います。

オブジェクト同士の参照はすべて fileIDguid で、愚直に辿ると .meta を読みに行く必要があります。参照先に差分がないことも多く、Files changed タブだけではまともにレビューできません。結果として、だいたい次の手順を踏むことになります。

  • feature branch を fetch する
  • switch (checkout) する
  • Unity Editor を起動する
  • Hierarchy と Inspector を眺める

この手順も面倒なうえ、base branch との diff ではなく HEAD を眺めているだけなので、雰囲気レビューになりがちです。

PrefabLens だと、同じ差分は次のように見えます。

.prefab や .unity はすぐ壊れる

Prefab / Scene の変更をセマンティックに確認する built-in な手段は (多分) なく、GUI 操作ゆえに Component が外れたり、フィールドの true / false を書き換えてしまったりしやすいです。Foo.prefab に対して Foo-old.prefab を用意し、更新後に無駄な変更が入っていないか目 grep する、という原始的な運用もあると思います。

.prefab や .unity はエンジニア以外も触る

プロジェクトによっては Prefab / Scene の制作はデザイナーが行い、エンジニアが後から微修正する、というワークフローも多いです。職種ごとのコンテキスト共有が薄いと、次のような事故が起きやすくなります。

  • 意図してアタッチした Component が外れている
  • RaycastTarget が true / false に変更されている
  • LayoutGroup 周りで何かが起きている

これが職種間の軋轢につながることもあるので、注意が必要です。

考えたこと

そこで次のようなアイデアを模索し始めました。

  • UnityYAML の差分がもう少し人間に優しいものになればよさそう
  • Unity Editor 上で、職種を問わず変更をチェックできるとよさそう
  • こんな時代なので、AI がやばい差分を発見できるとよさそう

作ったもの

上記 3 点に対して作ったのが、それぞれ Chrome Extension / Unity Plugin / CLI です。

diff エンジンは Zig 製の core が 1 つだけで、CLI はネイティブバイナリ、Chrome Extension は WASM、Unity Plugin は CLI を子プロセスとして使っています。どのツールで見ても差分結果が一致するのは、この構成のおかげです。

Chrome Extension

Unity ユーザーにとってやさしい見た目にはこだわっています。差分はできるだけ Hierarchy × Inspector に寄せて、ツリー構造・アタッチされた Component・各フィールドの差分が一目で分かるようにしています。

導入は Chrome Web Store から拡張を入れ、Files changed などから GitHub にサインインするだけです。認証は GitHub の device flow なので、PAT を発行して貼り付ける作業はありません。

Sign in with GitHub を押す。

Continue を押す。

8 桁のコードは自動入力されるので、そのまま Continue を押す。入力されない場合は、Sign in with GitHub を押した元の画面に数字が出ています。

Authorize を押して完了。


エンジニア以外にも使ってもらう前提で、脱落ポイントを減らしたくて device flow を選びました。

diff エンジンは前述のとおり WASM で、処理はすべてブラウザ内で完結します。開発者側のサーバーはなく、通信先は github.com, api.github.com のみ、OAuth アクセストークンは chrome.storage.local に保存するだけです。業務でも使ってもらえるよう、この辺りは配慮しました。

Unity Plugin

Window > PrefabLens を開くと、左に Base ref との間で差分がある UnityYAML アセット一覧、右に選択したアセットのセマンティック diff が表示されます。

一番のこだわりは、Base に任意の ref (branch・tag・commit) を指定できることです。動機で書いた「diff ではなく HEAD を眺めているだけ」という問題に対して、feature branch を開いたまま base branch との差分を Unity 内で確認できます。Foo-old.prefab を複製して目 grep する運用も、これで卒業できます。

導入は OpenUPM (または Package Manager の git URL) で追加して Window を開くだけです。Window にフォーカスが戻ったタイミングで自動リフレッシュするので、Prefab をいじったあとに Window を触ると一覧が最新化されます。参照解決はローカルの AssetDatabase 経由で、Chrome Extension と同様にプロジェクト内パスで表示されます。

コミット前のセルフチェック用途を想定しています。GUI 操作の副作用で意図しない差分が混ざりやすいので、出す前に一度眺めて「Component が外れていないか」「RaycastTarget が変わっていないか」を自分で確認する。レビューで指摘される前に作った本人が気づける状態を作るのが、職種間の軋轢を生まない近道だと思っています。

CLI

Zig 製の単一バイナリで、Homebrew / Scoop / mise からインストールできます。

brew install hashiiiii/tap/prefablens

引数まわりの体験には結構こだわっていて、何も考えずに prefablens[1] と打てば HEAD vs working tree の変更をすべて tree 表示します。ref と path の組み合わせも直感的に書けるようにしてあります。

prefablens                                # HEAD vs working tree (全変更ファイル)
prefablens main                           # main vs working tree
prefablens HEAD~1 HEAD Assets/Foo.prefab  # ref 同士で 1 ファイルだけ
prefablens before.prefab after.prefab     # 2 ファイル比較

出力は人間向けの tree に加えて --json--html を用意しています。AI レビューのパイプラインに載せたり、pre-commit hook や CI で機械的に回したりする用途を想定しています。

prefablens --json main | claude -p "意図しない変更が混ざっていないか確認して"

正直、AI フレンドリーかどうかを定量的には判断できていません。ただ、オブジェクト参照を解決した状態で返せるので、.meta を辿らせたり生の UnityYAML を食わせたりするよりは、無駄なトークン消費を抑えられるはずです。

exit code も 0 (成功) / 1 (実行時エラー) / 2 (usage エラー) の Contract として明文化してあるので、スクリプトから安心して扱えます。

また --open を付けると self-contained な HTML レポートが生成されてブラウザで開きます。

HTML レポートは外部アセット依存のない 1 ファイルなので、CI の artifact にしたりそのまま人に渡したりできます。

まとめ

UnityYAML のレビューが辛い、という課題に対して Chrome Extension / Unity Plugin / CLI の 3 つを作りました。

技術的な話に関しては、また別で記事を書こうと思います。

Pre-release なので荒いところもありますが、Unity アセットのレビューで困っている人がいれば試してもらえると嬉しいです。フィードバックや Issue も歓迎です。

脚注
  1. コマンド名は pls なども候補だったが、各自が alias を書けばいいということで分かりやすさを優先 ↩︎

Discussion