Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ This repo uses `mise` to pin toolchains (see `mise.toml`).
- TypeScript (ESM) with strict type-checking (`tsconfig.json`).
- Prefer small, composable modules and re-export via `src/**/index.ts`.
- Use lowercase filenames; use `kebab-case` for multi-word files (e.g., `render-loop.ts`).
- Run `mise run test && mise run precommit` after any edit.
- Run `mise run format` before opening a PR; let `oxfmt` decide whitespace.
- This project targets Bun-native development; optimizing to remove Bun dependencies from the core package is not a goal.

## Testing Guidelines

Expand Down
2 changes: 2 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ await app.mount({ inline: true, inlineCleanupOnExit: true });

- [**ドキュメント**](./docs/) (アーキテクチャ, ロードマップ)
- [**Inline モード**](./docs/inline-mode.ja.md)
- [**DevTools**](./docs/devtools.ja.md)
- [**ホットリロード**](./docs/hot-reload.ja.md)
- [**GitHub**](https://github.com/HALQME/btuin) (ソースコード, Issue)

## 言語
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ await app.mount({ inline: true, inlineCleanupOnExit: true });

- [**Documentation**](./docs/) (Architecture, Roadmap)
- [**Inline Mode**](./docs/inline-mode.md)
- [**DevTools**](./docs/devtools.md)
- [**Hot Reload**](./docs/hot-reload.md)
- [**GitHub**](https://github.com/HALQME/btuin) (Source Code, Issues)

## Language
Expand Down
4 changes: 4 additions & 0 deletions bin/btuin
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bun
import { btuinCli } from "../src/cli/main";

await btuinCli(Bun.argv.slice(2));
65 changes: 65 additions & 0 deletions docs/devtools.ja.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# DevTools

btuin には、TUI 開発時にアプリを観測するための軽量なブラウザ UI があります。

## ブラウザ DevTools(おすすめ)

開発用ランナー(`btuin dev ...`)を使う場合、ブラウザ DevTools は自動で有効化されます(無効化は `--no-devtools`)。
また、DevTools の URL をブラウザで自動で開きます(無効化は `--no-open-browser`)。

表示された URL をブラウザで開くと、ログとスナップショットが確認できます。

スナップショットは **Preview**(レイアウトのボックス + テキスト)と **JSON**(生の payload)の両方で確認できます。

コードを変更したくない場合は、環境変数でも有効化できます:

- `BTUIN_DEVTOOLS=1`(有効化)
- `BTUIN_DEVTOOLS_HOST` / `BTUIN_DEVTOOLS_PORT`(任意)
- `BTUIN_DEVTOOLS_CONTROLLER`(任意 / controller の module spec/path)

# ホットリロード(開発用ランナー)

`btuin` の raw 入力処理はプロセス全体で共有されるシングルトンを使っています。そのため、プロセス内で “remount” を繰り返すような HMR(ホットモジュールリロード)的な実装をすると、キー入力ハンドラが積み上がって入力が二重に届くなどの問題が起きます。

そこで現状は、開発時のホットリロードは **プロセスを再起動する方式(dev runner)** を推奨します。変更検知で同じターミナル上で TUI を再実行するだけです。

## CLI

```bash
btuin dev <entry> [options] [-- <args...>]
```

例:

```bash
btuin dev examples/devtools.ts
btuin dev src/main.ts --watch src --watch examples
btuin dev src/main.ts -- --foo bar
```

主なオプション:

- `--watch <path>`(複数指定可)
- `--debounce <ms>`(デフォルト: `50`)
- `--cwd <path>`(デフォルト: `process.cwd()`)
- `--no-tcp`(TCP リロードトリガー無効化)
- `--tcp-host <host>`(デフォルト: `127.0.0.1`)
- `--tcp-port <port>`(デフォルト: `0`)

## TCPトリガ(任意)

`btuin dev` はデフォルトで TCP を有効化(ポートは自動選択)します。

別ターミナルからトリガ:

```bash
printf 'reload\n' | nc 127.0.0.1 <port>
```

JSONLでもOK:

```bash
printf '{"type":"reload"}\n' | nc 127.0.0.1 <port>
```

注意: ホットリロードは `btuin dev`(dev runner)が適用します。
65 changes: 65 additions & 0 deletions docs/devtools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# DevTools

btuin includes a lightweight browser UI for observing your app during TUI development.

## Browser DevTools (recommended)

If you use the dev runner (`btuin dev ...`), browser DevTools is auto-enabled (disable with `--no-devtools`).
The runner also auto-opens the DevTools URL in your browser (disable with `--no-open-browser`).

Open the printed URL in your browser. It shows logs and a snapshot stream.

The Snapshot view includes a simple **Preview** (layout boxes + text) and a **JSON** view (raw snapshot payload).

You can also enable it without code by setting env vars:

- `BTUIN_DEVTOOLS=1` (enable)
- `BTUIN_DEVTOOLS_HOST` / `BTUIN_DEVTOOLS_PORT` (optional)
- `BTUIN_DEVTOOLS_CONTROLLER` (optional; module spec/path for the controller)

# Hot Reload (Dev Runner)

`btuin` treats raw terminal input handling as a process-wide singleton. Because of that, doing a true in-process “remount” loop (HMR-style) would accumulate key handlers and lead to duplicated input events.

Instead, the recommended development workflow is to **restart the app process** on changes (hot reload as a dev runner). It simply re-runs your TUI in the same terminal.

## CLI

```bash
btuin dev <entry> [options] [-- <args...>]
```

Examples:

```bash
btuin dev examples/devtools.ts
btuin dev src/main.ts --watch src --watch examples
btuin dev src/main.ts -- --foo bar
```

Options:

- `--watch <path>` (repeatable)
- `--debounce <ms>` (default: `50`)
- `--cwd <path>` (default: `process.cwd()`)
- `--no-tcp` (disable TCP reload trigger)
- `--tcp-host <host>` (default: `127.0.0.1`)
- `--tcp-port <port>` (default: `0`)

## TCP Trigger (Optional)

`btuin dev` enables TCP by default (ephemeral port).

Trigger reload from another terminal:

```bash
printf 'reload\n' | nc 127.0.0.1 <port>
```

Or JSONL:

```bash
printf '{"type":"reload"}\n' | nc 127.0.0.1 <port>
```

Note: hot reload is applied by `btuin dev` (dev runner).
58 changes: 39 additions & 19 deletions docs/roadmap.ja.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
# ロードマップ

- [x] 入力
- [x] 入力パーサーをステートフル化(チャンク分割耐性): `src/terminal/parser/ansi.ts`
- [x] **入力**
- [x] 入力パーサーをステートフル化(チャンク分割耐性)
- [x] `ESC` 単体 vs `Alt+Key` の曖昧さを解消
- [x] ブラケットペーストを「1イベント」に正規化: `src/terminal/parser/ansi.ts`
- [x] ブラケットペーストを「1イベント」に正規化
- [x] ブラケットペーストの on/off をランタイムへ統合
- [ ] マウス
- [ ] マウス入力(SGR など)をランタイムへ統合(有効化/無効化・イベント形式の確定)
- [ ] **マウス**
- [ ] マウス入力(SGR など)をランタイムへ統合
- [ ] ヒットテスト(`ComputedLayout` と座標の照合、重なり順の決定)
- [ ] バブリング/伝播(子→親、キャンセル可能なイベントモデル)
- [ ] Developer Tools
- [ ] シェル統合
- [x] stdout/stderr capture 基盤(listener/console patch/テストモード): `src/terminal/capture.ts`
- [ ] `useLog`(capture → reactive state)でログUIを作る
- [ ] デバッグ
- [ ] インスペクターモード(境界線/座標/サイズ可視化)
- [ ] ホットリロード
- [ ] **Developer Tools**
- [x] シェル統合(stdout/stderr capture, `useLog`)
- [x] デバッグ基盤(インスペクターモード, ホットリロード)
- [ ] **レイアウトエンジンの詳細可視化**
- [x] Flexbox プロパティのインスペクト(`flex-grow`, `padding` 等の表示)
- [x] 計算済みボックスモデルのカラー表示(Margin/Padding の視覚化)
- [x] Z-Index / 階層構造の 3D 可視化
- [ ] **パフォーマンス・プロファイリング**
- [x] レンダリング・タイムライン(FFI境界・レイアウト計算・Diff生成の計測)
- [x] リアクティビティ・グラフ(どの Ref がどのコンポーネントを更新したかの可視化)
- [ ] **双方向デバッグ**
- [ ] ブラウザ側からのリアクティブ・ステート(Ref)の直接書き換え
- [ ] リモートキーイベント送信(ブラウザ仮想キーボードからの入力注入)
- [ ] **アーキテクチャ・最適化**
- [ ] **FFI通信の効率化**
- [ ] フルシリアライズの回避(Dirty Checking による部分的なレイアウト更新)
- [ ] **大規模描画サポート**
- [ ] 仮想ウィンドウ化(Virtual Scrolling)による数万行のリスト表示
- [ ] スクロールリージョン(DECSTBM)を活用した高速スクロール
- [ ] **リアクティビティの高度化**
- [ ] Effect Scope の導入(コンポーネントに紐付いた Effect の自動追跡・破棄)
- [ ] **開発体験 (DX) / 大規模開発サポート**
- [ ] **状態共有パターン**
- [ ] `Provide/Inject` または `Context API` 相当の依存注入機能
- [ ] **安全性・堅牢性**
- [x] FFI 境界の同期テスト
- [ ] 致命的エラー時のセーフティネット(パニック時の Raw Mode 強制解除)
- [ ] **AI・アクセシビリティ**
- [ ] セマンティック・メタデータのサポート(AIエージェントや将来のA11y支援用)
- [ ] コンポーネント
- [ ] `TextInput` を実用レベルへ(編集・カーソル移動・IME)
- [ ] `ScrollView` / `ListView`(仮想スクロール、マウスホイール連動)
- [x] 配布
- [x] GitHub Release 用 tarball 生成(`src/layout-engine/native/` 同梱): `.github/workflows/release.yml`
- [x] `npm pack` の成果物を展開し、`src/layout-engine/native/` と `src/layout-engine/index.ts` の解決が噛み合うことを自動チェック
- [x] GitHub Release 用 tarball 生成
- [x] npm pack 成果物の整合性チェック
- [x] Inline モード
- [ ] コンポーネント
- [ ] `TextInput` を実用レベルへ(編集・カーソル移動・IME確定後の反映)
- [ ] `ScrollView` / `ListView`(必要に応じて仮想スクロール、マウスホイール連動)
- [x] 安全性
- [x] FFI 境界の同期テスト(Rust 定数/構造体 ↔ JS 定義)を CI に追加
- [ ] ドキュメント / スターター
- [ ] `examples/` の拡充
29 changes: 0 additions & 29 deletions docs/roadmap.md

This file was deleted.

7 changes: 2 additions & 5 deletions examples/counter.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { createApp, ref, watchEffect } from "@/index";
import { createApp, ref } from "@/index";
import { Text, VStack } from "@/view";

const app = createApp({
init({ onKey, setExitOutput, runtime }) {
const count = ref(0);
onKey((k) => {
setExitOutput(count.value.toString());
if (k.name === "up") count.value++;
if (k.name === "down") count.value--;
if (k.name === "q") runtime.exit(0);
});

watchEffect(() => {
setExitOutput(count.value.toString());
});

return { count };
},
render({ count }) {
Expand Down
Loading