gohud

ゲーム UI を、リソース1枚で動かす

gohud は Godot 4.6 以降で使う HUD・UI キットだ。浮かぶウィンドウ、ボトムシート、ダイアログ、フォーム、 スナックバー、コーチマーク、HUD バー、クイックスロット、バーチャルスティックがテーマ1枚と 差し替え可能なアイコンセット1枚で動き、セーフエリア・仮想キーボード・RTL・タッチターゲットを自分で面倒みる。 6つのプリセット — デフォルト・SF・中世、それぞれにダークとライト — が1行で色と形を同時に変える。

Godot 4.6+ v1.0.1 純粋な GDScript オートロード不要 MIT プリセット6種 21言語 アイコン100種同梱

ゲーム画面ではこう見える

中世と SF のプリセット — キャラクターシート、インベントリ、クエスト。フォーム、グリッド、 プロンプトカード。角張ったパネルとタッチ操作。プリセットの切り替えはコード1行だ。

gohud 中世テーマ — 体力・マナ・スタミナのバーが並ぶキャラクターシート、クイックスロットの雑嚢、鍛造した金枠のクエストジャーナル
中世 — キャラクター・インベントリ・クエスト
gohud 中世テーマ — 名前入力欄・トグル・チェックボックス・音量スライダーのある入力パネル、タイルのグリッド、承諾と辞退を選ぶパーティ招待のプロンプトカード
中世 — フォーム・グリッド・プロンプトカード
gohud SF テーマ — 六角形のスティック、固定 / 追従 / 相対の切り替え、丸いアクションボタンを載せた面取りタッチ操作パネル
SF — 角張ったパネルとタッチ操作

6つのプリセットと切り替え方 →

肩代わりしてくれるもの

ゲーム UI で時間を食うのはボタンの形ではなく、端末ごとにずれていくすべてだ。 gohud はそのずれを1か所で引き受ける。

寸法はすべてトークン

余白・角・文字サイズは数値で書かず名前で呼ぶ。テーマを差し替えれば画面全体がまとめて動く。

見える大きさ ≠ 押せる大きさ

閉じるボタンは 36dp に見えてタッチターゲットは 48dp。スロットが密集して重なる場所は、中心が近いほうが押下を取る。

ノッチとキーボード

HUD はセーフエリアの内側に収まり、仮想キーボードが出れば入力欄がその上へ持ち上がる。

戻るは1枚だけ閉じる

Escape と Android の戻るは最前面の1枚だけを閉じる。重ねたウィンドウがまとめて消えない。

通知は入力を奪わない

スナックバーの上を押しても、その下のボタンが反応する。フォーカスも奪わない。

アイコンは名前で頼む

ウィジェットが知っているのは GoIconSet.CLOSE だけ。セットを差し替えればコードに触れずに絵が変わる。

6つの見た目、1行

GoUi.use_preset() がテーマ・スキン・アイコンをまとめて入れ替える — 丸み、面取りの SF、鍛造した中世の枠。

読めるかどうかは測る

どのテーマも WCAG で測ってある。ボタンの状態ごとのラベルも、純白・純黒の上に載る半透明 HUD パネルも含めて。

プラグインを有効にしなくても全部動く。 有効にすると GoRuntime オートロードが付いてウィンドウサイズ・ dp 倍率・キーボード高さを追い、設定リソースとプリセットを選ぶプロジェクト設定が増える — 便利なだけで必須ではない。

gohud をインストール

入口は二つ。AI エージェントに任せるか、フォルダーをプロジェクトに入れるか — ほかに設定するものはない。

インストール

クイックスタート

五行でテーマの当たった画面が出る。最初から最後までは、インストールのページに。

クイックスタート

見た目を変える — 色だけでなく形も

Theme が作り替えられるのはエンジンが描くものだけだ。StyleBoxFlat が持つ角は丸だけで、 スティック・クイックスロット・コーチマークはコードが直接描くため、テーマをいくら替えても形は変わらない。 そこで gohud は、テーマ・スキン・アイコンをひとまとまりで選ぶプリセットを用意している。

GoUi.use_preset(GoThemePresets.MEDIEVAL_DARK)   # テーマ・スキン・アイコンがまとめて替わる
プリセット見た目
default_darkgohud 本来の姿 — 丸い角、やわらかい青のアクセント
default_light同じ形をライトパレットで
scifi_dark面取りした角、シアンのネオン縁と発光、六角形のスティック、照準ブラケット
scifi_light同じ角張った形を明るい設計図のパレットで
medieval_dark暗い鉄と革、アンティークゴールドの枠、リベット、彫刻風アイコン、Cinzel の見出し
medieval_light羊皮紙・インク・青銅に同じ鍛造の枠
default_dark プリセットの gohud ギャラリー — 丸い角と青のアクセント
default_dark — 丸い角、やわらかい青のアクセント
default_light プリセット — 同じ形をライトパレットで
default_light — 同じ形、ライトパレット
scifi_dark プリセット — 面取りした角とシアンのネオン
scifi_dark — 面取りの角、シアンのネオン
scifi_light プリセット — 同じ角張った形を設計図のパレットで
scifi_light — 同じ角張った形、設計図のパレット

この4枚は同じギャラリー画面だ。コードは1行も違わず、変えたのはプリセット名だけ。 ボタンの角、トグルの形、リストの行、入力欄の枠が、そろって動いているのが分かる。

中世コレクション

medieval_dark は鉄と革にアンティークゴールドを合わせ、medieval_light は羊皮紙とインクを使う。 メニューの枠にはリベットと小さな角飾りを置き、常に見えている HUD は静かなままにした。 彫刻風アイコン16種がアイテム名を描き直し、同梱の Cinzel フォントはタイトルとサブタイトルにだけ使う。

medieval_dark — キャラクターシート、クイックスロットの雑嚢、クエストジャーナル
medieval_dark — 鉄と革
medieval_light — 同じキャラクター・雑嚢・クエストの画面を羊皮紙で
medieval_light — 羊皮紙とインク

どちらも標準ウィジェットだけで組んだ examples/medieval/medieval.tscn だ。 中世テーマの解説と、自分だけの王国の作り方 →

同じ画面を、スマートフォンでもデスクトップでも

ギャラリーの4枚は縦持ちのスマートフォンだ。下は同じコードを 1280×800 で開いたもので、本文は読みやすい幅 (480dp) で止まって中央に立ち、HUD は隅に残る。フォームは浮かぶ HUD をよけて回り込むが、 もともと重なっていなければ動かない — 広い画面で無理に押しやると、本文が中心からずれてしまう。

1280×800 の default_dark — 本文は中央、HUD は隅
default_dark · 1280×800
1280×800 の scifi_dark — 同じ配置に面取りパネルとネオン
scifi_dark · 1280×800

同じシート、違う見た目

default_dark のボトムシート
デフォルト — 丸いカード、固定された検索行とフッター
scifi_dark のボトムシート — 上辺にネオンのアクセント
SF — 上辺のアクセント、切り落とした角、発光

エディタからは プロジェクト設定 → gohud → Theme → Preset で選び、設定リソースからは GoConfig.preset で指定する。themeskinicons を明示的に 埋めると、そちらがプリセットより優先される — プリセットを選んだうえで1つだけ差し替えられる。

新しいテーマは JSON ファイル1枚だ。 new_theme.py kingdom --from medieval_dark が、 継承した値をすべて書き出したパレットを作る。make_theme.py kingdom がテーマ・コントロールの絵・ スキンのダイヤルまで生成し、プリセットは選択リストに自動で現れる。設定とダイヤルのすべて →

スキン — テーマが届かない場所

スキンが受け持つのは、スティック、クイックスロットの面、コーチマークのリング、チップ、スケルトン、 アラート、区切り線、セクション見出しだ。継承して、変えたいものだけを上書きすればよい。

class_name MySkin extends GoSkin

func slot_box(accent: Color, lit: bool) -> StyleBox:
    var box := GoStyleBoxCut.new()
    box.bg_color = accent
    box.cut = 6.0
    box.edge_color = accent
    return box
クラス作れる形
GoStyleBoxCut角を斜めに切り落とした面取り、1辺だけ太いアクセント縁、外へにじむ発光
GoStyleBoxBracket中身を囲わず、四隅の印だけを引く
GoStyleBoxMedievalリベット・角の彫刻・ベベルのハイライト・素材の質感を持つ鍛造の枠

3つとも Theme リソースへそのまま保存できる — だからこそテーマが色だけでなくまで変えられる。 GoSkinSciFiGoSkinMedieval が同梱のサブクラスだ。

GoStyle.box() は必ず StyleBoxFlat を返す。 呼び出し側が受け取って bg_colorcorner_radius を調整するからだ。独自の形を保ったままにしたいときは GoStyle.surface() を使う。

ウィジェット

部品を一覧で。ひとつずつ詳しく →

クラス基底役割
GoSurfaceControl浮かぶカードの外殻 — 中央・下・アンカー配置、固定ヘッダーとフッター、スクロール本文、ドラッグでのサイズ変更
GoSheetCanvasLayer下からせり上がるページ。専用レイヤーを持つので HUD より確実に上に出る
GoDialogsNodeawait で受け取る確認と通知。取り消せない操作には destructive
GoFormMarginContainer幅に上限を設け、仮想キーボードを、avoid_hud なら HUD も避けるフォーム
GoScrollScrollContainerタッチでのスクロール。スクロールバーはカードの余白へ収まる
GoNoticePanelContainer入力もフォーカスも奪わないスナックバー
GoPromptCardPanelContainerゲームを止めずに尋ねるカード
GoCoachMarkControl実物のコントロールを指し示すツアー。指した対象を押すと次へ進む
GoHudAnchorControlHUD をセーフエリア内の9か所のどれかに留める
GoBarControl体力・マナ・経験値のバー。変化はなめらかに補間される
GoSlotButtonクイックスロット1つ — アイコン・個数・クールダウン・ショートカットを1つの面に
GoJoystickControl固定・追従・相対モードのバーチャルスティック
GoIconButtonButton小さく見えて大きく押せる
GoStyle静的ボタン、リスト行、入力欄、チップ、表、タブなどを同じ流儀で作る

待たせる、伝える、数える

クラス基底役割
GoSnackbarNode自分で居場所を決めるメッセージ
GoSpinnerControl終わりの見えない待ち時間
GoBadgePanelContainer未読の点、NEW の札、99+

フォームとリスト

クラス基底役割
GoFieldVBoxContainer間違いを抱えられる行
GoInputGroupHBoxContainerボタンと溶接された入力欄
GoComboboxButton検索できるピッカー
GoCodeInputVBoxContainerクーポンとギフトコード
GoTableVBoxContainer並べ替えできる見出し、選べる行
GoPaginationHBoxContainerページ番号、あるいは「もっと見る」の行

ゲームで実際に使う形

クラス基底役割
GoRewardCalendarVBoxContainer毎日のログインボーナス
GoRadar · GoDonutControlひと目で分かるステータス
GoCarouselVBoxContainerバナーとキャラクター選択
GoKbdHBoxContainer嘘をつかないキー表示

画面の上に重ねる

クラス基底役割
GoDrawerCanvasLayer横から出るパネル
GoPopoverRefCounted脇に留まるカード
GoContextMenuRefCounted長押しと右クリック
GoConsoleCanvasLayer開発者コンソール

AI SKILL

gohud には AI スキルが入っている — API のすべて、すぐ動くテンプレート、プレビュー起動器。下の文をまるごとコーディングエージェントに貼れば、gohud を入れて使い方まで覚える。

AI SKILL

読みやすさは目分量ではなく実測で決める

「きれい」は好みだが、「読める」は測れる。 薄い灰色の文字は良いモニタでは平気に見えて、 日中の屋外ではスマートフォンから消える — 目で選んでいれば、いつか必ずそうなる。

python3 addons/gohud/tools/check_contrast.py

すべての色の組み合わせと、ボタンの状態ごとのラベルとその下のパネルを、6つのテーマすべてで WCAG に 照らして測る。半透明の色は実際の背景に合成してから測る — そのまま測ると、画面に出ている見え方より 良い比率が出てしまう。

だから文字色は選ぶのではなく導き出す。ビルダーはパレットの値を出発点にして、その文字が載りうる すべての面でしきい値を超えるまで明度を押し上げる。パレットを変えればコントラストも追従する。 その規則と、背後にある落とし穴 →

検査・リリース・このサイト

入口1つですべての検査が走る。それぞれが、ほかからは見えないものを見ている。

bash addons/gohud/tools/check_all.sh
検査捕まえるもの
4つの画面サイズでの run_tests.shウィジェットの挙動とレイアウト、RTL での位置、キーボードフォーカス、実行時のスキンのコントラスト、全プリセット
new_project_check.shホストプロジェクトへの隠れた依存。--zip なら配布物そのまま、--export なら Web ビルドまで
check_contrast.py全テーマファイルの WCAG コントラスト — ボタンの状態も半透明パネルも含めて
check_generated.py · check_scaffold.sh生成されたテーマがパレットと一致するか、使い捨てのテーマが生成できてコントラストを通るか
check_package.pypackage.json のバージョンの反映、変更履歴の移動、ZIP の中身を一時コピー上で
check_site.pyこのサイトのリンク・アンカー・文書言語・用語集・ダイヤル表
直近の記録 — 2026-09-13、Godot 4.7.2、macOS、Compatibility レンダラー。 空のプロジェクトで 390×844・844×390・768×1024・1280×800 の4サイズとも 438/438、GoRuntime オートロードを有効にしても再び 438/438、 Web エクスポート成功、6テーマでコントラスト不足は 0。この実行に Godot 4.6 と Android・iOS の実機は含まれていない。

リリース版を作る

cat addons/gohud/package.json       # { "version": "1.1.0" }
bash addons/gohud/tools/package.sh  # 1.1.0 → builds/1.1.0/gohud-1.1.0.zip

バージョンは package.json に書かれた値で、パッケージングがそれを上げることはない。 新しいバージョンを出すときは、先にその数字を書き換える。 成功すると plugin.cfgGoUi.VERSION をその値に合わせ、そのバージョンを初めてパッケージングしたときだけ CHANGELOG.md の Unreleased の記述を日付付きの項目へ移す。 同じバージョンでもう一度実行すると ZIP を作り直して前のものと置き換える。失敗すれば何も変わらない。 ZIP にはこのサイトもテストもツールも package.json も入らない。

このサイト

python3 addons/gohud/tools/make_site.py            # 用語集とスキンのダイヤル表をソースから生成する
python3 addons/gohud/tools/check_site.py           # リンク・アンカー・言語・用語集・生成された表を検査する
bash addons/gohud/tools/site_shots.sh /tmp/shots   # 各ページのデスクトップ幅とスマートフォン幅を撮る

ページは www/ にあるただの HTML だ — ルートが英語、ko/ が韓国語。 GitHub Actions のワークフローがこのフォルダをサイトのルートとして公開する。