# -*- coding: utf-8 -*- # 動画「ロボットが店に広がるかを決めるのは、賢さか」— 考察回「壁打ちの型」の2本目(もとは LOG389)の場面 # 書き写した元: 頭脳は脳のように分かれる/scenes_kabe.py(型の決まりは video_rules.md 10節) # 紙の文字は真ん中にそろえる/線を使わず面で分ける(事実=墨・エイイチの見立て=濃い灰・ハコブくん=薄い灰) # 朱は判子とリアクション(ボツ・入れとく・この見立ては、エイイチから)だけ/字幕は動かさない # 脱線(画面いっぱいの絵)は4回: 1時間に6回(マンガ)・朝の街(写真風)・最後の動作(マンガ)・扉(マンガ)。どれも Gemini で作った絵 # 天丼: ハコブくんが固まると、頭の上に「再開」のボタンが出る。エイイチが押す(2回)。最後だけハコブくんが自分で押す import os from kabe_kit import * import scene_kit as _sk _tl = Timeline() tl = _tl N = len(_tl.idx) A = lambda i, off=0.0: tl.start(i) + off # 動画の頭からの秒 S = tl.speech # その文を読み終わるまでの長さ LOGO = _sk.LOGO BRAND = f'' SANS = "font-family:'Noto Sans CJK JP',sans-serif;" BG = "src/bg/" GEM = "絵は生成AI(Gemini)で作成" BLOCKS = [] def block(name, sents, fn, video=None): b0 = _tl.start(sents[0]) T = lambda i, off=0.0: tl.start(i) - b0 + off E = lambda i: tl.end(i) - b0 b = dict(name=name, sents=list(sents)) if video: b["video"] = video else: b["html"] = page(fn(T, E) + BRAND) BLOCKS.append(b) def inkl(text, t, step=0.05): """「/」で行を分けて書く(1〜2文字だけ次の行に落ちないように)""" out, tt = [], t for k, part in enumerate(text.split("/")): out.append(ink(part, tt, step)); tt += len(part) * step return "
".join(out) def line(text, t, size=30, weight=700, step=0.05, style=""): return f'
{ink(text, t, step)}
' def qline(text, t, size=46, step=0.06, style=""): return f'
{ink(text, t, step)}
' def src(text, t=0.0): return f'
{text}
' BTN_CSS = """""" def btn(t_show, t_press, t_hide, who="エイイチが押す"): """ハコブくんの頭の上の「再開」ボタン(天丼)""" return (BTN_CSS + f'
{who}再開
' + f'
ピッ
') # ================= 0 つかみ ================= def hook(T, E): fly = (T(2, 0.1), T(3, 0.15)) return (dassen(BG + "1時間に6回.jpg", fly[0] + 0.05, fly[1] - 0.05, words="!1時間に|6回。", word_style="top:120px;font-size:130px", src_note=GEM) + paper(tag("考察ノート") + '
' + line("仮に、成功率", T(0, 0.2), size=34, weight=500) + f'
0%
' + f'
{ink("1時間に600回働くと、", T(1, 0.3), 0.06)}
' + f'
{land("6回", T(1, 3.0), "font-size:120px;font-weight:900")}{ink("人が駆けつける", T(1, 3.5), 0.07)}
' + '
' + src("例の計算(X の議論の指摘をもとに)", T(0, 0.5)), 0.0, flights=[fly]) + stamp("優秀?", T(3, 0.3), "right:380px;top:560px;font-size:64px") + shake_js([(T(3, 0.65), 0.3)]) + counter_js("c99", T(0, 1.0), T(0, 2.6), 99, dec=0)) block("hook", [0, 1, 2, 3, 4], hook) def hook_q(T, E): return paper(tag("考察回 壁打ち") + '

' f'ロボットが
' f'店に広がるかを
' f'決めるのは、
' f'{land("賢さ", T(5, 2.4), "font-size:104px;font-weight:900")}か。

', 0.0) block("hook_q", [5], hook_q) # ================= 1 自己紹介(DAY124 の映像とテロップ) ================= O_TITLE = '
フィジカルAI解説
案内役:ハコブくん(AI音声)
' O_EIICHI = '
エイイチ
デザイナー/ロボティクスの研究・開発
' O_OUTRO = '
相談は概要欄の連絡先から
高評価・チャンネル登録/コメントはエイイチが全部読んでいます
' OVERLAYS = {"title": _sk.overlay(O_TITLE), "title_eiichi": _sk.overlay(O_EIICHI), "outro": _sk.overlay(O_OUTRO)} _t_title = tl.end(7) - tl.start(6) block("title", [6, 7], None, video=("src/day124_crop.mp4", 4.5, "png/ovl/title.png")) block("title_eiichi", [8], None, video=("src/day124_crop.mp4", 4.5 + _t_title, "png/ovl/title_eiichi.png")) def title_kabe(T, E): return paper(tag("考察回") + '
' + f'
{land("壁打ち", T(9, 0.5))}
' + line("エイイチの考えに、ハコブくんが付き合う", T(9, 1.3), size=34, weight=500) + '
', 0.0) block("title_kabe", [9], title_kabe) # ================= 2 持ち込み(脱線: 朝の街・ボタン1回目) ================= def bring(T, E): fly = (T(13, 0.3), E(13) - 0.1) col = lambda kind, head, sub, t: (f'
' f'{head}
{sub}
') return (dassen(BG + "朝の街.jpg", fly[0] + 0.05, fly[1], words="一夜で、|
|!来ない。", word_style="top:150px;font-size:120px", src_note=GEM) + paper(tag("持ち込み") + '
' + line("エイイチが持ち込んだ、X の議論", T(10, 0.4), size=28, weight=500, style="color:#5a564f") + f'
{ink("ロボットにも、", T(11, 0.4), 0.06)}
' f'{land("ChatGPT の瞬間", T(11, 1.4), "font-size:84px;font-weight:900")}{ink("は来る?", T(11, 2.4), 0.08)}
' + '
' + f'
' + card("hb", "明日の朝、僕にも来る", T(13, 0.4), "ハコブくん", w=460, botsu=E(13) + 0.1, fade=T(14, 0.3), style="font-size:30px") + '
' + f'
' + col("hb", "ChatGPT", "開けば、すぐ試せる", T(15, 0.4)) + col("fact", "ロボット", "置く場所・止まったとき・店のやり方", T(16, 0.5)) + '
', 0.0, flights=[fly]) + btn(T(16, S(16) + 0.2), T(17, -0.25), T(17, 1.2))) block("bring", [10, 11, 12, 13, 14, 15, 16, 17], bring) # ================= 3 やり取り1:なぜ配膳ロボットが先に広がったか ================= def why(T, E): big = lambda txt, t: (f'
' f'{txt}
') return paper(tag("やり取り 1 / どんな仕事から?") + '
' + qline("どんな仕事から、広がるのか", T(18, 0.3), size=48) + f'
{big("失敗が
許せる", T(18, 2.8))}{big("繰り返しが
多い", T(18, 4.2))}
' + card("mi", inkl("データも取りやすい。入れるハードルも低い。/広がり始めたのも、このあたり", T(19, 0.4), 0.045), T(19, 0.15), "見立て ・ エイイチ", w=860, anim="wipe") + '
', 0.0) block("why", [18, 19, 20], why) def first(T, E): c = lambda txt, t: (f'
{txt}
') return (paper(tag("ファミレスの配膳ロボット") + '
' + qline("条件が、全部そろっていた", T(21, 0.8), size=50) + card("mi", inkl("とうとうロボットが店舗に入った!", T(22, 0.5), 0.06), T(22, 0.2), "エイイチ(初めて店で見たとき)", w=820, anim="wipe", style="font-size:42px;font-weight:700") + f'
{c("止まっても、
料理が少し遅れるだけ", T(24, 0.3))}{c("毎日、
何百回も往復する", T(24, 2.6))}{c("ホールの人が
集まらない", T(24, 4.2))}
' + '
', 0.0) + stamp("感激", T(22, 3.0), "right:380px;top:300px;font-size:64px") + shake_js([(T(22, 3.35), 0.3)])) block("first", [21, 22, 23, 24], first) def last(T, E): tf = T(27, S(27) - 0.5) fly = (T(27, S(27) + 0.1), T(28, 0.7)) return (dassen(BG + "最後の動作.jpg", fly[0] + 0.05, fly[1] - 0.05, words="!最後の|動作。", word_style="top:90px;font-size:130px", src_note=GEM) + paper(tag("一番難しい所") + '
' + qline("一番難しい所を、ロボットにやらせていない", T(25, 0.3), size=40) + '
' + card("fact", '料理をテーブルに置く
お客さん', T(26, 0.3), None, w=420) + card("fact", 'トレーに載せる
店員さん', T(26, 2.2), None, w=420) + '
' + card("hb", "料理も、僕が置く", T(27, 0.6), "ハコブくん", w=420, botsu=T(28, 0.9), fade=T(28, 1.1), style="font-size:30px") + card("mi", inkl("だから、人に任せた", T(28, 0.9), 0.06), T(28, 0.75), "エイイチ", w=480, anim="wipe") + qline("頑張らない所を決めて、広がった", T(29, 1.6), size=40) + '
', 0.0, flights=[fly]) + f'
ドテッ
' + shake_js([(tf + 0.3, 0.25)])) block("last", [25, 26, 27, 28, 29], last) # ================= 4 山場:扱えるか ================= def card_mi_float(T): """店のスタッフさんでも使えてる(エイイチ)を紙の上部に""" return (f'
' + card("mi", inkl("店のスタッフさんでも使えてる。ポイント高い", T(32, 0.4), 0.05), T(32, 0.15), "エイイチ", w=820, anim="wipe", fade=T(33, 0.0)) + '
') def easy(T, E): press = T(31, 1.6) return (BTN_CSS + paper(tag("もう1つの強み") + '
' + line("使い方は、テーブル番号のボタンを押すだけ", T(31, 0.2), size=34, weight=700) + f'
' + ''.join( f'
{k + 1}
' for k in range(4)) + '
' + card("mi", inkl("店のスタッフさんでも使えてる。ポイント高い", T(32, 0.4), 0.05), T(32, 0.15), "エイイチ", w=820, anim="wipe") + f'
{ink("研修もマニュアルも、", T(33, 0.3), 0.06)}{land("ほぼ不要", T(33, 2.0), "font-size:70px;font-weight:900")}
' + card("hb", inkl("賢くても、止まったときにどうすればいいか/分からなければ、広がらない", T(34, 0.8), 0.04), T(34, 0.5), "裏を返すと", w=900) + '
', 0.0) + f'
ピッ
' ) block("easy", [30, 31, 32, 33, 34], easy) def peak(T, E): return ('
' '
' '
' '

' f'止まったとき、
' f'店の人が
' f'{land("戻せる", T(35, 2.6), "font-weight:900;font-size:84px")}か。

' f'
ハコブくんの整理 / エイイチ「そうなんだよな」
' '
') block("peak", [35], peak) def q3(T, E): row = lambda b, txt, t, sub="": (f'
' f'{b}{txt}
{sub}
') return paper(tag("見極めの、3つの問い") + '
' + row("1つ目", "止まった理由が、分かるか", T(37, 0.3), "通れません/物を見失いました") + row("2つ目", "その場の人が、戻せるか", T(38, 0.3), "エンジニアを呼ばずに") + row("3つ目", "次の動きが、周りに読めるか", T(39, 0.3), "読めないと、怖い") + '
', 0.0) block("q3", [36, 37, 38, 39], q3) def demo(T, E): return (paper(tag("デモの点数") + '
' + qline("この3つは、技術のデモでは", T(40, 0.3), size=46) + f'
{land("ほとんど評価されない", T(40, 1.8), "font-size:60px;font-weight:900")}
' + card("mi", inkl("デモの点数には、入らない", T(41, 0.4), 0.06), T(41, 0.15), "エイイチ", w=600, anim="wipe") + card("hb", "さっきコケた所は、点数に入れないで", T(42, 1.0), "ハコブくん", w=640, style="font-size:30px") + '
', 0.0) + stamp("入れとく", T(43, 0.05), "right:380px;top:640px;font-size:56px") + shake_js([(T(43, 0.4), 0.25)])) block("demo", [40, 41, 42, 43], demo) # ================= 5 やり取り2:足りなくなるのは誰か(ボタン2回目) ================= def who(T, E): return (paper(tag("やり取り 2 / 足りなくなるのは誰か") + '
' + line("動き回る仕事のロボットは、機体が", T(44, 2.0), size=34, weight=700) + f'
{land("安く↓", T(44, 4.6))}
' + card("mi", inkl("その分、入れる営業や/エンジニアが足りなくなる", T(46, 0.4), 0.05), T(45, 0.15), "見立て ・ エイイチ", w=760, anim="wipe") + card("mi", inkl("利益が残るのは、/作る側より、入れて回す側", T(47, 0.4), 0.05), T(47, 0.15), "見立て ・ エイイチ", w=820, anim="wipe", style="font-size:38px;font-weight:700") + '
', 0.0) + stamp("この見立ては、エイイチから", T(47, S(47) + 0.1), "left:1060px;top:150px") + shake_js([(T(47, S(47) + 0.45), 0.3)])) block("who", [44, 45, 46, 47], who) def who2(T, E): row = lambda txt, t: f'
{txt}
' return (paper(tag("足りなくなる人") + '
' + qline("足りなくなるのは、こんな人", T(48, 0.2), size=42) + row("通路の幅や段差を見る", T(48, 1.8)) + row("どこまでロボットに任せるか、線を引く", T(48, 3.6)) + row("止まったときの対処を、店のルールにする", T(48, 5.8)) + card("hb", "今みたいに戻してくれる人が、足りない", T(49, 1.0), "ハコブくん", w=680, style="font-size:30px;margin-top:16px") + '
', 0.0) + btn(T(48, S(48) + 0.2), T(49, -0.25), T(49, 1.2))) block("who2", [48, 49], who2) def local(T, E): return paper(tag("地方では") + '
' + card("mi", inkl("入れるのは、地方の方が切実。/どう解決できるかが鍵", T(50, 0.4), 0.045), T(50, 0.15), "見立て ・ エイイチ", w=860, anim="wipe") + card("mi", inkl("家電量販店や電気屋さんは、どうだろう?", T(51, 0.4), 0.05), T(51, 0.15), "エイイチ", w=720, anim="wipe") + '
' + card("fact", '町の電気屋さん
すぐ来てくれる関係がある
→ 止まったときの駆けつけ
', T(52, 0.3), None, w=420) + card("hb", '任せる線を、
店と決める
まだ、どちらにもない
→ 離れた所から専門の人
', T(53, 0.4), None, w=420) + '
' + card("mi", inkl("役割を分ける", T(54, 0.3), 0.06), T(54, 0.1), "エイイチ", w=380, anim="wipe") + '
', 0.0) block("local", [50, 51, 52, 53, 54], local) # ================= 6 やり取り3:止まらない作りと、扉 ================= def iris(T, E): big = lambda el, unit, t: f'
0{unit}
' return (paper(tag("やり取り 3 / アイリスオーヤマは?") + '
' + card("mi", inkl("アイリスオーヤマは、どうしてる?", T(55, 0.4), 0.05), T(55, 0.15), "エイイチ", w=640, anim="wipe") + f'
{big("c7k", "社以上", T(56, 1.0))}{big("c25k", "台以上", T(56, 2.6))}
' + card("fact", inkl("充電切れ・紙パックがいっぱい、で、/すぐ人の作業に戻る", T(57, 0.5), 0.04), T(57, 0.2), "事業の責任者", w=880) + card("fact", inkl("運用を直し続ける人が、現場にいない", T(58, 0.5), 0.05), T(58, 0.2), "広める上での壁", w=720) + '
' + src("出どころ:マイナビニュース(2026-06-29)", T(56, 0.3)), 0.0) + counter_js("c7k", T(56, 1.6), T(56, 3.0), 7000, dec=0) + counter_js("c25k", T(56, 3.0), T(56, 4.4), 25000, dec=0)) block("iris", [55, 56, 57, 58], iris) def iris2(T, E): return paper(tag("止まらない作り") + '
' + '
' + card("fact", "掃除が終わると、自分で充電に戻る", T(59, 1.2), "新しい清掃ロボ", w=430) + card("fact", "紙パックを、替えやすく", T(59, 3.6), "新しい清掃ロボ", w=380) + '
' + f'
{land("紙パック", T(60, 0.2))}
' + line("直し続ける人がいないなら、人を呼ばない作りにする", T(60, 1.6), size=30, weight=500) + card("mi", inkl("家電の会社らしい", T(61, 0.3), 0.06), T(61, 0.1), "エイイチ", w=440, anim="wipe") + '
' + src("出どころ:マイナビニュース(2026-06-29)"), 0.0) block("iris2", [59, 60, 61], iris2) def door(T, E): fly = (T(63, S(63) - 0.8), T(64, 0.25)) return (dassen(BG + "扉.jpg", fly[0] + 0.05, fly[1] - 0.05, words="開けて……。", word_style="top:60px;font-size:120px", src_note=GEM) + paper(tag("残る壁") + '
' + qline("残る壁は、下げ膳", T(62, 0.3), size=52) + line("食べ終わったお皿を、洗い場まで運ぶ仕事", T(62, 2.0), size=30, weight=500) + card("mi", inkl("バックヤードに行くには、/扉を開けられないといけない", T(63, 0.4), 0.045), T(63, 0.15), "見立て ・ エイイチ", w=880, anim="wipe") + card("hb", "扉は、体当たりで開ける", T(64, 0.5), "ハコブくん", w=500, botsu=E(64) - 0.6, style="font-size:30px") + '
', 0.0, flights=[fly])) block("door", [62, 63, 64], door) def door2(T, E): lab = lambda txt, t: f'
{ink(txt, t, 0.05)}
' seg = lambda txt, w, bg, fg, t: (f'
{txt}
') return paper(tag("扉を通らない手") + '
' + line("求められるのは、調理場と客席の仕切り", T(65, 0.4), size=34, weight=700) + line("形は、地域の決まりや保健所の判断で変わる", T(65, 3.4), size=26, weight=500, style="color:#5a564f") + '
' + '
' + f'
{lab("洗い場側", T(66, 1.0))}
{lab("両側から取り出せる棚", T(66, 1.8))}
{lab("客席側", T(66, 1.0))}
' + '
' + seg("調理場", 300, "#cfc8ba", "#22201c", T(66, 1.2)) + seg("棚", 300, "#22201c", "#f5f3ee", T(66, 2.6)) + seg("ロボット", 300, "#ece9e2", "#22201c", T(66, 4.4)) + '
' + '
' + card("mi", inkl("現場設計だね。/直接、洗い場まで行けたら最高", T(67, 0.4), 0.05), T(67, 0.15), "見立て ・ エイイチ", w=760, anim="wipe") + line("新しい店や改装のときに、通り道ごと設計する", T(68, 0.8), size=30, weight=700) + '
' + src("出どころ:食品衛生法の施設基準(例:那覇市・北九州市の基準)", T(65, 0.3)), 0.0) block("door2", [65, 66, 67, 68], door2) # ================= 7 まとめ ================= SUM_CSS = """@keyframes gather { from { opacity:0; transform: translate(var(--dx),var(--dy)) rotate(var(--r)); } to { opacity:1; transform: none; } }""" def summ(T, E): row = lambda b, mid, dx, dy, r, t: (f'
{b}{mid}
') b3 = lambda txt, t: card("hb", txt, t, None, w=290, botsu=t + 0.25, style="font-size:22px;padding:10px 12px;white-space:nowrap") return ('' + paper(tag("残っている壁") + '
' + row("店の作り", "扉・通路・下げ台", 420, 420, 8, T(70, 3.0)) + row("仕事の分け方", "置くのは人、運ぶのはロボット", 300, -60, -6, T(70, 4.2)) + row("調整", "保健所・地域の決まり", -420, 180, 10, T(70, 5.4)) + f'

' f'{ink("決めていたのは、店の人が自分で扱えるように、", T(71, 0.3), 0.05)}
{land("作業と店の作りを、切り直せるか。", T(71, 3.2), "font-size:50px")}

' + f'
{b3("明日の朝、僕にも来る", T(72, 1.4))}{b3("料理も僕が置く", T(72, 1.8))}{b3("扉は体当たり", T(72, 2.2))}
' + card("mi", inkl("全部やらなくていい", T(73, 0.3), 0.06), T(73, 0.1), "エイイチ", w=440, anim="wipe", style="padding:10px 30px") + '
', 0.0)) block("sum", [69, 70, 71, 72, 73], summ) # ================= 8 残った問い(ボタン3回目・自分で押す) ================= def rest(T, E): return paper(tag("残った問い") + '
' + card("mi", inkl("この辺の問題を解決する力を持つ人が、/重宝されそう", T(74, 0.4), 0.045), T(74, 0.15), "見立て ・ エイイチ", w=860, anim="wipe") + qline("店とロボットのあいだに立つ役", T(75, 0.4), size=46) + f'
{ink("名前も、求人の枠も、", T(75, 3.8), 0.06)}{land("まだない", T(75, 5.2), "font-size:64px;font-weight:900")}
' + card("mi", inkl("大型のお店から、スタートしたい", T(77, 0.3), 0.06), T(77, 0.1), "エイイチ", w=620, anim="wipe") + card("hb", '考察ノートの全文
pixelstomotors.com / LOG389
', T(79, 0.3), "サイトの記事", w=600) + '
', 0.0) block("rest", [74, 75, 76, 77, 78, 79], rest) def ask(T, E): return (paper(tag("あなたの店では") + '
' + qline("あなたの店で", T(80, 0.2), size=56) + qline("ロボットが止まったら、", T(80, 1.0), size=56) + qline("誰が戻しますか。", T(80, 2.2), size=56) + '
' + card("mi", inkl("それが一番えらい", T(82, 0.3), 0.06), T(82, 0.1), "エイイチ", w=440, anim="wipe") + '
', 0.0) + btn(T(80, S(80) + 0.3), T(81, -0.3), T(81, 1.0), who="自分で押す")) block("ask", [80, 81, 82], ask) # ================= 9 アウトロ ================= block("outro", [83, 84, 85], None, video=("src/day124_crop.mp4", 18.0, "png/ovl/outro.png")) assert [i for b in BLOCKS for i in b["sents"]] == list(range(N)), "場面の文の番号が抜けている・重なっている" # ================= ハコブくん ================= # 表情は narration.py の表情が基本。ここは文の途中で替える所: (文, 文の頭から何秒, 何秒間, 表情) HK_FACE = [ (3, 0.0, 2.0, "doubt"), (16, S(16) + 0.1, 1.4, "dot"), # 固まる(ボタン1回目) (22, 0.0, 4.5, "joy"), (27, S(27) - 0.5, 3.0, "x"), # コケる (28, 0.0, 2.0, "x"), (35, 0.0, 6.0, "think"), (43, 0.0, 1.5, "trouble"), (47, 0.0, 4.0, "surprise"), (48, S(48) + 0.1, 1.4, "dot"), # 固まる(ボタン2回目) (60, 0.0, 2.0, "surprise"), (63, 0.0, 4.0, "trouble"), (80, S(80) + 0.2, 1.3, "dot"), # 固まる(自分で押す) ] HK_FACE = [(A(i, a), A(i, a) + d, f) for i, a, d, f in HK_FACE] # 体ごとの動き: jump=驚いて全身で飛び出す / fall=前のめりにコケる(up で起き上がる) / reflex=のけぞる HK_MOVES = [ dict(kind="fall", t0=A(27, S(27) - 0.5), t1=A(29, 0.0), dur=0.5), dict(kind="jump", t0=A(60, 0.0), dur=1.9), ] HK_ALPHA = [(A(35, 0.0), tl.end(35), 0.3), # 暗い場面では薄く (A(27, S(27) + 0.15), A(28, 0.65), 0.0), # 最後の動作の絵にはハコブくんが描いてあるので、重ねない (A(63, S(63) - 0.75), A(64, 0.2), 0.0)] # 扉の絵も同じ # ================= エイイチ ================= # (文, 文の頭から何秒, 姿) 1腕組み 2うなずく 3指さす 4首をかしげる 5ひらめく 6のけぞって驚く 7半目でツッコむ 8吹き出して笑う EI_POSE = [ (0, 0.0, 1), (2, 0.5, 4), (3, 0.0, 7), (4, 1.0, 8), (5, 0.0, 1), (8, 0.0, 2), (9, 0.0, 1), (10, 0.0, 3), (12, 0.0, 4), (13, 0.3, 6), (14, 0.0, 1), (16, S(16) + 0.1, 3), (17, 0.8, 2), (18, 0.0, 1), (19, 0.0, 2), (20, 0.0, 3), (21, 0.0, 2), (22, 0.0, 5), (23, 0.5, 8), (24, 0.0, 1), (25, 0.0, 4), (27, 0.0, 4), (27, S(27) - 0.4, 6), (28, 0.0, 7), (29, 0.6, 2), (30, 0.0, 1), (32, 0.0, 3), (33, 0.0, 2), (34, 0.0, 1), (35, 0.0, 2), (36, 0.0, 1), (39, 0.0, 4), (40, 0.0, 2), (41, 0.0, 3), (42, 0.5, 8), (43, 0.0, 3), (44, 0.0, 1), (45, 0.0, 3), (47, 0.0, 5), (48, 0.0, 2), (48, S(48) + 0.1, 3), (49, 0.8, 2), (50, 0.0, 3), (51, 0.0, 4), (52, 0.0, 2), (54, 0.0, 3), (55, 0.0, 4), (56, 1.0, 6), (57, 0.0, 1), (59, 0.0, 2), (60, 0.0, 6), (61, 0.0, 8), (62, 0.0, 1), (63, 0.0, 3), (64, 0.0, 7), (65, 0.0, 1), (67, 0.0, 3), (68, 0.0, 2), (69, 0.0, 2), (72, 0.8, 8), (73, 0.0, 3), (74, 0.0, 3), (75, 0.0, 2), (76, 0.0, 4), (77, 0.0, 5), (78, 0.0, 1), (79, 0.0, 2), (80, 0.0, 1), (81, 0.0, 6), (82, 0.0, 8), (83, 0.0, 2), ] EI_POSE = sorted((A(i, a), p) for i, a, p in EI_POSE) # 置き方の替え: (開始, 終了, 置き方)。hide=出さない / big=暗い場面で大きく光らせる EI_PLACE = [ (A(6), tl.end(7), "hide"), (A(35), tl.end(35), "big"), ] # ================= 効果音 ================= # (文, 文の頭から何秒, 音, ナレーションより何dB) SE = [ (3, 0.3, "se_pop", -8), (22, 3.0, "se_pop", -8), (31, 1.6, "se_ding", -10), (44, 4.6, "se_pop", -10), (11, 1.4, "se_pop", -12), (2, 0.1, "se_whoosh", -10), (3, 0.15, "se_whoosh", -14), (13, 0.3, "se_whoosh", -10), (13, 99, "se_pop", -12), (16, S(16) + 0.2, "se_pop", -12), (17, -0.25, "se_ding", -10), (27, S(27) - 0.2, "se_whoosh", -12), (27, S(27) + 0.05, "se_pop", -6), (28, 0.7, "se_whoosh", -14), (28, 0.9, "se_pop", -12), (43, 0.05, "se_pop", -8), (47, S(47) + 0.1, "se_pop", -8), (48, S(48) + 0.2, "se_pop", -12), (49, -0.25, "se_ding", -10), (60, 0.0, "se_rise", -10), (63, S(63) - 0.8, "se_whoosh", -10), (64, 0.25, "se_whoosh", -14), (64, 1.6, "se_pop", -12), (72, 1.65, "se_pop", -14), (72, 2.05, "se_pop", -14), (72, 2.45, "se_pop", -14), (80, S(80) + 0.3, "se_pop", -12), (81, -0.3, "se_ding", -10), ] SE = [s for s in SE if s[1] != 99] # 一覧の画像に撮る時刻(場面の頭からの秒)。書かない場面は最後の0.4秒前 def _rel(b, i, off=0.0): return tl.start(i) - _tl.start(b["sents"][0]) + off SHEET = {} for _b in BLOCKS: _end = _tl.end(_b["sents"][-1]) - _tl.start(_b["sents"][0]) - 0.4 SHEET[_b["name"]] = [_end] _B = {b["name"]: b for b in BLOCKS} SHEET["hook"] = [_rel(_B["hook"], 1, 5.0), _rel(_B["hook"], 2, 1.5), SHEET["hook"][0]] SHEET["easy"] = [_rel(_B["easy"], 32, 1.5), _rel(_B["easy"], 31, 1.8), SHEET["easy"][0]] SHEET["door2"] = [_rel(_B["door2"], 66, 6.0), SHEET["door2"][0]] SHEET["bring"] = [_rel(_B["bring"], 13, 2.0), _rel(_B["bring"], 16, S(16) + 0.6), SHEET["bring"][0]] SHEET["last"] = [_rel(_B["last"], 27, S(27) - 0.1), _rel(_B["last"], 27, S(27) + 1.0), SHEET["last"][0]] SHEET["who2"] = [_rel(_B["who2"], 48, S(48) + 0.6), SHEET["who2"][0]] SHEET["iris2"] = [_rel(_B["iris2"], 60, 0.8), SHEET["iris2"][0]] SHEET["door"] = [_rel(_B["door"], 63, S(63) - 0.2), SHEET["door"][0]] SHEET["ask"] = [_rel(_B["ask"], 80, S(80) + 0.6), SHEET["ask"][0]] SHEET["title"] = [2.0]