SuperLightTUI

June 11, 2026 · View on GitHub

SuperLightTUI

書くのは速く。依存ツリーは軽量(直接の必須依存は 4 つ、デフォルト機能で解決後 25 クレート。ratatui + crossterm は 68)。

Crate Badge Docs Badge CI Badge MSRV Badge Downloads Badge License Badge

ドキュメント · クイックスタート · ウィジェットガイド · パターンガイド · サンプル集 · バックエンドガイド · アーキテクチャ

English · 中文 · Español · 日本語 · 한국어

SuperLightTUI は、公開される文法を意図的に小さく保った Rust 向けの immediate-mode TUI ライブラリです。 クロージャを 1 つ書けば、SLT が毎フレームそれを呼び出し、レイアウト、フォーカス、差分計算、レンダリングを処理します。

高速なプロダクト反復、読みやすい Rust 構文、そして真面目なバックエンド規律を両立するために設計されています。 そのため、ツールを素早く試作する人にも、ドキュメントから UI を生成するコーディングエージェントにも自然に合います。

ショーケース

Widget Demo
Widget Demo
cargo run --example demo
Dashboard
Dashboard
cargo run --example demo_dashboard
Website
Website Layout
cargo run --example demo_website
Spreadsheet
Spreadsheet
cargo run --example demo_spreadsheet
Games
Games
cargo run --example demo_game
DOOM Fire
DOOM Fire Effect
cargo run --release --example demo_fire
Pretext Reflow
Pretext Reflow — マウスカーソルの周りでテキストがリアルタイムに再配置されます
cargo run --example demo_pretext

クイックスタート

cargo add superlighttui
fn main() -> std::io::Result<()> {
    slt::run(|ui: &mut slt::Context| {
        ui.text("hello, world");
    })
}

5 行で始められます。App トレイトも、Model/Update/View も、手書きのイベントループも不要です。Ctrl+C もそのまま動作します。

60 秒でわかる文法

多くのアプリは次の 4 つから始まります。

  1. 状態は普通の Rust の変数や構造体に置く。
  2. レイアウトは主に row()col()container() で組む。
  3. スタイルはメソッドチェーンで付ける。
  4. インタラクティブなウィジェットはたいてい Response を返す。
ui.bordered(Border::Rounded).title("Status").p(1).gap(1).col(|ui| {
    ui.text("SLT").bold().fg(Color::Cyan);
    ui.row(|ui| {
        ui.text("mode:");
        ui.text("ready").fg(Color::Green);
        ui.spacer();
        if ui.button("Quit").clicked {
            ui.quit();
        }
    });
});

これが中核となる mental model です。残りは別フレームワークではなく、深さと拡張です。

実際のアプリ

use slt::{Border, Color, Context, KeyCode};

fn main() -> std::io::Result<()> {
    let mut count: i32 = 0;

    slt::run(|ui: &mut Context| {
        if ui.key('q') {
            ui.quit();
        }
        if ui.key('k') || ui.key_code(KeyCode::Up) {
            count += 1;
        }
        if ui.key('j') || ui.key_code(KeyCode::Down) {
            count -= 1;
        }

        ui.bordered(Border::Rounded).title("Counter").p(1).gap(1).col(|ui| {
            ui.text("Counter").bold().fg(Color::Cyan);
            ui.row(|ui| {
                ui.text("Count:");
                let color = if count >= 0 { Color::Green } else { Color::Red };
                ui.text(format!("{count}")).bold().fg(color);
            });
            ui.text("k +1 / j -1 / q quit").dim();
        });
    })
}

なぜ SLT か

  • 公開文法が小さい。多くの画面は普通の Rust の状態、row() / col() / container()、メソッドチェーン、Response で始められます。
  • フレームワークの儀式が少ない。動き始めるために app trait、retained tree、message enum を先に用意しなくてよいケースが多いです。
  • 部品は充実していて、バックエンドは真面目。共通ウィジェットが focus、hover、click、scroll を自動で結び付け、内部ランタイムは BackendAppStateframe() を通して保守的な低レベル経路を維持します。
  • 内部実装も保守的に固めています。shared frame kernel、明示的な backend contract test、zero unsafe、feature-gated runtime path、all-features/no-default-features/WASM/clippy/examples/cargo-hack/semver/deny の検証で品質を固定しています。

Rust ユーザーにとっては、retained-mode の TUI フレームワークより初期設定が少なくて済むことが多いです。 AI 支援ワークフローにとっては、ドキュメントとサンプルから公開文法を推測しやすいという意味でもあります。

SLT は、Rust の型安全性やバックエンドの escape hatch を保ったまま、ターミナルアプリを素早く作りたいときに特に向いています。 一方で、retained component tree を主軸にしたい場合や GUI-first のツールキットが欲しい場合は、別のライブラリのほうが適しているかもしれません。

レンダリングの仕組み

SLT のレンダリングパイプラインが、文法を小さく保てる理由です。 あなたのコードが触れるのは最初のステージだけ — 残りはエンジンが処理します。

graph LR
    subgraph your_code ["Your Code"]
        A["Closure"]
    end
    subgraph engine ["SLT Engine"]
        B[Commands] --> C[Build Tree] --> D[Flexbox] --> E[Collect] --> F[Render] --> G["Diff + Flush"]
    end
    A -->|"records intent"| B
    G -.->|"prev-frame feedback"| A

ui.*() の呼び出しはコマンドをフラットリストに記録するだけ — ツリー構築もレイアウト計算もしません。 エンジンがそれらのコマンドを4 ステージの DFS パイプラインに通します — 各ステージが専門化されています: レイアウトツリー構築、flexbox 計算、インタラクションとフィードバックデータの収集、バックバッファへのセル描画 — その後、前フレームとの diff を取り、変更分だけ flush します。

このアーキテクチャが文法をシンプルにできる理由です:

  • 儀式がありません。 Immediate-mode なので App トレイト、Model/Message/Update/View は不要です。クロージャが UI そのもの。状態は普通の Rust 変数、制御フローは if/for です。
  • レイアウトが見えません。 ui.col(|ui| { ... }) は「カラムを開く」コマンドを記録します。エンジンがツリーを構築し flexbox を実行 — LayoutNode は露出しません。
  • パフォーマンスが自動です。 ダブルバッファがフレーム間でセルを比較し、変更された ANSI 属性だけを出力します。毎フレーム全体を再描画しても、エンジンが高速に処理します。手動の dirty tracking は不要です。
  • インタラクションが自動接続されます。 ui.button("Save") だけで hover、click、focus が無料で得られます。collect ステージは 7 つの独立したサブ走査(ヒット領域、focus rect、スクロール領域、group rect、content rect、focus group、raw-draw rect)を 1 回の DFS に統合しました — そのため最上位パイプラインは 4 パスであり、10 パスではありません。
  • 同期的フィードバック。 インタラクションは前フレームのレイアウト位置を使います(60 FPS では知覚不可能)。コールバックも async レイアウトクエリも不要 — コードはリニアなままです。

完全な 8 ステージのライフサイクルは アーキテクチャ を参照してください。

よく使う API

// テキストとレイアウト
ui.text("Hello").bold().fg(Color::Cyan);
ui.row(|ui| {
    ui.text("left");
    ui.spacer();
    ui.text("right");
});

// 入力とアクション
ui.text_input(&mut name);
if ui.button("Save").clicked {}
ui.checkbox("Dark mode", &mut dark);

// データとナビゲーション
ui.tabs(&mut tabs);
ui.list(&mut items);
ui.table(&mut data);
ui.command_palette(&mut palette);

// オーバーレイとリッチ出力
ui.toast(&mut toasts);
ui.modal(|ui| {
    ui.text("Confirm?").bold();
});
ui.markdown("# Hello **world**");

// 可視化
ui.chart(|c| {
    c.line(&data);
    c.grid(true);
}, 50, 16);
ui.sparkline(&values, 16);
ui.canvas(40, 10, |cv| {
    cv.circle(20, 20, 15);
});

分類済みの一覧は ウィジェットガイド、組み合わせ方の考え方は パターンガイド を参照してください。

ライブラリを学ぶ

ドキュメント内容
ドキュメントドキュメント全体の構造とガイドマップ
クイックスタートインストール、最初のアプリ、クロージャの mental model、レイアウト、ウィジェット状態
ウィジェットガイドウィジェット、ランタイムメソッド、状態型の完全カタログ
パターンガイド状態配置、画面分割、ヘルパー抽出、大きなアプリの構造
サンプル集プロダクト形状や機能別に整理した実行可能サンプル
バックエンドガイドBackendAppStateframe()、inline mode、static output
テストガイドTestBackendEventBuilder、multi-frame test、backend contract test
デバッグガイドF12 オーバーレイ、clipping、focus の意外な挙動、previous-frame behavior
AIガイドAI ビルダーやコーディングエージェント向けの最短導線
アーキテクチャモジュールマップ、フレームライフサイクル、layout/render パイプライン
機能フラグガイドfeature flag、optional dependency、推奨組み合わせ
アニメーションガイドTween、spring、keyframe、sequence、stagger
テーマガイドTheme struct、preset、ThemeBuilder、カスタムテーマ
設計原則API の制約と設計哲学

代表的なサンプル

サンプルコマンド焦点
hellocargo run --example hello最小のアプリ
countercargo run --example counter状態 + キーボード入力
democargo run --example demo幅広いウィジェットツアー
demo_dashboardcargo run --example demo_dashboardダッシュボードレイアウト
demo_clicargo run --example demo_cliCLI ツールのレイアウト
demo_infovizcargo run --example demo_infovizチャートとデータ可視化
demo_gamecargo run --example demo_gameimmediate-mode のインタラクション
demo_design_systemcargo run --example demo_design_systemデザイントークン、テーマ、スタイル継承
inlinecargo run --example inline通常のプロンプトの下に inline 描画
async_democargo run --example async_demo --features asyncバックグラウンドメッセージ

分類済みの完全な一覧は サンプル集 にあります。

カスタムウィジェットとバックエンド

  • 再利用できる高レベルの部品が欲しいなら Widget を実装します。
  • ターミナル以外の描画先、外部イベントループ、組み込みランタイムが必要なら Backend を実装して frame() を駆動します。
  • ヘッドレスな描画確認と安定したインタラクションテストには TestBackend を使います。

escape hatch が必要になっても、公開文法は小さいままです。

コントリビューション

コントリビュート を読んだ後、設計原則アーキテクチャ を参照してください。 リリース工程では format、check、clippy、test、example、backend gate が通り続けることを前提にしています。

ライセンス

MIT