scenario-godot-ui について
Godot 4.7.2 の UI 開発向けスキルです。画面サイズ、言語、入力方式に対応する UI の構築を支援し、レイアウト検査、画像確認、フォーカス移動、ローカライズテストで検証します。
主な機能
- 01ストレッチと画面適応の設定
- 02コードによる共通テーマの構築
- 03シーンと UI 構造の生成
- 04画面サイズ別レイアウト検査
- 05フォーカスと入力操作の確認
- 06ローカライズと疑似ローカライズの検証
活用シーン
- 01スマートフォンとデスクトップのレイアウト確認
- 02セーフエリア内のコントロール配置検証
- 03キーボードとゲームパッドのフォーカス操作テスト
- 04テキストのはみ出しや翻訳漏れの発見
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-godot-uiインストール後、Claude Code で/scenario-godot-uiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/gd_ui.pyscripts/agentkit/ui/hud_bar.gdmenu_stack.gdsafe_area.gdui_audit.gdui_capture.gdui_focus.gdui_layout.gdui_rebind.gdui_selftest.gdui_settings.gdui_stretch.gdui_theme.gdscripts/agentkit/ui/examples/build_g7.gd詳細
Godot UI(UI 開発者)
対象:Godot 4.7.2.stable、macOS Apple Silicon。
ここでいうエキスパートレベルとは、縦向きの 1080x2400 スマートフォンから 3840x2160 モニターまで、あらゆる言語で、マウス、ゲームパッド、スクリーンリーダーを使っても成立するレイアウトを、数値と画像で実証できることです。ストレッチ変換で拡大縮小し、コンテナで配置し、コードで構築した 1 つの Theme でスタイルを設定します。レイアウトマトリックスとコンタクトシートで確認できるまでは、何も出荷しません。ここに記載された関連スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。ユーザーが不在の場合は、ツールのスキーマに基づいて進め、不足している点を明記してください。
必須の背景知識: scenario-godot-expert(チャンネル、レビューループ、6.3 の落とし穴)。
スタンス(エキスパートならではの違い)
- 1080p 用ではなく、極端なサイズに合わせて基準サイズを選びます。
canvas_items+expandと Handheld Orientationsensorを組み合わせた正方形の基準サイズ(720x720)なら、縦向きと横向きで同じスケールを使えます(ドキュメント、Multiple resolutions)。実測値は、両向きの 1080x2400 スマートフォンで 1.5x、4K で 3x です。同じスマートフォンで 1152x648 の基準サイズを使うと、キャンバスは 0.9375x になり、ボタン 3 つが小さすぎます[追加、実測済み]。Godotneers の 1920x1080 基準サイズ(1_OFJLyqlXI)は、デスクトップ専用です。 - コンテナで配置し、アンカーで固定します。 サイズは交渉で決まります。最小サイズが下限となり、Expand が余った領域を確保し、Fill がそれを使います(Godotneers 1_OFJLyqlXI 00:35:00、Karto 5Hog6a0EYa0 00:14:39)。幅 400 px の HBox での実測では、Fill なしで Expand を設定すると、確保した領域が空いたままになり、隣の要素が x 380 まで押し出されます。Expand なしで Fill またはストレッチ比率を設定しても変化はありません。比率は合算され、1:3 なら 386 px のうち 96 px と 290 px になります(Karto 00:15:45)。アンカープリセットは親を基準にします。
set_anchors_preset()だけでは古いオフセットが維持されるため(FULL_RECT にしても 50x50 の子要素は 50x50 のままです)、set_anchors_and_offsets_preset()を使ってください(Karto 00:05:24、実測済み)。角に配置する要素には成長方向の指定も必要です。指定しないと、長いテキストが画面外にはみ出します[追加、1152 px のキャンバスで幅 1462 px になることを実測済み]。 - 見た目はコードで構築した 1 つの Theme リソースにまとめ、ノードごとのオーバーライドではなく型バリエーションを使います。(ドキュメント、Theme type variations)。StyleBox は共有 Resource です。2 つのノードで同じオーバーライドを使うと、両方が変更されます(Karto 00:19:00)。
- フォーカスを明示的に設定します。 シーン開始時には何にもフォーカスがないため、何かが
grab_focus()を呼び出すまではui_downは何もしません(ドキュメント、Controller navigation、実測済み)。メニュースタックを維持し、背後にあるパネルを無効にして、メニューを開いた要素にフォーカスを戻します(Mostly Mad Productions ecJZipjUj6k 00:08:57)。 - 現在の選択項目は画面上で最もコントラストが高い要素にし、本文を優先し、フォントは最大でも 2、3 種類に抑え、アウトロはイントロより速くします(Rawb Herb、GodotCon 2025、sjmAD1ZLBcE 00:31:42、00:21:34、00:55:38)。
- テキストはリテラルではなくキーで管理します。 名前付きプレースホルダーには
format()、複数形にはtr_n()、同じ英語表現にはコンテキストを使い、動的テキストでは自動翻訳を無効にします(ドキュメント、Internationalizing games)。フォントにはリマップではなくフォールバックを設定します。 - HUD は受動的にし、シグナル駆動にします。 HUD のルートとラッパーはマウス入力を無視し、値は
_processではなくシグナルで変更します(1_OFJLyqlXI、Yuw7CK5H8eA、f90ieBOoIYQ の共通見解)。文字列が新しいと形状が再計算されます(200 個のラベルで、フレームあたりの CPU 時間は 1.1 ms から 1.5 ms)。同じ文字列を割り当てた場合は早期終了するため、コストがかかるのは割り当てではなくテキストの変更です[追加、実測済み]。配列をその場で変更してもセッターは呼ばれません(appendの後は 0 回、再代入後は 1 回)。そのため、状態配列は独自のシグナルを発行します(NoBSGodot Yuw7CK5H8eA 00:05:06、実測済み)。 - まずヘッドレスでデバイスサイズを検証し、その後に表示を確認します。 ヘッドレスでは、
root.sizeに任意のサイズを設定するとプロジェクトのストレッチが適用されるため、レイアウトマトリックスを数秒で実行できます。その後、ウィンドウ表示でキャプチャし、ノッチを描画した各デバイスの画面をレンダリングします[追加、実測済み]。
最初に決めること
| 入力 | 変更内容 | 指定がない場合のデフォルト |
|---|---|---|
| プラットフォームと画面の向き | 基準サイズ、画面の向き、タッチターゲットのサイズ | スマートフォンの縦向き+横向き、デスクトップは最大4K:基準サイズ720x720、canvas_items、expand、画面の向き6(センサー) |
| アートスタイル | ストレッチモードとスケールモード | ベクターまたは高解像度:canvas_items+小数スケール、ピクセルアート:viewport、基準サイズ640x360、整数スケール、排他フルスクリーン(ドキュメント) |
| 入力デバイス | フォーカス対応、再割り当て画面、タッチサイズ | マウス、キーボード、ゲームパッド、タッチ |
| 言語 | フォント、RTL、エクスポート時のText Server Data | テスト用にenに加えて、長い言語(de)、CJK(ja)、RTL(ar)を各1つ |
| アクセシビリティの基準 | スクリーンリーダー、UIスケールスライダー、コントラスト | 本文テキストはWCAG 4.5:1、content_scale_factorを介してUIスケールを0.75~2.0に設定 |
| レンダラー | 設定でのアップスケーラーの選択 | Forward+(Joltを維持)。Compatibilityでは3Dスケーリングが強制的にバイリニアになります |
ワークフロー
1. プロジェクト設定。 ストレッチ関連のキーを明示的に記述します。手書きのproject.godotでは、disabledとkeep(差分)を設定します。gd_env.set_project_settingで
display/window/size/viewport_width/height、stretch/mode、stretch/aspect、
handheld/orientation、gui/theme/customを設定します。3d/physics_engine="Jolt Physics"とレンダラーが維持されていることを確認します。GATE:各ターゲットに対するgd_ui.stretch_math(window, base, ...)が期待される論理サイズとスケールを返すこと(224ケースでエンジンと一致し、原点とスケールも含む)。
2. コードでテーマを設定。 ui_theme.gdのbuild(overrides)はThemeを返します。太いアクセントカラーのフォーカス枠を備えたButtonの状態、Label、パネル、スライダー、タブ、ProgressBar、TitleLabel、HudLabel、HudValue、PrimaryButton、HudPanel、HealthBar、TrailBarのバリエーションを含みます。.tresとして保存し、デフォルトフォントにはCJKとアラビア語のフォールバックを備えたSystemFontを設定します。フォントは最大でも2~3種類にします。複数のスケールで描画されるテキスト(3倍表示のHUD数値など)にはMSDFを使用します。
gui/theme/default_font_multichannel_signed_distance_fieldまたはフォントの
multichannel_signed_distance_fieldを設定します。どちらもデフォルトではfalseです(Karto 5Hog6a0EYa0 00:20:50、実測)。デフォルトのTheme Scaleは一度だけ読み込まれます。実行時に設定しても何も変わりませんでした(実測)。エディターではThemeを編集した後、再描画するにはシーンの再読み込みが必要です(Godotneers 00:22:10)。また、オーバーライドはチェックボックスをオンにするまで無効です(Karto 00:17:25)。コードではadd_theme_*_overrideだけが有効で、実行時のTheme編集は即時に反映されます(実測)。GATE:contrast_report()で本文の組み合わせが4.5:1以上であること(実測で最も低い4.37は無効状態であり、許容範囲です)。check_variations()で誤記されたバリエーションが見つからないこと。
3. コード内のシーン。 ルートには全領域を覆う Control を置き、safe_area.gd
の MarginContainer、その下に各種コンテナを配置します。ボタンの高さは、基準解像度 720 で論理ピクセル 88(倍率 1.5x のスマートフォンでは 132 px)にします。
設定行は TabContainer 内の ScrollContainer に配置します。HUD は CanvasLayer 上に置き、ルートの
MOUSE_FILTER_IGNORE を設定し、ミニマップには AspectRatioContainer を使います。円形のミニマップや縦長のフレームには
clip_children マスク(角丸 Panel の Clip Only)を使えますが、別の z_index を持つ子要素はマスクを抜ける
(GDQuest W4j4tnQLcTA 00:03:47、実測)ため、マスク対象のコンテンツは z 0 に保つか、SubViewport を使います。
トグルはテキストで「On」/「Off」と表示します(CoffeeCrow 9H_fN4OxyIE 00:08:11)。safe_area.gd は
size_changed のたびに再計算します(倍率 1.5x では上マージン 104、2x では 82、実測)。
examples/build_g7.gd は G7 セット全体を構築します。GATE:ui_audit.gd の
audit_tree() が hud_blocks_input、icon_keep_size、grows_offscreen_*、no_accessible_name、
shared_stylebox_override、unknown_variation を返さないこと。
4. ヘッドレスでのレイアウトマトリックス。
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)
を 8 種類のターゲット(スマートフォンの縦向きと横向き、4:3 タブレット、1366x768、1080p、21:9、4K、800x600)に対して実行します。GATE:
各シーンについて、en、de、および 0.4 倍に拡張した疑似ローカライズで、画面外、セーフエリア外、小さいタッチ領域、テキスト(クリップまたはオーバーフロー)、重なり、折りたたみの問題がゼロであること。
5. ウィンドウモードでキャプチャマトリックスを実行し、目視確認します。
gd_ui.capture_matrix(P, scene, targets, safe_insets=...) は各ターゲットを物理解像度でレンダリングし、黒帯と赤いノッチ帯を付けてコンタクトシートを作成します。シートを開いてください。GATE:
image_checks が何も検出しないこと。目視で、選択状態が見えること、グリフ(CJK、アラビア語)がクリップされていないこと、ノッチ帯が背景のみに重なること、バーとフレームが保たれていることを確認します。埋め込み Window の content_scale_* を介してキャプチャしてはいけません。スケーリングされずに描画されます(P13、実測)。
6. フォーカスと入力。 gd_ui.focus_walk(P, scene, steps) は push_input を通して
ui_* アクションを送信し、フォーカス所有者を記録します。ui_focus.graph() は到達不能なフォーカス可能項目を一覧表示します。メニューのスタックでは、開く、キャンセルする、開いた元の項目にフォーカスを戻す、という動作を確認します。GATE:デフォルトからすべてのフォーカス可能項目に到達できること。フォーカスがない状態から最初のキー入力でデフォルトにフォーカスが移ること。覆われたパネルに到達できないこと。
7. キー割り当ての変更。 ui_rebind.gd:入力を受け付ける(エコーなし、Escape を除外、スティックは 0.5 を超える)、正規化する(物理キーコード、デバイス -1、軸の符号)、競合を報告し、入れ替えるか拒否し、ConfigFile として保存し、プロジェクト設定からリセットします。DisplayServer.keyboard_get_label_from_physical() でキーを表示します(ウィンドウモードのみ)。フランス語配列では、物理 Q キーは「A」と表示されます(実測)。パッドのボタンは自分で追加します。4.7.2 では ui_accept と ui_cancel はキーのみ(Enter、Kp Enter、Space、Escape)を対象とするため、Joypad Button 0 と 1 を追加します(Mostly Mad ecJZipjUj6k 00:12:00、実測)。GATE:保存と読み込みを経ても、キーボードと任意のパッドの両方で割り当てが一致すること。
8. ローカライズ。 ?plural 列を含む CSV を用意し、オフラインで gd_ui.check_csv を実行してから --import を行い、その後
gd_ui.register_translations を実行します。en、fr、de、ja、ar、および疑似ローカライズでテストします。expansion_ratio
の既定値は 0.0 のため、0.3 から 0.4 に設定して reload_pseudolocalization() を呼び出します(実測)。
--language fr は永続化されないテスト用オプションです。アニメーション付きテキストには RichTextEffect を使います。bbcode 変数と
_process_custom_fx(char_fx) を用意し、char_fx.env からオプションを取得します(Cashew OldDew KMqYeRae6rM 00:14:01;
実測では [lift px=6] の読み取り値は 6.0)。install_effect() でインストールします。GATE:ロケールごとに欠落キーがないこと。アラビア語で反転すること(アンカーと HBox の順序)。en と fr で複数形が正しいこと。レイアウトマトリックスに問題がないこと。
9. 設定とコスト。 ui_settings.gd の自動読み込み機能で、ウィンドウモード、vsync、レンダリングスケールとアップスケーラー、品質、UI スケール、バス音量、ロケールを適用し、保存して再読み込みします。GATE:保存と読み込みを経ても設定が保持されること。ui_scale を 1.5 にすると、1280x720 のキャンバスが 853x480 になること。
数値
| 値 | 比較対象 | 出典 |
|---|---|---|
基本サイズ 720x720、canvas_items、expand、端末の向きセンサー | スマートフォンの縦向きと横向き、およびデスクトップ | ドキュメント、複数の解像度 |
| 1080x2400 と 2400x1080 では 1.5 倍、3840x2160 では 3.0 倍、1366x768 では 1.0672 倍 | 基本サイズ 720x720 | 実測 [追加] |
2400x1080 のスマートフォンで基本サイズ 720x1280 を使用:expand は 0.844 倍で 2844x1280(UI が縮小)、keep_width は 897 px のサイドバー、1080x2400 での keep_height は 240 px のバー | アスペクト比の選択より正方形の基本サイズが優れている理由 | 実測 [追加] |
ピクセルアートは 640x360 の viewport を整数倍で使用。1366x768 で 1.0672 倍の viewport を使うと再サンプリングによりテキストがぼやける | 720p から 4K | ドキュメント、実測 |
| 4K の基本サイズではデフォルトのテーマスケールを 2.0〜3.0、1080p のモバイル向け基本サイズでは 1.5〜2.0 に設定。一度だけ読み込み(実行時に設定:変更なし) | 基本サイズ | ドキュメント、実測 |
| タッチターゲットはスマートフォンで 126 px、タブレットで 96 px(約 420 dpi と 320 dpi で 48 dp) | 物理ピクセル | [追加] |
| 基本サイズ 720 でボタンは論理サイズ 88 | スマートフォンで 132 px | [追加、実測] |
| WCAG:本文は 4.5:1、大きなテキストは 3:1 | テキストと背景のコントラスト | WCAG 2 [追加] |
| ダメージの軌跡:ワンショットタイマーは 0.4 s、ヒットごとに再起動。回復は即時 | 体力の変化 | DashNothing f90ieBOoIYQ 00:01:26 |
| テキストサーバーデータは約 4 MB | エクスポートサイズ、スペースを含まないスクリプト用 | ドキュメント |
| 200 個のラベル:毎フレーム新しいテキストを生成すると 1.1〜1.5 ms、毎フレーム 10 個なら 0.17〜0.23 ms、同じテキストなら 0.1 ms 未満(アイドル時) | ヘッドレス M5 Max でのフレームごとの CPU 使用時間 | 実測 [追加] |
品質ゲート
測定可能な項目:test_ui_live.py の U1〜U15 がすべて合格(コンパイル、ストレッチの同等性、CSV、レイアウトマトリックス、キャプチャ、
フォーカス、再割り当て、HUD、ローカライズ、エンジンの情報、テーマと設定、コスト、埋め込み Window、ラウンド 2 の
レイアウトとテーマの情報、クリップマスクとテキストエフェクト);各シーンとロケールのレイアウトマトリックスに問題がないこと;
監査に問題がないこと;本文のペアのコントラストが 4.5:1 以上であること;保存と読み込みの往復テストに合格すること。視覚的な項目:シーンとロケールごとに 1 枚ずつコンタクトシートを作成(メニュー、HUD、設定 ja、メニュー ar、設定 pseudo)して開き、フォーカスが見えること、グリフが欠けていないこと、ノッチの下に何も隠れていないこと、想定どおりレターボックスが表示されること、グレースケールでも選択状態が見えること(Rawb Herb)。
よくある間違い
| 間違い | 発生する状況 | 修正方法 |
|---|---|---|
| スマートフォン向けゲームのベースに1920x1080または1152x648を使う | 縦向き画面でボタンが小さくなる(1080x2400でスケールが0.9375) | 正方形のベース720x720 + 拡張 |
| エージェントが作成したproject.godotでストレッチキーが抜けている | UIが固定サイズになり、4Kで黒い余白ができる | モードとアスペクト比を明示的に設定する |
| ゲーム上にデフォルトのSTOPフィルターを持つFull-rect Controlがある | クリックが_unhandled_inputに届かない(0 of 1) | HUDのルートとラッパーにMOUSE_FILTER_IGNOREを設定する |
| 拡大方向を指定せずにコーナープリセットを使う | スコアのテキストが右端からはみ出す | grow_horizontal = GROW_DIRECTION_BEGIN |
開いたときにgrab_focus()を呼び出さない | パッドを操作しても反応しない | メニューのスタックが最初のナビゲーションイベントでデフォルト項目にフォーカスを設定する |
コンテナ内のTextureRectをKEEP_SIZEのままにする | 512 pxのアイコンによって64 pxの行が614x512になる。IGNORE_SIZEにして最小サイズを指定しないと幅が0になる | EXPAND_FIT_WIDTH_PROPORTIONAL(計測値は64x64)、またはサイズを無視して最小サイズを設定し、Stretch Keep Aspect Centeredを使う(Godotneers 1_OFJLyqlXI 00:10:28) |
| OptionButtonの項目に英語を直書きする | 日本語画面に「Windowed」と表示される | 項目をキー(OPT_WINDOWED)にする |
| タブをテーマのデフォルトのままにする | タブが小さすぎてタッチしづらい | コンテンツマージンを指定したタブのStyleBoxを設定する。マトリックスはTabBarをチェックします |
| 合成イベントからデバイス0で保存されたバインド | パッド2または実際のキーボード(device 16)で反応しない | device -1に正規化する |
| 疑似ローカライズを有効にしたが、拡張を変更しない、または再読み込みしない | パディングがない(デフォルト比率は0.0) | expansion_ratioを設定し、TranslationServer.reload_pseudolocalization()を呼び出す |
| 古いチュートリアルのカスタムノードでPOT生成を信頼する | 文字列が欠落する(4.2のバグ) | 4.3で修正済み(Cashew OldDew v0tJPsNNOM8 00:08:00、再実行なし)。CSVキーを使えばPOTを回避できます |
| プロジェクト設定でLocale Testを設定する | フランス語で出荷される | クリアし、--language frを使う |
エフェクトのためにvisible = falseでコンテナの子を非表示にする | 兄弟要素が跳ねる(再レイアウト) | modulate.a = 0またはoffset_transform_scaleを使う(MrElipteach pK2vI2-jCH4 00:02:54) |
| マウスクリック後にフォーカスリングが表示されることを期待する | 次にキーまたはパッドを押したときだけリングが表示される | 仕様です。gui/common/show_focus_state_on_pointer_event 1(テキスト入力のみ) |
ハンドオフ
- 入力:状態の自動読み込みとシグナル(scenario-godot-architecture)、入力アクションと値 (scenario-godot-gameplay)、バス名 Master、Music、SFX(scenario-godot-audio)、アイコン、パネル、 フォント(scenario-* スキル。ナインパッチのマージンはコードで設定します)。
- 出力:レンダリングスケールとアップスケーラーの仕様(scenario-godot-rendering-lighting)、Text Server Data、
実機のセーフエリアとタッチ操作(scenario-godot-performance-export)、イントロとアウトロのトラック、
offset_transformによる動き(scenario-godot-animation)、CI 用のtest_ui_live.py(scenario-godot-pipeline-automation)。
Godot 4.7 に関するメモ
offset_transform_*(4.7)は再レイアウトせずにコンテナの子要素を移動します。offset_transform_visual_onlyのデフォルトは true のため、クリック判定はレイアウト矩形に対して行われます(実測済み)。 中央ピボットにはpivot_offset_ratio(4.7)、grab_focus(hide_focus)(4.6)を使用します。AccessibilityServer(4.7)、accessibility_name、FOCUS_ACCESSIBILITY(RichTextLabel のデフォルト)があります。accessibility_supportが 0 Auto の場合、支援アプリがアクティブなときにのみ実行されます。auto_translate_modeはauto_translateに置き換わりました。FoldableContainer(4.5)、VirtualJoystick、PopupMenu.allow_search(4.7)が追加されました。[img]はwidth_unit/height_unitを受け取ります。アップスケーラー:FSR2=2、 MetalFX spatial=3、temporal=4。push_input(event, true)は論理座標を受け取ります。Godot 3 の名称(rect_size、add_color_override、margin_*、stretch2d、process_custom_fx)は廃止されています。
参考資料
references/procedures.md:P1 から P15 までの完全なコードパス、ライブテスト ID と結果。references/expert-notes.md:各ソースから得られる内容と タイムスタンプ。references/critique.md:UI のビルドとそのキャプチャを評価するための 基準。references/gui-paths.md:コンピューター操作エージェント向けに、エディターで 同じ手順を実行する方法。references/sources.md:すべてのソース、認証情報、URL、最適な タイムスタンプ。scripts/gd_ui.py、scripts/agentkit/ui/*.gd、scripts/agentkit/ui/examples/build_g7.gd。