RSVP速読リーダーを自作した記録:画像2枚の企画からPhase 5まで、蔵書DBの本を1,500字/分で読めるか試す

開発misc-dev

RSVP速読リーダーを自作した記録:画像2枚の企画からPhase 5まで、蔵書DBの本を1,500字/分で読めるか試す

朝7時すぎ、クリップボードに保存した画像2枚を Claude Code に貼り付けた。 どちらも速読表示の画面で、1枚は止めたところを、もう1枚は流しているところを写している。 RSVP リーダーと呼ばれる種類の表示で、文章を小さなかたまりに切り、画面の同じ位置へ次々に出していく。 これを作る企画を立てるところから、この日は始まった。

この時点では、2枚の画像はまだ計画書の外にあった。

画像2枚から計画書へ

svg-diagram スキルを読ませたうえで、計画書を書いてもらった。 全体構成の図を SVG で作り、本文と判断事項5件を書き、Codex のレビューを通してから見せる流れである。 Codex の判定は「承認」で、致命的な指摘はなかった。

判断事項は、計画書の HTML に埋め込んだ回答フォームで選ぶ。 8899番のポートは別のセッションが使っていたので、そこには触れずに8901番で立ち上げてもらった。

ここで、ふと引っかかった。 Vue って、Vue 3 の次に Vue 4 のようなものが出ていなかったか。 npm で確かめてもらうと、Vue 4 はまだ出ていなかった。 あとで作った雛形も、Vue 3.5、Vite 8、TypeScript 6 の組み合わせになった。

せっかくなので、渡した画像2枚は計画書の中に参照画像として入れておいてもらった。 入れた先は「1. 何を作るか」の節で、参照画像1が停止中、参照画像2が再生中の画面である。 参照画像1では、下半分にルビ付きの全文パネルが出ていて、「ある日の」がハイライトされている。

人物辞書に kuromoji は使わない

判断事項の4番目は、登場人物の辞書をどう作るかだった。 自由記述欄には、アプリの中では作らないと書いた。 開発環境で Claude Code や Codex(サブスクリプションの枠内)に本の本文を読ませ、作品ごとに JSON を作らせる。 本文は Turso に置いた蔵書 DB から取ってくる。

形態素解析の kuromoji を入れる案もあった。 ただ、1回の処理にどれくらいかかるかは分からないものの、たぶんサブスクリプションの枠内でできそうだし、LLM に読ませるほうが正確ではないかと考えた。 kuromoji でやった場合の精度と比べてみたい気持ちはある。 とはいえ、それほど精度は高くない気がしている。

そこで、いったん kuromoji は入れないことにした。 代わりに、蔵書 DB から1冊を書き出す開発用スクリプトと、その本の人物辞書を作る手順を、スキルとして計画に加えてもらった。 改訂した計画書も、Codex の再レビューは「承認」だった。

Phase 0 と Phase 1:雛形から青空文庫の変換まで

Phase 0 では、Node と pnpm のバージョンと、Vite の雛形ツールが対話なしで動くかどうかを確かめてもらった。 雛形からデモ用の部品を除いて新しいリポジトリへ移し、Vitest と BudouX を足した。 テストと型検査込みのビルドが通り、dev サーバーの画面にもコンソールエラーは出なかった。 GitHub の非公開リポジトリに push し、公開範囲が PRIVATE になっていることも確かめてもらった。

Phase 1 の素材は、青空文庫の『蜘蛛の糸』である。 最初に、「2,868字」が見出し(一、二、三)を含んだ数なのかを実測させ、字数の数え方を決めた。 続いて青空文庫テキストの変換を書いてもらった。 ルビは、明示する形と、直前の漢字にかかる省略形の両方を扱う。 外字、見出し、冒頭の記号説明、末尾の底本情報も処理の対象にした。

その先は、人名の位置探し、BudouX による分割、かたまりの組み立て、表示時間の計算と続く。 テストは38件から48件まで増えた。 計画書の完了条件5つをすべてテストで確かめてから、c23679a をコミットして push した。

Codex レビューの上限を1万行に上げる

ここで作業を止めて、Codex コミットレビューの設定を変えた。 差分の行数の上限が7,000行になっていたが、この値にはあまり意味がないと感じたので、1万行に上げてもらった。 すると Claude Code から、制限時間も今の比率(7,000行で420秒)に合わせて600秒にしてはどうかという提案があり、それにも乗った。

ゲートのスクリプトは、別のセッションのレビューが動いている最中だった。 手順書は実行中のレビューに影響しないので先に直させ、スクリプト本体は別セッションのレビューが終わるのを待ってから書き換えさせた。

ついでに、今回のコミットも念のためレビューに通してもらった。 外字の対応表のコミット(3a1dc14)は、レビューが飛ばされていたものである。 Codex の判定は「指摘事項なし」だった。

Phase 2:一文は短すぎないほうがいいのか

Phase 2 は再生の最小版である。 判断を含む処理(再生時計、残り時間の累積、時刻の表示形式、速度の範囲制限)は純粋関数にしてテストし、Vue の側は画面とタイマーだけにした。

1枚目の表示は参照画像と同じ状態になった。 「ある日の」が出て、下に「1 / 2,868字 残り 約2:22」とある。 速度は1,500字/分である。 再生を始めて約7秒後には「143 / 2,868字 残り 約2:15」になり、残り時間も7秒ぶん減っていた。

ここで一つ疑問が湧いた。 ものによっては、一文がだいぶ短すぎる。 5文字に満たないかたまりがあると、文の意味をとるのがかえって遅くなる気がする。 最低文字数のようなものは設定しないのかと聞いた。

設定はすでにあった。 既定値は、元にした投稿と同じ「3字以上」で、まだ画面には出していなかった(Phase 3 の設定パネルで出す予定だった)。 『蜘蛛の糸』で最低字数を変えたときの違いを、かたまりの数、平均の長さ、5字未満の割合、全体の時間、冒頭の区切りの表にしてもらった。 すると、最低字数を変えても全体の時間は変わらなかった。 これは面白かった。

5字で進めることにした。 もう一つ気になったのは、冒頭の「極楽の蓮池のふちを」である。 ここは1つのかたまりで出てほしい。

原因は、5字未満のかたまりを次へつなぐだけの作りにあった。 読点をかたまりの終わりとして扱うように変え、2文節ずつまとめる処理でも同じ扱いにそろえてもらった。 操作バーに最低字数の選択欄を置き、区切り直しても読んでいる位置が保たれるようにしてもらった。

テストは70件になった。 画面を読み込み直すと、「極楽の蓮池のふちを、」が1つのかたまりで出た。 ヘッダーのキー操作の説明で「↑↓」だけが青い記号で出ていることには、再生の確認中に Claude Code が気づいていた。 Windows の絵文字フォントで描かれているらしい。 一度直させたあとも青っぽく見えたので、拡大して確かめさせた。 狭い画面で文字を自動で縮める処理も足し、390px のスマホ幅はエミュレーションで確かめてもらった。 既定の最小字数を5字にして、6cb1ca4 をコミットして push した。

Phase 3:参照画像と同じ画面になるまで

Phase 3 で作ったのは次の4つである。

  • 停止中の全文パネル(ルビ付き、現在位置のハイライト、クリックでその位置へ移動)
  • 人名に色を付けた表示と、ラベルの行
  • 2段の操作バー
  • Shift+←→ による段落単位の移動

全文パネルのクリックは、3段落目の53か所をすべて押して確かめてもらった。 どれもクリックした文字を含むかたまりへ移り、ずれは0件だった。 テスト91件と型検査が通り、2b5457b をコミットして push した。

朝に貼った2枚の画像は、ここで完了条件として効いてきた。 停止中は参照画像1、再生中は参照画像2と同じ状態になることを画面で確かめて、Phase 3 を閉じた。

Phase 4 以降は明日へ

続きは明日やることにして、Phase 4 からは Google タスクに回した。 その前に、計画書に「9. 進捗と再開のしかた」を追記させ、コミットして push した。 Phase 4〜6 は、翌日(9月28日)が期日の Google タスク3件として登録した。 期日と本文が入っていることも、1件ずつ確かめてもらった。

Phase 4:縦表示と、続きから読める保存

翌朝(9月28日)、Google タスクに回した Phase 4 から再開した。 やることは2つある。 V キーで縦表示に切り替えることと、作品ごとの読書位置と設定を保存して、開き直したら戻すことだ。

縦表示では、長いかたまりほど文字が縮む。 横長の PC の画面だと、14字のかたまりが横なら56px、縦なら(停止中は)25px になった。 人間の視野は横に広いから、横表示のほうがいいのではないかと聞いてみた。 返ってきたのは、おおむね横が有利だが、理由は視野の広さではない、という答えだった。 RSVP は視線を動かさず、見ている点の近くに字を出す。 効いてくるのは、その点のまわりで字を見分けられる範囲のほうで、それが上下より左右にやや広いとされているらしい。 既定は横のままにした。

確認の途中で、V キーを押しても縦にならない場面があった。 原因は Chrome に入れている拡張の Vimium で、v を自分のショートカットとして先に拾っていた。 操作パネルに「縦表示」のチェックも置いたので、Vimium の設定で除外するまではそちらで切り替える。

保存では、読書位置をかたまりの番号ではなく「何字目か」で持たせた。 区切り方を変えると、かたまりの番号がずれるからだ。 614字目で止めて読み込み直すと、同じかたまりから、縦表示のまま再開した。 188f3aa をコミットして push した。

Phase 5:蔵書 DB の本を読めるようにする

本命はここからだった。 Turso の蔵書 DB には、OCR した本が398冊入っている。 ただ中身は OCR の結果を Markdown にしたもので、そのまま流すと表紙や目次、表の残骸、画像のタグまで再生に出てくる。 ページの切れ目で文が途中で切れていたり、本文の行に見出しの記号が付いていたりもする。

そこで、本を書き出すときに、読む文章だけに整える処理を作ってもらった。 試しに選んだのは伝記の『江副浩正』(馬場マコト・土屋洋)で、整形前の267,204字が、21章・254,469字になった。 整える規則は、実物の崩れを見ながら足していった。 本文の行に付いた見出し記号、ページ上部に繰り返し出る章名、1〜2字だけ残ったルビの拾い残し、といったものだ。 誤認識そのものは直していない。 原本に戻れないからだ。

開く速さも測ってもらった。 最初は、本棚でクリックしてから最初のかたまりが出るまで約1秒かかっていた。 配列を毎回作り直す書き方のせいで、長い本ほど手間が膨らんでいたらしい。 直したあとは646〜804ms(3回)になり、再生中のもたつきも出なかった。 129,137字目で閉じて開き直すと、本棚に「50%(129,137字目)から」と出て、同じ位置から続きを読めた。

コミットのたびに、Codex のレビューが high の指摘を返してきた。 重要度は Codex の判定をそのまま使わず、Claude Code に中身を見て判定し直させている。 7件の指摘のうち6件を直し、1件(まだ蔵書 DB で見ていない形の表を見逃す)は理由を残して見送った。 0851417 で Phase 5 を閉じた。

開くとエラー、の正体

できあがった本棚で『江副浩正』をクリックすると、エラーが出て開けなかった。 ところが Claude Code が新しいタブで試すと、開ける。 違いは、私のタブが前日から開きっぱなしだったことだった。 開発サーバーの自動更新で、読書画面は古いまま、本の読み込み処理だけが新しいコードに差し替わっていたのだ。 タブを再読み込みしたら直った。 同じことが起きたら「画面が古いままです。ページを再読み込みしてください」と出るようにしてもらった。

音声で「第1章だけ入れて」

本を丸ごとではなく、ある章だけ入れたいこともある。 音声で「〇〇の第1章だけ入れて」と頼めるようにしたかった。

書き出しスクリプトに、書名で探す、章の一覧を出す、章を指定して書き出す、の3つを足してもらった。 章だけ書き出すと、本棚には「江副浩正(第一章 東京駅東北新幹線ホーム)」のように別の1冊として並び、読書位置も別に持つ。 手順は、このリポジトリ専用のスキル(import-book)にまとめた。

音声では書名の聞き違いが起きる。 実際、私の音声入力でも「江副」が「江添」になっていた。 そこでスキルには、見つからなければ語を短くしたり表記を変えたりして探し直す手順を入れた。 章は番号ではなく章名で突き合わせる。 『江副浩正』は序章が1番目なので、「第1章」は2番目の章になるからだ。

1,500字/分は速いのか

既定の速度は、元にした投稿と同じ1,500字/分にしてある。 これは速読として普通なのか、それとも遅いのかを聞いてみた。

読み方字/分(目安)
普通の黙読400〜600
元の投稿(18万字を3時間)約1,000
このアプリの既定1,500(句読点の間などを含めると約1,150)
速読教室の宣伝数千〜数万

答えは、遅くはない、というものだった。 普通の黙読の2.5〜3倍で、中身を理解しながら読める速さとしては上限に近いという。 読書の研究では、普通の速さの2倍あたりを超えると理解がはっきり落ちるという結果が繰り返し出ていて、数千字/分の速読は実態としては拾い読みに近い、とも言っていた。 RSVP では目が少し戻って読み直すことができないので、同じ速さでも理解は落ちやすいらしい。 表の数字と研究の話は Claude Code が覚えていた目安で、出典まではまだ当たっていない。

これから:自分で読んで試す

ここからは、実際に本を読んで、中身が入ってくるかを自分で試していく。 調整できるのは次のパラメータだ。

項目範囲既定
速度300〜3,000字/分(↑↓で100ずつ)1,500
最小字数3〜8字5字
まとめる1〜3文節ずつ、8字・12字めやす1文節ずつ
句読点で間をとるオン/オフオン
名前で少し長くオン/オフオン
表示横/縦(V キー)横

試すことは次のとおり。

  • 『江副浩正』を 800〜1,000字/分から読み始める(内容が詰まった本で、OCR の崩れもあるため)
  • 章を読み終えるたびに、中身を2〜3行で説明できるかを確かめる。できれば ↑ で100字/分上げ、できなければ下げる
  • 小説(『蜘蛛の糸』)で 1,500字/分がどう感じるかを比べる
  • 横と縦を同じ速さで読み比べる

次の Phase 6 では、『江副浩正』の人物辞書を作って、名前の色分けを出す予定だ。

学びメモ

  • 最低字数を変えても、『蜘蛛の糸』全体の再生時間は変わらなかった。「極楽の蓮池のふちを、」をひとかたまりにできるかどうかは、読点の扱いで決まった
  • 画像2枚を計画書に参照画像として入れておくと、Phase 3 でそのまま完了条件になった
  • 人物辞書は、kuromoji ではなくサブスクリプション内の LLM に本文を読ませて作る方針にした
  • 読書位置は「何字目か」で持つと、区切り方を変えてもずれない
  • 長い本を開くのが遅かったのは、分割そのものより、組み立てで配列を毎回作り直していたせいだった
  • 開きっぱなしのタブは、開発サーバーの自動更新で古い画面と新しいコードが混ざることがある。「開けない」ときは、まず再読み込みする

kuromoji でやった場合との精度の比較は、やってみたいと言ったまま手を付けていない。

#RSVP#速読#Vue#BudouX#kuromoji#Turso#Codex#Claude Code