# DEVLOG — comfyui-comic-creater
---
## 2026-11-10(v1.70.0: OCR・MOSS-Image のステージを高さ固定にしてズームを追加、サムネイル更新)
### ステージの高さ固定とズーム
**動機**: OCR タブの画像は幅 640px・高さ 680px、MOSS-Image のレイアウトは幅 560px・高さ 620px が上限で、横長の画像では高さ 270px 程度まで小さくなり、小さい文字枠の操作が難しかった。表示枠の高さも画像の縦横比で変わっていた。
**実装**(新規 `static/js/stage-zoom.js`、`29-ocr-tab.js`・`moss.js`・`comfyui.css`・`index.html`)
- 両タブの外枠(`#ocr-stage-wrap` / `#moss-layout-wrap`)を `.stage-viewport`(高さ `clamp(360px, calc(100vh - 300px), 1400px)`、`overflow: auto`)にした。表示倍率 = フィット倍率(表示枠に全体が収まる)× ズーム(1〜8)。上限幅(640/560px)は撤廃し、表示枠いっぱいまで使う。
- ステージは `margin: auto` で中央寄せ。`justify-content: center` だと拡大時に左・上へはみ出た部分へスクロールできないため。
- 操作: ツールバー右端の −/+(1.25 倍刻み)・倍率表示・「全体」、Ctrl+ホイール(トラックパッドのピンチも ctrlKey 付き wheel)、中ボタンドラッグでスクロール(`mousedown` で自動スクロールを抑止)、`+` / `-` / `0` キー(入力欄にフォーカスがあるときは無効)。
- 倍率表示は「全体表示 = 100%」基準(当初は実画素に対する倍率を出していたが、ユーザー要望で変更)。
- カーソル基準の拡縮: 拡縮前にアンカー点のステージ内比率を記録し、再描画後にその点が同じ画面位置に来るよう `scrollLeft/Top` を補正。
- 座標変換はもともと両タブとも `getBoundingClientRect` と倍率で行っていたため、描画・移動・拡縮のロジックは無変更。MOSS の `pointerdown` には `e.button !== 0` のガードを追加(中ボタンで枠を描かないように)。OCR は新しい画像の読み込みでズームを 1 に戻す。MOSS はタブ再表示時に `renderCanvas()` し直す(非表示中は表示枠の寸法が 0 のため)。
- i18n(日英中)`zoom.in` / `zoom.out` / `zoom.fit` / `zoom.fitTitle` / `zoom.hint`。ヘルプは OCR に「表示の拡大(ズーム)」節、MOSS のレイアウトエディタに 1 項目を追加(日英中)。README 3 言語に追記。
**検証**(Playwright、1600×950): OCR に 1600×800 の画像を貼り付け、フィットで幅 1092px(以前は 640px 上限)。Ctrl+ホイールで 183% にしてもアンカー点の比率が (0.750, 0.257) で保たれ、拡大中に比率 0.70〜0.80 へドラッグした枠が 0.700〜0.800 に描かれることを確認。MOSS でも拡大中のドラッグ位置と描かれた枠のずれは枠線の 1px のみ。「全体」ボタンが浮動小数の比較で無視されるバグをこの検証で見つけて修正(`setZoom(1, null, true)` で強制再描画)。コンソールエラーなし。中ボタンドラッグと実マウスでの操作感は未確認。
### サムネイル更新
- `docs/thumb.png`(Comfy Registry のアイコン)を新しい画像に差し替え、720×480 に縮小(元は 1728×1152・約 3.4MB → 約 680KB)。最初に渡された画像はロゴが「Comic Creater」と誤記だったため、差し替え版を待ってから反映した。
**How to apply**: 他のタブのキャンバスにズームを付けるときは `createStageZoom({ wrap, stage, controls, render, isActive })` を使い、描画側は `zoom.scaleFor(w, h)` で倍率を得る。座標変換は倍率と `getBoundingClientRect` で行うこと(固定値の倍率を持たない)。
---
## 2026-11-08(v1.69.1: Chat TE と画像生成が同時に動かないように待つ、マニュアル v1.69.1 対応)
### Chat TE の実行中に画像生成が始まる問題
**症状(Kapture 確認時のログ)**: v1.69.0 の `/free` は Chat TE の前に動いていた(17:06:42 `Using RAM pressure cache.`)が、17:06:44 に Qwen3-VL-8B を読んで全体読みをしている最中の 17:06:52 に MOSS 生成が始まり、2つが同時に GPU を使った。17:07:00 に `Chat TE: generation failed`(HTTP 500)。MOSS は完了したが、comfy-aimdo の `resident_count sync error` 警告が続いた。
**原因**: v1.69.0 は「Chat TE が終わった後」の生成と「生成の後」の Chat TE しか想定していなかった。目印(`afterChatTe`)は応答後に付くため、実行中に始まった生成は何も待たずに進んでいた。Chat TE 側も、ComfyUI のキューで生成中かどうかを見ていなかった。
**修正**(`vram-prepare.js`・`29-ocr-tab.js`)
- `beforeChatTe(base, onWait)` で `_chatTeRunning`(Promise)を立て、`/queue` の実行中・待機中が空になるまで 1 秒ごとに待つ(最大 15 分、待ちに入ったら進行表示「ComfyUIの生成が終わるのを待っています…」)。その後、従来どおり必要なら `/free`。
- `afterChatTe` で目印を付けてから `_chatTeRunning` を解除する。`chatteRead` は status/load/chat を try/finally で囲み、失敗時も必ず呼ぶ。
- 画像生成前の `freeAfterChatTe` は、同じオリジンで Chat TE が実行中なら通知(「OCRのChat TE(全体読み)が終わるまで生成を待ちます」)を出して終わるまで待ち、その後 `/free`。
- i18n(日英中)`ocr.progressChatteWaitQueue`・`vram.chatteWaiting`、ヘルプ(全体読み)に追記。
**検証**: ページを再読み込みせず、Kapture で `vram-prepare.js` をクエリ付きで別インスタンスとして import して確認。`beforeChatTe` 後に呼んだ `prepareVramForGeneration` は 2 秒後も未完了で、`afterChatTe` の後に `/free` して完了した。ComfyUI で生成中に Chat TE を始めたときの待ちは未確認。
### マニュアル v1.69.1 対応
- 原稿(リポジトリ外 `manual/{ja,en}`)と同梱版(`docs/manual/{ja,en}`)を v1.69.1 に更新。第9章 Draw にカラーパレットとショートカット(v1.67.0 で未反映だった)、第10章 MOSS-Image に「選択」と削除の取り消し、OCR に「枠を直す」節と Chat TE の VRAM 対策の注意、第14章に ComfyUI が止まる症状と枠を誤って描く症状、付録に OCR タブ・Draw ツールのキー操作を追加。
- 同梱版は原稿から `[画像:〇〇]`/`[Image: ...]` 行と隣の空行、日本語目次の版の説明行を除いて生成(改訂前の原稿から現在の同梱版を完全に再現できることを確認してから実行)。README のマニュアル節を「v1.69.1対応」に。Kindle 版は対象外(追加の画像プレースホルダーはなし)。
---
## 2026-11-08(v1.69.0: OCR・MOSS-Image の bbox に選択モードと削除の取り消し、Chat TE と画像生成の VRAM 重なりで ComfyUI が落ちる問題の対策)
### 選択モード(不意の描画を防ぐ)
**背景**: OCR タブ・MOSS-Image タブのキャンバスは、空いている所(MOSS は未選択の枠の内側も)をドラッグすると常に新しい枠を描くため、枠を動かすつもりで小さな枠を描いてしまうことがあった。
**実装**
- MOSS-Image: 描画種別ボタン群の先頭に「選択」(`data-type="select"`)を追加。`isSelectMode()` のとき、空き領域の押下は選択解除だけ、枠の内側は未選択でも常に移動(`grab = true`)、`pending` からの描画への切り替え(Shift+ドラッグ含む)もしない。選んだ種別は localStorage `ccc_moss_draw_type` に保存。
- OCR: 「描画種別」の左に「選択|描画」のトグル(`#ocr-stage-mode`)を追加。選択モードでは空き領域の押下で選択解除だけ。描画種別のプルダウンを変えると描画モードに戻る。localStorage `ccc_ocr_stage_mode`。
- 既定は従来どおり描画(MOSS は「物体」)。
### 削除の取り消し
**実装**: 「元に戻す」ボタン(MOSS は削除の右、OCR は全クリアの右)と Ctrl+Z(Cmd+Z)。タブ表示中かつ入力欄にフォーカスがないときだけ効く。
- 全体のスナップショットではなく、削除した枠を `{ 枠のコピー, 元の配列位置 }` で積み(最大 30 回)、戻すときは元の位置の昇順で `splice` して重なり順も戻す。削除後に他の枠を動かしても、その操作は巻き戻らない。戻した枠は選択状態にする。
- 対象: MOSS は削除ボタン・Delete キー・新規作成・取り込み全クリア(`removeItems(pred)` に集約)、OCR は削除・Delete キー・全クリア(`removeBoxes(pred)`)。
- 履歴を消すタイミング: MOSS はコマ/フキダシ/OCR の取り込み(座標が拡縮されることがあるため)、OCR は画像の読み込み(id を 1 から振り直すため衝突する)と検出のやり直し。
### Chat TE と画像生成の VRAM 重なりで ComfyUI が落ちる
**症状**: MOSS-Image で生成に失敗し、「ComfyUIに接続できません」になる。
**原因(ログで確認)**: 16:17 と 16:42 の 2 回とも、MOSS の TE(7GB)と本体(5GB)が ComfyUI に staged のまま、OCR タブの Chat TE が `qwen3vl_8b_fp8_scaled`(10GB)を同じプロセスに読み込んだ直後に `Chat TE: generation failed` → `CUDA error: an illegal memory access`。16:18 には comfy-aimdo の `cuMemcpyHtoDAsync failed result=710`、Windows 側の nvlddmkm 153・LiveKernelEvent 141(GPU のタイムアウト/リセット)も出ていた。通常の OOM と違い CUDA エラーが sticky になり、以後のすべての実行(次の MOSS 生成の CLIP encode)が失敗するため、再起動まで使えない。従来の `prepareVramForGeneration()` は Ollama のモデルしか退避せず、ComfyUI 内のモデル同士の重なりは防げなかった。
**修正**(`vram-prepare.js`)
- `freeComfyModels(base)`: ComfyUI 標準の `POST /free {unload_models, free_memory}`。キューの処理スレッドが非同期に処理するため 1.5 秒待つ。
- `beforeChatTe(base)`: Chat TE の status/load の前に呼ぶ。前回の Chat TE 以降に ComfyUI で何も生成していなければ(`/history?max_items=1` の最新 prompt_id が前回と同じ)降ろさない。Chat TE の API 呼び出しは履歴に残らないので判定に使える。
- `afterChatTe(base)`: chat/completions の応答直後(失敗時も 8B が載っている可能性があるので結果を見る前)に目印を付ける。
- `prepareVramForGeneration(extraUrls, { comfyGen = true })`: 先頭で、同じオリジンの ComfyUI で Chat TE を使った後なら `/free` して通知。「VRAM調整」が off でも行う。OCR タブの Ollama 用の呼び出しは `comfyGen: false`。MOSS・Workflow Studio 経由の生成(T2I/I2I/Inpaint 等)は既存の呼び出しでそのまま対象になる。
- ComfyUI の `CLIP.generate()` は毎回 `load_model()` で GPU へ読み直すため、`/free` 後も Chat TE はそのまま動く。
**未検証**: 実機での再発防止(Kapture 切断中)。`/free` 後 1.5 秒で足りない場合は待ち時間を延ばす。重なりを避けても再発するなら comfy-aimdo(動的 VRAM)/ドライバー側を疑う。目印はページ内の変数なので、Chat TE 使用後にリロードしてから生成すると降ろさない。
**How to apply**: ComfyUI の同じプロセスに大きなモデルを読む機能(Chat TE のような API 経由のロード)を追加するときは、Ollama の退避だけでなく ComfyUI 内の他のモデルとの重なりも考える。CUDA の illegal memory access は一度出ると再起動まで直らないため、事前に降ろす設計にする。
---
## 2026-11-08(v1.68.1: PixiJS FX が particle-pixijs をレジストリから入れ直すと開けない不具合を修正)
**症状**: レイアウトタブ「画像」サブタブ・Imageタブの PixiJS FX を開くと「カスタムノード comfyUI-particle-pixijs の読み込みに失敗しました」のアラートが出て使えない。
**原因**: comfyUI-particle-pixijs を Comfy Registry / Manager 経由で入れ直したことで、インストール先フォルダ名が `comfyUI-particle-pixijs` から小文字の `comfyui-particle-pixijs` に変わった。ComfyUI は `WEB_DIRECTORY` をフォルダ名で `/extensions/<フォルダ名>/` に配信し、aiohttp のルートは大文字小文字を区別するため、`pixifx.js` が固定で import していた `/extensions/comfyUI-particle-pixijs/particle_engine.js` が 404 になっていた(Windows のファイルパスは区別しないので、フォルダ自体は存在するように見える)。
**修正**: `pixifx.js` の `EXT_BASE` を `EXT_BASES`(小文字→従来名の順)に変更し、`loadModules()` で順に import を試して、最初に成功したものを使う。どちらも失敗したときだけ従来のアラートを出す。particle-pixijs 側も v1.7.1 で `pyproject.toml` に `[tool.comfy] web = "web"` を追加し、どの入れ方でも小文字の URL で配信されるようにした。
**点検**: 他の連携先の固定URLも確認した。`/extensions/comfyui-vrm-pose-editor/`(pose3d.js・text3d.js)はリポジトリ名・pyproject名・フォルダ名がすべて小文字で、入れ方によらず同じURLなので影響なし。`/vps`・`/mask_editor/...`・`/pose_library/...` は各ノードの Python で定義されたサーバーAPIルートで、フォルダ名に依存しない。
**How to apply**: 他のカスタムノードの JS を `/extensions/...` で参照する場合は、フォルダ名がインストール方法で変わる(レジストリ=小文字の registry id、git clone=リポジトリ名)ことを前提に、小文字の pyproject 名を優先しつつフォールバックを持たせる。
---
## 2026-11-08(v1.68.0: 3Dポーズの 🎛 Editor を VRM Pose Studio に切替可能に)
**背景**: レイアウトタブ「3Dポーズ」の 🎛 Editor(comfyui-vrm-pose-editor の Light & Pose Editor)の代わりに、複数モデル・カメラ・タイムラインを扱える VRM Pose Studio(ComfyUI-VRM-Pose-Studio、`/vps`)でもポーズを作ってコマへ入れたい、という要望。VPS はライブラリではなく独立したSPAなので、従来のように動的importしてコマ上に重ねる方式は取れない。
**方式**: CC(`/ccc`)と VPS(`/vps`)は同じ ComfyUI のオリジンで配信されるため、CC から `window.open` で開けば VPS の `window.opener` が CC になり、関数を直接呼び合える。iframe埋め込み(画面が狭い)やエンジンの直接import(VPS の大改修が必要)は不採用。
**実装**(切り替わるのは 🎛 Editor ボタンの動作だけ。コマ上の3Dビュー・コマに配置・コマに確定は従来どおり)
- 設定タブに「3Dポーズ エディタ」(localStorage `ccc_pose3d_editor_engine` = `pose-editor` / `vps`)。VPS を選ぶと `HEAD /vps` で有無を確認して表示。
- `23-pose3d-bridge.js`: 🎛 Editor で、選択中のコマ(3Dビュー配置中ならそのコマ)を送り先に固定し、枠 `{ width, height, points, label }` を作る(points はコマ外接矩形を基準に0〜1へ正規化した多角形、解像度は長辺1024〜2048、label はコマ選択欄と同じ名前)。
- CC が公開する関数: `window.ccGetPanelFrame()`(VPS が起動時に枠を取得)、`window.ccReceiveVpsImage({ dataUrl, width, height })`(VPS の「📤 CCのコマへ送る」で呼ばれ、コマ外接矩形を覆う配置で `insertImage`。ページ移動・コマ削除時は例外を返し VPS 側でトースト表示)。開いたままの VPS には `vpsWin.vpsApplyCcFrame(frame)` で枠だけ差し替える。
- i18n 日英中、ヘルプ(3Dポーズサブタブ・設定タブ)、README 3言語。
**落とし穴**
- ComfyUI のトップメニューは `window.open(url, "vrm_pose_studio")` で VPS を開く。CC から同じ名前で開くと既存ウィンドウ(opener = ComfyUI)が再利用され CC とつながらないため、CC 専用の名前 `vrm_pose_studio_cc` を使う。
- `window.open('', name)` は同名のウィンドウがあれば再読み込みせずに返すので、CC を再読み込みした後も開いたままの VPS につながる(空なら `/vps?cc=1` へ移動)。
- `/vps` の有無を `fetch` で確かめてから開くとクリックの同期処理から外れてポップアップブロックされるため、有無の確認は設定画面で事前に行い、クリック時は必ず先に `window.open` する。
- `insertImage` は選択状態(下書き/オーバーレイ/コマ)で挿入先を決める。ページ切替直後は `selectedOverlay = true` になっているため、挿入の間だけ送り先コマを選択扱いにして元に戻す。
**VPS 側**(ComfyUI-VRM-Pose-Studio に同時に実装): コマ枠の表示(外側をグレーの半透明、赤い点線、コマ名タグ)、出力サイズをコマに一時固定(プロジェクトには保存しない、「解除」で戻す)、送信ボタンを「CCのコマへ送る」に切替、CC から開いたときは背景透過・地面非表示で開始。あわせてビューポートを出力枠の外側まで描くパスパルトゥー表示に変更。
**検証**: Kaptureが接続できなかったため、Playwright(ComfyUI :8189)で確認。設定の検出表示、斜めの5角形のコマの枠表示とコマ名タグ、開いたままの VPS への枠の差し替え(タブが増えない)、CC 再読み込み後の再接続、送信でコマの形にクリップされて挿入されること、元に戻す、VPS の保存データの出力サイズが変わらないこと、未保存扱いにならないこと、背景透過・地面非表示を確認。
---
## 2026-11-05(v1.67.0: Imageタブ — Drawツールのカラーパレットとショートカット)
**背景**: Drawツールの2段目(`ie-tool-options`)は空だった。ペイントのように色を並べ、基本色とカスタム色を登録したいという要望。
**実装**
- 新規 `static/js/image-tab/DrawPalette.js`: 色1/色2、基本色20色、カスタム色20枠の表示と登録を担当。右クリックメニューで現在の色の登録・色の編集・削除(カスタム色)・初期の色に戻す(変更済みの基本色)。保存先は localStorage `ie_draw_palette_v1`。作品データには含めない。
- `image-tab.js`: 色の変更を `_setDrawColor` に集約(パレット・右パネルのColor入力・スポイト)。モードは `_setDrawMode`、サイズは `_setDrawBrushSize` / `_stepDrawBrushSize` に分離。
- ショートカット(Drawツール中のみ): `D` Draw / `E` Erase / `X` 色1・色2切替 / `[` `]` サイズ増減(1〜10pxは1、10〜50pxは5、50〜200pxは10刻み)/ `B` ブラシ選択モーダルの開閉。Bは他のツールからはこれまでどおりDrawへの切り替え。モーダル表示中は D/E/X/[/] を無効にし、Escで閉じられるようにした。
- ブラシの初期色を赤から黒に変更(色1/色2 = 黒/白)。
**原因と対処**: `New` などのドキュメント初期化で `DrawTool` が作り直され、ブラシ色だけ初期色に戻ってパレットとずれた。Drawツールの表示時にパレットの現在色をブラシへ反映するようにし、パレットを色の正とした。ブラシサイズなど色以外の設定は従来どおり初期値に戻る。
**検証**: Kaptureが接続できなかったため、Playwright(ComfyUI :8189)で確認。パレットからの描画色、登録と再読み込み後の保持、右クリックメニュー、スポイト連動、各ショートカット、入力欄やCtrl/Alt同時押しで反応しないこと、サイズ全範囲の増減を確認し、コンソールエラーなし。
ブラウザ標準のカラーピッカーの表示、ABRブラシ未インポート時の通知、日本語キーボードでの `[` `]` の実打鍵は、ユーザーの確認後にリリースした。
---
## 2026-10-27(v1.66.0: MOSS-Imageの最前面/最背面、単独テキストのcaption、OCR→MOSSの変換)
**1. MOSS-Imageのレイアウトエディタ: 「最前面」「最背面」を追加**
- 既存の「前面へ」「背面へ」(1つずつ入れ替え)の両端に追加。`moss.js` の `moveSelectedToEdge(toFront)` が選択中の枠を配列の末尾/先頭へ移す(すでに端なら何もしない)。ボタンは `moss-item-top-btn` / `moss-item-bottom-btn`、i18n `moss.itemTop` / `moss.itemBottom`(日英中)、ヘルプ・マニュアルに追記。
**2. 単独テキストのcaptionを常に `Narration text.` に**
- 従来は、フキダシ等の枠に入らない単独の文字枠を、空白を除いて6文字以下なら `Sound effect.`、それ以外は `Narration text.` としていた。名前・見出しが擬音になる誤りがあるため、文字数による判定を廃止(`ocr-core.js` の `toMossItems` と `moss.js` の `textCaptionOf`)。擬音は `sfx` クラス(レイアウト検出・意思決定モデル)だけが `Sound effect lettering.` になる。
---
## 2026-10-27(マニュアルをv1.66.0対応に更新: 日本語・英語、同梱版 `docs/manual/` を含む)
v1.59.0対応から、v1.60.0〜v1.65.0と今回のv1.66.0(OCRのChat TE全体読み・MOSS-Image最前面/最背面・Nanobanana+のQwen Image 2.1画像枚数対応)を反映した。**Kindle版(EPUB・スクリーンショット)は後日**。
- 第10章を中心に改訂: 章タイトルを「Nanobanana+・Workflow Studio・MOSS-Image・OCR」に変更。10-3/10-4を「Nanobanana+(Nanobananaモード)」・1画面統合(左=プロンプトと基本設定、右=Image-to-Image)・サブタブ「Nanobanana履歴」に合わせて修正。10-5のSend CC(Image)。10-6にMOSS-Imageの変更(レイアウト オーバーレイ・Imageタブで開く・テキストを無効で生成・Shift+クリック複数選択・最前面/最背面・新規作成/取り込み全クリア・プロンプト拡張・単独テキストのcaptionは常にナレーション)。**10-7 Nanobanana+のローカルモード**と**10-8 OCRタブ**を章末に追加(既存の節番号は振り直していない)。
- そのほか: 第1・3章(タブ12個、Nanobanana+とOCRの行)、第7・9章(Insertの「テキストを挿入」モーダル)、第13章(VRAM調整がOCRにも働く)、第14章(トラブル表にOCR・ローカルモード・MOSS-Imageの文字)、付録(用語集、Shift+クリック)、はじめに・目次のバージョン表記、撮影リスト(008・040撮り直し、051・052追加、049撮り直し推奨)。日英で見出し数・画像プレースホルダー数が一致することを確認した。
- 同梱版 `docs/manual/{ja,en}` は、前回と同じ方法(原稿から `[画像:〇〇]` / `[Image: ...]` 行を取り除き、日本語目次の出版方針メモ行を除く)で再生成した。v1.59.0の原稿から同じ手順で現行の同梱版が完全に再現できることを先に確認してから出力した。READMEのマニュアル節(日・英)を「v1.66.0対応」に更新。
- 原稿(`eagle_comic_creator_spa/manual/`)はリポジトリ外のため、コミットには含まれない。Kindle版は原稿と撮影リストを元に、スクリーンショット撮影(新規051・052、撮り直し008・040・049)とあわせて後日行う。
---
## 2026-10-27(v1.66.0: Nanobanana+ — Qwen Image 2.1 の画像入力をドロップ枚数に合わせる)
**背景**: Qwen Image 2.1 の Image Edit サブグラフ(`TextEncodeQwenImage21`)は `images.image_1`〜`image_10` の最大10入力を持ち、未接続の入力は使われない。一方ワークフロー内のLoadImageは固定数(登録の「Qwen2.1 (2枚)」なら2個)で、3枚目以降は切り捨てられていた(WFSは i 枚目→ノードID順の i 番目のLoadImage)。
**実装(CC側のみ。WFSの変更なし)**
- 新規 `static/js/nb-image-slots.js`(DOM非依存): `findImageSlots`(`images.image_N` を2つ以上持つノードを探す)/ `maxImageSlots`(上限、最大10)/ `fitImageSlots(wf, n)`(litegraph形式のワークフローJSONで、既存のLoadImageを取り除き、枚数ぶんのLoadImageをID昇順に作って `images.image_1..n` へ接続。元のオブジェクトは変えない)。
- 安全側で何もしない条件: 画像入力の元がLoadImage以外/そのLoadImageが他(例: ImageCompare)にもつながっている/画像入力と無関係なLoadImageが別にある(スロット順がずれるため)。例: `qwen_image21turbo_i2i.json` は変更されず従来どおり。
- `14-integrations.js` `sendMultiImageI2IToWorkflowStudio`: ワークフロー取得後に `fitImageSlots` を通してWFSへ渡す。
- `nanobanana.js`: `maxI2I()`(ローカルで画像入力が複数あるワークフローはその数、それ以外は14)と `refreshLocalMax()`(選択中のワークフローを取得して上限を調べ、画像グリッドの「(n/上限)」と空きスロット数に反映。モード切替・ワークフロー切替・⚙設定を閉じたときに更新)。
**検証**: ユーザーのワークフロー4種・Klein でN=1/3/10/12を単体確認(リンク整合・10枚で打ち止め)。実機(Kapture、ComfyUI :8189)で「Qwen2.1 (2枚)」を選ぶと上限が (0/10)、Klein は (0/14)。4枚ドロップして生成すると、キューのプロンプトに LoadImage が4つ・`TextEncodeQwenImage21` に `image_1..4` が接続され、4枚を使った結果が返った。
**未了**: 上限を超えて入れた場合の挙動(既存の切り捨て警告)。ヘルプ・READMEは同日追記済み(Nanobanana+のローカルモード欄)。
---
## 2026-10-27(v1.66.0: OCRタブ — Chat TE(Qwen3-VL)による全体読み)
**背景**: 縦書きの多い雑誌表紙で、LightOnOCRは0語・manga版は17語と読めない。ComfyUIのChat TEノード(テキストエンコーダーをそのままチャットに使う)で比較した。
**比較(雑誌表紙4枚・目視の正解キーワード52語、同一プロンプト)**
- Chat TE Qwen3-VL-8B 44語(thinking OFF)/ Qwen3-VL-4B 38(thinking ON。OFFだと全画像でほぼ空=2語)/ Qwen3.5-9B 35 / Qwen2.5-VL-7B 34。
- Ollama: glm-ocr 35 / qwen3.5:9b 34 / gemma4:e4b 24 / PaddleOCR-VL-1.6 24 / PaddleOCR-VL-manga 17 / LightOnOCR-3 0(4枚目は900秒でタイムアウト)。
- Qwen3-VLにbbox_2dを出させる試みは、座標がずれ、途中で同じ記号の繰り返しに陥るため不採用。位置はOCRの枠から取り、文字だけ全体読みで置き換える設計にした。
**実装**
- `ocr-core.js`: `CHATTE_PROMPT` / `pickChatTeModel`(8B→4B→Qwen3.5)/ `chatTeThinking`(4Bだけthinking ON)/ `parseChatTeLines`(思考ブロック・連続同一行の除去)/ `textSimilarity`(バイグラムDice)/ `applyChatTeLines`(類似度0.4以上かつ極端に長くない行だけで枠の文字を置換、合わない行は返す)。プリセット `cover`・`text` で全体読みオン、`illustration` でオフ。
- `29-ocr-tab.js` + `index.html` + i18n(日英中): 「全体読み(Chat TE / ComfyUI)」欄(有効・URL既定=location.origin・モデル・「全体読みだけ実行」・合わなかった行の欄)。実行前にVRAM調整でOllamaを退避。モデルが未ロード・別モデルなら `/chat_te/load` で読み込む。
- 実機検証(Kapture、ComfyUI :8189、声優アニメディア表紙): 単独実行で68行、雑誌表紙モードの通し実行で59枠中10件を置換・23行が未対応。
**注意**: 8Bの再ロードはOllamaにモデルが残っているとVRAM不足で接続が切れる(`WinError 10054`)ことがあった。VRAM調整をオンにしておく。他のOCR入力・4枚すべての通し検証は未了。README・ヘルプ(OCR節の「全体読み(Chat TE)」)は追記済み。
---
## 2026-10-27(v1.65.0: Nanobanana+タブ — ローカルImage Editワークフロー対応、生成設定/I2Iの1画面化)
**背景**: Nanobananaタブ(Gemini API / ComfyUIネイティブ専用)を、ローカルのImage Edit系ワークフロー(Flux.3 Image Klein、Qwen Image 2.1等)でも使えるようにしたい、という要望。計画は `PLAN_nanobanana_local_image_edit.md`。
**1. タブ名とモード切替**
- タブ名を「Nanobanana+」に変更(i18n 3言語、ヘルプ・README)。上部に「Nanobanana / ローカル」ラジオ。ローカル時のみワークフローのドロップダウンと⚙ボタンを表示。モードの出し分けは `#nanobanana-tab[data-mode]` と CSS クラス `nb-cloud-only` / `nb-local-only`(`comfyui.css`)で行う(個別に `display` を操作しない)。
- ⚙ダイアログ(`nanobanana.js` の `openLocalSettings`): 表示名+WFS保存済みワークフロー(`/api/wfm/workflows` の一覧)の組を複数登録・削除。`localStorage` の `ccc_nanobanana_local`(`mode` / `selected` / `entries` / `seedMode` / `seed`)。初期登録なし。
**2. ローカル生成の経路(複数画像対応)**
- `14-integrations.js` に `sendMultiImageI2IToWorkflowStudio(imageBlobs, params, workflowFile)` を追加(`/api/wfm/workflows/raw` でJSON取得→WFSのiframeブリッジ `_wfmReceiveMultiImageI2IRunRequest` へ)。`prepareVramForGeneration()` も踏襲。
- 結果のURLはWFSの `blob:` URLなので、必ずdata URLへ変換してから `saveNanobananaImageAndMaybeEagle` で `cc_nanobanana` へ保存(過去の「blob URLの永続化」事故の再発防止)。履歴(history.jsonl)への記録はNanobananaモードのみ。
- **WFS側が必要**(v0.8.12): 画像 i 枚目をワークフロー内 i 番目のLoadImageへ割り当て、超過分は無視して `usedImages`/`slotCount` を返す。CC側は超過時に警告。
**3. 共通の基本設定(ローカル)**
- 生成枚数・画像サイズ(既定/プリセット/カスタム)・Steps・CFG・サンプラー・スケジューラ・Denoise。サンプラー/スケジューラの選択肢は `/object_info/KSampler` から取得。未指定(既定/空欄)はワークフローの値のまま。WFSの既存 `setGenerationParams` を再利用。
- **限界(仕様)**: KSampler系以外の構成、および出力サイズを入力画像から決める構成には効かない。実機で確認: Flux.3 Image Klein(`ReferenceMultiLatent` 使用)は `EmptyFlux2LatentImage` が解析対象外になり画像サイズが反映されない(プロンプト・画像・Steps・CFG・シードは反映)。
**4. シード(MOSS-Imageタブを参考)**
- ローカル専用に「ランダム/固定/生成ごとに+1」+「直前のシード」+「このシードを固定」。ランダムはCC側で乱数を決めて固定値としてWFSへ渡す(直前のシードを表示・再現できるようにするため)。複数枚は枚数ごとに+1。
- **Nanobananaモードではシード欄を非表示**: Gemini直叩きはシードをAPIへ送らず(履歴に記録されるだけ)、ネイティブ経路でもComfyUIのキャッシュキーにしか使われないため。cloud/nativeは常にランダム扱い。ネガティブ・サイズ・枚数はバックエンドで使われているので残している。
**5. レイアウト**
- サブタブ「生成設定」と「I2I入力」を1つに統合し、左右2分割(左=プロンプト+基本設定、右=Image-to-Image 3列×4行)。履歴サブタブは「Nanobanana履歴」に改名。
- ステータス表示の競合を修正: モード切替直後に、クラウド側の非同期のAPIキー確認が後から返ってローカルのステータスを上書きしていた(`refreshApiKey` で返却後にモードを再確認)。
**実機検証(ComfyUI_5 / 8189)**: ラジオ切替・⚙登録・生成(Qwen2.1 1枚/2枚入力、Flux.3 Klein)・共通設定(サイズ/Steps/CFG/サンプラー/スケジューラ/Denoise/シード)の実行ワークフローへの反映・シード3モード・結果保存を確認。Kaptureのファイル選択ダイアログは使えないため、`DataTransfer` で `` に画像を流し込んで検証。
- **How to apply**: ファイル選択直後(`FileReader` の読込完了前)に生成ボタンを押すと画像0枚で生成される(既存Nanobananaと同じ制約)。テストで自動化するときは読込を待つ。
**未対応・申し送り**: Flux.3 Klein以外のワークフロー(SD_3等)の個別検証、ローカル結果の履歴記録、ヘルプの「画像サイズが効かないワークフローがある」注記は上記ヘルプ本文に反映済み。
---
## 2026-10-26(v1.64.0: テキスト挿入モーダル(スクリプト/OCR)、MOSS-Image操作の改善、WFS Send CC(Image)受け口)
**1. 「Insert」ボタンのモーダル化(レイアウト/Imageタブ共通)**
- `static/js/text-insert-modal.js` を新設。挿入元(スクリプトのセル / OCRタブの検出テキスト)を選び、OCRのときは「フォントサイズを領域サイズから自動換算」か「指定サイズ」、書字方向(枠の形から自動/横/縦)を選ぶ。選択は `ccc_text_insert_v1`(localStorage)に保存。
- 純粋ロジックは `ocr-core.js` に追加: `toTextInsertItems`(本文のある text/balloon/sfx/caption 枠を読み順で、`guessVertical` で縦横推定)、`fitFontSize`(行数・文字数・全角=1/半角=0.55em から枠に収まるサイズ。縦書きは行=列、行間1.2em)。OCRタブからは `getOcrTextItems()`(`29-ocr-tab.js`)で現在の検出結果を渡す。
- レイアウトタブ(`insertOcrTexts`、`09e-text-tool.js`): OCR画像の正規化座標をページのviewBoxへ対応させ、各枠の中心にテキストブロックの中心を合わせて(`getBBox` でシフト)**オーバーレイ**へ1件ずつ挿入。指定サイズはpt(×3.528でSVG単位)。履歴は1回分。
- Imageタブ: テキストツールのオプションバーに Insert ボタンを新設(従来Imageタブには無かった)。OCRは枠位置にテキストレイヤーを作り「OCR」グループ(2件以上のとき)へ。スクリプトはキャンバス中央に1レイヤー。指定サイズはpx。
- 実機(8189)でモーダル表示とコンソールエラー無しまで確認。実際の挿入位置・縦書き配置・グループ表示は未検証。
**2. MOSS-Imageタブ**
- 「選択中の画像をページ全面へ配置」を「レイアウト オーバーレイ」に改名。「Imageタブで開く」ボタンを追加(`onOpenInImage`: `switchTab('image')` → `_ccImageTab.loadFromUrl`)。
- 「テキストを無効で生成」チェック(`moss-no-text`)を「画像を生成」の下に追加。`layoutPayload()` から type='text' の枠を除くだけで枠は削除しない(生成とJSONプレビューの両方、設定は保存)。ユーザー検証: 全体プロンプトに表紙・雑誌・タイポグラフィなどの語が含まれると文字が描かれるため、それらを取り除けば画像のみで生成できた。
- OCRタブの「レイアウトとして送る」を「MOSS-Imageタブへ送る」に改名(ヘルプ・README反映)。
**3. WFS Send CC(Image)の受け口**
- `window.sendImageToImageTab(url, name)`(`14-integrations.js`): Imageタブへ切り替えてから `loadFromUrl`(作業中のレイヤーがあれば新規レイヤー、無ければ新規キャンバス)。成功なら true。WFSのGalleryタブの「Send CC Image」(Workflow Studio v0.8.11)が `window.parent` 経由で呼ぶ。I2I送信元の記録(`_ccI2ITargetMode`)には依存しない。
- 実機でImageタブ未初期化の状態からの連続2回呼び出し(新規キャンバス→新規レイヤー)と、WFS側ボタンからの読み込みを確認。
**How to apply**: Python経由でJS文字列を書き換えるとき、`
` や `'` は引用符・heredocの扱いで意図せず実改行/生の引用符になる(今回 `split('
')` と英語ヘルプ中の `'` で2度構文エラーになった)。書き込み後は必ず `node --check`(.mjsコピー)で確認する。
---
## 2026-10-25(OCR/MOSS: Shift+クリック複数選択、bboxずれの原因調査、意思決定モデルによる切り抜き判定、全体プロンプト、グレースケール、用途別モード、v1.63.0)
**1. Shift+クリックの複数選択・一括移動(OCRタブ・MOSS-Imageタブ)**
- OCRタブ: `O.multi`(selId以外の追加選択)と `isSel` / `toggleMulti`。選択中の枠のどれかをドラッグするとグループ全体を移動し、外接矩形が画像内に収まるよう移動量を制限。Delete・削除ボタンは選択全体が対象。リサイズと「選択枠を読み直す」は主選択1枠のみ。
- MOSS-Imageタブ: Shift+ドラッグは従来どおり「その上に新規描画」なので、**Shift+クリック(4px未満)のときだけ選択の追加/解除**にした(`drag.shift` の pending)。プロパティ欄・順序ボタン・リサイズは主選択のみ。
- 実機未検証(node構文チェックのみ)。
**2. bboxずれの原因調査(結論: 検出モデルの精度、取り込み処理は正常)**
- 合成の縦書きページ(正方形・1400×820・820×1400・イラスト入り)で LightOnOCR の座標を正解と比較: 誤差は全て1%未満(約0.5%)。縮小・正規化・表示の経路にもずれなし。
- ずれて見えた枠は薄紫(captionクラス)= gemma4:e4b のレイアウト検出。縦長の文字列に対し、幅は約4倍に太く、高さは約6割に縮み、上へずれた枠を返す(`box_2d` の精度が粗い)。qwen3.5:9b は caption系を検出できなかった。
- LightOnOCR は文字の本文を `message.thinking` に入れて `content` が空になることがある(`think: false` を付けたアプリ側は問題なし。素のスクリプトで叩くときは `thinking` も見る)。
**3. 意思決定モデル(画像対応)の実測**
- 前提: Ollama 0.40.11。`d3:4b`(`capabilities: decision, vision`)、`clef-flash`(0.40で動作)、`clef:latest` は旧形式のDLだと400(`ollama pull clef:latest` で再取得が必要)。`/v1/systemone` に `images: [base64]` を付けて切り抜きを渡す。
- 合成の縦書き8ページ・48要素(balloon/caption/sfx/text)から、正しい枠・上にずらした枠・gemma4風の短く太い枠・上半分だけの枠・空領域の切り抜きを作成(d3:4bは240件、clef-flashは120件。clef:latestは未測定)。
- 文字の有無: d3:4b・clef-flashとも正しい枠・空領域は全問正解(空の誤検出なし)。
- クラス分類(正しい枠): d3:4b 48/48、clef-flash 23/24(sfx→text 1件)。
- 枠が文字を切っていないか: しきい値0.5だと悪い枠の見抜きは約半数。AUCは d3:4b(ずれ0.92・短く太い0.92・上半分0.80)、clef-flash(0.98・0.85・0.73)。最適しきい値でも正解率81〜85%。**位置補正の判定器にはまだ使えない**。
- 速度: clef-flash 約3.3秒/件、d3:4b 約8秒/件(240件で32分)。
- 合成ページでの結果であり、実ページでは下がる見込み。実データ20〜50件に正解を付けた検証が未了。
**4. 実装(OCRタブ、任意機能・既定オフ)**
- `ocr-core.js` に `DECIDE_QUESTIONS`(has_text=noul、cls=choice)、`pickDecisionModel`(clef-flash→d3)、`parseDecision`、`applyDecision` を追加。モデル欄に「検出後に切り抜きを意思決定モデルで判定する(任意)」と「判定モデル」(`/api/tags` の capabilities に `decision` と `vision` が両方あるものだけを列挙)。
- 実行時は OCR → 再読み取り → 判定の順。OCRの文字枠(text)は種類を確率0.6以上のときだけ書き換え、VLMの容器枠(balloon/sfx/caption)は「文字あり」確率0.3未満なら除外。失敗が2回続いたら打ち切り、OCR結果は残す。500系は4秒待って1回だけ再試行(VRAM入れ替え対策)。
- `clef:latest` は再DL後の動作を未検証。
**5. 全体プロンプトのVLM作成(OCRタブ、任意機能・既定オフ)**
- 設定欄の「全体プロンプトも作成し、MOSS-Imageへ送るときに置き換える」をONにして検出すると、検出モデル(VLM)が画像全体を英語2〜3文で説明し、OCRタブのテキスト欄(手で修正可)に入れる。「全体プロンプトを作成」ボタンで検出済み画像にも単独で作れる。
- 「MOSS-Imageへ送る」時、チェックONかつ文章があるときだけ `importOcrItems(items, { aspect, prompt })` が `#moss-prompt` を置き換える(レイアウト使用時はsummaryになる)。OFFまたは空なら触れない。
- プロンプトは `OVERALL_PROMPT`(場面・画風・構図・雰囲気、文字の書き起こし禁止)、返答は `cleanOverall` で前置き・コードフェンス・引用符を除去、1200字まで。VLMは検出モデルと同じ(`ocr-layout-model`)。作成に失敗しても検出結果は残す。画像ごとの内容なので設定には保存しない。
- 実機未検証(node構文チェックと `cleanOverall` の単体確認のみ)。
**6. OCRの前処理(グレースケール)と自動やり直し**
- 実測(目視で語句リストを作った雑誌表紙3枚、長辺1600px、LightOnOCR): グレースケールはカラーと同等以上。ページ1 20/25→20/25、ページ2 15/24→15/24、ページ3は**カラーが0件(空)、グレーは22/26**。コントラスト補正(autocontrast)は不安定で、ページ2で空(0/24)、ページ1で同じ語が連続し11/25に悪化したため不採用。`repeat_penalty` 1.3 はほぼ全ケースで枠が1〜10件に激減し逆効果。
- 白黒マンガは元がほぼグレーで差が出ない。合成ページでは赤・青の効果音がグレー化で取りこぼしやすく、カラー46/48・グレー44/48・補正43/48(効果音だけ差)。
- カラーが空になる・同じ語を繰り返すのは前処理の問題ではなくモデルがときどき失敗するため。グレーにすると返ることがある。
- 実装: モデル欄に「OCRの前処理: そのまま / グレースケール」(既定そのまま)。「そのまま」のとき、OCR結果が空、または文字枠30件以上で種類数/枠数が0.5未満(`ocrLooksFailed`)なら、グレースケールで1回だけやり直す(やり直し結果が失敗に見えなくなる、または枠が増えたときに採用。完了表示に追記)。グレー画像は必要時にcanvasで作り画像ごとにキャッシュ。レイアウト検出・読み直し・判定は従来どおりカラー。3ページのみの測定。実機未検証。
**7. OCRタブでの設定タブ「VRAM調整」の利用**
- 検出の実行前と、意思決定モデルでの判定前に `prepareVramForGeneration([baseUrl()])` を呼ぶ(modeがoffなら何もしない。画面上のOllama URLも対象に含める)。判定モデル(clef-flash約10GB)の前に直前までのOCR・VLMを退避させて空きを作る目的。失敗しても検出は続ける。
- 退避できるのはOllamaのモデルのみ。ComfyUI側が占有するVRAMは対象外。allモードでは実行直前に読み込み済みのOCRモデルも退避されるため再ロードの数秒がかかる。実機未検証。
**8. OCRタブのモード(用途別プリセット、7種のドロップダウン)**
- 設定欄の最上部に折りたたみ式の「モード」(開閉は `ccc_ocr_mode_open` に保存)。選ぶと個別設定(OCR・レイアウト検出とクラス・読み直し・判定・全体プロンプト・前処理)を一括で反映し、個別設定を手で変えると自動で「カスタム」になる(プリセット適用中は `O.applyingPreset` で区別、changeイベントは出さない)。読み直し・判定は使えるモデルが無ければオンにしない。保存設定が無い初回だけ manga、既存設定がある場合は custom(今の設定を維持)。
- モード: 自動 / マンガページ / 雑誌表紙・ポスター(OCRのみ・グレー再試行・全体プロンプト) / 文字のみ(OCRのみ) / イラスト(OCRなし・レイアウト検出+全体プロンプト) / 縦長ページ(分割読み) / カスタム。プリセットは `ocr-core.js` の `OCR_MODE_PRESETS`。新規チェックボックス「文字検出(OCR)を行う」を追加。
- 自動: 高さ/幅が2.5以上なら縦長、それ以外は縮小画像(長辺512)を意思決定モデルに見せて `choice`(manga/cover/text/illustration)で選ばせ、確率0.4未満・失敗・モデル無しは manga。選ばれたモードは完了メッセージに付く。精度は未検証(実験的)。
- 縦長の分割読み: `tileRects`(タイル高さ=幅×1.4、重なり12%、最後は下端に合わせる)で分割し、各タイルを長辺1600pxで読み(空・繰り返しならタイルごとにグレースケール再試行)、`mapTileBoxes` で全体座標へ戻し、`dedupeTileBoxes` で重なり部分の二重検出を除く(IoU>0.4かつ同じ文字、またはIoU>0.7、面積の大きいほうを残す)。
- 実機(Kapture): 7モードの設定反映・カスタム化・折りたたみ保存を確認。合成の縦長画像(600×3000)で自動→縦長が選ばれ、4タイルで8件を重複なく検出(位置は正解どおり)。表紙風の合成画像で自動→表紙が選ばれ設定が反映された。実際のマンガ・表紙・イラストでの自動判定の精度、完了メッセージへのモード名追記は未検証。
**9. 保留**
- OCRの枠でVLM容器枠を置き換える補正(案1: 文字を含む枠の外接矩形へスナップ)は未実装。
- 判定の並列化、実ページでの精度検証、clef:latestの測定。
---
## 2026-10-24(OCRタブ: 切り抜きの読み直し、PaddleOCR-VL系の検証、v1.62.0)
**1. 他OCRモデルの実測(Ollama、漫画ページ1枚+合成7件)**
- **glm-ocr**: bboxなし・プロンプト無視。本文は正確だが、縦書きで文字を落とす(合成 4/7)。
- **unlimited-ocr**: `label [x1,y1,x2,y2]本文`(0〜999)を返し、`image` 枠がコマ枠とほぼ一致。縦書き文字は取りこぼす。
- **deepseek-ocr**: `/api/generate` の `<|grounding|>Locate <|ref|>X<|/ref|>` だけがbbox。1問い合わせ=1枠で精度は低く、`/api/chat` では壊れる。日本語も弱い。
- **PaddleOCR-VL(マンガ特化 `hf.co/LunarOilRig/PaddleOCR-VL-manga-GGUF:Q4_K_M`、1.6 `hf.co/PaddlePaddle/PaddleOCR-VL-1.6-GGUF`)**: mmprojが別ファイルでも `ollama pull hf.co/…` だけでvision対応で動く。プロンプトは `OCR:`。`Spotting:` はOllama経由だと本文のみでbboxは出ない。実画像の縦書き装飾文字(正解「アノワタクシハ」)はマンガ特化版だけが正解(LightOn「アノマリー」、glm「ルール」、1.6「ンッうやつーっ」)。合成7件は manga 7/7(「…」「!」「?」を半角化)、1.6 6/7、LightOn 5/7。
- どのモデルも複数クラス(コマ・キャラ・フキダシ)の一括検出はできず、gemma4のJSON検出は引き続き必要。
**2. アップスケール実験(Lanczos、1〜4倍)**
- 実画像の切り抜き(49×215px・101×31px)は倍率で結果が変わらない。誤読はモデル要因。
- 合成の極小文字(16px)では LightOnOCR だけ 1倍 1/7 → 2倍以上 5/7(1倍は極小画像でHTTP 500も出た)。マンガ特化版は1倍が最良で、拡大すると「ドドドドッ」の文字数が増える。
- 方針: 基本は等倍、読み直しモデルがLightOnOCR系のときだけ短辺96px未満を2倍。AI超解像は未検証。
**3. 実装**
- `ocr-core.js` に `pickRereadModel` / `rereadPrompt` / `rereadScale` / `cropRect` / `normalizeJaPunct`(日本語を含む文字列の `...`→`…`、`!`→`!`、`?`→`?`)を追加。
- OCRタブのモデル欄に「文字枠を切り抜いて別モデルで読み直す」と「読み直しモデル」(既定は manga → PaddleOCR-VL → glm-ocr の順に選ぶ。無ければ既定オフ)。実行時は文字枠を順に読み直し、失敗が2回続いたら打ち切って元のOCR文字を残す。ツールバーに「選択枠を読み直す」を追加。
- Ollamaが一時的に500を返す(モデル入れ替え直後にランナーが落ちる)ことがあるため、1回だけ自動で再試行する。
- 実機(Kapture): 縦書き「アノワタクシハ」が LightOnOCR単体の「アークタクシー」から正解に変わる(全体2秒)。未導入モデルは404で打ち切り、元の文字が残る。
**4. 保留**
- 読み直しの並列実行・進捗の取り消し。枠の数だけ時間が掛かる。
- Ollama経由でPaddleOCR-VLのbbox(Spotting)を取る方法。ロケーショントークンが落ちている可能性があるが原因は未調査。
---
## 2026-10-24(OCRタブ新規: Ollama LightOnOCR-3でbbox・文字検出、MOSS-Imageレイアウト連携、v1.61.0)
**1. 構成**
- `static/js/ocr-core.js`(DOM非依存: プロンプト・パース・MOSS変換)、`static/js/main/29-ocr-tab.js`(UI)。Ollamaへはブラウザから直接 `/api/chat`(Autoタブと同じ方式。サーバー側の変更なし)。
- `moss.js` に `importOcrItems` を追加。取り込み枠は `src: 'ocr'`(再送で入れ替え、「取り込み全クリア」の対象)。MOSSの初期化(保存済みレイアウトの復元)完了を待ってから足す。
**2. モデルの実測**
- LightOnOCR-3:4b(`maternion/`、実体はqwen35系)は ` 本文`(0〜1000正規化)を返す。**ラベル(panel/character等)を指示しても無視される**。出るのは text / title / image のみ。
- そのため文字はOCRモデル、コマ・キャラ・フキダシ・擬音・キャプション・顔・物体は別の汎用VLM(既定 `gemma4:e4b`)のJSON検出(`box_2d` は **[y1,x1,y2,x2]**)で担う。VLMの枠は大まかで、枠の編集UIを付けた。
**3. UIの調整**
- ドロップは画像枠だけでなくタブ全体で受ける(枠外に落とすとブラウザが画像を別タブで開いていた)。別タブの画像はファイルでなくURLで渡るためURLからの取得にも対応。
- モデル設定欄は `` の折りたたみ(開閉は `ccc_ocr_models_open` に保存)。
**4. 保留**
- 現在のページ/Imageタブ/MOSS生成結果を直接OCRの入力にする経路は未実装(画像ファイルのドロップ・貼り付けのみ)。
- 縦書きの列数(改行)はOCR出力から取れないため、縦書きの文字は1列として扱う。
---
## 2026-10-23(MOSS-Image タブ: プロンプト拡張、レイアウトの新規作成/取り込み全クリア、v1.60.0)
**1. プロンプト拡張(enable_prompt_enhancer)のON/OFF(新機能)**
- ComfyUI公式テンプレート「Text to Image (MOSS-Image)」(サブグラフ)のスイッチと同じ方式。ONにすると、`CLIPLoader`(type `moss_image` = Qwen3.5-9B)を `TextGenerate`(LLM)として使い、公式のシステムプロンプトで短い指示を詳細な英語キャプションに書き換えてから `CLIPTextEncode` へ渡す。CCの従来のワークフローには拡張処理がなかった(実質OFF)。
- `py/ccc.py` の `_moss_workflow` に `TextGenerate`(ノード `20`)を追加し、ポジティブの `text` を `['20', 0]` に差し替える。システムプロンプトは定数 `_MOSS_ENHANCER_SYSTEM`。`TextGenerate` の動的コンボ(`sampling_mode`)はAPI形式では `sampling_mode: 'on'` と `sampling_mode.temperature` のようなドット区切りキーで渡す(検証エラーなし・実行成功を確認)。
- **レイアウト(bbox)使用時は拡張しない**: プロンプトがレイアウトJSONになり、LLMで書き換えると構造が壊れるため(`has_layout` のとき `enhance=False`)。コマ単位モードと、枠のない1頁モードで有効。UIは `moss-enhance` チェック(プロンプト欄の下)、リクエストは `enhance_prompt`、応答に `enhanced`。
- 実測(seed固定、25step・CFG 2.5): 「a cat sleeping in an orange bowl, manga style」はOFFだと効果線・擬似文字・吹き出しの混ざった漫画ページ風になり、ONだと約150語のキャプション(「No text appears in the image.」を含む)になって文字のない1枚絵になった。1サンプルの比較。
- 拡張後の文はUIに出さない(`_native_nb_run` が出力ノードの画像しか返さないため)。
**2. レイアウトの「新規作成」と「取り込み全クリア」**
- 描画種別の左隣に「新規作成」(全bboxを削除)。従来の「全クリア」は「取り込み全クリア」に改名し、取り込んだ枠(`src` が `panel` / `balloon` / `text`)だけを削除する(手描きの枠は残す)。
- 取り込みコマ枠には従来 `src` がなかったので `src: 'panel'` を付けた。旧バージョンで保存済みの取り込みコマ枠は印がなく、取り込み全クリアでは消えない(新規作成を使う)。
**3. 調査したが採用しなかったこと(制限文)**
- Soda-Storyboard の「コマ単位プロンプトに枠・文字・吹き出しを描かせない制限文を常に付ける」を試した。コマ単位モードで、シード固定・コマ内容固定で比較。
- CFG 1(dmd8・Turbo 4step)では **Negative Prompt が効かない**(Negativeの有無で画像が完全に同一)。
- 「No panel borders, no frames, no text, no speech bubbles.」だけだと枠・文字・吹き出しは残る。「A single illustration filling the entire image, not a manga page.」を足した文言+CFG 2.5+Negativeで、枠・吹き出しのない1枚絵になった。
- 1頁モード(コマbbox取込済み)では、全体に付加しても枠は残る(枠が取込bboxに引きずられる)。
- 効果が1シード・1コマの比較で確実性が低いため、今回は実装しない判断にした。代わりにプロンプト拡張が同じ問題(文字・枠の混入)に効く可能性がある。
- 検証用の生成が、作品「フキダシ見本」の1ページ目コマ1へ配置されて保存されていた(作品はそのままでよいとの判断)。
**How to apply:** `py/ccc.py` を変更したため、更新後はComfyUIの再起動が必要。MOSS-Imageの検証でNegativeの効果を見るときは、CFGが1より大きいプリセット(標準・軽量)を使う。
---
## 2026-10-22(同梱版マニュアルをv1.59.0に更新)
`docs/manual/`(日本語・英語)をv1.53.2からv1.59.0対応に更新した。コード変更なし。
- v1.54.0〜v1.59.0の変更を反映: Nanobanana生成方式の切替(設定タブ、`COMFY_API_KEY`)、フキダシ内セリフの位置ドラッグ、テキスト角ハンドルの拡縮方向、動画ツールの移動モード、MOSS-Imageタブ(第10章に10-6を追加)。タブ数10→11。トラブル表・付録のキー操作も追記。
- 同梱版は画像なしのため、`[画像:〇〇]` / `[Image: ...]` の行を取り除いて出力した(Kindle版の原稿には残る)。
- READMEに「マニュアル」節(日英)を追加。
---
## 2026-10-22(MOSS-Image タブ: 吹き出しなしの単独テキストの取込、panelラベルの使い分け、空の文字枠の送信除外、v1.59.0)
**1. 吹き出しなしの単独テキストの取り込み(新機能)**
- 「フキダシ・セリフを取り込む」に、チェックボックス「吹き出しなしの文字も取り込む」(既定オン)を追加。テキストツールで置いた `` を文字枠として取り込む。フキダシ内のテキスト(`g.balloon-shape` の子)と `defs` / `clipPath` / `mask` / `pattern` 内のテキストは対象外。
- 回転・拡縮・せん断・縦書きを含む実際の見た目の範囲が要るため、文字だけの新しいSVGを画面外(`position:fixed; left:-100000px`)へ描画し、`getBoundingClientRect()` で実測する(`extractFreeTexts`)。`document.fonts.ready` を待ってから測る。枠は実測範囲+フォントサイズの0.15倍の余白で、`fitBox=false`(文字を編集しても枠が縮まない)。フォントサイズは `font-size` × `data-scale-x/y` の幾何平均 × キャンバス倍率。縦書きは `style` の `writing-mode`。
- caption は常に `Narration text.`(当初は文字数による推定で6文字以下=`Sound effect.` としていたが、名前などを擬音と誤るため2026-10-27に廃止。擬音は `sfx` クラスで扱う。ページ自由テキストの取り込み `moss.js` の `textCaptionOf` も同様)。回転した文字は外接矩形になる(MOSS-Imageの枠は回転を表せない)。
- 再取込は、取り込み済みの枠(`src: 'balloon'` / `'text'`)だけを入れ替える。チェックを外して取り込むと、前回の単独テキストの枠は残る。
**2. セキュリティ修正(取込の途中で発見・修正)**
- 初版は保存済みページのSVG文字列を `innerHTML` で画面外のDOMへ入れていたため、保存済みSVGに紛れた `onload` / `onerror` 等が実行されうる(旧方式では実際に実行されることを確認)。まず `DOMParser` + `sanitizeSvgTree()` に変えたが、禁止リスト方式では名前空間付きの要素(``)、`` / ``、`style` 内の `url()` 等の抜け道を塞ぎきれない。
- 最終形は許可リスト方式: 保存済みSVGは描画せず(パースしただけのDOMは何も実行しない)、`` / `` と許可リストの属性(`x y dx dy font-* letter-spacing text-anchor transform data-scale-*`)・許可プロパティだけの `style`・祖先 `` の `transform`(`matrix/translate/scale/rotate/skew` の形式のみ)を、新しく作ったSVGへ写して測る。値は括弧・`;`・`:`・`/` を通さない。攻撃用SVG(名前空間付き `script`、XHTMLの `iframe srcdoc`、`set` / `animate`、`javascript:` のリンク、`style` 内の `url()`)で、スクリプトの実行0件・外部通信0件を確認した。
**3. 枠固定の文字の表示**
- 取り込んだフキダシ・単独テキスト(`fitBox=false`)の表示を、枠の幅で折り返す(`white-space: pre-wrap`)。実ページの思考フキダシの長い英文が、枠の外へ1行ではみ出して見えていたため。MOSS-Image も枠の中で折り返す。単独テキストは左上(縦書きは右上)から置く。
**4. panel ラベルの使い分けと、空の文字枠の送信除外**
- 描画種別・種別セレクトに「コマ」(`panel` ラベル)を追加(黄色)。コマ取込の `panel` ラベル化はチェックボックス(既定は `object`)。`panel` は学習時にあるラベルだが、公開仕様は `object / character / text` のみ。32枚(8シード×4通り)の測定で、`object` との差は誤差の範囲内(枠線・ガターの再現度)、`summary.canvas: "multi_panel"` も同様だった。ユーザーが使い分けられるように選べる形にした。
- 文字が空(空白のみ)の `text` item は、`_moss_layout_prompt` で除外する。送ると、モデルがその領域を「文字を書く領域」と解釈して、罫線入りの紙のようなものを描いてしまう(8シード中8)。公式コンパイラも空の `text` を拒否する。UIでは破線で薄く表示する(入力のたびに切り替わる)。
**5. 調査(実装なし)**
- MOSS-Image の bbox: 公式仕様では、`items` のキーは `label / caption / bbox / text / tags / palette` のみ、bbox は軸並行の長方形(4つの数値)。回転角・形状(多角形)の項目はない(公式コンパイラは未知のフィールドを拒否)。非公式の `rotation` 項目は無視される。caption の英文での回転指示は、回転後の外接矩形と併用すると傾くが、文字が崩れやすい。形状は caption の英文で表現する。
- 参照画像ノード `ThetaCursed/ComfyUI-MOSSImageTextEncoder`(Qwen3.5の視覚タワー経由の参照画像条件づけ)を実機で検証(導入はコミット `289170a` 固定。CC本体は未使用): エラーなく動き、参照なしは標準と画素同一、時間・VRAM問題なし。レイアウトなしでは参照が構図を乗っ取る(シート全体を渡すとシートそのものが出る)。レイアウトJSON併用なら構図は保たれるが、全身の参照は近景のコマに白背景が漏れる。単純なデザインでは文章の外見説明で参照と同等に揃う。このため「キャラ設定(文章)の登録・自動挿入」を先に検討したが、今回は見送り(スクリプトタブの要素・Autoタブの脚本との関係を整理してから再検討)。
**6. 検証**
- 実ページ(ユーザーの保存済み45ページ)で、フキダシ168件・単独テキスト8件を、エラー・異常値なしで抽出できた。実ページ「これはTEST_p1_1791201461030」の取込結果(位置・大きさ・フォントサイズ)を元データと突き合わせて一致を確認し、取り込んだレイアウトで生成して、縦長の吹き出し・思考フキダシ(英文)・擬音「あ」が指定の位置に描かれた。
- 英語・中国語UIの表示をKaptureで確認(種別ボタン・取込チェック・ホバー説明・ヘルプのMOSS節。中国語UIの「コマ」は既存のMOSS用語に合わせて「分镜」)。
- 未確認: 擬音かナレーションかの推定の精度、回転した単独テキストの実ページでの見た目。
- `py/ccc.py` を変更したため、反映にはComfyUIの再起動が必要(再起動後に、`panel` ラベルの通過と空の文字枠の除外をAPIで確認済み)。
**How to apply**
- ページのSVG文字列を、保存済みでも外部由来でも、`innerHTML` でDOMへ入れない。DOMへ描画する必要があるなら、許可リスト方式で必要な要素・属性だけを新しいDOMへ写す。禁止リスト方式(`sanitizeSvgTree`)は、名前空間付きの要素やアニメーション要素を塞ぎきれない。
- 外部モデルの仕様外の入力(空の `text` など)は、「無視されるだけ」と仮定せず、同じシードで有無を比べて確かめる。
- 回転・拡縮を含む `` の範囲は、数式ではなく、画面外に描画して `getBoundingClientRect()` で測るのが確実(`document.fonts.ready` を待つ)。
- 再取込できる要素には `src` のような印を付け、再取込では印の付いたものだけを入れ替える。
---
## 2026-10-22(MOSS-Image タブ: シードの動作モード、フキダシ・セリフの自動取込、シード欄のレイアウト変更、v1.58.1)
**1. シードの動作モード(修正・改善)**
- 従来は、シードが `-1`(ランダム)のとき、生成のたびに使われたシード値が入力欄へ書き戻されていた。そのため次の生成からは固定シードになり、ランダムのままにするには毎回 `-1` へ戻す必要があった。
- 「ランダム(既定)/固定/生成ごとに+1」を選べるようにした。ランダムのときは入力欄の値に関係なく毎回 `-1` を送る(入力欄は無効表示)。固定は入力欄の値。「+1」は入力欄の値から始め、生成後に使った枚数ぶん進める(入力欄が負のときは初回だけランダム)。
- ランダムで使われたシードは「直前のシード」に表示し、「このシードを固定」で固定モードへ切り替えられる(気に入った結果の再現用)。コマ単位モードは「元のシード+コマの順番」で、直前のシードには最初のコマの値を出す。モードは localStorage に保存。
- 右パネルのシード欄は 1 行目=「シード:」、2 行目=モードと値、3 行目=直前のシード(左)と固定ボタン(右寄せ)の 3 行構成にし、生成の状態表示(「生成完了」など)をシード欄の下へ移した。
**2. フキダシ・セリフの自動取込(新機能)**
- レイアウトエディタに「フキダシ・セリフを取り込む」ボタンを追加。ページのレコード(`dbGet('pages', …)`)のオーバーレイ(`overlaySvgContent`)と各コマ(`panelSvgContent`)から `g.balloon-shape` を取り出し、セリフ(`data-bubble-text`)が入っているものを「文字」枠として取り込む。
- 位置・大きさは `data-cx/cy/rx/ry`(ページのSVG座標)から、コマ取込と同じ換算(キャンバス/ページ)で作る。枠は**フキダシの輪郭**。フォントサイズは `data-font-size-svg` × 縦の倍率、縦書きは `data-bubble-text-vertical`、形は `data-shape-type` を caption の英文(Speech bubble. / Thought bubble. / Shouting burst-shaped bubble. など)へ変換する。読み順(上から下、同じ段は右から左)に並べる。
- 取り込んだ枠には `src: 'balloon'` を付け、再取込では取り込み済みの枠だけを入れ替える(手で足した枠は残す)。キャンバスの縦横比がページと違うときは、ページに合わせて既存の枠も拡縮する(確認ダイアログ)。
- 文字枠に `fitBox` を追加し、「選択中の要素」に「枠を文字の大きさに合わせる」を追加した。取り込んだ枠は `fitBox=false`(文字を編集しても枠が縮まない。表示は枠の中央)。`autoSizeText` と手動リサイズ後のフォントサイズ更新は `fitBox=false` では行わない。
- 単独のテキスト要素(吹き出しなしの文字)は対象外(今後の検討)。コマ単位モードでは使われない。
**3. 検証**
- テスト用のページレコードを IndexedDB へ書き込み、縦書き・思考・爆発の 3 種のフキダシを取り込んで、座標・フォントサイズの換算、セリフなしのスキップ、再取込の入れ替え(手で足した物体が残る)、`fitBox` の切替を Playwright で確認した。取り込んだレイアウトで生成すると、縦書きの吹き出しと叫びの吹き出しが指定の位置・大きさで描かれた。
- シードは、ランダム(2 回とも `-1` 送信、入力欄は不変)、固定(同じシード)、+1(100 → 101)を実機生成で確認した。
- 未確認: 実際に使っているページでの取込、英語・中国語 UI の表示、コマ単位モードでのシード(コマごとの値)。
**How to apply**
- 「ランダムなら毎回違う値」の機能で、使った値を入力欄へ書き戻すと次回から固定になる。入力欄は「指定する値」専用にし、使った値は別の表示(直前のシード)に出す。
- 取り込み元を持つ要素には `src` のような印を付け、再取込では印の付いたものだけを入れ替える。手編集した要素を消さずに済む。
- 枠のサイズを内容から自動決定する要素でも、外部の形(フキダシの輪郭など)に合わせたい場合は自動サイズを切れるフラグ(`fitBox`)を持たせる。
---
## 2026-10-21(MOSS-Image タブ(ローカル生成・レイアウトエディタ)を追加、v1.58.0)
**1. MOSS-Image タブ(新機能)**
- ComfyUI 本体がネイティブ対応した画像生成モデル MOSS-Image(OpenMOSS、5B DiT、テキストエンコーダ Qwen3.5-9B、VAE FLUX.2、Apache-2.0)を、専用タブ「MOSS-Image」からローカル生成する。Comfy クレジット・外部 API キーは不要。日本語を含む文字の描画に強く、物体・キャラ・文字の位置を bbox で指定できる。
- 画面は 3 カラム: 左=レイアウトエディタ、中=設定パネル(プロンプト / JSON / モデル・サンプラー の上部タブ。プロンプトタブ最上段の「生成対象」は `` で折りたたみ可)、右=生成・結果・配置。
- 生成モードは「1 頁まるごと」(ページ全面のオーバーレイへ配置)「コマ単位」(各コマの縦横比から約 1MP で生成し、`insertImage` の placement と `preserveAspectRatio:'none'` でコマへストレッチ配置)「自由サイズ」(生成のみ)。
- 「現在のページのコマを取り込む」でコマ枠を物体の枠として取り込み(キャンバスはページの縦横比・約 2MP に自動調整、caption に位置表現)。設定とレイアウトは localStorage(`ccc_moss_v1`)に保存。
**2. バックエンド(`py/ccc.py`)**
- `_moss_workflow` で API 形式のワークフロー(`UNETLoader` →(`LoraLoaderModelOnly`)→(`SkipLayerGuidanceDiTSimple` 層 22・0〜0.5)→ `KSampler`、`CLIPLoader`(type=`moss_image`)、`VAELoader`、`EmptyFlux2LatentImage`、`SaveImage`(`cc_moss/MOSS`))を組み立て、Nanobanana のネイティブ経路と同じ方式で `/prompt` へ直接投入する。ワークフロー JSON ファイルは持たない。
- `_native_nb_run` に出力ノード ID・client_id・タイムアウトを引数化し、API キーが空ならパートナー認証を付けない(従来の呼び出しは既定値で同じ動作)。
- ルート `POST /api/ccc/moss/generate`(生成。画像本体は返さず `/view` 用の参照のみ)と `POST /api/ccc/moss/layout-prompt`(レイアウト → JSON のプレビュー用)。モデル一覧は ComfyUI 自身の `/object_info` から取得する。
- レイアウト JSON は ComfyUI 標準の `MOSSImageLayoutPrompt` と同じ形式(`summary` / `items`(label・caption・text・bbox)/ `bbox_coord_space=abs_centralized` / `bbox_format=yxyx`。bbox はキャンバス中心原点のピクセル `[y0,x0,y1,x1]`)を `_moss_layout_prompt` で生成する。
**3. レイアウトエディタと文字枠**
- 描画種別(物体=緑・キャラ=ピンク・文字=水色)をボタンで選び、ドラッグで枠を描く。前面へ/背面へ/削除、Delete キー、枠の縁・番号・選択中の枠の内側のドラッグで移動、角で拡縮。
- 未選択の枠の内側のドラッグは「その上に新しい枠を描く」(クリックのみなら選択)、Shift+ドラッグは常に描画。枠の内側を常に移動にすると、コマ(物体)の上にセリフ枠を置けなかったための仕様。
- 文字枠は描いた直後に枠内へ直接入力(Escape / Ctrl+Enter で確定)。フォントサイズ(画像上の px)を持ち、枠は入力した文字の大きさになる(全角 1em・半角 0.55em・行間 1.2・余白 0.3 倍の近似)。手動リサイズすると、その枠に収まる最大のフォントサイズへ更新される。
- 縦書き: 「文字」の右隣の横書き/縦書きトグルは新しく描く文字枠の既定のみ(選択中の枠には作用させない。作用させると、描いた直後に切り替えるとその枠が書き換わるため)。描いた後は「選択中の要素」の書字方向で変更する。縦書きは改行=列(右→左)として表示・入力・サイズ見積もりを縦組みにする。MOSS-Image のレイアウト形式に書字方向の項目は無いため、縦書きの文字枠は caption の末尾に `Vertical text, written top to bottom, columns from right to left.` を自動付与する。この指示だけで縦書きに描かれることを実機生成で確認した。
**4. 検証**
- API 経由で 832×1216・25step・日本語セリフ入りの 2 コマレイアウトを生成(約 35 秒)し、コマ構図・セリフ・擬音が指定位置に描画された。縦書き指定を含むレイアウトでも、縦書き(右→左の列)で描画された。UI の生成ボタンから DMD 8step でも生成できた。
- 枠の描画・移動・拡縮・クリック選択・文字の直接入力と再編集・フォントサイズ変更・縦書き切替・3 カラムとタブ切替・リロード後の復元を Playwright / Kapture で確認。
- 未確認: ページのコマ取り込みの実機動作、コマ単位/1 頁モードでの配置、英語・中国語 UI の表示、画面幅 1500px 未満の折り返し表示、指定フォントサイズと実際の文字サイズの一致、縦書きの安定性(1 回の生成のみ)。
**5. 未対応・検討**
- フキダシ・セリフ(`g.balloon-shape` の `dataset.bubbleText` など)の自動取込、Auto タブの画像生成エンジンへの追加は未実装(`PLAN_backlog.md` に記載)。
- ヘルプ(日英中)・README(日英中)に MOSS-Image の節を追加した。
**How to apply**
- キャンバス上のドラッグ操作で `pointerdown` に `preventDefault()` を入れると、ブラウザの `dblclick` が発火しないことがある。二度押しは `pointerdown` の時刻と対象で自前判定する。
- 枠の上に別の要素を描きたいキャンバスでは、「枠内のドラッグ=移動」を固定にせず、選択状態と Shift で描画と移動を切り分ける。
- `py/ccc.py` に新しいルートを足したときは、ComfyUI の再起動後でないと 404 になる(JS・HTML・CSS はリロードで反映)。
- レイアウト形式に無い指示(縦書きなど)は、caption の英文で渡すと効く場合がある。
---
## 2026-10-17(動画ツールの移動モードとオーバーレイのはみ出し修正、テキスト・描画図形の保存抑制、v1.57.0)
**1. 動画ツール: 移動モード(✥)を追加**
- 動画サブタブでは動画オブジェクトをクリックするだけでオーバーレイのプレビュー状態になり、位置を動かすには他のツールへ切り替える必要があった。再生ボタン(▶)の左隣に ✥ ボタンを追加。ON中は `_videoSuspendOverlay()` でオーバーレイを透明・クリック透過にして動画だけ止め、下の `` を通常の画像と同じようにドラッグ移動・リサイズ・回転できる。ON中は動画オブジェクトをクリックしてもオーバーレイは出ない(`_ccVideoOnObjectSelected` で抑止)。OFFにすると移動後の位置でオーバーレイを再表示する。状態は `state.video.moveMode`。
**2. 動画オーバーレイがページ上端からはみ出してツールメニューに重なる問題(修正)**
- 原因: オーバーレイ(`z-index:150`)は動画オブジェクトの表示矩形をそのまま使うため、ページ端からはみ出した動画では直上のツールメニューへ食い込み(実機再現で約100px)、クリックを奪っていた。
- 実装: `_videoSyncPosition` で、プレビュー領域(`#layout-preview`)の範囲に `clip-path: inset(...)` でクリップする。
**3. テキスト・描画図形のクリックだけの保存を抑制**
- v1.56.0 で画像・フキダシ・グループに入れたものと同じ。テキスト(`09e-text-tool.js`)と描画図形(`17c-layer-draw-handles.js`)も、実際に動かした場合だけ `savePanelSvg` / `saveOverlaySvg` を呼ぶ。クリック選択だけでは全SVGの複製・直列化・DB保存を走らせない。
- 描画図形のドラッグには `pushHistory`(Ctrl+Z 用履歴)が無い(未対応)。
**How to apply**
- 絶対配置のオーバーレイをSVG上の要素に重ねる機能は、プレビュー領域でのクリップを必ず入れる(はみ出し対象が他のUIを覆わないように)。
- ドラッグ系の mouseup で保存する処理は、「動かしたか」のフラグで保存を分ける。
---
## 2026-10-17(レイアウトタブの操作遅延の解消、テキスト角ハンドルの拡縮方向、フキダシ内テキストの位置ドラッグ、v1.56.0)
**1. レイアウトタブでオブジェクトの操作が遅い・レイヤーパネルの選択が効かない(修正)**
- 原因: 3Dポーズ画像の要素に `data-pose3d-model`(VRMモデルのbase64、1枚あたり約56MB)が埋め込まれており、実機のページでSVG全体が約114MBになっていた。クリックしただけでも `mouseup` で `savePanelSvg`(SVG全体の複製・直列化・IndexedDB保存)が走るため、次の操作が詰まり、保存完了時の `renderLayerPanel()` でクリック中のレイヤー行が差し替わって `click` が届かなかった。
- 実装: `23-pose3d-bridge.js` でモデルを埋め込まないようにした(読み出し側は元々無く、再編集はポーズJSON `data-pose3d-pose` のみで足りる)。`renderLayoutTab` でページを開く際に既存の `data-pose3d-model` を正規表現で除去してDBへ書き戻し(`_stripPose3dModelFromPage`)、`savePanelSvg` でも保存時に除去する。実機でSVGが約114MB→約1.1MBに低下。
- 画像・フキダシ・グループのドラッグ処理(`08-panels-images.js`、`06a-polygon-geometry.js`)は、実際に動かした場合だけ保存する(クリック選択のみでは保存しない)。
- 未対応: テキスト・描画図形のドラッグにも同種の構造が残っている可能性がある(未調査)。
**2. テキストの角ハンドルのリサイズ方向(変更)**
- 従来は中心からの距離比で拡縮していたため、どの角をドラッグしても同じ動きだった。反対側の角を固定し、固定角→ドラッグ角の対角線上へカーソルを射影した比でフォントサイズを決める方式に変更(`09e-text-tool.js`)。拡縮でずれた固定角はテキストごと平行移動して戻す。回転・変形したテキストでも変形後の角座標(`_textLocalToSvg`)で扱う。辺ハンドルの縦横伸縮・回転は従来どおり。
**3. フキダシ内テキストの位置をドラッグで移動(新機能)**
- テキストを内包したフキダシの選択時、テキストの周りに紫の点線ボックスを表示し、左下の三角コーナーのドラッグでテキストだけを動かせる。ダブルクリック(三角コーナー・フキダシ)で従来のモーダル。
- 位置は `data-text-offset-x/y`(フキダシのローカル座標での寄せ位置からの追加移動量)に保存し、`_bubbleTextRenderText` で全tspanへ加算する。回転したフキダシでも向きに沿って動く。モーダルで上下寄せ・文字寄せを変えるとオフセットは解除(寄せ位置を優先)。
- 点線ボックス(`.balloon-textbox`)と三角コーナー(`.balloon-textbox-mark`)は編集用の表示で、保存用クローン(`savePanelSvg` / `saveOverlaySvg`)から除外する。実装は `09c-balloon-handles.js`(`updateBubbleTextBox`)、ドラッグ処理は `09d-balloon-tools.js`。動かしたときだけ履歴・保存を行う。
**How to apply**
- 保存が重いと感じたら、まず `svg.outerHTML.length` と、巨大な属性(`data-*`)を持つ要素がないかを疑う。
- 新たに要素へ大きなデータ属性を埋め込む機能を作る場合は、SVGへ永続化する前に別ストアへ逃がすこと。
---
## 2026-10-14(Nanobanana: 生成方式を設定タブで切替し、半自動マンガ・Autoタブにも適用、v1.55.0)
v1.54.0 で Nanobanana タブにだけ追加した「ComfyUIネイティブノード」方式を、共通の設定として設定タブで切り替えられるようにし、半自動マンガ(スクリプト)と Auto タブの Nanobanana 生成にも適用した。3か所とも `requestNanobananaGenerate(payload)`(base64画像の配列を返す共通の入口)を通るため、呼び出し側はほぼ無改修。
**UI**
- 設定タブに「Nanobanana 設定」(`settings-nanobanana-engine`)を追加。選択は localStorage(`ccc_nanobanana_engine`)に保存し、Nanobanana タブの選択欄と `ccc-nanobanana-engine-changed` イベントで連動する。接続状態(Gemini キー / `COMFY_API_KEY`)も表示。
- `nanobanana.js`: `getNanobananaEngine` / `setNanobananaEngine` を追加・export。`checkNanobananaKeyStatus`(半自動マンガのモーダルでも使用)と `requestNanobananaGenerate` が設定に従う。
**バックエンド(`ccc.py`)**
- `POST /api/ccc/nanobanana/native/generate` に `return_b64` を追加: ワークフローの出力を `SaveImage` ではなく `PreviewImage`(temp、再起動で消える)にし、結果を `/view` から base64 で返す。呼び出し側が自前の保存先(`cc_nanobanana` / `cc_auto`)へ保存するため、ComfyUI の `output` に重複ファイルを残さない。PNG の `prompt` / `workflow` 埋め込みは SaveImage と同様に付くので、保存先のPNGにもメタデータが残る。
- モデル名の対応: 半自動マンガ・Auto は Gemini の ID で指定してくるため、`gemini-nano-banana-2.1` → `Gemini Nano Banana 2.1`、`gemini-3.1-flash-image` → `Nano Banana 2 (Gemini 3.1 Flash Image)`、`gemini-3.1-flash-lite-image` → `Nano Banana 2 Lite` に対応づけ。`gemini-3-pro-image`(Nano Banana Pro)はネイティブでは別ノード(`GeminiImage2Node`)のため **未対応**(`nanobanana_native_unsupported_model`)。Lite の 2K/4K はエラー(黙って1Kに丸めない)。エラー文言は3言語。
**実機確認(ComfyUI_5 / ポート8189、v0.40.0)**
- 設定タブの切替が Nanobanana タブ(選択欄・モデル欄・接続状態)に連動すること、Pro 未対応・Lite の 2K・不正モデルのエラー文言が出ることを確認(課金なし)。
- 半自動マンガと同じ形(参考画像1枚付き I2I、`gemini-nano-banana-2.1`)で共通の入口を実呼び出し: 18.4秒、base64 の PNG(848×1264、`prompt` / `workflow` チャンク入り)が返り、`output/cc_nanobanana_native/` に重複は増えない(プレビューと参考画像は temp)。
- Auto タブの `generateAutoImage` は、生成リクエストをスタブにして、設定に応じて `/native/generate`(`return_b64: true`)と従来の `/nanobanana/generate` が切り替わり、どちらも `save-auto-image` へ保存することを確認。モデル名の対応表は関数単位で確認(高価な `gemini-3.1-flash-image` は課金回避のため実生成せず)。
**注意**
- 半自動マンガの画像は `cc_nanobanana` に保存される。Workflow Studio v0.8.6 で、メタデータが埋め込まれた画像は Prompt タブが表示されるようにした。
- パートナーAPIノードの認証は、これまでどおり Comic Creator 側の `.env` の `COMFY_API_KEY`(サーバー側から付与)。
## 2026-10-14(Nanobanana: ComfyUIネイティブノード経由の生成を併用可能に、v1.54.0)
ComfyUI v0.40.0 の確認の流れで、Nanobanana のメタデータ・履歴の扱いを見直した。現行の Gemini API 直叩き経路は、返却画像をバイト列のまま保存するため PNG に生成条件が入らず、`history.jsonl` への別記録が必要だった。一方 ComfyUI 本体のパートナーAPIノード(Nano Banana 2.1)は SaveImage が `prompt` / `workflow` を PNG に埋め込むため、履歴ファイルが不要になる。そこで **置き換えではなく併用** として、ネイティブ経路を追加した。
**UI(Nanobanana タブ)**
- 基本設定に「生成方式」を追加(`Gemini API(自分のAPIキー)` / `ComfyUIネイティブノード(Comfyクレジット)`)。選択は localStorage(`ccc_nanobanana_engine`)に保存。
- ネイティブ選択時はモデル欄が Gemini Nano Banana 2.1 / Nano Banana 2 (Gemini 3.1 Flash Image) / Nano Banana 2 Lite に切り替わり、履歴の自動記録・「履歴に記録」ボタンは非表示。接続状態表示は `COMFY_API_KEY` の有無を見る。
- 結果は ComfyUI の `/view` から表示し、Eagle 自動登録は絶対URLで行う(相対パスはプラグイン内ファイル扱いになるため)。
**バックエンド(`ccc.py`)**
- `GET /api/ccc/nanobanana/native/status`(キーの有無のみ)、`POST /api/ccc/nanobanana/native/generate` を追加。API形式のワークフロー(`GeminiNanoBanana2V2` + `SaveImage`、参考画像は `LoadImage`)を組み立て、ComfyUI 自身の `/prompt` へ投入して `/history` で完了を待つ。
- 認証は `.env` の `COMFY_API_KEY`(platform.comfy.org で発行)を `extra_data.api_key_comfy_org` としてサーバー側から渡す(ブラウザへは出さない)。参考画像は temp 領域へアップロードし、`name [temp]` で参照する。
- キー名: DynamicCombo の子入力は `model.aspect_ratio` / `model.resolution` / `model.thinking_level`、参考画像(Autogrow)は `model.images.image_`。本体の展開ロジックで確定(未知キーは無視されるため、検証が通っても正しいとは限らない点に注意)。
- 出力先は `output/cc_nanobanana_native/NB_*.png`。`cc_nanobanana` とは別フォルダにしたのは、Workflow Studio 側が `cc_nanobanana` を「メタデータ無し+history.jsonl参照」の特別扱いにしているため。
- `seed` は Gemini へは送られず ComfyUI のキャッシュキーとしてだけ働く(実コードで確認)。同じ入力の再実行はキャッシュが返るため、枚数ごとに seed をずらす。ネガティブプロンプトの専用入力は無いため、従来どおり `NEGATIVE_PROMPT:` としてプロンプト末尾へ追記する。
- Lite は 1K のみ(2K/4K 指定は `nanobanana_native_resolution_unsupported`)。エラーコード(`nanobanana_native_key_missing` / `_unauthorized` / `_failed` / `_invalid_model` / `_resolution_unsupported`)は i18n(ja/en/zh)に追加。
**実機確認(ComfyUI_5 / ポート8189、v0.40.0)**
- ダミーキーで参考画像アップロード → `/prompt` 投入 → `/history` 判定 → `nanobanana_native_unauthorized` への変換まで確認(課金なし)。
- 実キーで Nano Banana 2.1(1K・2:3)を1枚生成: 18秒、848×1264。PNG に `prompt` / `workflow` チャンクが入り、モデル・アスペクト比・解像度・thinking_level・シード・プロンプトが読める。
- Workflow Studio の Metadata 抽出(モデル名・シード・プロンプト)と Gallery 一覧・画像メタ取得で、通常の画像として扱えることを確認(`cc_nanobanana_native` は history.jsonl 非対応のフォルダ)。
- 画面操作(方式切替・生成ボタン・結果表示・「コマに挿入」の有効化)は、生成リクエストだけをスタブ化して確認。
**対象外**
- 半自動マンガの一括生成(Nanobanana バッチ)は従来の Gemini API 経路のまま。
- 既存の `history.jsonl` と、Workflow Studio 側の `cc_nanobanana` フォルダの特別扱いは、過去の画像のため残す。
## 2026-10-13(マニュアル執筆中に見つかった改善候補20件への対応、v1.53.2)
マニュアル執筆中に洗い出した仕様の落とし穴(`manual/改善候補メモ.md`、v1.53.1対象の20件)をすべて対応した。方針はユーザー判断で、実装・ヘルプ修正・項目削除のいずれかを項目ごとに選んだ。
**テンプレート・ページ**
- #1 初回起動時に基本テンプレート「A4縦_3コマ」「A4横_3コマ」を自動登録(`06b-template-manager.js`の`_tmplSeedDefaultTemplates`)。ウィザードと同じSVG形式(0.01mm単位・白背景rect + panel_0 + panel_N)を生成して`parseSVGForTemplate`で登録。localStorageのフラグ(`ccc_default_templates_seeded_v1`)で一度だけ実行し、削除しても再登録しない。既存ユーザーにも次回起動時に1回だけ追加される。テンプレート名は表示言語ごと(`tmpl.defaultA4Portrait/Landscape`)。
- #2 「ページ新規作成」を「クイック」に改称(`page.createPage`)し、コマ線幅のprompt()を廃止。テンプレートの線幅のまま1ページ作成してレイアウトタブへ移動する(線幅の変更はレイアウトタブの「コマ枠線幅」)。`insertTemplatePageToWork()`への統一はせず、1ページ即作成のメニューとして位置付けた。
**出力**
- #3 `_updateExportPageRange`: 総ページ数が変わった(作品/グループの切替等)ときだけ範囲を「1〜総数」にリセットし、同じ総数での再描画ではユーザー入力を保持。
- #4 `onSwitchToOutputTab`: 作業中の作品があれば自動でその作品に絞り込む。作業中の作品が変わったときだけ適用し、手動でフィルタ解除した場合は同じ作品の間は再適用しない。
- #9 書き出しで参照されていなかった「フキダシのみ」を削除(HTML・排他制御・i18n)。
- #10 PDF・EPUB選択時は「背景のみ」「zip保存」を無効(グレー)表示。
**i18n・表記**
- #5 トップバーCCボタンのツールチップを英語表記(`web/comfyui/ccc_menu.js`)。
- #6 初回の表示言語を`navigator.languages`から決定(ja/en/zh、該当なしは日本語)。保存済みの言語設定があればそちらを優先。
- #16 Imageタブのトースト・prompt約69種を`image.msg.*`としてi18n化(ja/en/zh)。値を含む文言は関数形式。`image-tab.js`内では`const t`の局所変数による隠蔽があるため`window.t`で呼ぶ。Open PSDのツールチップもi18n化。
- #17 Imageタブのテキスト入力欄をレイアウトタブの「テキスト入力」に合わせ、Enter=改行・Ctrl/Cmd+Enter=確定・Esc=キャンセルに統一。プレースホルダーにヒントを表示。
- #7 ヘルプの「右サイドパネル」表記のうち、ツールのサブタブ説明を「プレビュー上部のツール設定帯」に修正(レイヤーパネル・表示サイズは実際に右側なので据え置き)。#11 作品管理の「グループから削除」を「stockへ移動」に修正(テンプレートタブの同名ボタンは実在するため据え置き)。#15 フキダシ形状一覧に「キャプション(直角・尻尾なし)」を追記。いずれもja/en/zh。
**機能の実装・修正**
- #12 レイアウトタブ「画像」サブタブのBiRefNetを、Imageタブと同じMask Editor Oneの`/mask_editor/birefnet/*`ルートで実装(`16-processing-edit-tabs.js`)。画面を開いたときに`/mask_editor/birefnet/status`で利用可否を確認し、利用できない場合は選択肢を無効化して理由をラベルに表示する。
- #13 画像サブタブの実行結果が元画像の位置・表示サイズ・回転(`transform`・`preserveAspectRatio`)を引き継いで挿入されるようにし、成功後に元画像を非表示にする(レイヤーパネルの👁と同じ状態)。非表示化は挿入の履歴(undo)には含まれない。
- #14 My曲線の既定画像を`static/img/mychain_default.png`として同梱し、読み込み先を`/ccc_static/img/`に変更(`assets/**/*.png`は`.gitignore`対象のため従来は新規環境に届かなかった)。
- #18 Nanobananaで2枚以上生成したとき、全結果をサムネイル表示し、選んだ画像を「コマに挿入」できるようにした(`showResult(index)`・`selectedResultIndex`)。
- #19 Generateの挿入は置き換えではなく既存画像の上への重ね追加が実際の動作のため、挙動は変えずヘルプ・コードコメントを実態に合わせた。置き換えにする場合は挿入前に元画像を削除する処理が別途必要。
- #20 Eagle設定の「ComfyUI 生成画像を自動保存」は、どの処理からも参照されていなかったためグレーアウトし、Workflow Studioの設定タブ>Eagleで設定するよう案内文を追加。保存ボタンはこの値を書き込まない。
**配布**
- #8 `.comfyignore`に`!docs/manual/`を追加し、同梱版マニュアルを配布物に含める。Registry側が否定パターンを解釈するかは未確認。
**起動ログ**: `[ccc] Comic Creator loaded → http://127.0.0.1:8189/ccc`のポートが固定だったため、`comfy.cli_args`の`port`/`listen`から組み立てるように修正(`0.0.0.0`・`::`は`127.0.0.1`、IPv6は`[...]`で囲む)。
**検証**: Kaptureで#1・#2・#3・#4・#9・#10・#12(選択肢の有効/ラベル)・#20を実機確認。Playwrightで#6(en/zh/ja/frの4ロケール)・ヘルプ文面(17項目を巡回、3言語)・#16(「New」のダイアログ・トースト・Open PSDツールチップ、3言語)を確認。#12/#13の実行、#17のテキスト入力、#18の複数枚表示はユーザーが実機確認済み。起動ログのポート組み立ては、実際に別ポートで起動せず、該当コードのみ`port`/`listen`を変えて実行して確認。
**How to apply**: Playwrightのコンテキスト作成時の`locale`指定で、初回言語・多言語表示を保存設定なしで検証できる。ヘルプのようにタブ内で項目を切り替えて描画する画面は、全項目を巡回して実画面のテキストで照合する(ソースの文字列検索だけでは描画漏れを見落とす)。
---
## 2026-10-09(Nanobanana生成履歴をJSON Lines形式へ変更、v1.53.1)
v1.53.0でリリースした生成履歴機能(自由記述のテキストブロック形式、`history.txt`)について、ユーザーから「Workflow Studio側で履歴ファイルを読んで別表示する連携を確実にやる」という方針が示されたため、着手前にフォーマットをJSON Lines(1行1件のJSON)へ変更した。自由記述テキストは外部ツールからのパースが不安定になるため、プログラムからも人の手編集からも扱いやすいJSONLへ先に揃えておく判断。
- **ファイル名を`history.txt`→`history.jsonl`に変更**(`py/ccc.py`の`_NANOBANANA_HISTORY_FILENAME`)。旧`history.txt`は参照しなくなるが自動削除・移行はしていない(テスト記録2件が残ったまま、ユーザー判断で削除可)。
- **`handle_nanobanana_history_append`**: 従来の`====`区切りテキストブロック生成をやめ、`{timestamp, engine, model, width, height, image_size, seed, filenames, prompt, negative_prompt}`の辞書を`json.dumps(..., ensure_ascii=False) + '\n'`で1行追記するだけに変更。`engine`フィールドは今回追加(既定`'gemini'`)で、[[comic-creator-workflow]]に記録予定の次回作業(`PLAN_nanobanana_local_image_edit.md`、ローカルImage Edit対応)で`'local'`等を入れられるようにする先回りの変更。
- **`handle_nanobanana_history_get`**: ファイルを1行ずつ`json.loads`し、`entries`配列として返すように変更(従来の生テキスト`text`も互換のため残す)。手編集等で壊れた行は例外を握りつぶさず`{line, raw, parse_error}`として`entries`に含め、エラーで履歴全体が読めなくなることを避けた。
- **フロント(`nanobanana.js`)**: 履歴サブタブの表示は後方互換のため変更せず、`fetchNanobananaHistory()`が返す`entries`から`formatHistoryEntry()`で従来と同じ見た目のブロックテキストを組み立ててtextareaへ表示する(保存形式はJSONLだが、UI上の見た目は変えていない)。`appendNanobananaHistoryEntry()`自体は送信フィールドの形は変えておらず、`lastGenerationMeta`に`engine: 'gemini'`を追加しただけ。
- ヘルプ(ja/en/zh)・README(ja/en/zh)の`history.txt`表記をすべて`history.jsonl`に更新し、JSON Lines形式である旨を明記した。
**検証**: `python -m py_compile`・`node --check`・`vm.SourceTextModule`で構文確認のみ実施。ComfyUI再起動後の実機確認(自動記録・手動記録・履歴表示、特に`formatHistoryEntry`が旧形式と同じ見た目で表示されること)は未実施。
**How to apply**: 外部ツール(Workflow Studio等)からの連携を予定しているログ・記録系ファイルは、自由記述テキストではなく最初からJSON Lines等の構造化フォーマットで設計する。UI側の見た目を変えたくない場合は、保存はJSONL・表示はクライアント側で整形、という形で両立できる(今回の`formatHistoryEntry()`参照)。
---
## 2026-10-09(Nanobananaタブに生成履歴(テキストファイル)機能を追加、v1.53.0)
ユーザーから「Nanobananaで生成した画像にプロンプトを埋め込み、Workflow StudioのGalleryのプロンプト/Metadataタブで見たい」という依頼を受け、まずWFS側(`ComfyUI-Workflow-Studio`リポジトリ)のGallery実装を調査した。
**調査結果(コード変更前の事前調査)**: WFSの「プロンプト」「Metadata」タブ(`static/js/gallery-tab.js`の`renderPromptTab`・`static/js/metadata-tab.js`)は、PNGの`tEXt`チャンク(キー`prompt`、ComfyUI API形式のワークフローJSON)からノードを解析する仕組みで、**PNG専用**(`py/services/gallery_service.py`の`_read_png_metadata`/`_read_jpeg_metadata`を確認。JPEGは単純なCOMコメントマーカーしか読まず、構造化されたワークフロー解析には対応していない)。Nanobanana(Gemini API)の生成結果は多くの場合JPEGで返るため、この仕組みに正攻法で乗せるには常時PNG保存への変更か、WFS側コードの拡張が必要と判明。この調査結果と、PNG保存+ダミーワークフローノード(`WFS_PromptText`)埋め込み案を含む3案をAskUserQuestionで提示しようとしたところ、ユーザーからツール自体を却下され、「WFSのGalleryへの埋め込みではなく、Nanobananaタブ自身の機能として生成履歴をテキストファイルで残したい」という明確な代替要望が示された。
**実装(ユーザー指定仕様)**: 画像ファイルへの埋め込みではなく、1つのテキストファイルに「ファイル名・日時・プロンプト・設定」をまとめて記録する方式にした。編集・削除はアプリ側にUIを設けず、ユーザーがテキストファイルを直接編集する前提(この方がWFS側の実装に依存せず、PNG/JPEGどちらでも同じように使える)。
- **保存先**: `output/cc_nanobanana/history.txt`(画像の保存先と同じフォルダ)に、生成1回=1ブロックで追記(`py/ccc.py`の`handle_nanobanana_history_append`)。モデル・解像度・出力解像度・シード・ファイル名(バッチ全体をまとめて1ブロック)・Positive/Negativeプロンプトを記録。`GET /api/ccc/nanobanana/history`で全文取得、`POST /api/ccc/nanobanana/history/append`で追記(ルートはdispatchテーブル`_DISPATCH_GET`/`_DISPATCH_POST`と明示`add_get`/`add_post`の両方に登録。既存エンドポイントが両方に重複登録されている既存パターンに合わせた)。各フィールドは`_clip_history_field()`で長さ上限(prompt/negativeは4000文字、ファイル名は300文字×最大50件)を設け、異常に大きいリクエストでファイルが際限なく肥大化しないようにした。
- **UI(`templates/index.html`・`static/js/nanobanana.js`)**: Nanobananaタブの基本設定に「生成時に自動で履歴に記録」チェックボックス(`#nanobanana-history-auto`、`localStorage`の`ccc_nanobanana_history_auto`に保存、ブラウザ間では共有されない)を追加。サブタブに「履歴」を新設し、`history.txt`の全文を読み取り専用の`