語源英単語トレーナーに想起練習を実装し、ストリーム型クイズUXを移植するまで

開発eurekapu-nuxt4

語源英単語トレーナーに想起練習を実装し、ストリーム型クイズUXを移植するまで

単語帳を1周、2周と回すのが、なぜあんなに退屈なのか。朝いちばんでその話をした。ゴールは楽しむことではなく覚えることなので、面白くする工夫ではなく、効果が実証されている工夫を教えてほしいと頼んだ。

返ってきた答えは意外だった。退屈さは気分の問題ではなく、学習効率が落ちているサインだという。もう思い出す努力が要らない状態で反復しているから記憶に残らない。効果と面白さは同じ場所から来ていて、鍵は「思い出す機会」の量だった。インプットの回数ではなく、想起の回数が記憶を作る。腑に落ちた。

自分がこれまで単語を覚えるとき、直近3回分の履歴だけを見て復習範囲を決めていたことに気づいた。それは仕訳クイズの履歴機能とまったく同じ考え方だ。だったら、すでにアプリの中にある仕組みをそのまま単語アプリに転用できるのではないかと思い当たった。

履歴システムはもう仕込んであった

語源で貫く英単語(4,000語)には、以前つくった useQuizHistory がすでに接続されていた。未ログインなら localStorage、ログイン中ならD1に、直近3件の履歴を保持する仕組みで、仕訳クイズの履歴管理と同じ設計を流用したものだ。ただし履歴はフィルタ表示に使われているだけで、「マスターした単語は出さない」といった出題制御にはまだつながっていなかった。

調査エージェントを2体走らせて分かったのは、データはすでに演習向きに揃っているという事実だった。全4,000語(詳説141語+アトラス3,859語)が同じ型で、意味・語源メモ・例文・音声を持っている。4択クイズは詳説141語分だけ事前に焼き込まれていて、アトラス側は実行時に問題を組み立てる必要がある。questionIdの形式もすでに整った命名で振られていた。

設計エージェントの裏取りでは、既存の GogenQuizItem が問題オブジェクトを渡すだけで再利用できることと、誤答肢を作る参照実装が scripts/gogen/lib/distractors.ts にすでにあることも確定した。詳説18章の単語IDが章ごとに1〜141まで欠番なく振られていることも、この段階で確かめさせている。手ぶらで始める実装ではなかったわけだ。

計画をCodexにレビューさせたあと、実装に入らせた。問題生成モジュールにテストを足し、コーストップへの導線カードを追加し、i18n設定に新しいページを登録する。デバッグ用Chromeを9222で起動してMCPを繋ぎ直し、実機で描画を確認する段になって、hydrated が false のまま止まるという小さなつまずきもあったが、コンソールを見て潰させた。

章末クイズページの回帰も確認させ、全テストが緑になったところで「今日の復習」トレーナーが形になった。直近の履歴を踏まえて出す単語を選ぶ、思い出す機会そのものを毎日作るページだ。

3クリック先が分からない

その日のうちに、もう一つの相談が来た。もともと簿記の学習サイトとして作っていたところに英語コンテンツを足したので、レッスンズの一覧には「講義ノート」というタイトルで紛れ込んでいる。トレーナーへの入り口がどこにあるのか、作った本人にも分からなくなっていた。

現状を洗わせると、直接URLは /lessons/gogen-eitango/training で、画面上の導線は「講義ノート→語源で貫く英単語4000→コース目次の『今日の復習トレーナー』カード」の3クリックだった。目的地に着くまでの道のりが長いというより、途中の看板がどれも別の場所を指しているような迷い方をする構造だった。

トップページの導線まで洗い直させ、対象を一気に整理させた。トップページ→「問題集」→英単語カードの2クリックでトレーナーに届くようにし、途中で見つかった誤誘導バグも直させた。「単語アトラス」という呼び名も「単語リスト」に改めさせた。アトラスは格好はいいが、初見の人には何のページか伝わらない。

全テストを流し、/quiz のハブ化と各ページの表示を一つずつ確かめさせてから、整理は完了した。表記変更に依存するテストが残っていないかも洗わせ、別の学習コンテンツ(簿記3級の問題集ページ)や語源アプリ内の他ページに表示崩れが波及していないかまで、一つずつ見て回らせている。

セッションをまたいだ引き継ぎ

トレーナーの出題UXをmdx-playground側の「英単語850クイズ」に寄せたいと頼んだところで、サーバー側のエラーに当たった。同じ流れで作業を続けさせることができなくなったので、続きを別セッションに渡すための引き継ぎプロンプトを作らせた。ファイルパスをすべて実在確認させたうえで、そのまま貼り付けられる形に整えさせている。

実際の移植作業は、結局その新しいセッションのほうで進んだ。元のセッションには、あとになって「別のセッションで実行したようなので、レビューをかけてみてください」と頼み直す形になった。

別のリポジトリで見た記憶

引き継ぎ先を用意する前に、もう一つやることがあった。以前mdx-playground側で「選択肢を選んだら○×が即座に返ってきて、そのまま次の問題にスクロールして進む」コンテンツを作った記憶があったのだ。どのファイルだったかはもう思い出せず、探索をワークフローに任せることにした。

以前使ったSonnet 3.5をサブエージェントに指定しようとしたが、いまの環境では選べなかった。現行のSonnetを10体並列で立て、Vueコンポーネント・問題データ・ページ構成・マークダウン埋め込みの4方向から洗わせた。候補18件のうち6件はコードまで読ませて挙動を確認させている。

結果は「完全一致・3系統」。日本語作文クイズがまさにその原型で、そこから進化させたのが英単語850クイズのコンポーネントだと特定できた。ローカルのフルパスを聞き直し、実際に開いて「これですね」と確認する一手間も挟んでいる。名前だけ覚えていて中身を忘れていたものが、こうして裏取りされた形で戻ってくる感覚は独特だった。

実装を言語化してから渡す

このUXをeurekapu-nuxt4側に持っていきたい。ただ「同じ動きにして」と伝えるだけでは、実装の勘所が抜け落ちる。英単語850クイズの実装ファイルを読み込ませ、UXの要点を10章立ての実装メモに言語化させることにした。

メモに詰め込んだのは、ストリーム型であること、回答そのものが画面遷移のトリガーになっていること、selectAnswer の100ms遅延の意味、scrollIntoViewpadding: 35vh がワンセットで中央固定を作っている構造、三択自動生成時の重複除外、localStorage履歴による出題優先度づけ。移植でハマりやすい点も6つ拾わせた。これを memo/2026-07-20/quiz-stream-ux-implementation-memo.md として書き出させ、eurekapu-nuxt4のセッションに引き継ぐプロンプトを添えて渡した。

メモと原本を読み比べてから手を入れる

引き継いだ先では、いきなり書き換えには入らせなかった。まずメモと英単語850クイズの原本コードを読み比べさせ、「現状→移植後」の差分一覧を先に文章で組ませている。ファイルはまだ一つも変更していない段階で、章末クイズ共用の GogenQuizItem.vue は触らない、という判断を固めさせた。

すでに複数の学習ページから参照されているコンポーネントを直接いじると、影響範囲が読み切れなくなる。代わりに、トレーナー専用の composable・Container・QuestionCard・ResultSummaryを新規に足す形で実装させた。

選択 → 正誤を即表示 → 100ms後に次の問題を追加 → 中央へスクロール

移植後の挙動はこの4段で、原本のリズムをほぼそのまま踏襲している。実装と実機確認まで終わらせ、章末クイズ側は既存部品を変更していないので回帰も起きていない。コミットとデプロイはまだ先の話として残してある。

計画書 memo/2026-07-20/gogen-training-plan.md の追記も確かめさせた。実装内容とブラウザでの確認結果、テストの通過状況、まだ検証しきれていない項目までチェックボックスで残されている。あとで自分がこのメモだけを見て続きに戻れるかどうかが、ここでの唯一の判断基準だった。

学びメモ

  • 単語帳が退屈な理由は「思い出す努力」が足りていないサイン。想起の機会をどう作るかで学習設計そのものが変わる
  • 履歴システムを先に他機能(仕訳クイズ)で作ってあると、単語トレーナーのような別領域にもそのまま流用できる
  • 導線の分かりにくさは「入り口が1つ多い」ではなく「別の場所を指す看板が並んでいる」状態として現れる。看板ごと洗い直す必要がある
  • 良いUXパターンを覚えていても、どのファイルだったかは意外と忘れる。サブエージェント並列での再探索は、記憶の裏取りとして機能する
  • セッションが途中で切れても、パスを実在確認した引き継ぎプロンプトを残せば、続きは新しいセッションでそのまま拾える
  • 別プロジェクトへの移植は「同じ動きにして」では伝わらない。実装を読み込んだ言語化メモを一つ挟むと、移植先で共用コンポーネントを壊さない判断ができる