- ターミナルアプリはテキストベースなので本質的にアクセシブルだという前提は、現代の TUI では崩れており、Ink、Bubble Tea、tcell のようなフレームワークがスクリーンリーダー利用者にとって、より敵対的な環境を作りうる
- CLI は
stdin/stdout の線形ストリームとして出力が時系列に積み上がるが、TUI はターミナルを文字セルベースの 2D グリッド として扱うため、スクリーンリーダーが流れを追いにくくなる
gemini-cli では、Ink が React コンポーネントツリーをターミナルのグリッドに合わせて再描画しながら、スピナー・タイマー・会話履歴の間でカーソルを移動させることで、Speakup や NVDA に反復読み上げ、クラッシュ、入力遅延を引き起こしうる
nano、vim、menuconfig、Irssi のような古いツールは、カーソル非表示、単一列フォーカス、VT100 の スクロール領域 活用によって座標更新ノイズを減らし、入力行との干渉を最小化している
- アクセシブルなターミナルツールを作るには、ターミナルをキャンバスのように扱う宣言的 UI フレームワークや攻撃的な再描画を避け、単純で線形的な CLI ストリームに近い動作を保証する必要がある
「テキストだからアクセシブルだ」という誤解
- ターミナルで動作するアプリケーションが本質的にアクセシブルだという前提は、実際の利用環境とは一致しない
- グラフィック、複雑な DOM、WebGL キャンバスがないため、スクリーンリーダーが生の ASCII テキストを簡単に解釈できるという期待は、現代の TUI では崩れている
- Ink(JS/React)、Bubble Tea(Go)、tcell のようなターミナル UI フレームワークは、開発者体験(DX)の改善を目指しているが、視覚障害者にとってはより敵対的な環境を作ることがある
- 実装の悪いグラフィカルインターフェースよりも、現代の TUI のほうがアクセシビリティの面で悪い場合が多い
CLI と TUI の構造的な違い
-
CLI: 線形ストリーム
- CLI は
stdin/stdout ベースで動作し、コマンドを入力すると結果が下に追加され、カーソルが下がる
- 出力が線形で時系列に積み上がるため、Speakup のようなカーネルレベルのスクリーンリーダーに適している
-
TUI: 2D グリッド
- TUI はターミナルウィンドウをテキストストリームではなく、各文字セルがピクセルのように使われる 2D グリッドとして扱う
- 時間的な流れを捨てて空間的レイアウトを優先することで、スクリーンリーダーが追いにくい構造になる
gemini-cli で明らかになる問題
gemini-cli は Node.js と Ink フレームワークで書かれたツールであり、表面的には単純なチャットインターフェースに見える
- 内部では Ink が React コンポーネントツリーをターミナルのグリッドに合わせて調整しようとしている
- Speakup(Linux) や NVDA(Windows) で使うと、アプリケーションが単に失敗するレベルにとどまらず、スクリーンリーダーに読み上げる内容を絶えず流し込み続ける
-
レスポンシブなキャンバスのように振る舞う画面
- フレームワークが画面をレスポンシブなキャンバスとして扱うため、あらゆる更新が再描画を引き起こす
- AI が「考え中」のとき、タイマーやスピナーを更新するためにハードウェアカーソルをタイマー位置へ移動し、新しい時刻を書き込み、再び元の位置へ戻す
- 視覚ユーザーには一瞬で過ぎる動作だが、スクリーンリーダー利用者には「Responding... Time elapsed 1s... Responding... Time elapsed 2s...」のように繰り返し聞こえる
- カーソルがステータス表示、スピナー、会話履歴の間を瞬間的に移動するたび、Speakup はその瞬間にカーソル下にある内容を読み上げようとする
- その結果、タイマー更新と会話の断片が混ざって聞こえ、実際に入力している内容に集中しにくくなる
-
NVDA と貼り付け時に発生する不安定さ
- Windows で NVDA を使ってターミナルを開き、Linux マシンに SSH 接続したうえで
screen セッションに入り、テキストを貼り付けると、NVDA が即座にクラッシュしたり、システム全体が大きく不安定になったりすることがある
- 文字を入力したりテキストを貼り付けたりするたびにアプリケーション状態が変わり、フレームワークはインターフェースを再レンダリングすべきだと判断する
- 会話履歴が状態に含まれていると、数千行のテキストレイアウトを即座に再描画または再計算しようとする
- 会話メッセージが多いほど、この問題はより頻繁に発生する
- 動的コンテンツ通知を避けるための
Insert+5 の組み合わせでも、この問題は回避できない
-
入力遅延ループ
- Ink のようなフレームワークが Node.js のようなシングルスレッド環境で動作すると、履歴が大きくなるほど性能低下が大きくなる
- 大きなテキストブロックを貼り付けると、数千行分の差分を計算する必要がある
- システムは画面をどう再描画するかの計算に追われ、入力処理が遅れる
- キーを 1 回押しても、文字が再表示されるまで最大 10 秒 待たされることがある
古いツールが動作する理由
nano、vim、menuconfig のようなツールが、常にアクセシビリティに完璧だから使われているわけではない
- 重要なのは、これらのツールがカーソルを完全に隠したり、カーソル位置追跡によって生じるノイズを減らしたりできる点にある
-
nano と vim: カーソルを隠す
nano を --constantshow のようなカーソル位置表示オプション付きで実行したり、vim を特定の設定なしで使ったりすると、使い勝手が壊れることがある
- カーソルが見えており追跡が有効になると、Speakup は文字エコーよりもカーソル位置更新を優先する
- ユーザーが「a」を入力すると「a」ではなく「Column 2」が聞こえ、「b」を入力すると「Column 3」が聞こえる
- これらの古いツールは、視覚カーソルやステータスバー更新を抑制するよう設定できるため、スクリーンリーダーが座標更新ではなく文字入力ストリームに依存できるようにする
- 現代のフレームワークは通常、「no-cursor」や「headless」モードを提供せず、視覚カーソルが必須だと想定している
-
menuconfig: 単一列フォーカス
- Linux カーネルの
menuconfig は、厳格な単一列フォーカスを維持しているため機能する
- 枠線やタイトルがあっても、アクティブな領域は縦方向のリストであり、カーソルはそのリストに固定される
- 時計更新のために右下へ移動し、次にタイトル更新のために左上へ移動する、といった動きはしない
- 空間的複雑さが低く保たれるため、スクリーンリーダーが迷子になりにくい
-
Irssi: スクロール領域の活用
- Irssi はたまたまアクセシブルなのではなく、20年以上にわたって独自レンダリングエンジン経由で VT100 の スクロール領域 を活用してきたチャットツールである
- 新しいメッセージが届くと、ターミナルドライバに「1 行目から 23 行目までをスクロール領域として定義せよ」と指示する
- 続いて「上へスクロールせよ」という命令を送り、ターミナルが内容を上へ移動させたあと、その領域の下端に新しいテキストを描画する
- この方式は入力行との干渉を最小限に抑える
- 画面上のすべての文字を手動で書き直すのではなく、ターミナルのハードウェア機能に依存している
- 現代のフレームワークはこのようなハードウェア機能を無視し、画面状態の差分を計算して文字を書き直す方式を取るが、これは計算コストが高く、アクセシビリティにも敵対的である
gemini-cli のイシュー対応の問題
- Google と
gemini-cli メンテナーはアクセシビリティを気にしているように見えるが、リポジトリでは重要なアクセシビリティ回帰が放置されている
- Issue #3435 や Issue #11305 のようなアクセシビリティ回帰には、議論もロードマップも修正もない
- Issue #1553 はこうしたアクセシビリティ失敗を追跡するためのイシューだったが解決されず、ボットによって自動的にクローズされた
- ボットは、長期間活動がなくバックログ管理のために閉じるという一般的な文言でイシューを終了している
- メンテナーが数か月手を付けていないという理由でアクセシビリティ報告を閉じるのは、整理ではなく証拠隠しに近い
- バグを十分長く無視すれば存在しなかったことになる、というシグナルを与え、実際のソフトウェアは視覚障害者にとって依然として使えないまま残る
- プロジェクトの「Closed Issues」指標は改善して見えるかもしれないが、アクセシビリティ問題は解決されていない
アクセシブルなターミナルツールを作るための結論
- ターミナル向けアプリケーションでアクセシビリティを重視するなら、ターミナルをキャンバスのように扱う宣言的 UI フレームワークの使用をやめるべきである
- 「モダン」な TUI スタックは、開発者が React のようにコードを書きやすくする方向に最適化されており、機械がテキストを効率よくレンダリングする能力を犠牲にしている
- アプリケーションがユーザーによるカーソル非表示を保証できなかったり、スピナーやタイマー表示のために攻撃的な再描画に依存したりするなら、それはアクセシブルでないツールになる
- 視覚障害者にとっては、遅く、読み上げる内容を絶えず流し込み、カーソルを画面全体にばらまく「賢い」TUI よりも、単純で線形的な CLI ストリームのほうがはるかに優れている
2件のコメント
Hacker Newsのコメント
Claude CodeのレンダリングUIを見ていて、TUIはコマンドラインインターフェースというより DOSやBorland風のUIシステム に近いのだと初めて気づいた
CLAUDE_CODE_NO_FLICKER=1の設定を見ていたら、このTUIはターミナル制御コードで複数のレイヤーを重ねて表示する構造だとわかったReact向けのInkターミナル実装も読んでみた: https://github.com/vadimdemedes/ink
ピクセルベースのグラフィックではなく、昔のWordPerfectやWordStarのように見える仕組みが興味深かったし、視覚障害のあるユーザーにとっての使い勝手も似ている。ただ、DOSツール向けの 80x25点字パッド は、その後のスクリーンリーダーよりもうまく動いていた記憶がある
最近流行りのTUIを見れば見るほど、ますますひどく見える。プログラミング初期から積み上がった 最悪の慣行 を全部集めて、扱いづらくて重くて遅いゼリーの塊で包んだような感じで、自重で崩れそうだ
Windowsが一般的でなかったか、十分によくなかった時代にDOS上で作っていたものと同類なので、災厄になるか、動いているターミナルの能力を理解せずに作られているのも驚きではない
TUIがなぜ人気なのか、いつも少し不思議だった。ターミナルの強みは ストリーミングモデル にあり、組み合わせ可能なユーティリティはグラフィカルUIではずっと珍しい利点だ
ターミナルの制約によって、TUI設計が見た目よりもツールの目的に集中しやすくなるという点は理解できるが、個人的にはそれほど説得力のある理由ではない
Vim/Neovim/tmux/zellijなどを使い、ターミナルで生活しているエンジニア集団がすでにかなりいて、多くの開発作業がターミナルでスクリプトを実行する形なので、できるだけ多くの作業をそちらに移したい需要がある
macOSやLinuxのような主要プラットフォームでは、パッケージマネージャ経由の配布が事実上解決済みだが、クロスプラットフォームのネイティブアプリ配布はいまだに断片化している
こうした需要と配布面の利点のおかげで、Ink for ReactやBubble Tea for Goのような TUIコンポーネント が大きく進歩し、Electronは遅くて肥大化したアプリと結び付いたイメージがあるため、開発者には敬遠されがちだ
結局、成功した製品はClaude CodeがClaude Coworkへ続いたり、OpenCodeがOpenCode Webを追加したりするように別の形へ移っていくこともあるが、開発者ツールの プロダクト・マーケット・フィット をTUIで素早く試すのは簡単で、別のUIを出したあとでも多くのユーザーはターミナルに残るだろう
グラフィカルUIでも簡単に再現できただろうが、キーボードショートカットは後回しになってしまった
今でもそういう古いワークフローを懐かしむユーザーに会うことがあるが、彼らはそれを「古いテキストインターフェース」、つまりTUIと表現する。よく聞いてみると、本当に欲しいのは瞬きするほど速く、ショートカット中心の流れなのだ。データ入力で重要なのはアニメーションではなく 速度 だ
初心者は見た目の楽しさを好むが、熟練者はもうそこを気にしない
ターミナルが課す制約のおかげで、アプリはだいたい似た見た目で似た動きをする。外の世界では、UX標準は可能だというだけで日常的に無視されるが、TUIは言ってみれば最も驚きの少ない最適点にある
TUIツールのおかげで、必要なときだけ姿を現す自分だけのIDEを作れた。guakeとyakuakeのおかげで隠せて、zellijのおかげでプロジェクトやタブ単位で整理できる。今のように複数の役割が混ざった仕事には完璧に合っている
ただ、誰が見ても洗練されていると呼ぶことはないだろう
プロジェクト保守者の立場からは違って見えるかもしれない。プロジェクトを所有し維持する人たちは、Issueにおける OpenとClosedの意味 を決められるし、ユーザーが必ずしも同意する必要はない
たとえばOpenを「まだ分類されていない、あるいは積極的に作業中」という意味で使い、Closedを「このチケットは確認したが、現時点ではチームの誰も作業しないことにした」という意味で使える
つまりClosedは必ずしも「却下され、この決定は最終」という意味である必要はなく、「今の作業対象ではない」という意味でありうる。誰にとっても直感的ではないとしても、プロジェクトメンバーが作業量を整理するのに役立つなら正当化できる
Googleは一般に アクセシビリティ によく配慮しており、ほとんどの製品について適合性レポートも公開している: https://belonging.google/accessibility-conformance-reports/
この評価には同意する。さらに言えば、開発者たちが十分に満足していた CUA、つまりIBMのCommon User Accessインターフェース標準を守り、さらに標準化していれば、ずっと簡単だったはずだ: https://en.wikipedia.org/wiki/IBM_Common_User_Access
開発者がさまざまなUI構成を試したいならそうさせればいいが、機械にも人にも呼び出せるCUAを背後に維持しておけばよい。残念ながら、人間工学は開発者の得意分野だったことがない
これは TUIとWindows の間でよく文書化されている問題だ
90年代に大半のSAPシステムがAS/400ターミナルからWindows NTへ移行したとき、生産性が大きく落ちたという反応が多かった
SAPで働いたことはないが、母がその仕事をしていて、完全に表形式でファンクションキー中心だったワークフローが、マウスを握って動かし、何度もクリックする方式に変わった。多くの機能でタブ移動やFキーがなくなった
ESC ESC F4 F3 TAB TABだけでシステム全体をものすごい速さで横断する様子を見せてくれたが、それは実システムではなくターミナルだった要するに、Windowsベースのアプリは発見しやすさと新規ユーザーには向いているが、ターミナルベースのアプリはより速く、記憶ベースのナビゲーションと パワーユーザー に向いている
実際、プロやパワーユーザー向けに成功しているアプリはどれも高速経路を念頭に作られている。理由もなく嫌われがちなMicrosoftのリボンでさえその一例だ。キーボードで操作でき、カスタマイズ可能で、しかも発見しやすい
グラフィカルUIは制約を緩めるだけで、そのぶんUXを壊しやすくなる
TUIは本来シンプルな選択肢であるべきだったのに、今では ターミナルの衣装を着たWebアプリ になってしまった
Webアプリとはほど遠く、ほとんどすべての軸でさらに悪い
「テキストだからアクセシブルだ」という神話について言えば、そんなことはない。そう信じている人はいない
開発者がそう言うときは テキスト文書 のことを指しており、条件付きでgrep、cut、lsのような単一コマンドのターミナルアプリを含むだけだ。TUIについてそう言っているとは考えにくい
問題は宣言的UIフレームワークを使うこと自体ではなく、こうしたフレームワークが出力する レンダリングエンジン がアクセシビリティを考慮していないことにある
だが誰もそこに気を配らず、単に「ターミナルだけど見た目をきれいにしよう」で終わってしまったようだ
TUIはウィンドウのような要素なしで再発見されるだろう。まだ気づいている人は少ないが、C64コンソールのように スプライトベース になる可能性がある。どこかですでに誰かがやっているかもしれない
ウィンドウやパネルはもう手放していい。落ち着いたテキスト環境は2026年になっても依然として人類の文化的DNAの一部であり、この媒体では驚くほど未開拓だ
現代のWebの認知的な攻撃性のほうが、実際にはより悪夢に近いと思う。画像、動画、広告が文脈なく入り混じる、非常に幻覚的な意味においてそうだ
Lobste.rsの意見
この記事は、他のブログ記事と同じく AI支援で書かれたような臭い がかなり強い
LLMはこういうタイトルを好む: “The Architectural Flaw”, “The Lag Loop”, “Why The ‘Old Guard’ Works”, “The Lost Art of Scrolling Regions”, “The ‘Stale Bot’ excuse: A Case Study in Neglect”
優れたブログ記事になれたはずなのに、著者がアウトラインをChatGPTに放り込んで終わりにしたように見えるなら、読者にも著者にも損だ
ごく特殊な一回限りの問題を「古典的な」問題と呼ぶのも同じだ
本当に憂うつだ。要するに、Irssiのような アクセシブルなTUI もあるのに、現代のTUIフレームワークはそうした先例を無視し、グリッド差分計算とカーソル移動に依存している
スクリーンリーダーはカーソルが動くたびにその位置の内容を読むので、結果としてめちゃくちゃになったり、膨大な読み上げスパムが発生したりする
ここの技術的説明が完全に正確かは疑わしい
特にInkは長い間 増分レンダリング をまったくサポートしておらず、Inkを使うアプリの大半もまだ有効化していない。その増分レンダリングも 行ベース なので、実際のタイマー位置へカーソルを移動したりはしない
Gemini CLIは増分レンダリングを有効にするには 代替バッファの使用が必要 で、これは内蔵の スクリーンリーダー向けモード が有効だと 無効化される。関連オプションの文書は ここ にある
付け加えると、Pythonのrich/textualは、より遅く主にシングルスレッドな言語の上にありながらも、Inkよりずっと高速なことが多い。数千行の差分計算が必ずしもそこまで遅いわけではなく、10秒もかかるようなものではない
ユーザー体験が苛立たしく壊れている点は疑わないが、示されている正確な原因はLLMの幻覚か、不完全な情報に基づいている可能性がある。Inkの増分レンダリングは有効でも、説明されているようには動かない
実際には、全画面の再描画がスクリーンリーダーを混乱させ、行ベースの再描画が変更と無関係な任意の途切れたテキスト断片を再び読ませてしまう、という形で悪い可能性が高い
TUIだけを責めるのは公平ではない
本当の問題は、ほぼスタック全体の アクセシビリティ対応 がひどいことにある
第一に、GPUレンダリングのターミナルエミュレーターの大半は、システム提供のアクセシビリティAPIをまったく使っていない。テキストがGPUでレンダリングされると、アクセシビリティツールには「読める」ものではなく、ただの画像のように見えてしまう。Kitty、Alacritty、WezTermがこれに当たる。私のターミナルGhosttyはmacOSではアクセシビリティAPIで読めるし、iTerm2とTerminal.appも可能だ
第二に、TUIがアクセシビリティ情報をターミナルエミュレーターへ渡すためのターミナルシーケンスや標準的な仕組みがまったくない。ターミナルセル、実行区間、領域に対するARIA風の注釈に相当するものが必要だが、そうした試みは存在しない。TUIがカーソルをうまく扱っても、多くのユースケースでは問題が起きるだろう
例としてGhosttyでは、OSC133 とアクセシビリティAPIを統合し、各シェルプロンプト、入力、コマンドを単なるテキストボックスではなく、構造的に意味のある要素として公開する作業を進めてきた。これは、ターミナル仕様、TUI、ターミナルエミュレーターが一緒に噛み合う必要があることを示している
スタック全体が腐っていて、本気で直そうとしている人もほとんどいない。私も時間が限られる中で最善を尽くしているだけだが、これはエコシステム政治まで必要な巨大なテーマで、背負いきれない
おまけに、かっこよくも恐ろしい現実として、AIがここでアクセシビリティ改善を後押ししている。多くのAIツールがアクセシビリティAPIを使ったり悪用したりして、ウィンドウ一覧を読み、入力を実行している。そのため、より多くのアプリがAIのユースケースを理由に、アクセシビリティ統合をはるかに真剣に扱い始めている
Claude Codeとgemini-cliが readlineベース ではないので毎日腹が立つ
似たようなキー入力はいくつか入っているが、慣れ親しんだreadlineショートカットの長い裾野が欠けている
Anthropicは、「Web開発のように作るべきだ」という判断が誤りだったと認めて、readlineでやり直してもいい
こういうツールを作る開発者にとって馴染みのある開発体験が、ツールを使うユーザーにとって馴染みのあるユーザー体験より重要だ、という考えは間違っている
実際、きちんと保守されている有名なサードパーティ解決策もほとんどない。柔軟な入力ボックスが必要なら、最初から自分で作るしかない
Textualの優れたInputウィジェット や、JSエコシステムの別ライブラリである OpenTUI と対照的だ
LLMは好きではないので、UIが悪いのは個人的には利点だが、readlineを使わないのには理由があるのかもしれない
kakouneやhelixのようなターミナルエディタは、「カーソルを隠す」手口を使わない限り アクセシビリティ基準 を通すのは難しそうだ
それでもVS Codeほどアクセシブルではない可能性が高い
VS Code以外で、アクセシブルなクロスプラットフォームのIDE-liteやIDEには何があるだろう? VS Codeのますます敵対的な姿勢は気に入らない。JetBrains IDEかもしれない
欠点は、Emacs自体はクロスプラットフォームでも、emacspeakはTTSの都合でLinuxに弱い依存があるかもしれない点だ。あるいはそうでもないかもしれない。Windowsでは試したことがない
視覚障害者向けのアクセシビリティなら、emacspeakやプラットフォームの視覚障害者向け支援ツールが必要だ
アクセシビリティはスペクトラム であって、チェックボックスではない
Linksには別個の 点字ターミナルモード があり、偽のGUI要素をより単純な全画面メニューに置き換え、方向キーでの移動も行単位に変えている
もう一つ興味深い例は edbrowse だ。視覚障害者のKarl Dahlkeが作ったテキストモードブラウザで、より人気のあるテキストモードWebブラウザと違ってTUIを使わず、edスタイルのコマンドラインインターフェースを使っている
Inkフレームワーク なら、CLIがCPU 100%を使い、長いチャット履歴を延々と再描画したまま固まり続ける理由としてありそうだ。残念だ