配膳ロボットの解説動画を作る ― 背景を止めず、文字はカードに

解説動画の画面の8割近くが、止まった紙の図でした。前に作った配膳ロボットの解説動画(13分39秒)を5秒おきに164コマ取り出して数えると、127コマ(77.4%)が紙色の背景に図と文字を置いた画面でした。せっかく3Dの店でロボットを走らせ、ブラウザで動く試算のページも作っているのに、動画の大半ではそれが映っていませんでした。

この記事は、YouTube の解説動画「配膳ロボット、何台入れたら店は変わる?」(14分20秒)を、台本から公開の準備まで1日で作った記録です。題材は、ファミレスに配膳ロボットを入れたら待ち時間がどう変わるかを、パソコンの中で計算する試算(シミュレーション)です。お客さんが来る、料理ができる、誰かが運ぶ、皿を下げる、という出来事を時間の順に再現し、ロボットを0台から6台まで1台ずつ増やしました。動画では、案内役のロボット「ハコブくん」が AI の声で結果を話します。

途中で、画面の作りを大きく変えました。指示はこうです。

動画を作るときに背景にシミュレーションの動画を長く使うようにしてください(今までより背景動画を使うところは圧倒的に増やすしてください)テキストは背景をカードタイプで仕上げてください。

背景は、章ごとに1本の映像を切らずに流し続け、文字だけを黒い角丸のカードに載せて替える形にしました。 3Dの店の映像と試算ページの操作の録画を28本つなぎ、紙色の背景が映るコマは0になりました。カードの強調の色は最初に水色で作り、「基本はオレンジ、水色は追加の差し色」と直されて、記事や前の動画と同じオレンジに戻しています。

仕上げた動画の8つの場面。どれも後ろで Unity の店か試算ページの映像が流れ、真ん中に黒いカード、左下にハコブくん、下に字幕がある
やったことなぜ結果
解説動画をシリーズにして、第1回を「何台入れたら店は変わる?」にした
試算から3Dの店(Unity)まで、1本では入りきらないため
6回の流れを決めた。第1回は試算の回
台本を4版まで直した
別の AI(codex)の検証で、言い過ぎを27件指摘されたため
「1人少なくても回る」を「今回の線を下回った(待ちは延びる)」に直した
背景を流れ続ける映像にし、文字はカードに載せた
試算と3Dの店が動いているところを見せるため
紙色の背景のコマが 77.4% から 0% に
カードの差し色を水色からオレンジに戻した
記事や前の動画の色とそろえるため
基本はオレンジ #C4471F、もう一方を見せたい語だけ水色
Mac の中の作業場所で、180秒ずつに区切って書き出した
1回の作業が180秒で止まる場所だったため
動きの場面55個・背景の断片177個・仕上げ5区切りで14分20秒を書き出した
本編の X 投稿を、YouTube の公開予約に合わせて自動で出すようにした
動画を予約するたびに URL を貼るのは続かないため
ショートだけだった自動の予約に、本編も入るようにした

この記事の「見込める効果」は、ことわりのない限り、まだ測っていない見込みです。数字で書いてあるもの(長さ・コマの数・処理の秒数)は、書き出した動画とログから数えた値です。動画はまだ YouTube に出ていません。

ここから下は作業の記録です。台本の直し、画面の作り、書き出しの手順、自動投稿のつなぎ方と、使ったコード・設定の全文を残します。

作業ログ ― 解説動画をシリーズにして、第1回を「何台入れたら」にした

最初の依頼は「サービスロボット導入シミュレーションをベースにした動画を作って欲しい」でした。サービスロボット導入シミュレーションは、配膳ロボットなどを店に入れたら何が変わるかを、入れる前に試算する記録のシリーズです(pixelstomotors.com/series8)。試算のページでは、店・人数・台数・ロボットの使い方を変えると、待ち時間の数字が変わります。その後ろでは、同じ店を Unity(ゲームを作る道具)の3Dの空間に建て、ロボットを走らせています。

はじめはシリーズ全体のまとめを1本にするつもりでしたが、方針が変わりました。

いくつかシリーズにしたいのでまずは、配膳ロボット、何台入れたら店は変わる?のシミュレーションから始まって、その後にUnityシミュレーションにつながっていく流れを構築してほしい

そこで、記事のシリーズの中身を、動画の6回に割り振りました。

回題元にする記事
第1回何台入れたら店は変わる?
Log#1・Log#5(試算と、その点検)
第2回人は減らせる? いくら浮く?Log#8(費用と補助金)
第3回店の形で答えは変わるLog#6(店の平面図)
第4回3Dの店で走らせたら
Log#4・Log#7・Log#9(Unity の店)
第5回試算と3Dは合ったのかLog#10・Log#11
第6回導入前に、どこまで分かるか
Log#2(店で数える観察シート)

前に作った「配膳ロボットで1人減らせるか」(未公開・試算の前の版 v2.4 の数字)は、第2回にして、いまの試算 v2.7 の数字に直すことにしました。第1回と重なる前半は抜き、声は変わった文だけ作り直します。

数字は、サイトの試算から読んだ

動画の数字は、すべてサイトの試算 v2.7 から読みました。試算のページには、店・人数・台数・使い方の組み合わせ16,425通りについて、それぞれ40回計算した平均が入っています。v2.7 の決まりは「料理ができたら、まずロボットを待つ。2分たってもロボットが来なければ、人も運べる」です。ロボットの速さは仮に秒速0.5メートル(人の半分)、席は空いているのに片付けや案内を待たせた時間が平均10分以上になったら「店が回らない」と数えます。

条件(35卓のファミレス・1時間に35組・料理を運ぶだけ)
0台1台2台3台4台5台6台
スタッフ3人:店に来てから席に着くまで(分)
8.584.033.162.913.903.473.29
スタッフ3人:料理ができてから卓に着くまで(分)
0.972.211.020.650.550.520.51
スタッフ3人:席は空いているのに待たせた時間(分)
7.413.262.352.443.212.852.73
スタッフ3人:1人が歩いた距離(km)
3.882.692.352.342.372.382.36
スタッフ3人:ロボット1台が仕事でふさがっていた割合
—0.750.580.430.330.270.23
スタッフ2人:店に来てから席に着くまで(分)
28.2516.8514.2614.1714.8616.0715.37

スタッフ2人の行は、どの台数も「店が回らない」に入りました。ほかの店の種類では、焼肉の食べ放題(スタッフ2人)が0台27.45分・1台9.80分・2台6.37分、洗い場が遠い店(スタッフ2人)が0台10.94分・1台6.03分です。

現場を知る立場からの答えを、台本の芯にした

台本には、数字だけでなく、昔ファミレスで働いていた立場からの見立てを入れます。4つ聞いて、答えはこうでした。

1.意外な結果だなと。でも現時点での配膳ロボットの限界点もよくわかった。2.オレがみたのは2台くらいかな 3.お客さんの食べ終わったお皿下げてほしいし、パントリーに下げてきたお皿類を洗い場まで下げてほしい。シルバー(フォークとかスプーン)を拭いて欲しかった(地味に大変)4.ロボットを入れるだけでは良くならないこともあり、そこには専門家の知見が必要と知ってほしい

1は1台で料理が遅くなる結果への感想、2は店で見かけたロボットの台数、3はロボットに任せたかった仕事、4は見る人に持ち帰ってほしいことです。言い回しだけ整え、中身は足さずに台本に入れました。冒頭の「その店に何台いたか、覚えていますか」と「エイイチが見かけた店も、2台くらいだったそうです」は、2の答えから作っています。

台本は4版まで直し、codex の27件の指摘で「回る」の言い方を変えた

台本は85文、約4,984字です。書いたあと3回直しました。

版きっかけ直したこと
1版シリーズにすると決めた
第1回を「何台入れたら店は変わる?」として書いた
2版
書いたのとは別の AI に、出典と1文ずつ照らしてもらった
料理の遅れを2分13秒から2分12秒(2.2059分)に。「2台目まで」は席に着くまでと歩く距離に限った。2人で回らないのは「普通の混み具合で料理を運ぶだけなら」と条件を付けた
3版
codex の1回目が途中で止まったが、途中の所見が出ていた
「1人減らして回る」は、元の人数より待ちが悪化していても通る判定だ、という所見を受けて、混雑の日・食べ放題・洗い場が遠い店の延びを足した
4版codex の1回目(27件)
「回る」は今回の線を下回った意味だと言い、待ちは延びると添えた。ほか下の表

codex(OpenAI の、コードや文書を読んで検証する道具)には、台本の言い過ぎや根拠のない事実を、反対の立場から探してもらいます。1回目は「Selected model is at capacity(モデルが混んでいる)」で止まり、かけ直して15分15秒で返ってきました。判定は「直してから」です。

主な問題は数字の転記よりも、独自の判定基準を通ったことを「人を減らして店が回る」と表現している点と、仮の運用ルールの結果を実機の限界に結びつけている点です。

指摘のうち大きかったものと、直し方です。

指摘直し方
「1人少なくても回る」は、同じサービスのまま人を減らせたように聞こえる。料理の待ちは、混雑の日で45秒→2分17秒、食べ放題で1分17秒→3分26秒に延びている
「今回の線を下回った」と言い換え、待ちが延びることを同じ場面で言う
「いまの配膳ロボットの限界点も、よくわかった」は、製品の性能の限界が分かったように受け取られる
本人の感想として残し、直後に「今回分かったのは、この試算の条件での限界。今の製品の性能を測ったわけではない」と添える
4台で3.9分に延びたのを「ぶれの範囲」と言い切っている。40回の平均だけでは分からない
「偶然のばらつきかどうかは、この平均だけでは分からない」に
「動いていた割合」には、お客さんが料理を取るのを待つ時間も入っている
「仕事でふさがっていた割合」に言い換え、待つ時間も含むと言う
料理をロボットに載せて行き先を決める人の時間が入っていない
「この試算でまだ分からないこと」の章で言う
すかいらーくの導入台数の出典が報道だけ
すかいらーくホールディングスの公式の沿革(2022年12月に約2,100店へ3,000台の導入完了)に替えた

クイズの場面(料理が届くまでの58秒を当てる)は、冒頭と目次で答えを言ってしまっていたので外しました。ロボットの速さの冗談も外し、仮の値だと言う文にしています。「結論・立場・目次を1文にまとめる」という指摘は、チャンネルで決めている型なので採りませんでした。

codex の結果の全文は、記事の最後の「この記事で作った・直したファイルの全文」に載せています。

声は85文、尺は14分20秒のまま

声は ElevenLabs(AI の声を作るサービス)で、ハコブくんの声を使って Mac で作りました。85文で、長さは14分20秒(860.03秒)です。解説動画の上限の目安は13〜14分なので、文を抜いて縮める案も出しましたが、「このまま14分20秒」に決まりました。

画面を「紙の図」から「流れ続ける映像+黒いカード」に替えた

声を待つ間に、画面の形を選んでもらいました。選んだのは「大文字型+動きあり」です。言い切りたい一言を大きな文字で出し、ところどころで文字を叩きつけたり、数字を数え上げたりする作りです。

最初の版は、これまでの解説動画と同じく、紙色(#F5F5F0)の背景に図と文字を置く場面が中心でした。そこで、冒頭の指示が来ました。参考に3枚の画面写真が付いていて、どれも、暗い角丸の板に白い文字が載り、その後ろで映像が流れ続けていました(他の人の動画の画面なので、この記事には載せません)。

背景の映像は、試算ページの録画9本と Unity の店の映像10本

背景に使える映像を集めました。

種類本数中身
試算ページの操作の録画9
v2.7 のページをブラウザで開き、店を選ぶ・台数を増やす・1台・スタッフ2人・皿を集めて回る使い方・混雑の日・店の種類・食べ放題・洗い場が遠い店、を順に押していく様子
Unity の仮のファミレス(初期の版)
2
Log#4 で建てた店を斜めと上から
Unity で建てたファミレス(図面のある店③)
3
Log#9 の回で、人とロボット・ロボットの往復・戻り道
同じ店の、サイトの映像5
4つの視点・斜め・混んだ時間・すれ違い・実行中の画面(サイトの /site/srl/ に置いている映像)

試算ページの録画は、Playwright(ブラウザを自動で動かす道具)でページを開き、押す場所に丸いカーソルを動かしてから押す、という台本を書いて録りました(rec_背景の録画.py)。

背景は、章ごとに1本の映像を切らずに流し続ける

場面(カード)が替わるたびに背景の映像を頭から流すと、数秒ごとに映像が飛びます。そこで、どの場面からどの場面まで、どの映像の何秒目から流すかを RUNS という表に書き、場面が替わっても背景は続きから再生するようにしました。

RUNS = [
 ("u357o", 2, ["hook", "hook_q", "hook_try"]),
 ("four", 0, ["question", "define", "define2"]),
 ("u364a", 0, ["scope", "answer", "answer_two", "stance", "toc"]),
 ("busy", 0, ["c1", "setup"]),
 ("term", 0, ["simpy"]),
 ("pass", 0, ["speed"]),
 ("s_open", 0, ["entry"]),
 ("s_more", 0, ["entry_flat"]),
 ("u364c", 0, ["why1", "why1b", "why1c", "util", "walk", "c1_end"]),
 ("pass", 4, ["c2"]),
 ("s_one", 0, ["dish_ans", "dish_more"]),
 ("u364b", 0, ["rule", "rule2", "fair", "honne1", "c2_end"]),
 ("four", 8, ["c3"]),
 ("s_two", 0, ["two", "two_b", "two_c"]),
 ("u357t", 0, ["honne2", "honne2_list", "honne2_c"]),
 ("s_patrol", 0, ["patrol"]),
 ("s_crowd", 0, ["crowd", "crowd_note"]),
 ("s_table", 0, ["other"]),
 ("s_buffet", 0, ["buffet"]),
 ("s_hotel", 0, ["hotel"]),
 ("u364a", 30, ["large", "c3_end"]),
 ("obl", 0, ["mitate", "mitate1"]),
 ("u364c", 50, ["mitate2", "limits", "next"]),
 ("u364a", 50, ["answer2", "answer2b", "question_next"]),
 ("s_open", 0, ["try"]),
]

書き出した動画の時刻に直すと、背景は次の28本のつながりになりました(自己紹介とアウトロの3本を含む)。

始まり(秒)終わり(秒)背景
0.0053.83
u357o(Unity の仮のファミレス・斜め)
53.8365.17自己紹介
65.1777.57自己紹介(作り手の紹介)
77.57117.03four(4つの視点)
117.03233.40u364a(人とロボット)
233.40262.53
busy(上から・混んだ時間)
262.53280.43term(実行中の画面)
280.43291.67pass(上から・すれ違い)
291.67301.87
s_open(試算ページ:店を選ぶ)
301.87323.20
s_more(試算ページ:台数を増やす)
323.20396.70u364c(戻り道)
396.70402.70pass(上から・すれ違い)
402.70420.10
s_one(試算ページ:1台)
420.10505.93u364b(ロボットの往復)
505.93523.57four(4つの視点)
523.57550.60
s_two(試算ページ:スタッフ2人)
550.60571.67
u357t(Unity の仮のファミレス・上から)
571.67590.23
s_patrol(試算ページ:皿を集めて回る使い方)
590.23617.90
s_crowd(試算ページ:混雑の日)
617.90634.60
s_table(試算ページ:店の種類)
634.60660.10
s_buffet(試算ページ:食べ放題)
660.10670.67
s_hotel(試算ページ:洗い場が遠い店)
670.67689.93u364a(人とロボット)
689.93704.03obl(斜め)
704.03777.20u364c(戻り道)
777.20835.07u364a(人とロボット)
835.07844.50
s_open(試算ページ:店を選ぶ)
844.50860.03アウトロ

860秒のうち、Unity の店の映像が636.4秒、試算ページの録画が184.4秒、自己紹介とアウトロが39.3秒です。いちばん長く切れずに流れたのは、話の範囲から目次までの u364a(116.4秒)でした。

背景は暗くして文字を読みやすくしています。Unity の映像は明るさ0.62、試算ページの録画は0.5です。試算ページの録画は、操作が終わったら最後のコマで止めたままにし、頭に戻さないようにしました(同じ操作がくり返されると、見ている人が迷うため)。映像の左上には、何の映像かを小さな板で出します。Unity の店は、シリーズの後の回で扱う映像を先に使っているので、「Unity で建てたファミレス(図面のある店③・シリーズの後の回で扱う)」のように書きました。

カードは、黒い角丸の板に白い文字

文字は、黒い角丸の板(不透明度86%・角の丸み30px)に白で載せます。小見出しは42pxの薄い灰色、大きい文字は太さ900、補足は44pxの薄い灰色です。カードの型は、言い切りの一言(C_word)・大きい数字(C_num)・2つの対比(C_pair)・番号つきの行(C_list)・棒グラフ(C_bars)などを作り、場面ごとの中身を CARDS という表に書きました。55の場面を、背景の映像の上にカードを重ねた動画として1つずつ書き出しています。

カードは、字幕と左下のハコブくんの区画にかからない高さに置きます。書き出す前に、カードの下端が785pxを超えないかを確かめる小さな検査(precheck.py)を作り、3つの場面で補足の文を縮めました。

場面直す前に超えた所縮めた補足
stanceカードの下端が802px
人に足せば、席に着くまでは縮む
entry_flat2行になり下へはみ出した
3台目から先は3分台(4台の延びは、ばらつきか分からない)
limits2行になり下へはみ出した
止まり方は仮・ロボットどうしの邪魔は入れていない

紙色の背景が映っていたコマを数えた:77.4% → 0%

変わったことを数字で確かめるため、前の動画と今回の動画から5秒おきに1コマずつ取り出し、192×108に縮めて、字幕より上の帯(縦10〜70px)を見ました。その帯の画素のうち、紙色に近い色(赤・緑が226以上、青が216以上)の画素が45%を超えたコマを「紙色の背景」と数えています。

K=$HOME/mnt/KIOXIA/r2r2r-data/videos; cd /tmp && for v in "$K/配膳ロボットで1人減らせるか/配膳ロボットで1人減らせるか_確認用.mp4" "$HOME/build/out_確認用.mp4"; do rm -rf fr && mkdir fr && timeout 160 ffmpeg -loglevel error -i "$v" -vf "fps=1/5,scale=192:108" fr/%04d.png && python3 - <<'EOF'
import glob
from PIL import Image
fs=sorted(glob.glob('fr/*.png')); paper=0
for f in fs:
    im=Image.open(f).convert('RGB').crop((0,10,192,70)); px=list(im.getdata())
    n=sum(1 for r,g,b in px if r>225 and g>225 and b>215 and abs(r-g)<12)
    if n/len(px)>0.45: paper+=1
print(len(fs),'frames', paper,'paper', round(100*paper/len(fs),1),'%')
EOF
done
<stdin>:5: DeprecationWarning: Image.Image.getdata is deprecated and will be removed in Pillow 14 (2027-10-15). Use get_flattened_data instead.
164 frames 127 paper 77.4 %
<stdin>:5: DeprecationWarning: Image.Image.getdata is deprecated and will be removed in Pillow 14 (2027-10-15). Use get_flattened_data instead.
172 frames 0 paper 0.0 %
  • ねらい:試算の数字が、動いている店とページから出てきたものだと、見ている間ずっと分かるようにする
  • 変わったこと:紙色の背景が映っていたコマが、164コマ中127コマ(77.4%)から172コマ中0コマ(0%)になった。背景の切り替わりは28本のつながりの間の27か所だけ
  • 見込める効果:途中で離れる人が減るかもしれない(見込み)。公開後に、YouTube の分析画面の「視聴者維持率」を、前に公開した解説動画と比べて確かめる

カードの差し色を、水色からオレンジに戻した

最初の確認用の動画は、カードの強調を水色(#62BFF5)、もう一方の色を明るいオレンジ(#FF9466)にしていました。参考の画面写真が水色の強調だったためです。見たあとの返事がこれです。

差し色水色使ってもいいけど、基本はオレンジ色にして、追加の差し色で水色使ってください。元のオレンジと水色にしてください。

記事のサムネイルやこれまでの動画では、オレンジ #C4471F を「1画面で一番伝えたい語」に使っています。「元のオレンジ」はこの色と読み、強調をオレンジ #C4471F、もう一方を見せたい語だけ水色 #62BFF5 にしました。scenes.py で変えたのは1行です。

HL, WARN = "#C4471F", "#62BFF5"   # 基本はオレンジ(元の #C4471F)、追加の差し色に水色(2026-10-24 エイイチの指示)

#C4471F は暗めのオレンジなので、黒い板の上で読めるかを先に3つの場面で書き出して確かめ、そのまま55場面を書き出し直しました。

同じ3つの場面の直す前と直したあと。左は強調の語が水色、右は同じ語がオレンジで、番号もオレンジになっている

数字の棒グラフは、0台を灰色、1台と2台をオレンジにしました。「料理がロボットの帰りを待つ」のように、話の向きが逆になる語(よくなる話の中の、悪くなる所)には水色を使っています。2回目の確認用を見たあとの返事は「OKです!」でした。

Mac の中の作業場所で、180秒ずつに区切って書き出した

今回の書き出しは、Mac 連携の作業場所(Mac の中で動く Linux の環境。4コア・メモリ3GB)で行いました。素材の映像と中間ファイルを KIOXIA(外付けの SSD)から動かさずに使えるためです。ただし、1回の命令は180秒で止まり、命令が終わると裏で動かしていた処理も止まります。14分の動画は1回では書き出せないので、どの作業も「途中から続けられる形」にしました。

書き出しで詰まった所と、その直し方

詰まった所起きたこと直し方
ブラウザ(Chromium)が起動しない
libXdamage というライブラリがない
apt-get download で取り出し、dpkg -x で展開して LD_LIBRARY_PATH に足した
裏で動かした処理が消える
命令が終わると、ローカルのサーバーや書き出しも止まる
1回の命令の中で始めて終える長さに分けた
書いたファイルがすぐ読めない
KIOXIA に書いた直後、Chromium が ERR_FILE_NOT_FOUND を出す
中間ファイルは作業場所の手元($HOME/build)に置き、仕上がった物だけ KIOXIA に写す。写したら15秒おいて指紋(md5)を比べる
場面の表を読み込むだけで37秒
文ごとの時刻の割り付けを毎回計算していた
割り付けの結果を _timing_cache.pkl に置いて使い回す
最後のハコブくんを重ねる工程が180秒に収まらない
25,801コマをまとめて重ねていた
fin.py で172秒ずつ5つに分け、最後につなぐ

1回の命令で書き出せた量

色を直したあとに55場面を書き出し直したときの記録です。動きの場面は、1秒に約20コマ書き出せました。

回書き出した場面コマ数かかった秒数
1hook, hook_q98848
2
hook_try, question, define, define2
上限2,800の内94
3
scope, answer, answer_two, stance, toc(c1 の途中で止まった)
上限4,200で180秒を超えた
172
4
c1, setup, simpy, speed, entry, entry_flat, why1
2,934155
5
why1b, why1c, util, walk, c1_end, c2, dish_ans, dish_more
2,667133
6
rule, rule2, fair, honne1, c2_end, c3, two
3,276159
7
two_b, two_c, honne2, honne2_list, honne2_c, patrol, crowd, crowd_note, other
3,159
172(最後の1場面は次の回に)
8
other, buffet, hotel, large, c3_end, mitate, mitate1
2,584144
9
mitate2, limits, next, answer2
2,760163
10
answer2b, question_next, try
1,45492

場面ごとに1つずつファイルを書くので、途中で止まっても、できた場面は残ります。書きかけのファイル(.part.mp4)は次の回の頭で消しました。

背景の断片(1文ごとに、背景の映像に字幕を重ねた短い動画)は177個です。assemble.py を何度も動かし、できている断片は使い回しました。

回できていた断片の数
135
267
3101
4132
5158
6
177(つないで bg.mp4 を作った)

最後にハコブくんを重ね、音と合わせました。

工程かかった秒数
fin.py seg 0(0〜172秒)
77
seg 1 と seg 2 を同時に156
seg 3 と seg 4 を続けて150
join(つないで音を合わせる)
97

同時に動かしても速くならなかった(4コアを1本でほぼ使い切っていた)ので、3回目は続けて動かしています。仕上がりは、YouTube に上げる版 out.mp4 が73.6MB、確認用(画質を落とした版)が37.3MB です。確認用は「30MB以下」という決まりを超えましたが、チャットで送れたのでそのまま使いました。

書き出した動画は、8か所のコマを取り出して並べ、カードと字幕とハコブくんが重なっていないかを見てから送りました。

書き出しの手順をまとめた3つのスクリプト

mk.py(動きの場面をコマ数の上限まで書き出す)・fin.py(ハコブくんを区切って重ねる)・precheck.py(カードの位置の検査)は、どの動画でも使えるので、_制作ベース/vm_書き出し/ に置きました。全文は記事の最後に載せています。

概要欄・タイトル・サムネイルを作った

概要欄の目次は、書き出した時刻から自動で入れた

概要欄は、下書き(概要欄_下書き.md)に {t:文番号} と書いておくと、description.py が書き出した時刻に置き換えます。目次は13個、全体で2,660字になりました。

概要欄.txt を書きました(2660 字・目次 13 個)
▼目次
0:00 配膳ロボット、店に何台いた?
0:53 この番組について
1:17 今日の問い:何台入れたら、店は変わるのか
2:40 先に結論
3:53 1. スタッフ3人のまま、ロボットを増やすと
6:36 2. 1台だけだと、なぜ料理が遅くなるのか
8:25 3. 人を減らせる台数は、あるのか
9:10 元ファミレスのエイイチが、ロボットに任せたかった仕事
10:17 店が変わると、答えも変わる
11:29 エイイチの見立て
12:06 この試算でまだ分からないこと
12:57 冒頭の問いへの答え
14:04 エンディング

試算のページの版の表記が、v2.4 のままだった

概要欄に載せるリンクを1つずつ開いて確かめたとき、シリーズのページ(pixelstomotors.com/series8)の試算の説明に「試作 v2.4・16,425条件」と出ていました。埋め込みの試算の結果は v2.7("model":"v2.7")になっていて、表記だけが前の版のまま残っていました。動画では「試作 v2.7」と言っているので、見た人がページで食い違いに気づくことになります。

cd /home/claude/p2m-site && grep -n "試作 v2\|v2\.4" src/lib/records.ts | head; grep -n -o ".\{60\}v2\.7.\{60\}" public/sim/serving-robot.html | head -3
55:      note: '店を選び、人数・台数・ロボットの使い方を切り替えると、ピーク時の入店待ちや料理が届くまでの時間が変わります。標準ファミレスは、店の形(平面図)から選ぶこともできます。ロボットの費用と浮く人件費も比べられます(補助金の情報つき)。1つの条件を40回回した平均で、数字はすべて仮の前提による試算です(試作 v2.4・16,425条件)。',
406:s":10,"max_extra_min":600,"robot_first_wait_s":120,"model":"v2.7"},"plans":{"fam_p0":{"w":24.0,"d":19.2,"outline":[[0,0],[24

表記を v2.7 に直し、サイトをビルドして(652ページ・19.91秒)公開しました。

-      note: '…1つの条件を40回回した平均で、数字はすべて仮の前提による試算です(試作 v2.4・16,425条件)。',
+      note: '…1つの条件を40回回した平均で、数字はすべて仮の前提による試算です(試作 v2.7・16,425条件)。',
23:42:38 [@astrojs/sitemap] `sitemap-index.xml` created at `dist`
23:42:38 [build] 652 page(s) built in 19.91s
23:42:38 [build] Complete!
dist/series8.html

タイトルは3案から、サムネイルは2案から選んでもらった

タイトルの案は3つ出しました。

案タイトル
1
配膳ロボット、何台入れたら店は変わる? 0台から6台まで試算した
2
配膳ロボットは増やすほど良い? ファミレスの2時間を試算したら、1台だと料理が遅くなった
3
配膳ロボット何台で店は変わる? 2台まで変わり、人は減らせなかった【導入シミュレーション 第1回】

選ばれたのは案3です。「人は減らせなかった」は、35卓のファミレス・普通の混み具合・料理を運ぶだけ、という条件の結果です。混雑の日などで1人少なくても線を下回った例は、概要欄の「先に答え」と「扱う範囲」に書いています。

サムネイルは、Unity の店の映像の1コマを背景に2案作り、左の案A(図面のある店を斜めから・「1台だと遅い?」の札)に決まりました。どちらも生成 AI の画像は使っていません。

サムネイルの2案。左の案Aは図面のある店を斜めから見た絵に「配膳ロボット 何台入れたら店は変わる? 0〜6台で試算」、右の案Bは初期の店に寄った絵に「0台から6台まで試算 配膳ロボット 何台で店は変わる?」

本編から切り出すショートは作っていません。登録者や再生数が増えるまでは、指示があった動画だけ作る決まりにしているためです(2026-10-19 に決めたもの)。

本編の X 投稿を、YouTube の公開予約に合わせて自動で出すようにした

アップロード用の一式をそろえたところで、こう聞かれました。

SNS投稿は自動化を進めていますが、連携できていますか?

調べると、まだつながっていませんでした。X と LinkedIn の予約投稿は、GitHub に置いた予定表(sns/schedule.json)を GitHub Actions が15分ごとに読み、時刻が来たものを出す仕組みです(LOG376)。YouTube のショートは、1日2回(7:47・17:47)動く予定のタスクが、Mac が1時間ごとに書き出す自分のチャンネルの一覧(youtube_videos.json)から公開の時刻と URL を読み、予定表に入れています(LOG377)。ところが、その同期の部品はショートだけを拾い、予定のタスクもショートのファイルしか GitHub に上げない作りでした。LOG376 の最後にも「本編の動画の投稿を予定表に入れる仕組みは、まだありません」と書いてあります。この動画の投稿文は、投稿文_X_LinkedIn.txt に【URL】を空けたまま置いてあるだけでした。

つなぐ作業は3つと伝え、「この形でつなげてよい」と返事をもらいました。

作業中身
投稿文を置く
この動画の X の文を、{url} 入りの形で sns/VIDEO_serving-robots-how-many_sns_posts.json に置く
同期の部品を広げる
tools/sync_youtube_shorts.py が sns/VIDEO_*_sns_posts.json も読み、本編の動画と結びつけて公開の時刻で予定表に入れる。URL は https://youtu.be/{id}
予定のタスクを直す
名前を「ショートと本編のX予約をYouTubeに合わせる」にし、本編のファイルも GitHub に上げる

タイトルを直して上げても結びつくように、語と長さでも照らす

本編は、YouTube に上げるときにタイトルを少し直すことがあります。チャンネルの一覧を見ると、本編のタイトルは「秒速2000ミリのロボットが、人の隣ではゆっくりな理由|協働ロボットの安全の仕組み」のように長く、作業フォルダの名前とは違います。そこで結びつけ方を2段にしました。

  1. YouTube のタイトルが、json の youtube_title(タイトル.txt の文)と同じもの
  2. なければ、title_match の語(「配膳ロボット」「何台」)をすべて含み、長さが seconds(860秒)と3秒以内のもの

予定表に入れる時刻の決まりはショートと同じです。19:30 に別の X の予約があれば 20:00、それ以外は30分ずつ後ろへずらします。公開の時刻を過ぎてから見つけたものは入れません。LinkedIn は動画を直接アップロードする決まりなので、本編も手で出します。

試し:いまの一覧では何も変わらず、偽の行では 20:30 に入った

まず、いまのチャンネルの一覧で、直す前と直したあとの部品を動かしました。どちらも「変わったものはありません」で、ショートの予約は前と同じです。次に、タイトルを直して上げ、10月30日19:30(日本時間)に公開予約した、という偽の行を一覧に足して動かしました。

Y="/mnt/user-data/uploads/PixelstoMotors/デジタルツイン学習R2R2R/動画/_制作ベース/youtube_videos.json"; cd /home/claude/r2r2r-content && git show HEAD:tools/sync_youtube_shorts.py > /tmp/old_sync.py && cp /tmp/old_sync.py tools/_old_sync.py && echo "旧:" && python3 tools/_old_sync.py --videos "$Y" --dry-run; rm tools/_old_sync.py; echo "新:"; python3 tools/sync_youtube_shorts.py --videos "$Y" --dry-run
python3 - "$Y" <<'EOF'
import json,sys
d=json.load(open(sys.argv[1]))
d['動画'].append({"id":"TESTabc123","title":"配膳ロボット、何台入れたら店は変わる? 試算した【導入シミュレーション 第1回】","privacy":"private","publishAt":"2026-10-30T10:30:00Z","published":None,"seconds":861,"is_short":False,"parent":"","url":"https://www.youtube.com/watch?v=TESTabc123"})
json.dump(d,open('/tmp/yv_fake.json','w'),ensure_ascii=False)
EOF
rm -rf /tmp/rc && cp -r /home/claude/r2r2r-content /tmp/rc && cd /tmp/rc && echo "試し(タイトルを直して上げた想定):" && python3 tools/sync_youtube_shorts.py --videos /tmp/yv_fake.json && grep -n "VIDEO_" -A3 sns/schedule.json && python3 -c "import json;d=json.load(open('sns/VIDEO_serving-robots-how-many_sns_posts.json'));print(d['meta']['url']);print(d['posts']['x'])" && python3 tools/sns_autopost.py check; grep "2026-10-30T19:30" sns/schedule.json | head
旧:
変わったものはありません
新:
変わったものはありません
試し(タイトルを直して上げた想定):
足した VIDEO_serving-robots-how-many-x 2026-10-30T20:30:00+09:00 配膳ロボット、何台入れたら店は変わる? 試算した【導入シミュ
124:      "id": "VIDEO_serving-robots-how-many-x",
125:      "source": "sns/VIDEO_serving-robots-how-many_sns_posts.json",
126-      "platform": "x",
127-      "post_at": "2026-10-30T20:30:00+09:00"
128-    },
https://youtu.be/TESTabc123
配膳ロボットを0〜6台、ファミレスの混む2時間で試算。
席に着くまでが縮んだのは2台目まで。
1台だけだと、料理はかえって遅く届いた。
台数は、誰が先に運ぶかの決まりとセットで決める。
https://youtu.be/TESTabc123
#R2R2R #PixelsToMotors
問題ありません。
      "post_at": "2026-10-30T19:30:00+09:00"
      "post_at": "2026-10-30T19:30:00+09:00"

タイトルは json の youtube_title と違いますが、語と長さ(861秒)で結びつきました。その日の 19:30 には記事の投稿が、20:00 にはショートの投稿がすでに入っていたので、20:30 になっています。試しは、リポジトリを /tmp/rc に写した上で動かし、本物の予定表は変えていません。

試しのあとで、X の文を SNS の文章の質の決まり(1行目で手が止まる一文・シミュレーションならそう分かる言葉・小さな感想・話題のタグ2つ)に合わせて書き直しました。自分の名前のタグ(#R2R2R #PixelsToMotors)だけになっていたためです。

配膳ロボット、増やすほど店は良くなる?

ファミレスの混む2時間をパソコンの中で試算したら、席に着くまでが縮んだのは2台目まで。1台だと料理はかえって遅くなった…
台数は、誰が先に運ぶかの決まりとセットで決めたいね。解説動画にしたよ。
#配膳ロボット #飲食店
{url}

X の数え方(日本語は1字を2、URL は23)で274です。

  • ねらい:本編の動画を YouTube で公開予約したら、X の投稿は何もしなくても公開の時刻に出るようにする
  • 変わったこと:動画を作った会話が sns/VIDEO_*_sns_posts.json を置けば、予定のタスクが公開の時刻と URL を入れて予定表に足す。URL を貼る作業がなくなった
  • 見込める効果:出し忘れと、公開前に URL のない投稿が出る間違いがなくなる(見込み)。この動画の公開後、sns/posted.json に VIDEO_serving-robots-how-many-x の行が「投稿済み」で入るかで確かめる

注意が1つあります。予定のタスクが動くのは 7:47 と 17:47 なので、公開予約してから X の予約に入るまで、最大で半日ほどかかります。当日の夜に公開するなら、17:47 より前に YouTube で予約しておく必要があります。

予定のタスクの指示(直したあとの全文)

あなたは、YouTube で公開予約したショートと本編の動画の X 投稿を、公開の時刻に合わせて SNS の予定表に入れる係です。短く、次の手順だけをやって終える。ほかの作業はしない。返事は日本語。

1. Mac の YouTube の一覧を取り込む。device_stage_files で次のファイルを取り込む:
   ~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/動画/_制作ベース/youtube_videos.json
   (Mac が毎時5分に書き出している。Mac につながらない・取り込めないときは、何もせずに「Mac につながらなかった」と1行書いて終える)
2. GitHub の PixelstoMotors/r2r2r-content を clone する(git clone --depth 1 https://github.com/PixelstoMotors/r2r2r-content)。push できなければ add_repo で push 権限つきで足してからやり直す。
3. clone したフォルダで次を実行する:
   python3 tools/sync_youtube_shorts.py --videos <取り込んだ youtube_videos.json のパス>
   「変わったものはありません」なら、何もせずに終える。
4. 変わったものがあれば、python3 tools/sns_autopost.py check が「問題ありません」になることを確かめ、python3 tools/sns_autopost.py preview を動かしてから、sns/schedule.json・sns/schedule_preview.md・sns/SHORT_ep*_sns_posts.json・sns/VIDEO_*_sns_posts.json のうち変わったものだけを git add して commit し、main に push する(git add . は使わない。push の前に git pull --rebase)。commit のメッセージは「SNS予約:ショートと本編の X を YouTube の公開予約に合わせた」と、足した・直した行の一覧。check が通らなければ push しない。
5. 最後に、足した・直した予約(id と日時)を短く書く。

注意: tools/sync_youtube_shorts.py と docs/sns_autopost.md の「YouTube のショート」「YouTube の本編」の節が正。LinkedIn の予約は入れない。予定表のほかの行(記事・マンガ)は触らない。

video_rules.md に足したこと(88・89回目)

動画の作り方の決まり(video_rules.md)に、この動画で決めたことを書き足しました。iCloud の _制作ベース/video_rules.md と、プロジェクトの写しの両方に入れています。

4-4e. 背景に映像を長く流し、文字はカードに載せる(全文)

「何台入れたら店は変わる」(配膳ロボット導入シミュレーション 第1回)で決めた。エイイチ「背景にシミュレーションの動画を長く使う(今までより圧倒的に増やす)。テキストは背景をカードタイプで仕上げる」。4-4d の「静=無地の背景」を、この型では「静=映像が流れたまま、カードの文字だけが替わる」に置きかえる。

  • 背景: ほぼ全部の場面で、試算ページの操作の録画か Unity の店の映像を流す。紙色の無地の場面は作らない。同じ章の間は同じ映像を切らずに流し続ける(scenes.py の RUNS に「どの場面からどの場面まで、どの映像の何秒目から」を書き、場面が替わっても続きから再生する)。映像は暗くして文字を読みやすくする(Unity は 0.62、試算ページは 0.5 の明るさ)。試算ページの録画は、操作が終わったら最後のコマで止めてよい(頭に戻さない)
  • カード: 黒い角丸の板(rgba(8,8,8,.86)・角の丸み30px・左右84pxの余白)に白い文字。小見出しは 42px の薄い灰色、大きい文字は 900 の太さ、補足は 44px の薄い灰色。板は字幕とハコブくんの区画にかからない高さ(画面の上150px〜下300px の間の真ん中)に置く。カードの下端が785pxを超えないかを、書き出す前に確かめる(vm_書き出し/precheck.py)
  • 色: 基本の差し色はオレンジ #C4471F(記事・これまでの動画と同じ。強調する語・番号・章の印・棒グラフ)。追加の差し色に水色 #62BFF5(もう一方を見せたい語だけ)。最初に水色を基本にしたら、エイイチに「基本はオレンジ、追加の差し色で水色。元のオレンジと水色にして」と直された。黒い板の上でも #C4471F は読めた。暗い板の上では、青 #1A6C98 ではなく水色を使う(4-5 の「オレンジと青以外の色を足さない」の青を、この型では水色に置きかえる)
  • 映像の説明: 映像の左上に、何の映像かを小さな板で出す(例「Unity で建てたファミレス(図面のある店③・シリーズの後の回で扱う)」「試算ページ(pixelstomotors.com/series8・試作 v2.7)」)。右上に章の番号と名前の札。数字の出どころは札の下に小さく
  • 映像と話の時期: シリーズの後の回で扱う映像(Unity の店)を先に背景に使うときは、そう書く。Unity のエディタの道具の列や向きの印が映っていても、エイイチは通した(2026-10-24)
  • 書き方の例: 動画/何台入れたら店は変わる/scenes.py(BG・RUNS・CARD_CSS・C_word/C_num/C_pair/C_list/C_bars と CARDS。場面ごとに MOTION[名前] = dict(type=“html”, bg=…, html=…) を作る)

7節に足した、Mac の中の作業場所で書き出すときの手順(全文)

  • Mac の中の作業場所(device_bash)で書き出すとき(2026-10-24「何台入れたら店は変わる」): クラウドの作業環境が使えず、Mac 連携の shell(Linux・4コア・メモリ3GB)で書き出した。1回の呼び出しは180秒まで、呼び出しが終わるとバックグラウンドの処理も止まる。KIOXIA は書いた直後に読めないことがある(Chromium が ERR_FILE_NOT_FOUND)ので、中間ファイルは shell の手元($HOME/build)に置き、仕上がった物だけ KIOXIA に写す(写したら15秒おいて md5 を比べる)。Chromium は libXdamage がないので、apt-get download して dpkg -x で展開し LD_LIBRARY_PATH に足す。180秒に収める部品は _制作ベース/vm_書き出し/: mk.py(動きの場面を、まだない物から順に、指定のコマ数まで書き出す。1秒に約30コマなので、1回 2,800〜3,000 コマ。割り付けは _timing_cache.pkl に置いて読み直さない)、assemble.py はそのまま何度も動かす(背景の断片は1回に約30個。できた物は使い回す)、fin.py(ハコブくんを重ねる所を172秒ずつ5つに分けて1つ約80秒・最後に join で音と合わせる)、precheck.py(カードがハコブくんの区画にかからないか)

0節の手順22を、本編の X は自動で出す形に直した(直したあとの全文)

  1. C X と LinkedIn の投稿文を作る(書き方は article_rules.md の SNS 節。動画の投稿文は日本語だけにする。英語の投稿文は作らない(2026-10-24 エイイチの指示。英語で投稿するのはマンガだけ)。X は URL 込み140字・LinkedIn は日本語の本文と、コメント欄への補足(日本語))。LinkedIn の本文の最後には「YouTube のほかの動画: https://www.youtube.com/@PixelstoMotors」を入れる(2026-10-14 エイイチの指示。それまでの13本の投稿文にも足した)。LinkedIn の本文には、動画の URL(youtu.be など)を入れない。動画は LinkedIn に直接アップロードするので、チャンネルへのリンクだけでよい(2026-10-14 エイイチの指示)。YouTube 版の URL は、X とコメント欄の補足の出典にだけ書く。投稿文は 投稿文_X_LinkedIn.txt にして、iCloud の作業フォルダと KIOXIA の videos/{動画名}/アップロード用/ の両方に置く(2026-10-14 エイイチの指示。上げる物を1か所にまとめる)。X は自動で出す(2026-10-24 エイイチの指示): 投稿文を作ったら、X の文を {url} 入りにして GitHub r2r2r-content の sns/VIDEO_{英数字の名前}_sns_posts.json に置いて push する(書き方は r2r2r-content の docs/sns_autopost.md「YouTube の本編」)。エイイチが YouTube で公開予約すると、予定のタスク「ショートと本編のX予約をYouTubeに合わせる」(7:47・17:47)が公開の時刻で予定表に入れ、URL も入れて出す。タイトルを上げるときに直しても、語(title_match)と長さ(seconds)で結びつく。エ YouTube で公開予約する(X の URL を貼る作業はない)。LinkedIn は動画を直接アップロードして手で出す

まだ確かめていないこと

  • 背景を流し続けたことで、途中で離れる人が減るか。公開後に、YouTube の分析画面の視聴者維持率を、前に公開した解説動画と比べる
  • 本編の X 投稿が、実際に公開の時刻で予定表に入り、投稿されるか。YouTube で公開予約したあとの最初の同期(7:47 か 17:47)と、sns/posted.json で確かめる
  • 動画の投稿文の txt(投稿文_X_LinkedIn.txt)の X の文は、GitHub の json に入れた書き直し前の文のまま。自動で出るのは json の文なので、txt は LinkedIn の文と補足を見るためだけに使う
  • 第2回(「配膳ロボットで1人減らせるか」を v2.7 の数字に直す回)は、まだ手を付けていない

この記事で作った・直したファイルの全文

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(6本)

01_scenes.py.txt ― 動画/何台入れたら店は変わる/scenes.py・29,906字

02_src_rec__.py.txt ― 動画/何台入れたら店は変わる/src/rec_背景の録画.py・6,704字

03_narration.py.txt ― 動画/何台入れたら店は変わる/narration.py(台本・4版)・13,305字

04_codex___1_.md ― 動画/何台入れたら店は変わる/codex_検証結果_1回目.md・9,553字

05_r2r2r-content_tools_sync_youtube_shorts.py.txt ― r2r2r-content/tools/sync_youtube_shorts.py(本編も読むように直したあとの全文)・5,362字

06_sec10.txt ― r2r2r-content の commit c139161 の差分(同期の部品と docs/sns_autopost.md)・6,284字

動画/何台入れたら店は変わる/scenes.py

01_scenes.py.txt29,906字・450行・python
# -*- coding: utf-8 -*-
# 動画「配膳ロボット、何台入れたら店は変わる?」(シリーズ「配膳ロボット導入シミュレーション」第1回)の場面
PATTERN = 2   # 画面パターン2(大文字型・video_rules.md 4-4c)
MOVE = True   # 画面型の動き(4-4d)を強弱を付けて使う(2026-10-24 エイイチが選んだ)
# 2026-10-24: 「配膳ロボットで1人減らせるか」の scenes.py の形を写して書いた
# 背景の映像は、この動画のために新しく録った(試算 v2.7 のページを、p2m-site の public/sim/serving-robot.html からローカルで開いて録画。src/rec_背景の録画.py)
#   src/sim_*.mp4    試算ページ(open: 3人で0→3台・more: 3→6台・one: 1台の料理・table: 台数の比べ・two: 2人で0→6台・crowd: 混雑で0→1台・
#                    buffet: 焼肉食べ放題2人で0→1台・hotel: 洗い場が遠い店2人で0→1台・patrol: 2人で集めて回る3台)
別のタブで開く保存

動画/_制作ベース/vm_書き出し/mk.py

# motion_kit.main を、割り付けのキャッシュを使って、まだ書き出していない場面から順に、時間内に収まる分だけ回す
import sys, os, copy, pickle, time
B = os.environ['P2M_BASE']; sys.path.insert(0, os.getcwd()); sys.path.insert(1, B)
import timing
key, cached = pickle.load(open('_timing_cache.pkl', 'rb'))
timing.load = lambda first=None: copy.deepcopy(cached)
timing.layout = lambda idx: sum(o['frames'] for o in idx)
import scenes as SC, motion_kit as MK
budget = int(sys.argv[1]) if len(sys.argv) > 1 else 1500
force = sys.argv[2:]  # 作り直す場面
fr = {}
for o in cached:
    fr[o['scene']] = fr.get(o['scene'], 0) + o['frames']
todo, tot = [], 0
for name in SC.MOTION:
    if name not in fr: continue
    if os.path.exists(f'src/motion_{name}.mp4') and name not in force: continue
    if todo and tot + fr[name] > budget: break
    todo.append(name); tot += fr[name]
rest = [n for n in SC.MOTION if n in fr and not os.path.exists(f'src/motion_{n}.mp4') and n not in todo]
print('この回:', todo, tot, 'frames / 残り', len(rest), '場面', sum(fr[n] for n in rest), 'frames', flush=True)
if todo:
    sys.argv = ['motion_kit.py'] + todo
    MK.main()

動画/_制作ベース/vm_書き出し/fin.py

# assemble.py の最後(ハコブくんを重ねる・確認用)を、1回の時間に収まるよう区切って書き出す
#   python3 fin.py prep          ハコブくんの動きを決めて params.pkl に置く
#   python3 fin.py seg N SEC     N 番目の区切り(SEC 秒ずつ)を segs/seg_N.mp4 に(crf 20)と segs/chk_N.mp4(crf 29)に
#   python3 fin.py join          つないで音を合わせ、out.mp4 と out_確認用.mp4 を作る
import sys, os, json, pickle, subprocess, wave
B = os.environ['P2M_BASE']; sys.path.insert(0, os.getcwd()); sys.path.insert(1, B)
import numpy as np
from timing import FPS
from hakobu import Hakobu
hk = Hakobu()
idx = json.load(open('timeline.json'))
total = sum(o['frames'] for o in idx)
cmd = sys.argv[1]
if cmd == 'prep':
    w = wave.open('narration.wav'); pcm = np.frombuffer(w.readframes(w.getnframes()), np.int16)
    timeline = [(o['start'], o['start'] + o['frames'], o['start'] + o['speech'], o.get('face', 'base'), bool(o['text'])) for o in idx]
    params = hk.animate(timeline, pcm.astype(np.float32) / 32768.0)
    pickle.dump(params, open('params.pkl', 'wb')); print('frames', total, len(params))
elif cmd == 'seg':
    n, sec = int(sys.argv[2]), float(sys.argv[3]); L = int(sec * FPS)
    a, b = n * L, min(total, (n + 1) * L)
    if a >= total: sys.exit('範囲の外')
    params = pickle.load(open('params.pkl', 'rb'))
    os.makedirs('segs', exist_ok=True)
    out = f'segs/seg_{n:02d}.mp4'
    c = ['ffmpeg', '-v', 'error', '-y', '-ss', f'{a / FPS:.4f}', '-i', 'bg.mp4',
         '-f', 'rawvideo', '-pix_fmt', 'rgba', '-s', f'{hk.w}x{hk.h}', '-r', str(FPS), '-i', '-',
         '-filter_complex', f'[0:v][1:v]overlay=x={hk.x}:y={hk.y}:eof_action=pass,split[v1][v2]',
         '-map', '[v1]', '-c:v', 'libx264', '-preset', 'faster', '-crf', '20', '-pix_fmt', 'yuv420p', '-frames:v', str(b - a), '-an', out + '.part.mp4',
         '-map', '[v2]', '-c:v', 'libx264', '-preset', 'faster', '-crf', '29', '-pix_fmt', 'yuv420p', '-frames:v', str(b - a), '-an', f'segs/chk_{n:02d}.part.mp4']
    p = subprocess.Popen(c, stdin=subprocess.PIPE)
    for i in range(a, b):
        p.stdin.write(hk.frame(params[i]).tobytes())
    p.stdin.close()
    if p.wait(): sys.exit('失敗')
    os.replace(out + '.part.mp4', out); os.replace(f'segs/chk_{n:02d}.part.mp4', f'segs/chk_{n:02d}.mp4')
    print('seg', n, a, b, 'of', total)
elif cmd == 'join':
    n = int(sys.argv[2])
    for kind, outn, ab in (('seg', 'out.mp4', '192k'), ('chk', 'out_確認用.mp4', '112k')):
        open('segs/list.txt', 'w').write(''.join(f"file '{kind}_{i:02d}.mp4'\n" for i in range(n)))
        subprocess.run(['ffmpeg', '-v', 'error', '-y', '-f', 'concat', '-safe', '0', '-i', 'segs/list.txt', '-i', 'mix.wav', '-map', '0:v', '-map', '1:a',
                        '-c:v', 'copy', '-af', 'loudnorm=I=-16:TP=-1.5:LRA=11', '-c:a', 'aac', '-b:a', ab, '-ar', '48000', '-movflags', '+faststart',
                        '-frames:v', str(total), outn], check=True)
        print(outn, os.path.getsize(outn) / 1e6, 'MB')

動画/_制作ベース/vm_書き出し/precheck.py

import sys, os, copy, pickle
B = os.environ['P2M_BASE']; sys.path.insert(0, os.getcwd()); sys.path.insert(1, B)
import scenes as SC, motion_kit as MK
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
    b = p.chromium.launch(); pg = b.new_page(viewport={'width': 1920, 'height': 1080})
    for nm, m in SC.MOTION.items():
        open('/tmp/pc.html', 'w').write(MK.anim(m['html'])); pg.goto('file:///tmp/pc.html'); pg.evaluate('seek(999)')
        r = pg.evaluate("(()=>{const e=document.querySelector('.cd'); if(!e) return null; const r=e.getBoundingClientRect(); return [r.left,r.top,r.right,r.bottom]})()")
        if r and (r[3] > 785 or r[1] < 118):
            print(nm, [round(x) for x in r])
    b.close()
print('done')

動画/何台入れたら店は変わる/src/rec_背景の録画.py

02_src_rec__.py.txt6,704字・95行・python
# 第1回「何台入れたら店は変わる」の背景の録画(試算 v2.7 のページをローカルで開いて録る)
# 使い方: simulation/v2_7 で python3 -m http.server 8765 を動かし、xvfb-run -s '-screen 0 1920x1400x24' python3 rec_背景の録画.py [名前 ...]
# 「配膳ロボットで1人減らせるか」の src/rec_背景の録画.py を写して書き換えた(2026-10-24)
import asyncio, sys, os, subprocess
from playwright.async_api import async_playwright
URL = 'http://localhost:8765/serving-robot.v27.html'   # iCloud simulation/v2_7/serving-robot.v27.html(p2m-site public/sim/serving-robot.html と同じ md5 88adf2b2)
CUR = """(() => { if (document.getElementById('fakecur')) return;
 const c=document.createElement('div'); c.id='fakecur';
別のタブで開く保存

動画/何台入れたら店は変わる/narration.py(台本・4版)

03_narration.py.txt13,305字・225行・python
# -*- coding: utf-8 -*-
# 台本「配膳ロボット、何台入れたら店は変わる?」— シリーズ「配膳ロボット導入シミュレーション」第1回(/series8 の試算が元の解説回)
#   2026-10-24 4版。codex 1回目(「直してから」・結論「条件つきで成立」・27件)を受けた:
#     「回る」は今回の線を下回った意味・人を減らすと料理の待ちが延びる(混雑 45秒→2分17秒・食べ放題 1分17秒→3分26秒)・同じサービスのまま減らせたではない/
#     本人の「限界点」の後に、この試算の条件での限界と断る/4台のぶれは言い切らない/動いていた割合→仕事でふさがっていた割合(受け取り待ちを含む)/
#     空の店から始め片付けまで・ホールの仕事を何人でこなせるか(兼務・準備・休憩は外)・料理を載せる人の時間は入れていない・停止は台数に関係なく同じ確率/
#     料理は3卓ではなく3つまで・デザートとドリンクも/店の普通の混み具合はそれぞれ別の設定/食べ放題は約27分半(ページの表示は27.4)・約18分縮む/
#     ハコブくんのまとめ(見立てのあと)は、店長やスタッフ・メーカー・導入を手伝う人と一緒に確かめる、に(宣伝に聞こえすぎないように)/
別のタブで開く保存

動画/何台入れたら店は変わる/codex_検証結果_1回目.md

04_codex___1_.md9,553字・326行・markdown
# codex 敵対的検証 結果 1回目(何台入れたら店は変わる)

- 日時: 2026-10-24 18:50(JST)
- 依頼文: codex_敵対的検証依頼_何台入れたら店は変わる.md(md5 2e9afb7a8b0d4f49a7afe221c04e9ca4・25,339 バイト)
- 題(依頼文の1行目): # 敵対的検証依頼:YouTube台本「配膳ロボット、何台入れたら店は変わる? ― ファミレスの混む2時間を、0台から6台まで試算した」
- codex: codex-cli 0.163.0-alpha.11
- モデル: gpt-6.1-sol
- 考える深さ: high
別のタブで開く保存

動画/何台入れたら店は変わる/概要欄.txt

ファミレスで見かける配膳ロボット。すかいらーくグループは、2022年12月に約2,100店へ約3,000台の導入を終えました(単純に割ると1店あたり平均で約1.4台)。では、ロボットを増やせば増やすほど、店は良くなるのでしょうか。ファミレスの混む時間帯の2時間をパソコンの中で再現して、ロボットを0台から6台まで1台ずつ増やしてみました。

今日の問い:配膳ロボットを何台入れたら、店は変わるのか

先に答え:35卓のファミレスで、スタッフ3人のまま増やすと、お客さんが席に着くまでの時間は2台目までで大きく縮み(8.6分→3.2分)、3台目から先はほぼ横ばいでした。1台だけのときは、料理がロボットを待つ決まりのため、料理はかえって遅く届きました。普通の混み具合で料理を運ぶだけなら、試した6台までのどの台数でも、スタッフを3人から2人にすると店は回りませんでした。ただし、混雑の日や焼肉の食べ放題、洗い場が遠い店では、1台で1人少なくても今回の線を下回りました(待ち時間は延びます)。

この動画で見る3つ
・スタッフ3人のまま、ロボットを増やすと、何が変わるのか
・1台だけだと、なぜ料理が遅くなるのか
・人を減らせる台数は、あるのか

試算はサイトで、店・人数・台数・使い方を変えて試せます。
https://pixelstomotors.com/series8

▼目次
0:00 配膳ロボット、店に何台いた?
0:53 この番組について
1:17 今日の問い:何台入れたら、店は変わるのか
2:40 先に結論
3:53 1. スタッフ3人のまま、ロボットを増やすと
6:36 2. 1台だけだと、なぜ料理が遅くなるのか
8:25 3. 人を減らせる台数は、あるのか
9:10 元ファミレスのエイイチが、ロボットに任せたかった仕事
10:17 店が変わると、答えも変わる
11:29 エイイチの見立て
12:06 この試算でまだ分からないこと
12:57 冒頭の問いへの答え
14:04 エンディング

▼この動画で扱う範囲
・パソコンの中の試算です(Python の SimPy で、お客さんが来てから帰るまでの出来事を時間の順に再現)。数字の多くは、公開されている導入事例やメーカーの仕様をもとにした仮の値で、実際の店で測ったものではありません。ロボットの速さ(秒速0.5メートル)も仮の値です
・店は空の状態から始め、混む時間帯の2時間だけお客さんを受け入れ、最後の片付けが終わるまでを計算しています。どの条件も40回回した平均です
・「店が回らない」は、席は空いているのに片付けや案内を待たせた時間が平均10分以上の条件です。この10分は、比べるためにエイイチが決めた線です。「回る」は、この線を下回ったという意味で、同じ待ち時間のまま人を減らせたという意味ではありません
・料理はまずロボットを待ち、2分たってもロボットが来なければ人も運べる、という決まりで計算しています(試算 v2.7)
・比べているのは、混む時間のホールの仕事を何人でこなせるかだけです。兼務・準備・休憩、シフト全体で人を減らせるか、費用に見合うかは見ていません
・ロボットが止まるのは、台数に関係なく、往復の3割で数秒、1%で人が動かしに行く、と仮に置いています。ロボットどうしが通路で邪魔し合う時間と、料理をロボットに載せて行き先を決める人の時間は、まだ入っていません
・店ごとの「普通の混み具合」は、それぞれ別の設定です。近い店の数字は、自分の店の答えにはなりません

▼出典
・すかいらーくグループの配膳ロボット(2022年12月 約2,100店に3,000台の導入完了):すかいらーくホールディングス「歴史・沿革」 https://corp.skylark.co.jp/about/history/
・試算の数字:Pixels to Motors「サービスロボット導入シミュレーション」試作 v2.7 https://pixelstomotors.com/series8

▼関連する記事(作業ログ)
・試算を作った回:https://pixelstomotors.com/record/serving-robot-simulation-simpy
・試算を点検した回:https://pixelstomotors.com/record/audit-simulator-before-unity
・Unity にファミレスを建てた回:https://pixelstomotors.com/record/unity-family-restaurant-serving-robot

▼この番組について
「フィジカルAI解説|Pixels to Motors」は、フィジカルAIのニュースや実機の記録から、現場で使える形を考える番組です。
エイイチは、本業のデザイナーをしながら、ロボティクスの研究と開発をしています。その中で分かったことと、そこから考えた見立てを、案内役のハコブくんがお伝えします。
この動画は、シリーズ「配膳ロボット導入シミュレーション」の1回目です。次の回からは、人は減らせるのか・月いくら浮くのか、店の図面、Unity で建てた3Dの店へと進みます。

・ナレーションは AI 音声(ElevenLabs)です。話しているのは Pixels to Motors のキャラクター、ハコブくんです
・BGM は ElevenLabs Music で作った曲、効果音はコードで作った音です
・画面の映像は、サイトの試算ページを操作した録画と、Unity で作ったファミレスの映像です。Unity の店はシリーズの後の回で扱います

▼ロボットの開発・導入のご相談
メール:pixelstomotors@adaptdesign.jp

▼リンク
Webサイト:https://pixelstomotors.com
GitHub:https://github.com/PixelstoMotors
X:https://x.com/adaptdesignjp
LinkedIn:https://www.linkedin.com/in/eiichi-shimazu

チャンネル登録・高評価もよろしくお願いします。コメントは、エイイチが全部読んでいます。

#フィジカルAI #配膳ロボット #サービスロボット

r2r2r-content/tools/sync_youtube_shorts.py(本編も読むように直したあとの全文)

#!/usr/bin/env python3
"""sync_youtube_shorts.py — YouTube で公開予約したショートと本編の X 投稿を、公開の時刻に合わせて予定表に入れる。

元になるもの:
  sns/SHORT_ep{N}_sns_posts.json   ショートの X の文(posts.x_template。{url} がショートの URL に替わる)
  sns/VIDEO_{名前}_sns_posts.json  本編の X の文(2026-10-24 から。{url} が https://youtu.be/{id} に替わる)。
                                   動画との結びつけは、タイトルが meta.youtube_title と同じもの、
                                   なければ meta.title_match の語をすべて含み、長さが meta.seconds と3秒以内のもの
別のタブで開く保存

r2r2r-content/sns/VIDEO_serving-robots-how-many_sns_posts.json

{
  "meta": {
    "kind": "youtube_video",
    "title": "何台入れたら店は変わる(配膳ロボット導入シミュレーション 第1回)",
    "youtube_title": "配膳ロボット何台で店は変わる? 2台まで変わり、人は減らせなかった【導入シミュレーション 第1回】",
    "title_match": [
      "配膳ロボット",
      "何台"
    ],
    "seconds": 860,
    "url": "",
    "youtube_id": ""
  },
  "posts": {
    "x_template": "配膳ロボット、増やすほど店は良くなる?\n\nファミレスの混む2時間をパソコンの中で試算したら、席に着くまでが縮んだのは2台目まで。1台だと料理はかえって遅くなった…\n台数は、誰が先に運ぶかの決まりとセットで決めたいね。解説動画にしたよ。\n#配膳ロボット #飲食店\n{url}"
  },
  "note": "YouTube の本編の X 投稿。url と posts.x は tools/sync_youtube_shorts.py が YouTube の公開予約を見て入れる。LinkedIn は動画を直接アップロードする決まりなので入れない(文は iCloud の 動画/何台入れたら店は変わる/投稿文_X_LinkedIn.txt)"
}

r2r2r-content の commit c139161 の差分(同期の部品と docs/sns_autopost.md)

06_sec10.txt6,284字・116行・diff
commit c13916168e50c83107f094cbd2ba6243c62b846c
Author: Claude <noreply@anthropic.com>
Date:   Sat Oct 24 23:57:52 2026 +0900

    SNS予約:YouTube の本編の X 投稿も、公開予約に合わせて予定表に入れる
    
    - tools/sync_youtube_shorts.py が sns/VIDEO_*_sns_posts.json も読む(タイトル、なければ語と長さで結びつけ、URL は youtu.be)
    - 1本目:何台入れたら店は変わる(配膳ロボット導入シミュレーション 第1回)
別のタブで開く保存