mcpField
B
building-glamorous-tuis

building-glamorous-tuis

github.com/dicklesworthstoneデザイン・UI20881 回インストール2 日前に更新
リポジトリ

building-glamorous-tuis について

Charmbracelet のライブラリでターミナル UI を構築するためのリファレンススキルです。シェルスクリプトの入力、Go TUI、SSH 上の UI、実運用向けの設計パターンを扱います。

主な機能

  1. 01ライブラリ選定ガイド
  2. 02Gum によるシェルスクリプト入力
  3. 03Bubble Tea と Lip Gloss による Go TUI
  4. 04SSH 対応 TUI のパターン
  5. 05実運用向け設計と最適化
  6. 06レイアウト、フォーム、アニメーション、テスト

活用シーン

  1. 01シェルスクリプトや Go TUI のライブラリ選定
  2. 02スクリプトへの対話的な入力や選択の追加
  3. 03レスポンシブな複数画面のターミナル UI 構築
  4. 04TUI の性能と信頼性の改善

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dicklesworthstone/meta_skill --skill building-glamorous-tuis

インストール後、Claude Code で/building-glamorous-tuisを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
advanced-patterns.md
component-catalog.md
go-tui.md
infrastructure.md
production-architecture.md
PROMPTS.md
QUICK-REFERENCE.md
shell-scripts.md

詳細

Charmbracelet で魅力的な TUI を構築する

クイックルーター — まずはこちら

やりたいこと使用するものリファレンス
シェルスクリプトにプロンプトやスピナーを追加するGum(Go 不要)シェルスクリプト
Go の TUI を構築するBubble Tea + Lip GlossGo TUI
本番環境向けの Go TUI を構築する上記 + 高度なパターン本番環境向けアーキテクチャ
SSH 経由で TUI を提供するWish + Bubble Teaインフラストラクチャ
ターミナルのデモを録画するVHSシェルスクリプト
Bubbles のコンポーネントを探すlist、table、viewport、spinner、progress...コンポーネントカタログ
コピーして使えるパターンを見つけるレイアウト、フォーム、アニメーション、テストクイックリファレンス / 高度なパターン

選択ガイド

Is it a shell script?
├─ Yes → Use Gum
│        Need recording? → VHS
│        Need AI? → Mods
│
└─ No (Go application)
   │
   ├─ Just styled output? → Lip Gloss only
   ├─ Simple prompts/forms? → Huh standalone
   ├─ Full interactive TUI? → Bubble Tea + Bubbles + Lip Gloss
   │  │
   │  └─ Production-grade?  → Also add elite patterns:
   │     (multi-view, data-    two-phase async, immutable snapshots,
   │      dense, must be       adaptive layout, focus state machine,
   │      fast & polished)     semantic theming, pre-computed styles
   │                           → See Production Architecture reference
   │
   └─ Need SSH access? → Wish + Bubble Tea

シェルスクリプト(Go 不要)

brew install gum  # One-time install
# Input
NAME=$(gum input --placeholder "Your name")

# Selection
COLOR=$(gum choose "red" "green" "blue")

# Fuzzy filter from stdin
BRANCH=$(git branch | gum filter)

# Confirmation
gum confirm "Continue?" && echo "yes"

# Spinner
gum spin --title "Working..." -- long-command

# Styled output
gum style --border rounded --padding "1 2" "Hello"

Gum の完全ガイド → VHS の録画 → Mods AI →


Go アプリケーション

go get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipgloss
最小限の TUI(コピーして実行)
package main

import (
    "fmt"
    tea "github.com/charmbracelet/bubbletea"
    "github.com/charmbracelet/lipgloss"
)

var highlight = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)

type model struct {
    items  []string
    cursor int
}

func (m model) Init() tea.Cmd { return nil }

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:
        switch msg.String() {
        case "q", "ctrl+c":
            return m, tea.Quit
        case "up", "k":
            if m.cursor > 0 { m.cursor-- }
        case "down", "j":
            if m.cursor < len(m.items)-1 { m.cursor++ }
        case "enter":
            fmt.Printf("Selected: %s\n", m.items[m.cursor])
            return m, tea.Quit
        }
    }
    return m, nil
}

func (m model) View() string {
    s := ""
    for i, item := range m.items {
        if i == m.cursor {
            s += highlight.Render("▸ "+item) + "\n"
        } else {
            s += "  " + item + "\n"
        }
    }
    return s + "\n(↑/↓ move, enter select, q quit)"
}

func main() {
    m := model{items: []string{"Option A", "Option B", "Option C"}}
    tea.NewProgram(m).Run()
}
ライブラリ早見表
必要なものライブラリ例
TUI フレームワークbubbleteatea.NewProgram(model).Run()
コンポーネントbubbleslist.New()、textinput.New()
スタイル設定lipglossstyle.Foreground(lipgloss.Color("212"))
フォームhuhhuh.NewInput().Title("Name").Run()
Markdownglamourglamour.Render(md, "dark")
アニメーションharmonicaharmonica.NewSpring()

Go TUI の完全ガイド → Bubbles の全コンポーネント → レイアウトとアニメーションのパターン →


SSH アプリケーション(インフラストラクチャ)

s, _ := wish.NewServer(
    wish.WithAddress(":2222"),
    wish.WithHostKeyPath(".ssh/key"),
    wish.WithMiddleware(
        bubbletea.Middleware(handler),
        logging.Middleware(),
    ),
)
s.ListenAndServe()

接続:ssh localhost -p 2222

インフラストラクチャの完全ガイド →


本番環境向け TUI アーキテクチャ(高度なパターン)

基本的な Bubble Tea の使い方にとどまらず、TUI を高速で洗練されたプロフェッショナルな仕上がりにするパターンを紹介します。 各項目から、本番環境向けアーキテクチャの完全なコード例に移動できます。

TUI の動作が遅い、またはカクつく
症状パターン対処法
計算中に UI がブロックされる2 フェーズ非同期処理フェーズ 1 は即時に実行し、フェーズ 2 はバックグラウンドの goroutine で実行
描画処理が mutex を保持する不変スナップショットスナップショットを事前に構築し、アトミックなポインター交換を行う
ファイルの変更でカクつくバックグラウンドワーカーデバウンス付きウォッチャー + イベントの集約
フレームごとに数千回のメモリ割り当てが発生するスタイルの事前計算起動時にデリゲートのスタイルを一度だけ割り当てる
View() で O(n²) の文字列連結が発生するstrings.BuilderGrow() を使って Builder の容量を事前に確保する
Glamour がフレームごとに再描画されるMarkdown のキャッシュコンテンツハッシュでキャッシュし、幅の変更時に無効化する
操作中に GC が一時停止するアイドル時間の GCアイドル時間に GC を実行する
大規模なデータセットでメモリ使用量が増えるオブジェクトプーリング事前割り当てしたスライスと sync.Pool を使う
画面外の項目まで描画されるビューポートの仮想化表示中の行のみ描画する
端末によってレイアウトが崩れます
症状パターン解決策
固定幅が崩れるアダプティブレイアウト3〜4 段階のレスポンシブブレークポイント(80/100/140/180 列)
明るい背景の端末で色がおかしいセマンティックなテーマ設定lipgloss.AdaptiveColor + WCAG AA のコントラスト
項目の優先度が同じで、リストの順序が変わる決定的な並べ替え第 2 キーで同順位を解決する安定ソート
ソートモードが見えない動的ステータスバー左右のセグメントと余白の自動補完
更新する項目がありません決定的な並べ替え第 2 キーで同順位を解決する安定ソート
TUI に複数のビューがあり、構成が複雑になっています
症状パターン解決策
キーのルーティングが混乱するフォーカス状態マシン明示的なフォーカス列挙型 + モーダルの優先レイヤー
ネストしたビューでユーザーが迷うパンくずナビゲーションHome > Board > Priority のパス表示
オーバーレイを閉じると位置が失われるフォーカスの復元オーバーレイ表示前にフォーカスを保存し、閉じる際に復元
古い非同期結果が新しいデータを上書きする古いメッセージの検出結果を適用する前にデータハッシュを比較
フレームごとに複数のコンポーネントを更新するtea.Batch の蓄積cmds をスライスに集め、tea.Batch(cmds...) を返す
バックグラウンドのゴルーチンでパニックが発生すると TUI が停止するエラーリカバリーすべてのゴルーチンに defer/recover ラッパーを適用
データ豊富な可視化を追加したい
要望パターンコード
リスト列に棒グラフを表示するUnicode スパークライン8 段階のブロック文字を使った ▇▅▂
強度に応じて色を付ける知覚ベースのヒートマップグレー → ブルー → パープル → ピンクのグラデーション
端末に依存関係グラフを表示するASCII グラフレンダラーキャンバス + マンハッタン配線(╭─╮│╰╯)
経過時間を一目で把握する経過時間のカラーコード化新しい=緑、経過中=黄、古い=赤
意味のある境界線を使うセマンティックな境界線赤=ブロック中、緑=準備完了、黄=影響大
TUIを洗練されたプロフェッショナルな見た目にしたい
要望パターン主なアイデア
Vim風のgg/GVimキーの組み合わせキー入力の間、waitingForG状態を追跡します
もたつかない検索デバウンス検索150msのタイマーを使い、入力が止まったときだけ実行します
すべてのフィールドを一度に検索複合FilterValueすべてのフィールドを1つの文字列にまとめます
メタデータ付きの4行カードリッチデリゲートHeight()=4のカスタムデリゲートを使います
詳細をインラインで展開インライン展開dで切り替え、j/kで自動的に折りたたみます
クリップボードにコピークリップボード連携IDはy、MarkdownはCでコピーし、トーストで通知します
?/`/;のヘルプマルチレベルヘルプクイックリファレンス+チュートリアル+常時表示のサイドバー
モード切り替え対応のカンバンカンバンのスイムレーンボードの状態を事前計算し、O(1)で切り替えます
h/lで操作する折りたたみ可能なツリーツリーナビゲーションツリーを表示項目のリストに平坦化し、j/kで移動します
vimで編集するためにTUIを一時停止エディターの起動ターミナルではtea.ExecProcess、GUIではバックグラウンド処理を使います
展開/折りたたみ状態を記憶永続化される状態JSONに保存し、破損時は適切にフォールバックします
環境変数で調整環境設定NO_COLOR、テーマ、デバウンス、分割比率
オプション機能が利用できない場合グレースフルデグラデーション起動時に検出し、利用できない機能を非表示にします

本番環境向けアーキテクチャガイド全文 →


事前チェックリスト(すべてのTUI)

  • tea.WindowSizeMsgを処理する — すべてのコンポーネントをリサイズします
  • ctrl+cを処理する — クリーンアップし、ターミナルの状態を復元します
  • パイプ接続されたstdin/stdoutを検出する — プレーンテキストにフォールバックします
  • 最小80×24のターミナルでテストします
  • --no-tui/NO_TUIの回避手段を用意します
  • ライト背景とダーク背景の両方でテストします
  • NO_COLOR=1およびTERM=dumbでテストします

本番環境向けTUIについては、完全なチェックリスト(必須項目16件+仕上げ項目20件)を参照してください。


Charmを使わない方がよい場合

  • 出力をパイプに渡す場合: mytool | grep → プレーンテキスト
  • CI/CDの場合: ターミナルがないため、フラグ/環境変数を使います
  • 単純なプロンプトが1つだけの場合: fmt.Scanfで十分かもしれません

回避手段:

if !term.IsTerminal(os.Stdin.Fd()) || os.Getenv("NO_TUI") != "" {
    runPlainMode()
    return
}

すべての参考資料

知りたいこと参照先
コピーして使えるワンライナークイックリファレンス
TUIタスク用にClaudeへ渡すプロンプトプロンプト
Gum/VHS/Mods/Freeze/Glowシェルスクリプト
Bubble Teaのアーキテクチャ、デバッグ、アンチパターンGo TUI
BubblesのコンポーネントAPI(list、table、viewportなど)コンポーネントカタログ
テーマ設定、レイアウト、アニメーション、Huhフォーム、テスト高度なパターン
高度なパターン:非同期処理、スナップショット、フォーカス制御、アダプティブレイアウト、スパークライン、カンバン、ツリー、キャッシュ本番環境向けアーキテクチャ
Wish SSHサーバー、Soft Serve、teatestインフラストラクチャ

コメント