語源英単語アプリの例文を作り込んだ日 — 実写画像から抽象イラストへの方針転換・単語のマゼンタ強調・Piper TTSの再生ボタン
語源英単語アプリの例文を作り込んだ日 — 実写画像から抽象イラストへの方針転換・単語のマゼンタ強調・Piper TTSの再生ボタン
語源英単語アプリ(gogen-eitango)の例文まわりを一日かけて作り込んだ。convert の新方式の画像が返ってきたのを見て「こんな感じで嬉しい」と返事を打ち、その場で例文画像の方針を実写風から抽象イラスト風にひっくり返した。ほかにクイズの英→日/日→英の分離、例文の音声再生ボタン、チャプター表示の重複修正まで進んだ。
例文画像: 実写風(v2)から抽象イラスト風(v3)へ
例文画像は codex-image-gen スキル(GPT系の画像生成CLI)で量産している。1枚3〜7分かかり、レートリミットにも当たるので、30分おきに再試行する自動再開ループとランナー2〜3本の並列で回す構成にしてもらった。
最初は実写風(v2)で141枚を回していたが、途中で方式を見直した v3 の convert の画像を見て考えが変わった。controversy や convert のような抽象的な概念は、実写で無理に状況を作るより、抽象イラストの方が表現しやすい。「画像は全部こんな感じで、実写じゃない方がいい」と伝えて、convert が属する vert/vers の章から章単位で v3 に置き換えていくことにした。
v3 は、いきなり画像を生成させるのではなく、例文ごとの「構図仕様」を先にテキストで書かせてから生成する方式にした。全141例文分の仕様はサブエージェントを並列で章単位に派遣して書かせ、JSONの妥当性と語IDの完全一致を検証してから生成キューに投入した。
生成後の検収も別エージェントに任せた。サンプル20枚(全18語根をカバー)で19枚合格。唯一の不合格は versatile で、マゼンタの矢印を4本も使ってスタイルが逸脱していた。仕様を「アクセントは1点限定」に直して再生成し、同じ教訓を仕様テンプレートとスタイルガイドに横展開しておいた。この先の数千枚規模の量産には最初から効く。
表示の調整: 画像は例文の下、対象単語はマゼンタ、英文は大きく
画像と例文の並び順も直した。画像が先にあると、どの単語の例文なのかが一見して分からない。画像を例文(英文+和訳)の下に移動してもらった。
あわせて、例文中の見出し語をマゼンタ(サイトのアクセント色 #c026d3)で強調するようにした。例文が全部黒い文字だと「今回の対象はどれだっけ」と目が泳ぐ。converted のような活用形も拾えるように、ハイライトは純粋関数として app/utils/ に置かせ、テストで固めた。
例文の英文(The plan caused a lot of controversy など)のフォントも 0.95rem から 1.2rem に上げた。例文は読む対象なのに、周辺の説明文と同じサイズでは沈んでしまう。
クイズ: 英→日と日→英が上下に並ぶと答えが丸見え
クイズを眺めていて気づいた問題がひとつ。同じ単語の「英語→意味」クイズと「意味→英語」クイズが上下に両方表示されていて、片方の問題文がもう片方の答えになっている。これでは出題の意味がない。
「ちゃんと分けられるようにしておいて。最初は英→日だけでいい」と指示して、モード切替タブ(英語→意味/意味→英語)を付けさせ、デフォルトは英語→意味のみ表示に変えた。
音声: Piper TTS を1文だけ試してから再生ボタンを本実装
例文に音声も付けたくなった。無料でやれる選択肢を3つ挙げてもらい、聞いたことのなかった2番目のアプローチ — ローカルで動く Piper TTS — をまず1文だけ試させた。Windows用バイナリと英語音声モデル(en_US-lessac-medium)を落として、convert の例文 "Solar panels convert sunlight into electricity."(2.7秒)を読み上げさせる。
試作音声を聴いて採用を決め、「例文のところに再生ボタンを付けて」と本実装に進んだ。手順は、Piper で141語分(見出し語+例文)の音声をバッチ生成 → ffmpeg で mp3 圧縮 → データに音声パスを載せて再生ボタンをHTML化 → ページ側にクリック再生の仕組み、という流れ。いきなり141語分を回さず、1文で音質を確かめてから量産に入ったのは正解だった。
チャプター表示の重複をスクショで指摘
章ページを見ていたら、チャプター列に同じセクション一覧が繰り返し表示されている。スクショを貼って「重複してると思う」と確認させたら、再現と原因特定が返ってきた。
原因は、ビューアが「TOCの children = ページJSON内のチャプター配列」の1対1対応を前提にしているのに、children にセクション13個を入れて JSON側はチャプター1個しか入れていなかったこと。children の数だけ同じ一覧が描画されていた。章を「全体像/Stage 1〜3/章末コーナー」の5つのチャプターに分割し、TOC もそれに合わせて解消した。
画像の完走を待たずに並列で進めさせる
夕方の時点で v3 画像は92/141。完走まで75分以上かかる見込みだったので、「画像ある分だけでいい、作業中の画像はプレースホルダーでもいいから、並列で作業を進められないか」と聞いた。
返ってきた答えは想定より良くて、v2 実写画像が全141語分すでに存在し、v3 は同じファイルパスに上書きされる方式なので、プレースホルダーすら不要。今ある画像のまま全18章の公開化とQAを前倒しできた。QAの過程でデータバグも2件見つけて直している。
ついでにリモートセッションのIDを聞いたら、リモートではなくローカルセッションで、claude --resume {ID} で戻れるIDを教えてもらった。バックグラウンドの画像ランナーは別セッション時代に起動したもので、そちらのタスクディレクトリに出力が残り続けているという構造も把握できた。
最終的に画像は141枚完走(failed=0)。検収 → R2同期159ファイル → 全18章QA → デプロイ → コミット2本まで走り切った。
学びメモ
- 抽象概念の例文画像は実写より抽象イラスト。実写は「controversy の写真」を無理に作ろうとして破綻する。方針は1枚のサンプルを見た瞬間に決められる — 全量作ってから比較しなくていい
- 画像生成の品質管理は「構図仕様を先に書かせる → 生成 → サンプル検収 → 逸脱パターンを仕様テンプレートに横展開」のループが回る。versatile の矢印4本のような逸脱は、テンプレートに1行足すだけで以降の量産全部に効く
- 双方向クイズを同じ画面に並べると、片方が答えを漏らす。出題形式はモードで排他にする
- TTSのような未知のアプローチは、1文だけ生成して耳で確かめてからバッチに入る。141語分回してから「音質が合わない」と気づくのが最悪パターン
- 数時間かかるバッチの完走を待たない。上書き方式なら今あるアセットのままページを組めるので、量産と組み立てを並列に走らせられる