Yyatmita

【第4回】manginus——失敗から生まれた自作マンガエディタで第2話を完成させた

OSSマンガエディタの挫折を設計に反映し、MCP ネイティブなマンガエディタ manginus を自作。AI3者ネーム会議のシナリオで第2話を完成させるまでの記録

AIマンガ制作ワークフロー#ai-manga#manginus#comfyui#fastapi#react#websocket
← 前の記事: 【第3回】ガチャを強みにする——AI3者ネーム会議という悪魔的発想

「こう作ればいい」がわかっていた

第2回で あるOSSマンガエディタの MCP 化に挫折した。あのツールで苦労した原因は明確だった。

  • HTML 1枚の SPA 構成 — モジュール分割されていない
  • モデルとアクションの分離がない — データとUIが密結合
  • 癖のある自動処理が多数 — 外から制御すると意図しない副作用が起きる

裏を返せば、これを全部避ければいい。

第3回でAI3者ネーム会議のフローが完成した。ネームの出力は MD + YAML で構造化されている。あとはこのデータを食べて、マンガに変換するツールがあればいい。

manginus の設計思想

そのOSSエディタの反省をすべて設計に反映して、manginus というツールを自作した。名前は「manga」+「engine」から。

サーバーがデータの真実を持つ

そのOSSエディタはブラウザの中にすべてがあった。キャンバスの状態がデータの実体で、外から触ろうとすると DOM を操作するしかない。

manginus は逆だ。サーバー(FastAPI)がデータの真実を持つ。ブラウザはプレビュー用のビューアでしかない。

manginus アーキテクチャ:サーバーが中心にいて、ユーザー・Claude Code・ComfyUI・ブラウザとやり取りする

全操作は API

ヘッドレスでもマンガが完成できる——これが設計の核心だ。

ページ作成、コマ配置、画像配置、テキスト挿入、吹き出し、エフェクト。すべての操作に REST API がある。ブラウザを開かなくても、curl だけでマンガが作れる。Claude Code からも当然使える。

そのOSSエディタでは12個の MCP ツールを作って、最終的にセリフの微調整で詰まった。manginus では API が最初から設計に組み込まれているから、そもそもラッパーを作る必要がない。

リアルタイム同期

サーバーでデータが変わると、WebSocket 経由でブラウザに即座に反映される。Claude Code が API でコマを追加したら、ブラウザのプレビューがリアルタイムで更新される。

処理の進行が見える。画像を生成しているとき、セリフを配置しているとき、何が起きているかがリアルタイムでわかる。

ComfyUI 連携

画像生成は ComfyUI に任せる。manginus のサーバーから ComfyUI の API にワークフローを POST して、生成結果を自動でインポートする。NanoBanana Pro のワークフローもプリセットとして組み込んだ。

データモデル

マンガのデータ構造はシンプルなツリーだ。

Story
  ├── metadata (title, author, series, episode)
  └── Page[]
        └── Node[] (ツリー構造)
              ├── Panel (コマ枠)
              │     ├── Image (clipToParent)
              │     ├── SpeechBubble
              │     │     └── Text
              │     └── Effect
              └── Text (コマ外テキスト)

すべてが Node だ。コマも、画像も、テキストも、吹き出しも。Node は親子関係を持ち、座標は親からの相対値(0〜1)で表現する。コマの中に画像を置けば、コマを動かしたとき画像も一緒に動く。

OSSエディタで苦労した「モデルとアクションの分離がない」問題は、Pydantic のデータモデルを明確に定義することで解決した。データの変更は必ず API を通る。副作用はない。

ネームからマンガへ

AI3者ネーム会議で決まったネーム(MD + YAML)を manginus に食わせると、こういう流れで自動的にマンガが組み上がる。

1. プロジェクトセットアップ

uv run python scripts/setup_project.py \
  --title "EP02 自分がかわいい" \
  --series "ある管理職の物語" --episode 2 \
  --character 'ワタシ|base_prompt|ref.png' \
  --nemu /path/to/nemu.md \
  --generate-pages

キャラクター登録、ネーム読み込み、ページとコマの一括生成がこのコマンド1発で終わる。

2. 全コマ画像一括生成

uv run python scripts/generate_images.py --auto-adopt

ネームの各コマに書かれたプロンプトを読み取り、キャラクターの参照画像を添えて、ComfyUI(NanoBanana Pro)に送信する。生成された画像は自動でコマに配置される。

3. 確認と修正

uv run python scripts/export.py export /tmp --page 3 --scale 1

各ページを PNG でエクスポートして目視確認。気に入らないコマがあれば、そのコマだけ再生成するか、生成済みのバリエーションから別の画像を選ぶ(adopt)。

ここでも「修正するな、選べ」の原則が活きる。

4. エクスポート

uv run python scripts/export.py export /path/to/output --scale 3

Playwright でブラウザをヘッドレス起動し、各ページを3倍解像度で PNG に書き出す。印刷品質のマンガが出力される。

便利さを知ったら、もう戻れない

これが実際の manginus のビューアだ。

manginus ビューア——左にネーム・ページ情報、中央にマンガプレビュー、右にオブジェクトツリー

manginus ビューア:左にネーム、中央にプレビュー、右にオブジェクトツリー

左パネルにネームの情報が並んでいて、中央にマンガのプレビュー、右にオブジェクトツリー。Claude Code が API でコマや吹き出しを追加すると、リアルタイムでプレビューが更新される。

この体験をすると、もう普通のツールには戻れない。

「このコマの画像、もう少し引きで」と Claude Code に言えば、プロンプトを調整して ComfyUI に再送信して、生成結果をコマに配置してくれる。「吹き出しの位置を右にずらして」と言えば、API 一発で動く。ブラウザで見ながら、AIに操作してもらう。

今どきのツールは、AIに相談してやり方を教えてもらったり、操作してもらえないと、もう満足できなくなっている。API が公開されていないツール、AIが触れないツールは、どれだけ機能が豊富でも使いにくく感じてしまう。

そのOSSエディタは凝ったツールだった。でも外から制御できなかった。manginus は機能では劣るかもしれないが、AIと一緒に使える。その差は想像以上に大きい。

実制作で見えたこと

第2話の制作を通じて、いくつかのフィードバックがあった。

自動セリフ配置の改善。 最初は横書きになるケースがあった。マンガのセリフは縦書きが基本なので、全て縦書きに統一した。フォントも漫画用の源暎アンチックと源暎Nuゴシックを導入した。

吹き出しサイズの自動調整。 セリフの文字数に応じて吹き出しのサイズを自動計算するようにした。1行あたりの文字数もセリフの種類で最適化している——会話は7文字、叫びは5文字、モノローグは8文字、ナレーションは9文字。

NanoBanana が描く書き文字の抑制。 画像生成AIは親切にも画像内に効果音などの文字を描いてくれることがある。でもセリフは manginus 側で配置するから、画像内の文字は邪魔になる。no_text フラグで抑制できるようにした。

「たぶん続きは出ないと思います」の続き

第1話の末尾に「たぶん続きは出ないと思います。Gemini くんと会話するのは疲れました……」と書いた。

でも続きは出た。

Gemini での6時間の修正地獄。SaaS のクレジットガチャ。287枚のキャラガチャ。OSSエディタの MCP 化と挫折。「ガチャを強みにする」という発想の転換。AI3者ネーム会議。そして自作ツール manginus。

回り道をした。でも回り道のひとつひとつが、最終的な設計に反映されている。Gemini の修正地獄がなかったら「修正するな、選べ」にたどり着かなかった。OSSエディタの挫折がなかったら、manginus の「API ファースト」設計は生まれなかった。

第2話は、これらすべての失敗から生まれた。


この連載は今回で一区切りです。AIマンガ制作のワークフローは、第2話の制作を経てまだ発展途上です。ツールの改善や新しい知見が溜まったら、また書きます。

完成した第2話はこちら → 【マンガ】第2話: 自分がかわいい