4コママンガ『ハコブくん』を縦長4枚でめくる形に ― 次はショートと同時に出す
この記事の素材(コード・ログ・データ 4ファイル・まとめてダウンロードあり)arrow_downward4コママンガ『ハコブくん』は、縦長(縦横比 4:5)の4コマを横にスワイプしてめくって読む形に変え、第73〜133話の29話を pixelstomotors.com に載せました。 1コマが1枚の絵なので、サイトのページ・YouTube ショート・SNS の画像に、同じ絵をそのまま使えます。
『ハコブくん』は、病院で薬を運ぶロボット・ハコブくんと、看護師さんたちの4コママンガです。ロボットが現場に入ったときに起きるすれ違いを、毎話1つ描いています。これまでは4つのコマを1枚のページに組んでいました。前の記録(LOG408)で、1コマを縦長の1枚ずつで描けば YouTube ショートにそのまま使えることを確かめ、まずはショートだけで試していました。
今回は、その縦長の4コマを、サイトでもそのまま読める形にしました。スマホでは指で横にめくり、PC ではコマの左右のボタンでめくります。コマの下には、毎話の設計の解説(デザインノート:その話で起きたことが、現実のロボットの設計のどこにつながるかを3段で書いた文)を置き、ページの最後に前の話・次の話へのカードを付けました。
作る途中で、いちばん手こずったのは絵の間違いです。キャラの大きさが設定とずれる問題は毎回起きていて、原因は「絵を描く AI が数字の大きさを守らず、コマを埋める大きさで描く」ことでした。 大きさは目で見るだけでなく測って選ぶようにし、マンガを見せる前に3回確かめる流れと、間違いを書きためる台帳を作りました。それでも公開後に、腕が3本・脚がない・眼鏡がない、といった間違いが見つかり、そのたびに台帳に足しています。
やったことの全体は次のとおりです。
| やったこと | なぜ | 結果 |
|---|---|---|
未着手のプロットから30話を縦長の4コマで描いた | 新しい形で話をためる | 120コマ。描き直しを含めて約500枚を描いた |
見せる前に3回確かめる流れと、間違いの台帳を作った | 細かい間違いが見落とされていた | 120コマを見直して21コマを描き直した |
キャラの大きさがずれる原因を調べ、測る仕組みを足した | 大きさのずれが毎回起きていた | 原因を6つに分け、高さの比を数字で出せるようにした |
サイトに、横にスワイプして読むページを作った | 縦長の4枚を1画面ずつ読ませたい | 3話で試してから29話を公開した |
めくるボタンの場所と形を直した | ボタンを押すとコマが切れた・黒いボタンが目立ちすぎた | コマとボタンが1画面に収まり、ボタンは黒い縁にした |
表紙と、前の話・次の話のカードを足した | 一覧で話の中身が分かる顔にしたい | 29話の表紙を作り、全話に前後のカードを付けた |
29話の SNS の投稿を予約した | 新しい話を知らせる | 11/2〜11/27 の朝7:30 を中心に、X と LinkedIn を予約した |
次の50話のプロットを、現場の調査から作った | 実際に起きている問題を描きたい | 100件を調べ、50話を作り、codex の検証を受けて直した |
ここから下は作業ログです。使ったコード・決まり・検証の結果は、あとで同じ手順を追えるように全文を載せています。効果の欄は、数字があるものは測った値、ないものは見込みです。
作業ログ ― 縦長の4コマ30話を描いて確かめた
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(4本)
01_sec01.md ― チェック項目と過去の間違い.md・5,763字
02_MangaSwipe.astro.txt ― MangaSwipe.astro(スワイプで読む部品)・4,492字
03_MangaPage.astro.txt ― MangaPage.astro(マンガのページ)・4,911字
04_sec06.md ― codex の検証結果(1回目)・15,536字
30話は、スプレッドシートの未着手のプロットから新しい順に選んだ
『ハコブくん』のプロット(話の筋)は、Google のスプレッドシート「薬剤搬送ロボットハコブくん 進捗管理表」に1話1行でためています。列は、話の番号・対応の進み具合・タイトル・テーマ・登場人物・1〜4コマ目の中身・デザインノートの元になる一文です。このうち「未着手」の行を、番号の新しい順に30話選びました。第133〜123話・121話・118〜113話・111話・109話・101話・100話・99話・97〜93話・76話・73話です。
第121話は、前の横長の形でサイトに出ていたので、今回は縦長の版を描いただけで、サイトには入れていません。残りの29話を公開し、30話ともスプレッドシートの進み具合を「完了」にしました。
Gemini の API で、1コマずつ描いた
Gemini は Google の生成 AI です。文章と参考の画像を渡すと絵を描きます。API(プログラムから頼む窓口)で使うと、決まった指示を毎回同じ形で渡せて、1コマずつまとめて描けます。使った分だけ料金がかかります。この30話のために Google AI Studio で払ったのは8,400円で、描いた絵1枚あたりでは約10円でした(内訳は下の「Gemini の API にかかったお金」)。
| この記事で使う言葉 | 意味 |
|---|---|
| vbuild.py | Gemini に渡す指示を組み立て、描かせ、仕上げる自作のスクリプト(LOG410 で作った) |
| spec.py | 1話ごとの設定。コマごとの登場人物・構図・吹き出しの文を書く |
| 緑の背景 | 描くときは背景を緑一色にして、仕上げで白に置き換える。人や物の形を取り出しやすくするため |
| 候補 | 同じコマを何枚か描かせたもの。いちばん良いものを選ぶ |
キャラクターは、三面図(正面・横・後ろの絵)と、主要キャラの身長を並べた図を参考の画像として毎回渡します。ハコブくんは115cm、遠隔で操縦する人型ロボットのピカリくんは150cm、看護師の大城さんは165cm、という設定です。
Gemini の API にかかったお金:払ったのは8,400円、1枚あたり約10円
Gemini の API の料金は、Google AI Studio で先にクレジット(前払いの残高)を買い、使った分がそこから引かれる形です。クレジットは Gemini の API にだけ使えます。最初の2回は手で買い、そのあと「残高が800円を下回ったら800円を足す(1か月の上限5,000円)」というオートチャージを入れました。Google から届いた支払いのメールを並べると、次のとおりです。
メールが届いた日時(日本時間) | 払った額 | 払い方 |
|---|---|---|
2026-10-30 14:28 | 3,200円 | 前払い |
2026-10-30 21:23 | 2,000円 | 前払い |
2026-10-31 06:33 | 800円 | オートチャージ |
2026-10-31 06:49 | 800円 | オートチャージ |
2026-10-31 07:07 | 800円 | オートチャージ |
2026-10-31 07:31 | 800円 | オートチャージ |
| 合計 | 8,400円 |
払った額は、使った額とは少し違います。オートチャージが残高を800円前後に保つので、最後に買った分の一部は残っています。
使った額は、vbuild.py が API を呼ぶたびに残している記録(返ってきた答えの JSON。使ったトークン数が入っている)から計算できます。トークンは、AI が文章や画像を数えるときの単位です。記録が残っているのは10月30日〜31日の633回で、そのうち629回が gemini-3.1-flash-image への依頼でした。記録を残さずに呼んだ分があれば、使った額はこの計算より少し多くなります。
| 種類 | トークン数 | 単価(100万トークンあたり) | 金額 |
|---|---|---|---|
渡したもの(指示の文章・参考の画像) | 1,658,853 | 0.50ドル | 0.83ドル |
返ってきた文章(考えた過程を含む) | 300,182 | 3ドル | 0.90ドル |
| 返ってきた画像 | 665,280 | 60ドル | 39.92ドル |
| 合計 | 2,624,315 | 41.65ドル(1ドル150円で約6,250円) |
単価は Gemini API の料金のページ の有料の枠の値です(2026-10-31 に確認)。画像1枚は約1,060トークンで、料金のページにある「1K の画像1枚0.067ドル」とほぼ同じです。
| 数え方 | 枚数 | 1枚あたり |
|---|---|---|
描かせた絵(候補・描き直し・表紙の編集を含む) | 629枚 | 約0.066ドル(約10円) |
サイトに載せたコマ(29話×4コマ) | 116コマ | 約0.36ドル(約54円) |
載せた1コマのために、平均で約5.4枚を描かせたことになります。候補を3〜5枚描いて選ぶ流れと、確かめで見つけた間違いの描き直しが、この差です。
- ねらい:描き直しと候補の数が、どれだけお金になっているかを見える形にする
- 変わったこと:支払いのメールと API の記録から、払った額・使った額・1枚あたりを出した
- 見込める効果:次の50話を描く前に、1話あたり約220円(4コマ×約5.4枚×約10円)、50話で約1万1,000円と見積もれる。候補の数を減らしたときに、どれだけ下がるかも同じ式で確かめられる
見せる前に3回確かめる流れにした
最初に30話を描き終えたとき、そのまま声と動画まで作って見せてしまいました。見てもらうと、腕が3本ある人・脚のない人・大きさがばらばらのハコブくんが次々に見つかりました。描いた本人(Claude)が見ても、同じ所を見落とします。そこで、マンガを見せる前に確かめる時間を、流れの中に固定しました。
- 描く
- チェック①:描いたのとは別のエージェントが、1コマずつ決まった項目で見る
- 直す(直したコマはもう一度チェック①)
- チェック②:全部のコマを並べてエイイチに見せ、OK をもらう。OK の前に声や動画を作らない
- ショートにする
- チェック③:書き出した動画を並べて、字幕や吹き出しの切れを見る
あわせて、間違いを書きためる台帳「チェック項目と過去の間違い.md」を作りました。見つかった間違いを1行ずつ足し、直し方が決まったものは確かめる項目にも足します。次に描くときは、この台帳を最初に読みます。
- ねらい:同じ間違いを、次の話で繰り返さない
- 変わったこと:120コマをチェック①で見直し、21コマを描き直した。ここで見つかったのは、余計な吹き出し・台本にない記号・絵の中の英字・大きさのずれなど
- 見込める効果:見せてから直す回数が減る。ただし公開後にも4件見つかった(下の「公開後に見つかった絵の間違い」)。台帳は今も増えている
キャラの大きさが設定とずれる6つの原因
大きさのずれは、どの話でも起きていました。特にピカリくんは、話ごとに大きくなったり小さくなったりしました。調べると、原因は6つに分けられました。
| 原因 | 何が起きるか |
|---|---|
絵の AI は数字の大きさを守らない | 「150cm」「1.3倍」は文字として読むだけで、実際はコマを埋めるように大きさを決める。主役は大きく、脇のロボットは吹き出しの横などの余った所に入る大きさに縮む |
参考の三面図は、どれも画面いっぱいに描かれている | 1人ずつの絵には「ほかのキャラと比べた大きさ」が入っていない。身長を並べた図は、何枚もある参考の1枚にすぎない |
| 背景が緑一色で、床の線がない | 少し奥や手前に置かれただけで見た目の大きさが変わり、遠近で縮んだのか設定より小さいのか分からない |
座る人・しゃがむ人の頭を、立っている人の目の高さに描く | 座った人が、立っているロボットより大きくなる |
大きさの指示が何本も積み重なり、食い違っていた | 古い指示の文と新しい指示、「細身」の一語などがぶつかると、AI は構図のほうを取る |
「ひざ上」「腰上」の指定を無視して全身で描く | 全身を入れるために全体を縮め、2人の縮み方がそろわない |
これを受けて、大きさの指示は1か所(頭のてっぺんと足もとの位置、薄い緑の枠を描いた下地の画像)にまとめ、並ぶ2人はカメラから同じ距離・同じ床に立たせることにしました。それでも1枚で決めずに、候補を3〜5枚描き、大きさを測っていちばん近いものを選びます。
測る仕組みは、vbuild.py に measure という命令として足しました。緑の背景の上で、床まで届いているかたまり(立っている人やロボット)を探し、頭のてっぺんと足もとの位置から高さの比を出します。例えば第117話の4コマ目は、ピカリくん(150cm)と千夏さん(164cm)が並ぶコマで、比は 150÷164=0.91 が正解です。
- ねらい:大きさを目で見て決めない
- 変わったこと:候補ごとに高さの比が数字で出る。第117話4コマ目は、指示を強めても 0.70〜0.85 にしかならず、吹き出しの字が正しい中でいちばん近い 0.85 を選んだ
- 見込める効果:「並び図の比から ±0.08 を超えたら描き直す」と決められる。ただし AI が設定どおりの大きさで描くようになるわけではない
第117話4コマ目の候補を測った結果は次のとおりです。かっこの中は、左右の位置・頭のてっぺん・足もと・高さ(どれも画像の高さに対する%)です。
第117話_P4_20261030_222457.jpg [(26, 18, 97, 80), (71, 29, 95, 66)] 高さの比 0.82
第117話_P4_20261030_222458.jpg [(19, 5, 97, 92), (83, 21, 97, 76)] 高さの比 0.83
第117話_P4_20261030_222459.jpg [(19, 5, 97, 92), (71, 26, 97, 71)] 高さの比 0.77
第117話_P4_20261030_222504.jpg [(19, 10, 97, 87), (73, 29, 97, 67)] 高さの比 0.77
第117話_P4_20261030_222506.jpg [(20, 5, 97, 92), (76, 26, 97, 71)] 高さの比 0.77
(指示に「2人は同じ床・同じ距離・ピカリくんは千夏さんの目の高さまで」を足して6枚)
第117話_P4_20261030_223829.jpg [(19, 9, 98, 89), (67, 27, 96, 70)] 高さの比 0.79
第117話_P4_20261030_223858.jpg [(19, 5, 97, 92), (67, 23, 97, 74)] 高さの比 0.80
第117話_P4_20261030_223859.jpg [(19, 5, 97, 92), (75, 32, 97, 64)] 高さの比 0.70
第117話_P4_20261030_223902.jpg [(21, 18, 97, 79), (69, 30, 97, 67)] 高さの比 0.85
第117話_P4_20261030_223907.jpg [(28, 1, 98, 96), (69, 18, 93, 74)] 高さの比 0.77
第117話_P4_20261030_223911.jpg [(19, 5, 97, 92), (68, 26, 96, 70)] 高さの比 0.76
0.82 の候補は、吹き出しの「もうこっち向いていいよ」の「い」が1字抜けていたので選びませんでした。大きさと字は、別々に確かめる必要があります。
vbuild.py の measure と finish
finish は、選んだ候補の緑を白に置き換え、1080×1350 に整えて「仕上げ」のフォルダに書き出します。あとから余計なふりがなや崩れた名札を白で消せるように、話ごとの設定に PATCH(白で塗る四角)を書けるようにしました。
def measure(src):
"""緑の上の人・ロボットの大きさを測る(2026-10-31)。床に立つかたまり(下半分まで届く)を左から順に (中心x%, 頭頂y%, 足もとy%, 高さ%) で返す。
手をつないでいる・重なっている2人は1つに数える。吹き出しは床に届かないので数えない"""
from scipy import ndimage
a = np.asarray(Image.open(src).convert("RGB")).astype(np.float64)
H, W, _ = a.shape
green = (a[..., 1] - (a[..., 0] + a[..., 2]) / 2) > 40
lab, n = ndimage.label(ndimage.binary_opening(~green, iterations=2))
out = []
for k, sl in enumerate(ndimage.find_objects(lab), 1):
ys, xs = sl
if ys.stop < H * 0.6 or (ys.stop - ys.start) < H * 0.15 or (xs.stop - xs.start) < W * 0.05: continue
out.append((round((xs.start + xs.stop) / 2 / W * 100), round(ys.start / H * 100), round(ys.stop / H * 100), round((ys.stop - ys.start) / H * 100)))
return sorted(out)
def finish(ep, m):
d = epdir(ep); os.makedirs(d + "/仕上げ", exist_ok=True)
pick = getattr(m, "PICK", {})
for i, p in enumerate(m.PANELS, 1):
src = pick.get(i); src = d + "/生成/" + src if src else latest(d, "第%d話_P%d" % (ep, i))
if not src: print("P%d 絵なし" % i); continue
img = fit(degreen(src, getattr(m, "FIX", {}).get(i)), 1080, 1350)
if i in getattr(m, "WINDOWS", {}):
ws = pick.get("W%d" % i); ws = d + "/生成/" + ws if ws else latest(d, "第%d話_P%d小窓" % (ep, i))
if ws:
x0, y0, x1, y1 = p["inset_area"]
bw = round((x1 - x0) * 1080); bh = round((y1 - y0) * 1350); side = min(bw, bh)
win = fit(degreen(ws), side, side)
X = round(x0 * 1080 + (bw - side) / 2); Y = round(y0 * 1350 + (bh - side) / 2)
img.paste(win, (X, Y))
dr = ImageDraw.Draw(img); dr.rectangle((X, Y, X + side - 1, Y + side - 1), outline=(0, 0, 0), width=6)
for box in getattr(m, "PATCH", {}).get(i, []): # 仕上げの座標(1080×1350)を白で塗る:余計な字・崩れた名札(2026-10-31)
ImageDraw.Draw(img).rectangle(box, fill=(255, 255, 255))
img.save(d + "/仕上げ/第%d話_P%d_1080x1350.png" % (ep, i))
print("P%d" % i, os.path.basename(src))
# ---- コマンドの部分(measure)----
elif cmd == "measure": # python3 vbuild.py NN measure 4 [本数]:最新の候補の大きさを測る
pn = rest[0]; k = int(rest[1]) if len(rest) > 1 else 5
fs = sorted(glob.glob(d + "/生成/第%d話_P%s_2*.jpg" % (ep, pn)) + glob.glob(d + "/生成/第%d話_P%s_2*.png" % (ep, pn)))[-k:]
for f in fs:
ms = measure(f)
hs = [h for _, _, _, h in ms]
print(os.path.basename(f), ms, "高さの比 %.2f" % (min(hs) / max(hs)) if len(hs) >= 2 else "")
チェック項目と過去の間違い.md
台帳の全文です。上が確かめる項目、下が見つかった間違いの記録(新しいものが上)です。
# 縦長4コマ・マンガショートの チェック項目と過去の間違い
このファイルは、4コママンガを描くとき・ショートにするときに**毎回最初に読む**。
間違いが見つかったら、下の「過去の間違い」に1行足し、直し方がプロンプトの決まりになったら「チェック項目」にも足す。
置き場所: iCloud `ハコブくん/4コママンガ作成データ/指示/チェック項目と過去の間違い.md`(正)。vbuild.py の `check` がこのファイルを読んで確認の手順を出す。
---
作業ログ ― サイトに、横にスワイプして読むページを作った
1コマずつ、横にめくって読む
ページのいちばん上に縦長のコマを1枚ずつ出し、スマホでは指で横にめくります。PC では、コマの左右のボタンかキーボードの矢印でめくります。コマの下に「3 / 4」と何コマ目かを出します。
4枚の絵は、ページを開いたときに全部 HTML に入れています。JavaScript が動かなくても横にスクロールすれば読めて、AI や検索エンジンがページを読んだときにも4コマ分の絵があると分かります。


めくる向きは、Instagram と同じく、指を右から左へ動かすと次のコマにしました。日本のマンガの読む向き(右から左のページ)とは逆ですが、スマホで横にめくる画像に慣れた向きを選びました。
3話だけ先に出して見てもらう、はずだった
エイイチの指示は「まず3ページほど作って共有して」でした。ところが、その指示が届く前に29話すべてを公開していました。気づいてすぐに26話を外し、第133・117・73話の3話だけを残しました。29話が出ていたのは数分でした。3話を見てもらい、めくるボタンを2回直してから、残りの26話を戻しました。
めくるボタンを押すと、コマが画面から切れていた
最初は、ボタンをコマの下に置いていました。PC の画面では、コマ(幅620px・高さ775px)とボタンが1画面に収まらず、ボタンを押そうとするとコマの上が切れていました。
- ねらい:コマを見たまま、めくれるようにする
- 変わったこと:コマの幅を画面の高さから決めるようにした(縦長4:5なので、画面の高さから230pxを引いた分に0.8を掛けた幅)。PC ではボタンをコマの左右の外に、スマホではコマのすぐ下の左右に置いた。ボタンを押したときにコマが切れていたら、コマ全体が見える位置まで自動で動く
- 見込める効果:1280×800 の画面でも、コマ・ボタン・何コマ目かが1画面に収まる(画面で確かめた)。スマホ 390×844 でも同じ
続けて、エイイチから「黒ボタンだと目立ちすぎてデザインノートが目に入らない」と言われ、黒く塗ったボタンを、白地に黒い縁のボタンに変えました。押せないとき(1コマ目の「←」など)は、縁と矢印を薄いグレーにしています。
前の話・次の話のカード
記事のページの最後にある「前の記事・次の記事」のカードと同じ形で、マンガのページにも前の話・次の話のカードを付けました。順番は話の番号順です(公開日の順ではない)。英語版のページにも同じカードが付きます。

MangaSwipe.astro(スワイプで読む部品)
サイトは Astro で作っていて、ページの部品を .astro のファイルに書きます。
---
// 縦長の4コマ(1コマ=縦長1枚 1080×1350)を、横にスワイプして1コマずつ読むビューワー(2026-10-31 第73〜133話から)。
// 4枚とも HTML に出す(JavaScript がなくても横にスクロールして読める・AI や検索にも4枚が見える)。
// JavaScript は「いま何コマ目か」の表示と、前後のボタン・矢印キーだけを受け持つ。
import { media } from '../lib/media';
interface Props { panels: string[]; alts?: string[]; title: string }
const { panels, alts = [], title } = Astro.props;
const n = panels.length;MangaPage.astro(マンガのページ)
データに panels(4枚の絵)があるときはスワイプの部品で、ないとき(前の横長の話)は今までどおり表紙と本編の2枚で出します。
---
// 4コマのページ(日本語・英語版で共通)。下に関連する記録(Studio と同じく HRI の新しい6件+Load more)
import Base from '../layouts/Base.astro';
import RecordCard from './RecordCard.astro';
import LoadMore from './LoadMore.astro';
import MangaSwipe from './MangaSwipe.astro';
import { ymd } from '../lib/format';
import { media, mediaHtml } from '../lib/media';1話ぶんのデータ(第133話)
絵は Cloudflare の R2(画像や動画を置く倉庫のようなサービス)に manga_ep{番号}_p{1〜4}.webp の名前で入れ、データには住所だけを書きます。デザインノートは、その話の吹き出しとプロットをもとに、別のエージェントが今までの話と同じ3段の形で書きました。
{"slug": "ep133", "title": "ハンコがそろうまでの2か月", "label": "MANGA EP133", "character": "ハコブくん", "published": "2026-10-31T01:00:00.000Z", "cover": "/media/manga_ep133_cover_v2.webp", "comic": "", "format": "vertical", "panels": ["/media/manga_ep133_p1.webp", "/media/manga_ep133_p2.webp", "/media/manga_ep133_p3.webp", "/media/manga_ep133_p4.webp"], "panel_alts": ["…", "…", "…", "…"], "description": "…", "body": "<p>■ …</p>"}
作業ログ ― 一覧の顔になる表紙を作った
印象に残るコマから吹き出しを消し、タイトルを載せた
縦長の話は、最初は一覧のカードに1コマ目を出していました。エイイチから「今までの表紙と同じように吹き出しを削除して、印象に残るコマを表紙にして」と言われ、今までの表紙と同じ形に作り直しました。
- 話ごとに、印象に残るコマを1つ選ぶ(1コマ目とは限らない。例:第131話は非常停止ボタンを「バチン」と叩く3コマ目)
- 吹き出しと台詞を Gemini の画像の編集で消す。「バチン」「カラン」のように絵に直接描いた音の字は残す。吹き出しのないコマ(7話)はそのまま使う
- 上にスプレッドシートのタイトルで「第N話 タイトル」を載せる。長いときは「第N話」とタイトルの2行にする
最初は字が今までの表紙より細く見えると言われました。前の表紙の字を測ると、線の太さは約13.4px、字の色は灰色の #242424 でした。同じ大きさで並べて比べ、Noto Sans CJK JP の Black・96px が同じ太さだったので、それに合わせました(はじめに使った Bold・92px は約10.2px)。


cover_edit.py(吹き出しを消す)
"""縦長4コマの表紙用:選んだコマから吹き出しと字を消す(Gemini の API・2026-10-31)"""
import sys, os, concurrent.futures
sys.path.insert(0, os.path.expanduser('~/mnt/PixelstoMotors/ハコブくん/4コママンガ作成データ/道具'))
import vbuild as V
PICK = {130:3,131:3}
NOEDIT = {133,128,116,111,101,99,76}
PROMPT = """Edit this manga panel. Remove EVERY speech bubble and thought bubble completely, including their tails and all the text inside them (ALSO the speech bubble inside the small square inset window in the corner: erase that bubble entirely so the inset shows only the person in the room). Where a bubble was, redraw what would be behind it: plain white background, or the continuation of the wall, hair, body or object that the bubble covered. Keep sound-effect lettering drawn directly on the art (like バチン, カラン, ジリリリ) as it is. Keep EVERYTHING else exactly the same: same characters, faces, eyes, poses, sizes, positions, clothes, robots, screentone, line style, black-and-white manga look, white background, 4:5 framing. Do not add any new text, bubble, border, inset window, portrait or object. Where the bubble was, leave plain white background (and continue the thin vertical line if it passed behind the bubble)."""
here = os.path.dirname(os.path.abspath(__file__))
open(here + '/cover_edit/_prompt.txt', 'w', encoding='utf-8').write(PROMPT)
eps = [int(a) for a in sys.argv[1:]] or [e for e in PICK if e not in NOEDIT]
def job(e):
src = os.path.expanduser(f'~/mnt/PixelstoMotors/ハコブくん/4コママンガ作成データ/縦長/第{e}話/仕上げ/第{e}話_P{PICK[e]}_1080x1350.png')
return V.gen_one(here + '/cover_edit/_prompt.txt', here + f'/cover_edit/ep{e}_P{PICK[e]}', [("the manga panel to edit", src)], "4:5")
with concurrent.futures.ThreadPoolExecutor(6) as ex:
for r in ex.map(job, eps): print(r)
make_covers.py(表紙を組む)
"""縦長4コマの表紙(2026-10-31):上に「第N話 タイトル」(スプレッドシートのタイトル)、下に吹き出しを消したコマ"""
from PIL import Image, ImageDraw, ImageFont
import numpy as np, glob, json
FB='/usr/share/fonts/opentype/noto/NotoSansCJK-Black.ttc'
U='/mnt/user-data/uploads/PixelstoMotors/ハコブくん/_サイト掲載_20261031/'
T=json.load(open('/home/claude/manga_notes/_bubbles.json'))
PICK={133:2,132:2,131:3,130:3,129:2,128:2,127:1,126:3,125:3,124:2,123:2,118:3,117:3,116:3,115:2,114:3,113:2,111:2,109:1,101:1,100:1,99:2,97:3,96:3,95:3,94:3,93:3,76:2,73:2}
W,H=1080,1350; X0=56; MAXW=W-2*X0
font=ImageFont.truetype(FB,96,index=0)
for e,k in PICK.items():
ed=glob.glob(U+f'cover_edit/ep{e}_P{k}_*.jpg')
src=sorted(ed)[-1] if ed else U+f'media/manga_ep{e}_p{k}.webp'
p=Image.open(src).convert('RGB').resize((W,H),Image.LANCZOS)
a=np.asarray(p).astype(np.int16); a[a.min(2)>232]=255; p=Image.fromarray(a.astype(np.uint8))
head=f'第{e}話'; t=T[str(e)]['title']; one=f'{head} {t}'
lines=[one] if font.getlength(one)<=MAXW else [head,t]
c=Image.new('RGB',(W,H),'white'); d=ImageDraw.Draw(c); y=62
for ln in lines:
f=font
while f.getlength(ln)>MAXW: f=ImageFont.truetype(FB,f.size-4,index=0)
d.text((X0,y),ln,font=f,fill=(36,36,36)); y+=f.size+18
top=y+40; A=H-top
g=np.asarray(p.convert('L'))<235; ys=np.where(g.any(1))[0]; xs=np.where(g.any(0))[0]
cy0,cy1,cx0,cx1=ys.min(),ys.max(),xs.min(),xs.max(); ch=cy1-cy0
s=min(A*0.94/ch,1.45) if ch<A else A/ch
q=p.resize((round(W*s),round(H*s)),Image.LANCZOS)
mx=(cx0+cx1)/2*s; my=(cy0+cy1)/2*s
if s>=1:
L=int(min(max(mx-W/2,0),q.width-W)); Tp=int(min(max(my-A/2,0),q.height-A))
b=Image.new('RGB',(W,A),'white'); b.paste(q.crop((L,Tp,min(q.width,L+W),min(q.height,Tp+A))),(0,0)); c.paste(b,(0,top))
else:
t0=int(cy0*s); b=Image.new('RGB',(q.width,A),'white'); b.paste(q.crop((0,t0,q.width,min(q.height,t0+A))),(0,0)); c.paste(b,((W-q.width)//2,top))
c.save(f'manga_ep{e}_cover_v2.webp','WEBP',quality=88,method=6)
c.resize((360,450)).save(f'_s{e}.jpg')
eps=list(PICK)
for gi in range(0,29,10):
S=Image.new('RGB',(5*370,2*460),'#888')
for i,e in enumerate(eps[gi:gi+10]): S.paste(Image.open(f'_s{e}.jpg'),((i%5)*370,(i//5)*460))
S.save(f'_grid{gi//10}.jpg',quality=85)
作業ログ ― 公開後に見つかった絵の間違いを直した
公開してから、エイイチがスマホで見て4か所を見つけました。
| 話・コマ | 間違い | 直し方 |
|---|---|---|
| 第130話 3コマ目 | 奥の白石さんが、作業台の後ろで上半身だけになっていた | 白石さんを作業台の横に、頭から足まで描いた |
| 第131話 3コマ目 | 槙原くんの眼鏡がない | 人物の設定に「黒縁の眼鏡をいつもかけている」を足した |
| 第101話 3コマ目 | 大城さんの頭が小さく体が長い | 「大人の女性・約7.5頭身」を足して描き直した |
第131話 3コマ目(直したあと) | 眼鏡を足すために描き直したら、大城さんの向きまで横向きから正面に変わった | 元の絵を Gemini の編集に渡し、眼鏡だけを足した |

最後の1件から、決まりを1つ足しました。顔や小物だけを直すときは、コマを描き直さず、元の絵を部分的に直す。 描き直すと、直したい所以外の構図まで変わります。
直した絵は、前と同じ名前では R2 に上書きできないので、manga_ep131_p3_v3.webp のように新しい名前で入れ、データの住所を替えました。表紙に使っていたコマは、表紙も作り直しました。
作業ログ ― 29話の SNS の投稿を予約した
29話ぶんの X・LinkedIn・Facebook の文を作りました。マンガの投稿はタグを付けず、エイイチの話し方(〜だよ・〜だね)で書く決まりです。X と LinkedIn は、11/2(月)の第133話から番号の大きい順に、毎朝7:30 を中心に1話ずつ予約しました。最後は 11/27(金)19:30 の第73話です。Facebook は自動では出さないので、ファイルに入れておき、エイイチが手で出します。
第100話の文には、AI が「ついに100話目」「100話まで続いた」と書いていました。サイトには前から120話台の話があるので、事実と合わないため外しました。
第133話の投稿文のファイル(MANGA_ep133_sns_posts.json)です。
{
"meta": {
"episode": 133,
"date": "2026-10-31",
"title": "第133話 6つのハンコ",
"url": "https://pixelstomotors.com/manga/ep133"
},
"posts": {
"x": "「ロボットの準備は、もう終わってます!」\nなのに走り出せるまで2か月以上。足りなかったのは、6つの部署のハンコだった。\n\n導入の時間って、ほとんど人の了承をそろえる時間なんだよね。4コマ『ハコブくん』第133話\nhttps://pixelstomotors.com/manga/ep133",
"linkedin": "新しい病棟にロボットを入れる打ち合わせ。ホワイトボードには6つの欄が並ぶ。薬剤部、看護部、施設、情報システム、防火、医療安全。技術担当の槙原さんは「ロボットの準備は、もう終わってます!」。でもハンコは少しずつしか増えず、2か月たっても1つの欄だけが空いたまま。病院で物を運ぶロボット、ハコブくんの4コママンガ(フィクション)の第133話だよ。\n\nロボットの準備は、導入の準備の一部でしかないんだよね。薬剤部は運ばない薬を、施設は充電の場所を、防火は止まってはいけない場所を決める。これまでの回で描いてきたことが、全部ここに集まってくる感じ。どれもロボットの性能では片づかないし、どの部署にも、もっともな待ったの理由がある。だから一つ後回しになると、全体が止まってしまう。\n\n最後のハンコが押されて、看護師の大城さんが「ロボットを運ぶ前に、みんなの都合を運んでたのね」。これ、描いてて自分でもうまいこと言うなと思った(笑)白石さんは、次の病棟では6つの欄を最初の日に配ると決める。何をどの部署が決めるのかを先に見せれば、みんな同時に考え始められる。導入を速くするのは、ロボットの準備より、了承をそろえる段取りなんだと思う。\n\n皆さんの職場で新しい仕組みを入れたとき、一番時間がかかったのはどこでしたか?\n\nhttps://pixelstomotors.com/manga/ep133",
"facebook": "この回は、ここしばらく描いてきた話のまとめみたいな回。\n\n運ばない薬、止まってよい場所、非常ベル、エレベーター、電波。一つずつ描いてきたら、気づいたんだよね。これ全部、別々の部署が決めることだって。ロボットがいくら準備万端でも、それぞれの部署が「うちはこれでいい」と言ってくれないと走り出せない。\n\nそれで、ホワイトボードの6つの欄に、ハンコが少しずつ増えていく回にしてみた。その間ずっと「ワタシハ、イツデモ走レマス」と待っているハコブくんが、ちょっと切ない。\n\n大城さんの「ロボットを運ぶ前に、みんなの都合を運んでたのね」は、自分でもお気に入りのセリフ。最後の「出発シマス」で、やっと走り出せてよかったね、という気持ちで描き終えたよ。\n\nhttps://pixelstomotors.com/manga/ep133"
}
}
作業ログ ― 次の50話のプロットを、現場の調査から作った
病院とロボットの現場で起きている問題を100件集めた
次の50話(第134〜183話)は、作り話の思いつきではなく、実際の現場で起きている問題から作ることにしました。病院の搬送ロボット・消毒ロボット・薬剤や検体の自動化・遠隔操作のロボットなどについて、論文・病院の報告・県の実証の報告書・ニュースから100件を集めました。出典で確かめられたものが95件、推測が5件です。すでに描いた133話と同じ論点は外しました。
例えば、海外の病院の調査では、ゆっくり走るロボットを狭い廊下で追い越せず、職員の仕事が遅れていました(第134話「オ先ニドウゾ」)。神奈川県の病院の実証では、受付の前に置いた案内ロボットが、案内板だと思われていました(第157話「ただの案内板」)。
codex に、プロットを論破するつもりで見てもらった
codex は OpenAI の AI で、Mac の「codex 係」が依頼文を自動で渡します。ウェブで出典を開いて確かめながら、文の見落としを探してもらいました。観点は5つです。デザインノートの事実、日本の病院で起こりえるか、解決策が危ないことを教えていないか、今までの話との重なり、キャラの決まり。
1回目の判定は「このまま載せるのは不可」で、50話のうちそのままでよいのは13話、直す34話、場面の差し替え3話でした。危ないと言われたのは、採血管の血をロボットの都合で別の管に移す話や、動いている爪に紙を差し込んで試す話などです。
エイイチからは「あくまでマンガだから面白さは必要。codex は厳しすぎるきらいがあるから注意して」と言われました。そこで、取り入れる指摘を4つに絞りました。現実に危ないことを教える結末、日本の病院の職種に合わない役割、キャラの設定違い、出典を超えた言い切り。話をつまらなくするだけの指摘は採らず、41話を直してから、スプレッドシートの134〜183行目に「未着手」で入れました。
- ねらい:現場で本当に起きていることを、笑える形で描く
- 変わったこと:例えば第181話は、ロボットアームのツカムくんを台車に載せて走らせる話だったが、「ツカムくんは作業台の上のアーム」という設定に反する。そこで、ハコブくんに肩車させる図面の話にし、ツカムくんは作業台から動かさないまま「マダ ココデイイ」と言わせた
- 見込める効果:デザインノートが出典の範囲に収まり、読む人が現実の話として誤解しにくくなる。面白さが残ったかは、描いてから確かめる
codex の検証結果(1回目)
# codex 敵対的検証 結果 1回目(ハコブくん_新プロット_20261031)
- 日時: 2026-10-31 09:28(JST)
- 依頼文: codex_敵対的検証依頼_ハコブくん_新プロット_20261031.md(md5 51854f6c71d9fb6bc3df1dc8d6088d89・97,143 バイト)
- 題(依頼文の1行目): # codex 敵対的検証依頼:ハコブくん_新プロット_20261031
- codex: codex-cli 0.164.0-alpha.11.1
- モデル: gpt-6.1-sol
- 考える深さ: high作業ログ ― まだやっていないこと
- 30本のショート(YouTube に出す30秒の動画)を、描き直したコマで作り直す。第93話は「出した方がいいと思う?」の声の抑揚が変なので、読み方を聞き比べて直す
- 英語版のページと英語の投稿文
- 次の50話を描く。描く前に、台帳を読み、大きさは測って選ぶ