Skip to content

movie/ 実装レビュー: テキストが読む前に消える問題の根本原因と final-plan.md との乖離 #1

Description

@kzmszk

movie/ 実装レビュー(final-plan.md 照合)

movie/final-plan.md に基づく実装(movie_pipeline/ + remotion/ + config/ + prompts/)のレビュー結果。sleep-01 の実ビルド成果物(movie/build/sleep-01/)で各指摘を検証済み。

報告されていた症状「テキストの表示時間が短すぎて読む前に消える」は、単なる調整不足ではなく下記 #1 + #2 の複合バグが根本原因。


🔴 Critical

1. onScreen スキーマ契約の不一致 — quiz 以外のシーンで常設テキストが一切描画されていない(報告症状の主因)

  • prompts/scenario.md の出力例は quiz シーンの question/options のみで、他のシーン型の onScreen フィールド名を定義していない。
  • その結果、Claude 生成の sleep-01 script.jsononScreen.title / subtitle / note / points を出力した。
  • 一方 remotion/src/Root.tsx が読むのは headline / subhead / mark / items / sources / badge のみ。
  • 実測: sleep-01 の timeline.json では 11 シーン中 quiz 以外の 10 シーンすべてで headline が undefined。takeaway の箇条書き(items)も出典リスト(sources)も未描画。画面に出る大テキストは emphasis のフラッシュ(下記 #2、0.28〜2.4 秒)だけだった。
  • ヒューリスティック生成の exercise-01 は headline/subhead を出すため正常。--method claude の経路だけが壊れる
  • movie_pipeline/validate.pyonScreen を一切検証しないため素通りした。final-plan §4.2 は timeline.json を「TTS バックエンドとの契約」と定義しており、契約のスキーマ検証が欠けているのが構造的な原因。

対処案: (a) prompts/scenario.md にシーン型ごとの onScreen フィールドを明記、(b) validate.py にシーン型別の必須フィールド検証を追加(title/hook/explain→headline、answer→headline+mark、takeaway→items、sources→sources)、(c) 移行措置として Root.tsx 側で title→headline, subtitle/note→subhead, points→items のエイリアス吸収も可。

2. emphasis 演出が「headline を置換して発話中だけ表示」— サブ秒のフラッシュになる

  • Root.tsxDefaultScene: activeEmphasis(...) ?? scene.onScreen.headline。強調語が headline を置き換え、モーラ窓(実測 0.28〜2.4 秒、中央値 ~1 秒)だけ表示されて消える。
  • final-plan §6 の設計は「画面中央に巨大な強調語1つを常設表示し、今喋っている語がカラオケ式に光る」。置換+瞬間表示は設計と逆で、headline があっても画面がチラつく。movie/ 実装レビュー: テキストが読む前に消える問題の根本原因と final-plan.md との乖離 #1 で headline が undefined のため、症状が「無地の画面に単語が一瞬出て消える」として顕在化した。
  • 最低表示時間(例: 1.5〜2 秒)のフロアもどこにも無い。

対処案: headline は常設し、emphasis はハイライト(色・スケール)の切替のみにする。切替に最低表示時間のフロアを入れる。

🟠 High

3. 強調語のモーラ対応付けが「文字数=モーラ数」近似で系統的にずれる

  • movie_pipeline/timeline.py_emphasis_timing() は表層文字列の文字数をそのままモーラ index に使う。漢字は 1 文字複数モーラ(例:「睡眠」=2文字4モーラ)なので、窓が常に早く・短くなる。実測でも「俗説」0.28 秒、「請求書」0.42 秒など読解不能な窓が多数。
  • final-plan §3③ は AudioQuery の kana を使った表層→モーラ対応付けを指定し、照合失敗時は「キーワード先頭一括表示」へフォールバックする設計。実装のフォールバックは 0.35〜0.9 秒のフラッシュ(fallback: True)で、これも設計と異なる。

4. 尺ガードが未実装 — sleep-01 は 6分13秒(373 秒)で許容 4:40〜5:20 を大幅超過、無警告

  • final-plan §3②/§4.4 の「合成前尺チェック → pause 圧縮 → 台本自動圧縮リトライ → 人間フラグ」が丸ごと未実装。
  • validate.py は文字数(1000〜2100 字)しか見ておらず、sleep-01 は文字数チェックはパスしたまま実尺が 24% 超過した。timeline 生成後に totalSec を許容レンジと照合する検証だけでも先に入れる価値がある。

5. Claude 経路の検証リトライループ(最大2回)が未実装

  • final-plan §3② の「生成 → スキーマ検証 → 不合格ならエラー内容を添えて再生成(最大2回)」に対し、cli.py cmd_script は検証エラーで exit 2 して終わるだけ。
  • script_generator.py generate_script_with_claude()json.loads(raw["result"]) 一発で、コードフェンス付き応答や前置き文で即クラッシュする。subprocess.run(check=True) なので失敗時に stderr も表示されない。今回 movie/ 実装レビュー: テキストが読む前に消える問題の根本原因と final-plan.md との乖離 #1 の不正スキーマがそのまま下流に流れたのは、このループが無いことも一因。

🟡 Medium

6. シーン境界のフレーム丸めで 1 フレームの黒画面/重なりが出る(実データで再現)

  • Root.tsx はシーンの fromdurationInFrames独立に round() している。連続する秒値でも丸めが食い違う。
  • 実測(sleep-01, fps=30): explain-04 の直前に 1 フレームの隙間(背景のみの黒フレーム)、myth-01 の直前に 1 フレームの重なり。また最終シーンの終端がコンポジション長を 7 フレーム超えて尻切れ。
  • 対処: durationInFrames = round(endSec*fps) - round(startSec*fps) に統一する。

7. fitText 未使用で長文がはみ出しうる

  • final-plan §3⑥ は @remotion/layout-utilsfitText を指定し、依存にも入っているが、Root.tsx は全て固定 fontSize(headline 112px 等)。quiz の選択肢 6 個(sleep-01 で実際に 6 個)や長い headline で溢れる。validate.py の headline 警告閾値 34 字も plan の「主テキスト 28 字以内」と不整合。

8. Noto Sans JP がロードされていない(環境依存レンダ)

  • スタイルの fontFamily に名前があるだけで、フォントのバンドル/明示ロード(plan §6「Noto Sans JP バンドル+<Font> 明示ロード」)が無い。レンダ結果がマシンのインストール状況に依存し、10 本のブランド統一が保証されない。

9. VOICEVOX キャラクターのクレジット表記が無い

  • final-plan §7 は「規約に従いエンドロールにクレジット表記(キャラごとに義務あり)」。speakers.json は style_id 2/3(四国めたん・ずんだもん)を使うが、sources シーンにもエンドロールにも VOICEVOX:キャラ名 表記が無い。公開すると規約違反になる。

🟢 Minor

  • シーン id 重複の未検証: timeline.pyscene_map は id をキーに統合するため、LLM が id を重複させると黙って utterance がマージされ、同一シーンが二重に出力される。validate.py に一意性チェックを。
  • サンプリングレート固定: concat_wavs() は 24000Hz 決め打ちで、query に outputSamplingRate を明示設定していない。エンジン設定・スタイル次第で ValueError 停止。query 側で 24000 を明示するのが安全。
  • テスト無し: 尺計算・pause 規則・emphasis 対応付けは純関数でユニットテスト可能。2本目以降の横展開(plan §10 Step 6)前に最低限欲しい。

✅ 良かった点

  • 実測検証ゲート(±50ms)が設計どおり動作し、warnings に計算尺と実測尺の乖離が記録されている(sleep-01 で 7 件検出・実測採用)。
  • 無音挿入と timeline 書き戻しが同一ループ(plan §5 の「片側更新を構造的に不可能に」を遵守)。
  • dry-run モードにより VOICEVOX 無しでもパイプライン全体が通る。中間成果物が全てファイルで再実行可能。
  • 寛容パーサ・pacing.json・pronunciation.json・timeline 契約の分離は plan に忠実。

修正の優先順位(提案)

  1. movie/ 実装レビュー: テキストが読む前に消える問題の根本原因と final-plan.md との乖離 #1 + #2(症状の直接原因): プロンプトのスキーマ明記 + validate のシーン型別検証 + emphasis を常設ハイライト化
  2. #4 + #5: 尺ゲートと検証リトライループ(パイプラインの品質ゲートとして本丸)
  3. #3, #6, #9: 同期精度・黒フレーム・ライセンス
  4. #7, #8, Minor 群

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions