SCALE_mikke_撮影の文字化け対策
mikke! 撮影の「文字化け」対策(2026-07-27 恒久・大串指示)
大串FB「文字化けしてる」「文字化け定期的に起きるから起きないように体制修正してね」(2026-07-27)
実装=core/tools/shot_common.mjs/core/tools/shoot_fullpage.mjs(ver219)
「文字化け」の正体
見出しが団子に潰れる現象(実例=J.SECURITY の / Peoplecunity)。フォントの問題ではない。
参考サイトのFVは「同じ座標に複数の見出しを重ね置きし、表示中の1枚以外を opacity:0 / visibility:hidden で隠す」作りが多い(切り替え表示)。
撮影ツールの reveal()=「隠れている要素を表示に戻す」処理が、この裏面まで全部表示に倒すため、
People / Security / Community が同じ位置に重なって写る。
なぜ「定期的に」再発していたのか(真因)
撮り直しても直らない構造になっていた。
- 採用ゲートが「中身が写らない」と判定 → 保存せず
- 保存しないので 古い(文字化けした)画像がそのまま残る
- 後段の検品は既存ファイルを見るので 「要確認 0 件」と表示される
- → 壊れたまま本番に出続け、しばらくして大串が見つける
しかも J.SECURITY が撮れなかった理由も実測で判明した。段階測定:
| 処理 | 色数 | 輪郭 |
|---|---|---|
| freezeAnim 後 | 248種 | 24.4% |
| oneSlide 後 | 72種 | 2.6% |
| dedupeOverlap 後 | 8種 | 1.3% |
= 重なり解消の2処理が、FVの画像スライドごと消していた(FVが3枚のスライドで1画面を構成する作りだと、1枚化=画面の2/3が消える)。
一覧サムネ側(shoot_mikke.mjs)はこの2処理を通さないので、同じサイトが正常に撮れていた。この差分が答えだった。
入れた体制(4段構え・ver219)
1. 予防 — reveal() に構造判定
同じ親の中でほぼ同座標に重なる兄弟は、表示に倒すのを1枚だけにする(表示中があればそれ、無ければ先頭)。
- 幅の一致を条件にしてはいけない。切り替わる見出しは文字数で幅が変わる(実測 People=219px / Community=360px)。左上の一致だけで見る。
- 既存の防御は class*="swiper|slick|splide|slider|carousel" という名前頼みで、.mv__title のような独自命名を素通りしていた。名前は無限に増やせないので構造で見る。
2. 復旧 — 中身が消えたら重なり解消を外して撮り直す
isPoorShot を踏んだら、リロードして oneSlide / dedupeOverlap を飛ばしてもう一度撮る。
文字の重なりは①の reveal が面倒を見るので、外しても団子にならない。
→ J.SECURITY の PC/SP 両方が 撮影成功に転じた。
3. 検出 — 採用ゲートの重なり検査を強化
従来の検査は今回を素通りしていた。理由は2つ:
- 対象タグに span が無かった(犯人は <span class="mv-title-text">)
- 幅と高さの一致を要求していた(幅141px差で別物と判定)
→ span を対象に加え、「同タグ+同先頭クラス+同座標」なら大きさが違っても検出。
- ただし テキスト要素限定(H1/H2/H3/P/SPAN)。IMG/SVG の重なりはスライダーFVでは正常で、含めると撮影が通らなくなる(SHOGUN PIZZA で実測)。
4. 可視化 — 古い画像が残っている事実を必ず知らせる
保存できなかった時、既存ファイルがあれば警告に 「古い画像が残っています → ファイル名(撮影日)」 を明示。
黙って古いものを残すと「撮り直したのに直らない」が延々続く。
運用メモ
- どうしても撮れないサイトは
python3 tools/derive_shot.py --fv-from-thumb <id>(一覧サムネからFVを作る・大串承認済みの正規手段) - 撮り直し後の本番確認は必ずキャッシュを迂回する(
?cb=xxxを付ける)。ブラウザキャッシュで古い画像が見え、直っていないと誤認する - 既知の別件: SHOGUN PIZZA は「ロゴ重ね」で採用ゲートに弾かれる(ver207 から既知・FVはサムネ由来)
関連
追記(2026-07-31)— 今度は「撮影がFVを消していた」
大串FB「詳細ページのスマホ画像おかしくなってる」= CAFE TORTUE の SP が真っ黒。
段階測定(各処理の前後で色数・最頻色占有率を測る)で犯人を特定した。
| 処理 | 色数 | 単色率 |
|---|---|---|
| 待機後 | 450種 | 9%(正常) |
| killCurtain 後 | 12種 | 97%(破壊) |
| (killCurtain修正後)dedupeOverlap 後 | 12種 | 97%(破壊) |
- 犯人1 =
killCurtain:opening|intro|splash|loading|loader|curtain|mask|transitionという名前だけで全画面要素を消していた。
Vegas.js の背景スライダー.vegas-slide vegas-transition-fadeがtransitionに一致し、FVの背景そのものを幕として消していた。 - 犯人2 =
dedupeOverlap:同じスライド2枚を「重なり」とみなして消していた。 - → どちらも 「絵の中身(背景画像/大きなメディア/スライダーライブラリ名)を持つ器は消さない」 構造ガードで根治。
判断に迷うときは 「消さない」に倒す。幕が残った画像は検査で弾けるが、FVを消した白画像は「撮れている」ように見えてしまう。
同時に入れた保護(どれも汎用)
- 退化防止ガード:既存より半分以下に劣化する保存を拒否。
Promise.raceのタイムアウトは撮影処理を止めないため、打ち切り後に劣化画像が正常画像を上書きしていた
(実際に PC 175KB→15KB の事故が発生。git から復元済み)。 - PC/SP の独立化:旧実装は直列で、PCが失敗するとSPを撮りに行かなかった。
CAFE TORTUE は PC が既存優先で止まるため、SPだけ黒いまま永久に直らなかった。 flatRatio(最頻色の占有率)を新設:ロゴだけの画面は輪郭比をすり抜けるので、面積で判定する。
別セッションが同日に同じ弱点(ON THE TRIP の「真っ黒+ロゴ」)を別角度から直しており、コンフリクトを統合した。
結果: CAFE TORTUE SP 9KB → 78KB で正常化。fondesk / J.SECURITY で回帰なしを確認(fondesk 右下の細かい重なりは変更前と同一=既存課題)。
併走の教訓
この日は mikke! を2セッションが同時に触り、同じファイルの同じ関数を両方が直した。
shot_common.mjs でコンフリクトしたが、内容は補完的(相手=保存しない判定の強化/こちら=撮り直し判定の強化)だったため統合できた。
同じ領域を並行で触ると、片方が知らずにもう片方の前提を崩す。1システム=1セッションを守るのが安全。