scenario-godot-pipeline-automation について
Godot のツール・ビルドエンジニア向けに、アセット取り込み、テスト、CI、エクスポートを扱うパイプラインスキルです。再現可能なコマンドと検証ゲートで、アセット変更から確認済みのビルド成果物までをつなぎます。
主な機能
- 01GLB の検査とアセット取り込み
- 02インポート設定とテクスチャ処理
- 03アセット監査と gdUnit4 テスト
- 04サムネイル確認とエクスポート検証
- 05CI ワークフロー生成と検査
- 06エディターツールと MCP チャネル
活用シーン
- 01GLB アセット一括取り込みと選別
- 02サイズ、コリジョン、テクスチャの確認
- 03CI でのテストとエクスポート実行
- 04エディタースクリプトによるシーン変更
MCP 対応
プロジェクトのツーリングフォルダーに MCP サーバーを構築し、gp.mcp_stdio 経由で呼び出す方法が記載されています。共有マシンではヘッドレスツールのみを使い、MCP はシーンの検査と編集に用います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-godot-pipeline-automationインストール後、Claude Code で/scenario-godot-pipeline-automationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/gd_pipeline.pyscripts/agentkit/pipeline/glb_probe.gdprop_audit.gdprop_ingest.gdprop_rules.gdprop_textures.gdprop_thumbs.gdscripts/agentkit/prop_pipeline_addon/plugin.cfgplugin.gdprop_post_import.gdscripts/ci/godot_ci.shgodot-ci.ymlscripts/examples/gdext_c/pipeline_ext.cpipeline_ext.gdextensionscripts/examples/level_importer/lvl_import.gdplugin.cfgplugin.gdscripts/examples/tools/add_spawns.gdspawn_point.gdscripts/gdunit/door.gdtest_glb_probe.gdtest_imported_props.gdtest_prop_rules.gdtest_scene_runner.gd詳細
Godot パイプラインの自動化(ツールおよびビルドエンジニア)
対象:Godot 4.7.2.stable、macOS Apple Silicon、gdUnit4 6.2.1。
ここでいうエキスパートレベルとは、人間がクリックするすべての操作を、CIで同じ結果が2回得られるコマンドにし、すべての結果を、失敗するところが確認されたテストで検証することです。ツールエンジニアは、アート素材の追加やコミットからテスト済みのエクスポートに至るまでの工程(取り込み、インポート、エディターツール、テスト、CI、ネイティブ拡張機能、エージェントのチャネル)を担当します。ここに記載されている関連スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で進める場合は、ツールのスキーマに基づいて作業し、不足しているスキルを明記してください。
必須の前提知識: scenario-godot-expert(チャネル、gd_run と gd_env、レビューの反復、4.7での注意点)。このスキルでは scripts/gd_pipeline.py と AgentKit モジュール scripts/agentkit/pipeline/ を追加します。Godot 自体は起動せず、すべての実行は gd_run を経由します。
状況(2026-10-02): 200個のGLBアート素材(実際の画像から3Dへの変換ファイル12個を含む)を対象に、9つのテストファイルにわたる43個の実動チェック、2巡目のチェック(手順15)および8個のオフラインテストがすべて合格しています(references/procedures.md)。未実行:GitHubランナーでのワークフロー、godot-cppとRustのビルド(ここにはsconsもcargoもありません)。
方針(専門家との違い)
- 最初のインポート前にインポート設定を記述します。
[remap] importer="scene"と[params]だけを含む.glb.importサイドカーは、ヘッドレスの--importで有効になり、Godot が uid を追加します[追加、M2で確認済み]。そのため、取り込み時にファイルごとのスケール、ピボット、コリジョン、テクスチャモードを決めてから、一度だけインポートします。後から.importファイルを書き換えると、インポート時間が倍増し、リポジトリが変更状態になります。 - インポーターにはコードパスではなくデータを渡します。
EditorScenePostImportPluginでは、ファイルごとのオプション(pipeline/fit_height、pipeline/unit_scale、pipeline/fix_pivot、pipeline/collision)を宣言できます。これらは各サイドカーに記述され、インポートドックに表示されます。また、プラグインをproject.godotに登録すれば、ヘッドレスの--importでも実行されます[追加、M6、M10で確認済み]。プロジェクト全体で1つのプラグインを使い、pipeline/prop_idのないファイルには手を加えません。 - AIによる画像から3Dへの変換ファイルは、DCCファイルではありません。 ここにある実ファイル12個は「Khronos glTF Blender I/O」と名乗っているため、生成元の判定では見つけられず、マニフェストだけが見つけられます。これらは任意のスケールで作られており(おもちゃのロボットは高さ1.96 m)、マテリアル数は2~35個です。12個中8個は clearcoat、transmission、ior、specular を使用しており、4.7.2では警告なしに削除されます[追加、M8で確認済み]。マニフェストの高さに合わせてフィットさせ、DCCのプロップは単位を修正した後、作成時のサイズを維持します。
- パスではなくバイト列を解析します。 インポートコードについてのDinoleafのルールは、ソースを渡して
parse(bytes: PackedByteArray)を呼び出すことです。こうすれば同じパーサーをres://、user://、zipファイル、リテラルのバイト列を使ったテストに利用できます(sSurjCgebjw [00:04:46])。ここでのGLBプローブもこの方法で動作し、テストではメモリ上にGLBを構築します。 - テストは失敗を確認して初めて有効になります。 GUTの作者であるButch Wesleyの言葉どおり、まず赤、次に緑を確認し、関数本体を壊して既存コードにテストを追加します(ImqhHLlPfZg [00:13:40])。ここにあるすべてのテストスイートには、実行時に終了コード100を返すように仕込まれた失敗があります。
- エクスポートは終了コードではなく、生成物で評価します。 gdUnit4がパックに含まれていた5回中4回、ヘッドレスの
--export-packは「[ DONE ] savezip」の後、終了時にシグナル11でクラッシュしましたが、パックは完成していました[追加、観察結果]。ファイル、そのサイズ、内容を確認し、すべてのプリセットから開発用フォルダーを除外します。 - エージェントにとって、ヘッドレス出力が真実です(Fennara、2vSYP7GyA5U [00:02:51])。出力パネルのスクレイパーはディスク上に存在しない行のエラーを報告し、パネルにはプロジェクトのすべてのエラーが表示されるわけではありません[00:06:20]。どちらを信じる前にも、ヘッドレスで再実行してください。MCP サーバーはシーンの編集やスクリーンショットの取得には使えますが、エラーの真偽は判断できません。同じマシンを共有する場合は、ヘッドレスツールだけを呼び出してください[追加]。
- シグナルを使って動作をテストし、待機時間には上限を設けます。 GodotneersとgdUnit4の作者であるMike Schulzeは、シグナルと公開されている結果を検証し、プライベート状態は検証しません。シグナルが先に発生すると見逃してしまうため、アクションの前に
monitor_signals()を呼び出します(CreugthdgJ0 [00:36:34])。すべての待機にはタイムアウトを設定します。ヘッドレス環境には入力デバイスがないため、CIではGUI入力テストをスキップします(Butch Wesley [00:48:33]。gdUnit4 6.2.1でも同じ警告が表示されます)。
最初に決めること
| 入力 | 変更される項目 | デフォルト |
|---|---|---|
アート素材の投入:数、形式、マニフェスト(file,category,name,height_m,source) | 取り込みルール、AI の適合性 | GLB のみ。AI ファイルにはマニフェストが必須です |
| カテゴリーごとの予算(三角形、マテリアル、テクスチャの辺の長さ) | 警告と却下の基準 | prop_rules.gd のデフォルト値。scenario-godot-performance-export によるフレーム予算から設定します |
| テクスチャのパス:抽出後に VRAM を通す、または Basis Universal に埋め込む | インポート時間、ディスク容量、インポートドックの操作 | 抽出 |
| 対象プラットフォーム | VRAM 形式(モバイルおよび macOS ユニバーサル向けの import_etc2_astc)、プリセット | Linux および macOS デスクトップ |
| テストフレームワーク | ランナー、CI コマンド | JUnit レポートには gdUnit4、プロジェクトにすでにある場合は GUT。両方は使いません |
| CI ホスト | ワークフローファイル、キャッシュ | GitHub Actions、SHA-512 で検証済みの公式バイナリ |
ワークフロー
1. 調査して決定する(インポートなし)。 prop_ingest.gd:ingest は各ファイルをバイト列として読み込み、プローブします
(glb_probe.gd:ヘッダー、チャンク、三角形、マテリアル、
glTF の役割を示す画像、拡張機能、ワールド境界)。prop_rules.gd を適用し、受け入れたファイルを
res://props/<category>/<id>/<id>.glb にサイドカーとともにコピーして、props_manifest.json を書き込みます。
書き込みは内容が変更された場合にのみ行われます。プロジェクト内の素材投入先には空の .gdignore を置いてください。置かないとエディターもインポートします(手順 15 で確認済み)。コリジョンの命名には Godot のノード接尾辞を使い、インポート時に取り除きます
(手順 15 で確認済み):-col はメッシュを保持し、trimesh シェイプを持つ StaticBody3D を追加します。-convcol は凸形状を追加します。-colonly はボディのみを保持し、-noimp はノードを破棄します。
ゲート:件数が一致する(受け入れ + 警告 + 却下 + 重複 = ファイル数)。却下されたものにはすべて理由があり、エンジンエラーが 0 件であること。
2. インポートする。 gd_run.import_project(P)。ゲート:作業完了後に 4.7.2 が出力する終了時のノイズを除き、ERROR: 行がないこと(ERROR: N resources still in use at exit、
WARNING: N ObjectDB instances were leaked at exit、WARNING: N RIDs of type ... were leaked。
これら 3 件は除外します。手順 15)。受け入れたプロップすべてについて、.godot/imported に .scn があること。
3. テクスチャ処理(抽出モード)。 prop_textures.gd:fix は、抽出された各テクスチャの .import で VRAM 圧縮、ミップマップ、glTF のロールに応じた法線マップフラグ、カテゴリ別のサイズ上限を設定してから、再インポートします。ヘッドレスではフレームを描画しないため、detect_3d は切り替わらず、この処理を行わないと抽出したテクスチャはロスレスのままになります[追加、M7 で検証済み]。ゲート:抽出したすべてのテクスチャが .s3tc.ctex(モバイルを対象とする場合は ETC2/ASTC も)になります。
4. 監査とテスト。 prop_audit.gd:audit はすべてのプロップを読み込み、メタバージョン、ルート名、ピボット、調整後の高さ、高さの範囲、三角形数が予算の 3 倍以内であること、Collision ボディ、AnimationPlayer がないこと、VRAM テクスチャを確認します。同じ check_prop() を、すべてのプロップを対象とした 1 つの gdUnit4 ケース内で実行します。ゲート:失敗 0 件、JUnit の解析成功、仕込んだ失敗で終了コード 100。
5. 見た目。 prop_thumbs.gd:thumbs(ウィンドウモード、メインウィンドウ 160x90、SubViewport でレンダリング)は、各プロップを赤い 1 m の支柱の隣に斜めからの視点で配置します。gd_review.contact_sheet は 1500 px のシートを 100 個ずつ作成します。シートを開いて確認します。ゲート:黒く表示されたプロップや欠落したプロップがなく、支柱と比べてサイズが妥当で、浮いたり埋まったりしているものがありません。
6. 再実行して 1 ファイルを変更。 取り込みとインポートを再実行します。コピー 0 件、サイドカー 0 件、再インポート 0 件です。ソースを 1 つ変更すると、そのプロップとテクスチャだけが再インポートされます。ゲート:どちらも満たすこと。
7. エクスポート。 テンプレート:.tpz には templates/ 以下のすべて(35 ファイル)と、4.7.2.stable と記された version.txt が含まれます。データディレクトリ(Linux では ~/.local/share/godot。Voylin AbMESM0UEHk [00:11:34])にある export_templates/4.7.2.stable/ へ内容を移動します。C# プロジェクトでは、先に --build-solutions を実行します(4.7.2 の --help に記載されており、--editor も暗黙に指定されます)。続いて gd_run.ensure_preset、gp.exclude_from_export(P, preset)(テストフレームワーク、テスト、エージェントツール、エディター専用プラグイン)、gd_run.export を実行します。ゲート:成果物が存在し、空ではなく、パック一覧に開発用ファイルがなく、verify_pack がプロップを読み込めること。
8. CI。 gp.write_workflow(root, "game", presets=(...)) は .github/workflows/godot-ci.yml と tools/ci/godot_ci.sh を作成します。まずスクリプトをローカルで実行し、失敗するテストを仕込み、gp.lint_workflow で lint し、gp.check_urls で URL の HEAD リクエストを確認します。ゲート:ローカル実行の終了コード 0、仕込んだ失敗の終了コード 11、actionlint がクリーン、URL が 200。
9. エディターツール。 EditorScript の _run() は通常のメソッドです。gd_run.run_script(..., editor=True) ジョブはシーンを開き(EditorInterface.open_scene_from_path)、数フレーム待機して _run() を呼び出し、EditorInterface.save_scene() で保存します。変更は EditorInterface.get_editor_undo_redo() 経由で行い、後で Ctrl+Z が機能するようにします(Queble、nW7YtSSJzbQ [00:04:41])。新しいノードには owner を設定しないと、保存時に消えてしまいます(ドキュメント)。@export_tool_button の Callable と _get_configuration_warnings() は直接呼び出します。ゲート:元に戻す操作とやり直す操作で子ノード数が復元され、保存した .tscn に新しいノードが含まれ、正常な入力と不正な入力で警告が適切に切り替わること。
GridMap。 GridMap レベルには MeshLibrary が必要です。インポートしたメッシュごとに create_item(id)、set_item_mesh(id, mi.mesh) を実行し、.res として保存します(検証済み、手順 15)。
10. カスタム形式。 有効なプラグインによって登録された EditorImportPlugin は、ヘッドレスの --import 中に実行されます。解析エラーがあると ERR_PARSE_ERROR を返し、サイドカーでは valid=false のままになり、不正な行がログに記録されます。ゲート:正常なファイルは対応するリソース型として読み込まれ、不正なファイルは内容を理解できるメッセージとともに失敗し、形式のバージョンを上げると reimport_files() を通じて再インポートされること。
11. ネイティブコード。 プロファイリングで特定したホットスポット、またはネイティブライブラリが必要な場合に限ります(Snopek、4R0uoBJ5XSk [00:03:16])。一連の処理をスモークテストします。gdextension_interface.h をダンプし、ビルドし、.gdextension を作成して --import を実行し、その後 ClassDB.class_exists とバインドしたメソッドを 1 つ呼び出します。本番環境では名前を変更した entry_symbol と godot-cpp を使用します(Snopek [00:13:22])。未実行です(ここには scons がありません)。ゲート:クラスが登録され、メソッドが応答し、読み込みエラーがないこと。
12. エージェントのチャネル。 ライブシーンを検査するには、プロジェクトの
tooling フォルダーにある MCP サーバーをクローンしてビルドし、環境変数としてのみ GODOT_PATH を渡し、
gp.mcp_stdio(..., hold_project=P) 経由で呼び出します(GD_MAX ロックを共有します)。共有マシンでエディターやゲームを起動するツールは呼び出さないでください。GATE:ツールが一覧に記載されていること、ヘッドレス編集を 1 回行い、結果を gd_run で読み込んで検証済みであること。
数値
ここで測定した数値(Godot 4.7.2、2026-10-02)は、ファイル 200 個を投入した場合のもので、新規実行を 2 回行っています。投入分との比較です。 サムネイル、パック、CI、時間係数の数値については、procedures.md を参照してください。
| 指標 | 値 |
|---|---|
| 200 ファイルのフルパイプライン(インポート対象 190 個) | 21.8~24.2 秒:取り込み 0.6~1.4、インポート 17.4~19.7、テクスチャ処理 0.4~0.5、インポート 1.9~2.7、監査 0.6~0.7 |
| 再実行、変更なし | 取り込み 0.6~0.7 秒、インポート 1.4 秒、再インポートされたファイルは 0 個 |
| ファイルを 1 個変更 | インポート 1.4~1.6 秒、インポート済みファイル 4 個に変更あり(シーン+テクスチャ) |
| 代わりに Basis Universal を埋め込む | 合計 13.8~14.4 秒、.godot/imported は 154.5 MB に対して 80.6 MB |
| 却下ライン | カテゴリーごとの三角形予算の 3 倍超(AI ファイル 12 個中 3 個、三角形 69k~181k) |
| gdUnit4 6.2.1 の終了コード | 0 は成功、100 は失敗またはエラー、101 は孤立のみ、103 はヘッドレス実行が拒否された場合、104 は未対応の Godot バージョン、105 はスクリプトエラー(GdUnitTestSessionRunner.gd) |
godot_ci.sh の終了コード[追加] | 10 はインポート、11 はテスト、12 はエクスポートでファイルが生成されなかった場合 |
品質ゲート
- 測定可能:カウントに矛盾がないこと、各ステージのエンジンエラーが 0 件であること、監査の失敗が 0 件であること、gdUnit4 の終了コードが 0 で、仕込んだテストの終了コードが 100 であること、再実行時に再インポートされるファイルが 0 個であること、パックの一覧に
addons/gdUnit4、test/、addons/agentkit、addons/prop_pipelineが含まれないこと、project.godotでphysics/3d/physics_engine="Jolt Physics"、レンダラー、プラグインの行を確認済みであること、actionlint がクリーンであること。 - 視覚:コンタクトシートを開いて確認し、黒い小道具やテクスチャのない小道具、1 m の支柱を基準にしたスケール、ピボット、欠落パーツを調べます。
よくある間違い
| 間違い | 状況 | 修正 |
|---|---|---|
asset.generator で AI アセットを判別する | AI ファイルが DCC として扱われ、任意のスケールのままになる(おもちゃのロボットの高さが 1.96 m) | マニフェストの source 列 |
| すべての小道具をマニフェストの高さに合わせる | 作成時のサイズの違いが失われる(すべてのランプが 2.2 m になる) | DCC は単位を修正し、AI のみフィットさせる |
| 抽出したテクスチャの圧縮をヘッドレスに任せる | 可逆圧縮の .ctex が大きなパックに入る | テクスチャ処理、または [importer_defaults] texture(プロジェクト全体に適用され、UI にも影響します) |
gdUnit4 に -rd /abs/path を指定する | レポートが <project>/Users/... に保存され、CI が JUnit を見つけられない | -rd res://... |
インポート確認に ResourceLoader.exists() を使う | インポートに失敗しても「存在する」と判定される | .import の valid=false を読み取る |
_get_format_version() を上げて --import を実行する | 何も再インポートされない | -e ジョブで scan() を実行し、待機してから reimport_files() を呼び出す |
| デフォルトのエクスポートフィルターでリリースする | gdUnit4、テスト、エージェントツールがパックに含まれる | exclude_from_export |
Linux バイナリに upload-artifact を使う | 実行ビットが失われる | 先に tar でアーカイブする(Voylin、AbMESM0UEHk [00:20:10]) |
| 大まかなチェックサム検索 | mono ビルドの行にも一致する | 正確な名前を指定し、2 行を想定する |
--script -e ジョブからプラグインを切り替える | is_plugin_enabled が矛盾した値を返し、エンジンエラーが発生する | project.godot の [editor_plugins] を編集する |
GUT テストに pause_before_teardown() を残す | ウィンドウ表示での実行が停止する(25 秒後に強制終了)。ヘッドレスの GUT 9.7.1 では一時停止しない | -gignore_pause(Butch Wesley [00:32:08]、手順 15) |
| CI で GUI 入力テストを実行する | 失敗する:ヘッドレス環境には入力デバイスがない | should_skip_script() が理由を返す。GUT は Risky としてカウントし、終了コードは 0(Butch Wesley [00:48:33]、手順 15) |
| GUT の孤立ノード数を無視する | リークがそのままリリースされる(リークしたノード 3 個で「3 orphans」と出力される) | 1 から 80 への増加は実際のリーク(Butch Wesley [00:57:00]) |
マージ済みの .tscn を信頼する | コンフリクトマーカーでシーンが壊れても、ResourceLoader.exists() は true を返す | マージ後にすべての .tscn を読み込む(null と Parse Error、手順 15;Lilith Duncan CAJ_iIedx_I [00:01:36]) |
GDExtension の追加後、最初の --import を信頼する | シャットダウン時にクラッシュする(新規プロジェクト 3 件中 2 件)、終了コードも異常 | extension_list.cfg を確認し、スモークジョブを実行する |
引き継ぎ
- マニフェスト付きのGLB、テクスチャ、音声(scenario-blender-export、
scenario-*)、予算 (scenario-godot-performance-export)、シーン規約(scenario-godot-architecture、 scenario-godot-3d-world。プロップの見た目と動作を担当)を受け取ります。 - 監査済みプロップ、ショールーム、コンタクトシートをscenario-godot-3d-worldに、テストスイートとCIを すべての関係者に、プリセットをscenario-godot-performance-exportに納品します(署名、ストア)。ポリゴン削減は scenario-blender-expertに、マテリアルの修正はscenario-godot-rendering-lightingに送ります。
Godot 4.7に関する注意事項
EditorScenePostImportPluginでは、_pre_processがImporterMeshInstance3Dノードを確認し、_post_processがMeshInstance3Dを確認します(検証済み、手順15)。衝突用の接尾辞はどちらの段階でも すでに適用されています。EditorScript.get_scene()は非推奨です。EditorInterface.get_edited_scene_root()を使用してください(検証済み: ジョブログに非推奨の警告が記録されます)。EditorPlugin.add_dock(EditorDock)はadd_control_to_dockに置き換わります(4.6でも引き続き利用可能)。- 4.7.2(M8)でサポートされるglTF拡張機能:basisu、webp、texture_transform、emissive_strength、 unlit、pbrSpecularGlossiness、lights_punctual、node_visibility、animation_pointer、OMI physics。Draco、 meshopt、mesh quantization、clearcoat、transmission、ior、specularはサポートされません。
- GDExtension:
classdb_register_extension_class4とclassdb_construct_object2は4.7.2でも読み込まれますが、 非推奨です。本番環境ではgodot-cppを使用します。プロジェクトが拡張機能を読み込むのは、--importで.godot/extension_list.cfgが書き込まれた後です。 - 4.4以降では
.uidサイドカーファイルはスクリプトと一緒に移動します。4.6の.tscnファイルにはunique_idが含まれます。
参考資料
references/procedures.md(コード、実機テスト、結果を含むすべての手順。第2ラウンドはセクション15)、expert-notes.md(根拠となるソースとタイムスタンプによる判断)、critique.md(評価基準)、gui-paths.md(エディターGUI)、sources.md。- コード:
scripts/agentkit/prop_pipeline_addon/(addons/prop_pipelineプラグイン)、scripts/ci/(ワークフローとCIスクリプト)、scripts/gdunit/(gdUnit4テスト)、scripts/examples/(EditorScriptツール、レベルインポーター、C GDExtension)。