@sanohiro/casty 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +79 -102
- package/README.md +80 -103
- package/bin/casty.js +11 -2
- package/lib/browser.js +5 -9
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -1,48 +1,33 @@
|
|
|
1
1
|
# casty
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ターミナルで本物の Chrome ブラウザを動かす。
|
|
4
4
|
|
|
5
5
|
**[English](README.md)**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
casty は w3m や lynx のようなテキストブラウザではありません。ヘッドレス Chrome を起動し、CDP でレンダリング結果を取得して、Kitty graphics protocol でターミナルに描画します。Chrome のリモートデスクトップがターミナルに収まった感じです。
|
|
8
8
|
|
|
9
9
|
<video src="https://github.com/user-attachments/assets/552f1972-bb53-481e-9516-c36b7e5085d8" autoplay loop muted playsinline></video>
|
|
10
10
|
|
|
11
|
+
## 仕組み
|
|
12
|
+
|
|
11
13
|
```
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
│
|
|
15
|
-
│
|
|
16
|
-
│
|
|
17
|
-
|
|
14
|
+
ターミナル(あなた) casty Chrome(ヘッドレス)
|
|
15
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
16
|
+
│ Kitty │ ←── │ Screencast │ ←── │ 完全な Web │
|
|
17
|
+
│ graphics │ │ + 高解像度 │ │ レンダリング │
|
|
18
|
+
│ 画面表示 │ │ キャプチャ │ │ JS, CSS, │
|
|
19
|
+
│ │ ──→ │ 入力 │ ──→ │ Canvas, │
|
|
20
|
+
│ マウス/KB │ │ ブリッジ │ │ WebGL │
|
|
21
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- ヘッドレス Chrome によるフル Web レンダリング (生 CDP、Playwright 不使用)
|
|
23
|
-
- ボット検出回避のステルスパッチ (Google ログイン可能)
|
|
24
|
-
- Kitty graphics protocol による画像表示
|
|
25
|
-
- マウス操作 (クリック、スクロール、ドラッグ)
|
|
26
|
-
- キーボード入力を Chrome にパススルー
|
|
27
|
-
- Vimium 風ヒントモード (Alt+F) でキーボードナビゲーション
|
|
28
|
-
- アドレスバー + 検索 (Alt+L)
|
|
29
|
-
- ブックマーク (アドレスバーで `/b` 検索)
|
|
30
|
-
- テキスト選択コピー / クリップボードペースト
|
|
31
|
-
- ターミナルのフォントサイズに基づく自動ズーム
|
|
32
|
-
- 動的リサイズ (SIGWINCH)
|
|
33
|
-
- キーバインド設定 (`~/.casty/keys.json`)
|
|
34
|
-
- 各種設定 (`~/.casty/config.json`)
|
|
35
|
-
- ファイルダウンロード (`~/Downloads/` に保存)
|
|
36
|
-
- ローディングインジケーター
|
|
37
|
-
- プロファイル自動クリーンアップによる高速起動
|
|
38
|
-
|
|
39
|
-
## 必要環境
|
|
40
|
-
|
|
41
|
-
- **Kitty graphics protocol** 対応ターミナル
|
|
42
|
-
- Node.js >= 18
|
|
43
|
-
- `unzip`(Chrome Headless Shell の自動インストールに必要)
|
|
24
|
+
レンダリングはすべて Chrome がやります。casty はフレームをターミナルに流して入力を返すだけのブリッジ(約1200行)。Playwright も puppeteer も使わず、WebSocket で生 CDP を叩いています。
|
|
44
25
|
|
|
45
|
-
|
|
26
|
+
本物の Chrome なので JavaScript, CSS, Canvas, WebGL 全部動きます。ステルスパッチで Google ログインも通ります。マウスのクリック、スクロール、ドラッグ、キーボード入力 — 普通のブラウザと同じ操作ができます。
|
|
27
|
+
|
|
28
|
+
## どういうときに使う?
|
|
29
|
+
|
|
30
|
+
SSH でヘッドレスサーバーに入っていて Web ページを確認したいとき、普通は `curl` か `lynx` か X11 転送しかない。casty ならターミナルを離れずに本物のブラウザが使えます。X11 も VNC も Wayland もいらない。Kitty 対応ターミナルさえあれば OK。
|
|
46
31
|
|
|
47
32
|
## インストール
|
|
48
33
|
|
|
@@ -51,83 +36,65 @@ npm install -g @sanohiro/casty
|
|
|
51
36
|
casty
|
|
52
37
|
```
|
|
53
38
|
|
|
54
|
-
|
|
39
|
+
ソースから:
|
|
55
40
|
|
|
56
41
|
```bash
|
|
57
42
|
git clone https://github.com/sanohiro/casty.git
|
|
58
|
-
cd casty
|
|
59
|
-
npm install
|
|
43
|
+
cd casty && npm install
|
|
60
44
|
./bin/casty
|
|
61
45
|
```
|
|
62
46
|
|
|
63
|
-
初回起動時に Chrome Headless Shell が `~/.casty/browsers/`
|
|
47
|
+
初回起動時に Chrome Headless Shell が `~/.casty/browsers/` に自動インストールされます。
|
|
48
|
+
|
|
49
|
+
### 必要環境
|
|
50
|
+
|
|
51
|
+
- **Kitty graphics protocol** 対応ターミナル(動作確認済み: Ghostty, kitty, bcon)
|
|
52
|
+
- Node.js >= 18
|
|
53
|
+
- `unzip`(Chrome 自動インストールに必要)
|
|
64
54
|
|
|
65
55
|
## 使い方
|
|
66
56
|
|
|
67
57
|
```bash
|
|
68
58
|
casty https://google.com
|
|
69
59
|
casty https://youtube.com
|
|
70
|
-
casty # ホームページを開く
|
|
60
|
+
casty # ホームページを開く
|
|
71
61
|
```
|
|
72
62
|
|
|
73
63
|
### キーバインド
|
|
74
64
|
|
|
75
65
|
| キー | アクション |
|
|
76
66
|
|------|-----------|
|
|
77
|
-
| Alt+L |
|
|
78
|
-
| Alt+F |
|
|
79
|
-
| Alt+Left | 戻る |
|
|
80
|
-
| Alt+Right | 進む |
|
|
67
|
+
| Alt+L | アドレスバー |
|
|
68
|
+
| Alt+F | ヒントモード(Vimium 風) |
|
|
69
|
+
| Alt+Left / Right | 戻る / 進む |
|
|
81
70
|
| Alt+C | 選択テキストをコピー |
|
|
82
|
-
| Ctrl+V |
|
|
71
|
+
| Ctrl+V | ペースト |
|
|
83
72
|
| Ctrl+Q | 終了 |
|
|
84
|
-
| Ctrl+C | 終了 (フォールバック) |
|
|
85
|
-
|
|
86
|
-
`~/.casty/keys.json` でカスタマイズ可能 (ファイルは自動生成されません):
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{
|
|
90
|
-
"ctrl+q": "quit",
|
|
91
|
-
"alt+left": "back",
|
|
92
|
-
"alt+right": "forward",
|
|
93
|
-
"alt+l": "url_bar",
|
|
94
|
-
"alt+f": "hints",
|
|
95
|
-
"alt+c": "copy",
|
|
96
|
-
"ctrl+v": "paste"
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
73
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- **Alt+L** または1行目クリックでフォーカス — URL が全選択状態になる
|
|
103
|
-
- **Enter** で移動 (URL) または検索 (Google)
|
|
104
|
-
- **`/b クエリ`** でブックマーク検索
|
|
105
|
-
- **Escape** でキャンセル
|
|
106
|
-
- **Ctrl+A** 全選択、**Ctrl+U** 全消去、**Ctrl+W** 単語削除
|
|
74
|
+
`~/.casty/keys.json` でカスタマイズ可能。
|
|
107
75
|
|
|
108
76
|
### ヒントモード
|
|
109
77
|
|
|
110
|
-
**Alt+F**
|
|
78
|
+
**Alt+F** でクリック可能な要素にラベルを表示。ラベルを入力してクリック。ホームロウキー (`a s d f j k l`) を使用。
|
|
111
79
|
|
|
112
|
-
|
|
80
|
+
### アドレスバー
|
|
81
|
+
|
|
82
|
+
**Alt+L** で開く。URL または検索クエリを入力。`/b クエリ` でブックマーク検索。
|
|
113
83
|
|
|
114
84
|
### ブックマーク
|
|
115
85
|
|
|
116
|
-
`~/.casty/bookmarks.json`
|
|
86
|
+
`~/.casty/bookmarks.json` を作成:
|
|
117
87
|
|
|
118
88
|
```json
|
|
119
89
|
{
|
|
120
90
|
"GitHub": "https://github.com",
|
|
121
|
-
"Google": "https://google.com",
|
|
122
91
|
"YouTube": "https://youtube.com"
|
|
123
92
|
}
|
|
124
93
|
```
|
|
125
94
|
|
|
126
|
-
アドレスバーで `/b クエリ` と入力して検索 (名前・URL の部分一致、大文字小文字無視)。
|
|
127
|
-
|
|
128
95
|
### 設定
|
|
129
96
|
|
|
130
|
-
`~/.casty/config.json
|
|
97
|
+
`~/.casty/config.json`:
|
|
131
98
|
|
|
132
99
|
```json
|
|
133
100
|
{
|
|
@@ -141,40 +108,50 @@ casty # ホームページを開く (デフォルト: casty GitHub ページ)
|
|
|
141
108
|
|
|
142
109
|
| キー | 説明 | デフォルト |
|
|
143
110
|
|------|------|-----------|
|
|
144
|
-
| `homeUrl` |
|
|
145
|
-
| `searchUrl` | 検索エンジン URL
|
|
146
|
-
| `transport` |
|
|
147
|
-
| `format` |
|
|
148
|
-
| `mouseMode` |
|
|
149
|
-
|
|
150
|
-
##
|
|
111
|
+
| `homeUrl` | スタートページ | `https://github.com/sanohiro/casty` |
|
|
112
|
+
| `searchUrl` | 検索エンジン URL | `https://www.google.com/search?q=` |
|
|
113
|
+
| `transport` | 画像転送方式: `auto`, `file`, `inline` | `auto` (bcon/kitty→file、他→inline) |
|
|
114
|
+
| `format` | キャプチャ形式: `auto`, `png`, `jpeg` | `auto` (file→jpeg adaptive、inline→png) |
|
|
115
|
+
| `mouseMode` | `1002` (ボタンイベント) or `1003` (全イベント) | 自動 (Ghostty→1003、他→1002) |
|
|
116
|
+
|
|
117
|
+
## 比較
|
|
118
|
+
|
|
119
|
+
| | casty | Browsh | w3m/lynx |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| エンジン | Chrome | Firefox | 独自パーサー |
|
|
122
|
+
| 描画 | ピクセルそのまま | テキスト近似 | テキストのみ |
|
|
123
|
+
| JavaScript | 動く | 動く | 動かない |
|
|
124
|
+
| 表示方式 | Kitty graphics | 文字セル | 文字セル |
|
|
125
|
+
| 依存 | Node.js + Chrome | Go + Firefox | 単体 |
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary>技術詳細</summary>
|
|
129
|
+
|
|
130
|
+
全体で約1200行の JavaScript です。中でやっていること:
|
|
131
|
+
|
|
132
|
+
- chrome-headless-shell を起動して生 CDP WebSocket で通信
|
|
133
|
+
- `Runtime.enable` は絶対に送らない(Google ログインが壊れる。これは苦労して発見した)
|
|
134
|
+
- ステルスパッチは `Page.addScriptToEvaluateOnNewDocument` でページロード前に注入
|
|
135
|
+
- フレーム取得はハイブリッド方式: 低解像度 Screencast で変更を検知して、`Page.captureScreenshot` で DPR 対応の高解像度フレームを取得
|
|
136
|
+
- ファイル転送モードでは JPEG→PNG のアダプティブ切替: スクロール中や動画再生中は高速な JPEG、止まったら鮮明な PNG
|
|
137
|
+
- CSI 14t でターミナルのピクセルサイズを取得して自動ズーム
|
|
151
138
|
|
|
152
139
|
```
|
|
153
|
-
bin/
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
lib/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
keys.js # キーバインド設定
|
|
166
|
-
config.js # ユーザー設定
|
|
140
|
+
bin/casty シェルラッパー(Chrome インストール/更新)
|
|
141
|
+
bin/casty.js エントリポイント(ターミナル、ズーム、リサイズ)
|
|
142
|
+
lib/browser.js CDP ブラウザ制御、フレームキャプチャ
|
|
143
|
+
lib/cdp.js 軽量 CDP WebSocket クライアント
|
|
144
|
+
lib/chrome.js Chrome 検出、起動、プロファイルクリーンアップ
|
|
145
|
+
lib/kitty.js Kitty graphics protocol(file/inline)
|
|
146
|
+
lib/input.js マウス/キーボード処理
|
|
147
|
+
lib/hints.js Vimium 風ヒントモード
|
|
148
|
+
lib/urlbar.js アドレス/検索バー
|
|
149
|
+
lib/config.js ユーザー設定
|
|
150
|
+
lib/keys.js キーバインド設定
|
|
151
|
+
lib/bookmarks.js ブックマーク検索
|
|
167
152
|
```
|
|
168
153
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
1. 生 CDP で Chrome Headless Shell を起動 (Playwright 不使用、`Runtime.enable` も送信しない)
|
|
172
|
-
2. ページロード前にステルスパッチを注入してボット検出を回避
|
|
173
|
-
3. ハイブリッドフレーム取得: 低解像度 Screencast を変更検知トリガーとして使い、`Page.captureScreenshot` で高解像度フレームを取得
|
|
174
|
-
4. Kitty graphics protocol でフレームをターミナルに描画
|
|
175
|
-
5. ターミナル入力 (raw mode) をキャプチャし、CDP 経由で Chrome に送信
|
|
176
|
-
6. CSI 14t でターミナルのピクセルサイズを自動検出し、ズームを計算
|
|
177
|
-
7. 起動時にプロファイルをクリーンアップ (Cookie/LocalStorage を保持、キャッシュ類を削除) して高速起動を維持
|
|
154
|
+
</details>
|
|
178
155
|
|
|
179
156
|
## ライセンス
|
|
180
157
|
|
package/README.md
CHANGED
|
@@ -1,48 +1,33 @@
|
|
|
1
1
|
# casty
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Run a real Chrome browser inside your terminal.
|
|
4
4
|
|
|
5
|
-
**[
|
|
5
|
+
**[Japanese](README.ja.md)**
|
|
6
6
|
|
|
7
|
-
casty
|
|
7
|
+
casty is not a text-mode browser like w3m or lynx. It launches headless Chrome, grabs the rendered frames over CDP, and draws them in your terminal via Kitty graphics protocol. Think of it as a remote desktop for Chrome that fits in a terminal window.
|
|
8
8
|
|
|
9
9
|
<video src="https://github.com/user-attachments/assets/552f1972-bb53-481e-9516-c36b7e5085d8" autoplay loop muted playsinline></video>
|
|
10
10
|
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
11
13
|
```
|
|
12
|
-
Chrome (
|
|
13
|
-
|
|
14
|
-
│
|
|
15
|
-
│
|
|
16
|
-
│
|
|
17
|
-
|
|
14
|
+
Terminal (you) casty Chrome (headless)
|
|
15
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
16
|
+
│ Kitty │ ←── │ Screencast │ ←── │ Full web │
|
|
17
|
+
│ graphics │ │ + hi-res │ │ rendering │
|
|
18
|
+
│ display │ │ capture │ │ JS, CSS, │
|
|
19
|
+
│ │ ──→ │ Input │ ──→ │ Canvas, │
|
|
20
|
+
│ Mouse/KB │ │ bridge │ │ WebGL │
|
|
21
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- Full web rendering via headless Chrome (raw CDP, no Playwright)
|
|
23
|
-
- Stealth patches to avoid bot detection (Google login works)
|
|
24
|
-
- Kitty graphics protocol for image display
|
|
25
|
-
- Mouse support (click, scroll, drag)
|
|
26
|
-
- Keyboard passthrough to Chrome
|
|
27
|
-
- Vimium-style hint mode (Alt+F) for keyboard navigation
|
|
28
|
-
- Address bar with search (Alt+L)
|
|
29
|
-
- Bookmarks (`/b` search in address bar)
|
|
30
|
-
- Copy selected text / paste from clipboard
|
|
31
|
-
- Auto-zoom based on terminal font size
|
|
32
|
-
- Dynamic resize (SIGWINCH)
|
|
33
|
-
- Configurable keybindings (`~/.casty/keys.json`)
|
|
34
|
-
- Configurable settings (`~/.casty/config.json`)
|
|
35
|
-
- File downloads to `~/Downloads/`
|
|
36
|
-
- Loading indicator
|
|
37
|
-
- Fast startup with automatic profile cleanup
|
|
38
|
-
|
|
39
|
-
## Requirements
|
|
40
|
-
|
|
41
|
-
- **Kitty graphics protocol** compatible terminal
|
|
42
|
-
- Node.js >= 18
|
|
43
|
-
- `unzip` (for auto-installing Chrome Headless Shell)
|
|
24
|
+
Chrome does all the rendering. casty is just a bridge (~1200 lines) that streams frames to your terminal and sends input back. No Playwright, no puppeteer — raw CDP over WebSocket.
|
|
44
25
|
|
|
45
|
-
|
|
26
|
+
Since it's real Chrome, JavaScript, CSS, Canvas, and WebGL all work. Google login works too (stealth patches bypass bot detection). Mouse clicks, scrolling, dragging, typing — everything you'd expect.
|
|
27
|
+
|
|
28
|
+
## Why use this?
|
|
29
|
+
|
|
30
|
+
If you're working over SSH on a headless server and need to check a web page, your options are usually `curl`, `lynx`, or forwarding X11. casty gives you an actual browser without leaving the terminal. No X11, no VNC, no Wayland — just a Kitty-compatible terminal.
|
|
46
31
|
|
|
47
32
|
## Installation
|
|
48
33
|
|
|
@@ -51,83 +36,65 @@ npm install -g @sanohiro/casty
|
|
|
51
36
|
casty
|
|
52
37
|
```
|
|
53
38
|
|
|
54
|
-
Or
|
|
39
|
+
Or from source:
|
|
55
40
|
|
|
56
41
|
```bash
|
|
57
42
|
git clone https://github.com/sanohiro/casty.git
|
|
58
|
-
cd casty
|
|
59
|
-
npm install
|
|
43
|
+
cd casty && npm install
|
|
60
44
|
./bin/casty
|
|
61
45
|
```
|
|
62
46
|
|
|
63
|
-
Chrome Headless Shell is
|
|
47
|
+
Chrome Headless Shell is auto-installed to `~/.casty/browsers/` on first run.
|
|
48
|
+
|
|
49
|
+
### Requirements
|
|
50
|
+
|
|
51
|
+
- A terminal with **Kitty graphics protocol** support (tested on Ghostty, kitty, bcon)
|
|
52
|
+
- Node.js >= 18
|
|
53
|
+
- `unzip` (for Chrome auto-install)
|
|
64
54
|
|
|
65
55
|
## Usage
|
|
66
56
|
|
|
67
57
|
```bash
|
|
68
58
|
casty https://google.com
|
|
69
59
|
casty https://youtube.com
|
|
70
|
-
casty # opens home page
|
|
60
|
+
casty # opens home page
|
|
71
61
|
```
|
|
72
62
|
|
|
73
63
|
### Keybindings
|
|
74
64
|
|
|
75
65
|
| Key | Action |
|
|
76
66
|
|-----|--------|
|
|
77
|
-
| Alt+L |
|
|
78
|
-
| Alt+F | Hint mode (Vimium-style
|
|
79
|
-
| Alt+Left | Back |
|
|
80
|
-
| Alt+Right | Forward |
|
|
67
|
+
| Alt+L | Address bar |
|
|
68
|
+
| Alt+F | Hint mode (Vimium-style) |
|
|
69
|
+
| Alt+Left / Right | Back / Forward |
|
|
81
70
|
| Alt+C | Copy selected text |
|
|
82
|
-
| Ctrl+V | Paste
|
|
71
|
+
| Ctrl+V | Paste |
|
|
83
72
|
| Ctrl+Q | Quit |
|
|
84
|
-
| Ctrl+C | Quit (fallback) |
|
|
85
|
-
|
|
86
|
-
Customize via `~/.casty/keys.json` (file is not created automatically):
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{
|
|
90
|
-
"ctrl+q": "quit",
|
|
91
|
-
"alt+left": "back",
|
|
92
|
-
"alt+right": "forward",
|
|
93
|
-
"alt+l": "url_bar",
|
|
94
|
-
"alt+f": "hints",
|
|
95
|
-
"alt+c": "copy",
|
|
96
|
-
"ctrl+v": "paste"
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
73
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- **Alt+L** or click row 1 to focus — URL is selected, type to replace
|
|
103
|
-
- **Enter** to navigate (URLs) or search (Google)
|
|
104
|
-
- **`/b query`** to search bookmarks
|
|
105
|
-
- **Escape** to cancel
|
|
106
|
-
- **Ctrl+A** select all, **Ctrl+U** clear, **Ctrl+W** delete word
|
|
74
|
+
Customizable via `~/.casty/keys.json`.
|
|
107
75
|
|
|
108
76
|
### Hint Mode
|
|
109
77
|
|
|
110
|
-
|
|
78
|
+
**Alt+F** shows labels on clickable elements. Type the label to click. Labels use home-row keys (`a s d f j k l`).
|
|
111
79
|
|
|
112
|
-
|
|
80
|
+
### Address Bar
|
|
81
|
+
|
|
82
|
+
**Alt+L** to open. Type a URL or search query. `/b query` searches bookmarks.
|
|
113
83
|
|
|
114
84
|
### Bookmarks
|
|
115
85
|
|
|
116
|
-
Create `~/.casty/bookmarks.json
|
|
86
|
+
Create `~/.casty/bookmarks.json`:
|
|
117
87
|
|
|
118
88
|
```json
|
|
119
89
|
{
|
|
120
90
|
"GitHub": "https://github.com",
|
|
121
|
-
"Google": "https://google.com",
|
|
122
91
|
"YouTube": "https://youtube.com"
|
|
123
92
|
}
|
|
124
93
|
```
|
|
125
94
|
|
|
126
|
-
Search from the address bar with `/b query` (matches name or URL, case-insensitive).
|
|
127
|
-
|
|
128
95
|
### Configuration
|
|
129
96
|
|
|
130
|
-
|
|
97
|
+
`~/.casty/config.json`:
|
|
131
98
|
|
|
132
99
|
```json
|
|
133
100
|
{
|
|
@@ -141,40 +108,50 @@ Customize via `~/.casty/config.json` (file is not created automatically):
|
|
|
141
108
|
|
|
142
109
|
| Key | Description | Default |
|
|
143
110
|
|-----|-------------|---------|
|
|
144
|
-
| `homeUrl` |
|
|
145
|
-
| `searchUrl` | Search engine URL
|
|
146
|
-
| `transport` |
|
|
147
|
-
| `format` |
|
|
148
|
-
| `mouseMode` |
|
|
149
|
-
|
|
150
|
-
##
|
|
111
|
+
| `homeUrl` | Start page | `https://github.com/sanohiro/casty` |
|
|
112
|
+
| `searchUrl` | Search engine URL | `https://www.google.com/search?q=` |
|
|
113
|
+
| `transport` | Image transfer: `auto`, `file`, `inline` | `auto` (bcon/kitty→file, others→inline) |
|
|
114
|
+
| `format` | Capture format: `auto`, `png`, `jpeg` | `auto` (file→jpeg adaptive, inline→png) |
|
|
115
|
+
| `mouseMode` | `1002` (button-event) or `1003` (any-event) | Auto (Ghostty→1003, others→1002) |
|
|
116
|
+
|
|
117
|
+
## Comparison
|
|
118
|
+
|
|
119
|
+
| | casty | Browsh | w3m/lynx |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| Engine | Chrome | Firefox | Custom parser |
|
|
122
|
+
| Rendering | Pixel-perfect | Text approximation | Text only |
|
|
123
|
+
| JavaScript | Yes | Yes | No |
|
|
124
|
+
| Display | Kitty graphics | Character cells | Character cells |
|
|
125
|
+
| Dependencies | Node.js + Chrome | Go + Firefox | Standalone |
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary>Technical Details</summary>
|
|
129
|
+
|
|
130
|
+
The whole thing is about 1200 lines of JavaScript. Here's what's going on under the hood:
|
|
131
|
+
|
|
132
|
+
- Launches chrome-headless-shell and talks to it via raw CDP WebSocket
|
|
133
|
+
- `Runtime.enable` is never sent (it breaks Google login — discovered the hard way)
|
|
134
|
+
- Stealth patches are injected via `Page.addScriptToEvaluateOnNewDocument` before any page loads
|
|
135
|
+
- Frame capture is hybrid: low-res Screencast triggers change detection, then `Page.captureScreenshot` grabs hi-res frames with proper DPR
|
|
136
|
+
- File transfer mode uses adaptive JPEG→PNG: fast JPEG during scrolling/video, crisp PNG after things settle
|
|
137
|
+
- Terminal pixel size is detected via CSI 14t for auto-zoom
|
|
151
138
|
|
|
152
139
|
```
|
|
153
|
-
bin/
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
lib/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
keys.js # Configurable keybindings
|
|
166
|
-
config.js # User configuration
|
|
140
|
+
bin/casty Shell wrapper (Chrome install/update)
|
|
141
|
+
bin/casty.js Entry point (terminal, zoom, resize)
|
|
142
|
+
lib/browser.js CDP browser control, frame capture
|
|
143
|
+
lib/cdp.js Lightweight CDP WebSocket client
|
|
144
|
+
lib/chrome.js Chrome detection, launch, profile cleanup
|
|
145
|
+
lib/kitty.js Kitty graphics protocol (file/inline)
|
|
146
|
+
lib/input.js Mouse/keyboard handling
|
|
147
|
+
lib/hints.js Vimium-style hint mode
|
|
148
|
+
lib/urlbar.js Address/search bar
|
|
149
|
+
lib/config.js User configuration
|
|
150
|
+
lib/keys.js Keybinding config
|
|
151
|
+
lib/bookmarks.js Bookmark search
|
|
167
152
|
```
|
|
168
153
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
1. Launches Chrome Headless Shell via raw CDP (no Playwright, no `Runtime.enable`)
|
|
172
|
-
2. Injects stealth patches before page load to avoid bot detection
|
|
173
|
-
3. Uses hybrid frame capture: low-res Screencast as change detection trigger, `Page.captureScreenshot` for high-res frames
|
|
174
|
-
4. Renders frames to terminal via Kitty graphics protocol
|
|
175
|
-
5. Captures terminal input (raw mode) and dispatches to Chrome via CDP
|
|
176
|
-
6. Auto-detects terminal pixel size (CSI 14t) for zoom calculation
|
|
177
|
-
7. Cleans up profile on startup (keeps cookies/storage, removes caches) for fast launch
|
|
154
|
+
</details>
|
|
178
155
|
|
|
179
156
|
## License
|
|
180
157
|
|
package/bin/casty.js
CHANGED
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
// casty - TTY web browser using raw CDP and Kitty graphics protocol
|
|
3
3
|
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { dirname, join } from 'node:path';
|
|
7
8
|
|
|
9
|
+
// --version / -v
|
|
10
|
+
if (process.argv[2] === '--version' || process.argv[2] === '-v') {
|
|
11
|
+
const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
|
|
12
|
+
console.log(`casty ${pkg.version}`);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
// Ensure Chrome is installed (skip if launched from bin/casty shell script)
|
|
9
17
|
if (!process.env.CASTY_ENSURE_CHROME) {
|
|
10
18
|
const __bin = dirname(fileURLToPath(import.meta.url));
|
|
@@ -149,10 +157,11 @@ async function main() {
|
|
|
149
157
|
|
|
150
158
|
// Frame callback for screencast / captureScreenshot
|
|
151
159
|
// sendFrame includes cursor positioning (single write)
|
|
160
|
+
let urlBar = null;
|
|
152
161
|
function onFrame(data) {
|
|
153
162
|
if (renderPaused) return;
|
|
154
163
|
sendFrame(data);
|
|
155
|
-
urlBar.renderIfDirty();
|
|
164
|
+
if (urlBar) urlBar.renderIfDirty();
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
// Phase 3: Start screencast
|
|
@@ -163,7 +172,7 @@ async function main() {
|
|
|
163
172
|
onFrame,
|
|
164
173
|
});
|
|
165
174
|
|
|
166
|
-
|
|
175
|
+
urlBar = startInputHandling(client, cssCellW, cssCellH, bindings, pauseRender, forceCapture);
|
|
167
176
|
urlBar.render();
|
|
168
177
|
|
|
169
178
|
// Force capture on page load events (debounced — multiple events fire close together)
|
package/lib/browser.js
CHANGED
|
@@ -11,10 +11,6 @@ const CHROME_VERSION = '145.0.7632.6';
|
|
|
11
11
|
const USER_AGENT = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROME_VERSION} Safari/537.36`;
|
|
12
12
|
const PROFILE_DIR = join(homedir(), '.casty', 'profile');
|
|
13
13
|
|
|
14
|
-
// WEBGL_debug_renderer_info extension constants
|
|
15
|
-
const GL_UNMASKED_VENDOR = 0x9245; // UNMASKED_VENDOR_WEBGL
|
|
16
|
-
const GL_UNMASKED_RENDERER = 0x9246; // UNMASKED_RENDERER_WEBGL
|
|
17
|
-
|
|
18
14
|
// Screencast settings (low-res stream for change detection)
|
|
19
15
|
const SCREENCAST_SCALE = 4; // Downscale factor (1/4 resolution)
|
|
20
16
|
const SCREENCAST_NTH_FRAME = 1; // Every frame (no decimation, faster change detection)
|
|
@@ -27,7 +23,6 @@ const CAPTURE_STUCK_RESET = 5000; // Reset stuck capturing flag (ms)
|
|
|
27
23
|
// lang: primary language (e.g. "ja", "en-US")
|
|
28
24
|
function buildStealthScript(lang) {
|
|
29
25
|
// Build Accept-Language style list: primary, then en-US/en fallbacks
|
|
30
|
-
const langBase = lang.split('-')[0]; // "ja", "en", "zh", etc.
|
|
31
26
|
const languages = [lang];
|
|
32
27
|
if (lang !== 'en-US' && lang !== 'en') {
|
|
33
28
|
languages.push('en-US', 'en');
|
|
@@ -118,10 +113,11 @@ function buildAcceptLanguage(lang) {
|
|
|
118
113
|
|
|
119
114
|
// HTTP GET → JSON (using global fetch)
|
|
120
115
|
async function fetchJson(url) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
try {
|
|
117
|
+
const res = await fetch(url);
|
|
118
|
+
if (!res.ok) return null;
|
|
119
|
+
return await res.json();
|
|
120
|
+
} catch { return null; }
|
|
125
121
|
}
|
|
126
122
|
|
|
127
123
|
// Phase 1: Launch Chrome only (no terminal info needed, for parallel execution)
|