Из сборки игры — трейлер 1080p и три вертикальных ролика по одному сценарию. Программа сама проходит игру по сценарию нажатий, записывает геймплей, монтирует, ставит подписи, музыку и звуки и выравнивает громкость. Ниже — настоящий результат на нашей детской игре «Светляндия».
Слева — сырая запись из сборки игры (снята программой, без звука). Справа — готовый трейлер из этих записей.
Первые 1–2 секунды у каждого свои. Подписи стоят выше нижних 20% кадра и левее правой колонки кнопок — их не закроет интерфейс ленты.
Лучший моментвесь пруд вспыхивает · 17.9 с
Вопрос«Зажжёшь все фонарики?» · 20.8 с
До → послетёмный сад и сад в огнях · 18.8 с
Клипы с отметками начала и конца, кадрирование, подписи, переходы, музыка, звуки и три вертикальных ролика. Правка заказчика — это правка этого файла и перезапуск.
{ "project": "Светляндия — трейлер и 3 вертикальных ролика", "fps": 30, "style": { "accent": "#ffd54a", "text": "#ffffff", "outline": "#170f35", "box": "#6a3cc8", "card_bg": ["#0a1838", "#2b3a78"] }, "logo": "client/logo.png", "sources": { "garden": "capture/garden_portrait.mp4", "pond": "capture/pond_portrait.mp4", "aurora": "capture/aurora_portrait.mp4" }, "audio": { "music": { "auto": {"bpm": 100, "melody": "svet", "seed": 3}, "volume": -5, "fade_in": 0.3, "fade_out": 1.8 }, "sfx_events": { "volume": -9, "min_gap": 0.07, "map": { "tap": ["sfx/tap_1.wav", "sfx/tap_2.wav", "sfx/tap_3.wav", "sfx/tap_4.wav", "sfx/tap_5.wav"], "lamp": {"file": "sfx/lamp.wav", "volume": 4}, "zone": {"file": "sfx/zone.wav", "volume": 4}, "buy": "sfx/buy.wav", "combo": {"file": "sfx/combo.wav", "volume": 3}, "crack": "sfx/crack.wav", "hatch": {"file": "sfx/hatch.wav", "volume": 4}, "coin": "sfx/coin.wav", "ui": {"file": "sfx/ui.wav", "volume": -4} } }, "loudness": -14, "true_peak": -1.5 }, "contact_sheet": {"every": 2.0}, "outputs": { "log": "out/montage_log.json", "trailer": { "file": "out/trailer_16x9_1080p.mp4", "size": [1920, 1080], "font_sizes": {"cap": 82, "hook": 96}, "segments": [ { "src": "garden", "in": 0.0, "out": 1.9, "hold": 0.6, "frame": {"fit": "blur", "place": 0.68}, "fade_in": 0.5, "captions": [{"text": "Помоги бабушке\nзажечь *сад*", "pos": "left", "from": 0.3}] }, { "src": "garden", "in": 2.1, "out": 4.9, "frame": {"fit": "blur", "place": 0.68}, "transition": "fade", "tdur": 0.35, "captions": [{"text": "Тапай —\nлови *светлячков*", "pos": "left"}] }, { "src": "garden", "in": 5.4, "out": 8.4, "frame": {"fit": "blur", "place": 0.32}, "transition": "slideleft", "tdur": 0.35, "sfx": [{"file": "sfx/whoosh.wav", "at": -0.25, "volume": -12}], "captions": [{"text": "Зажигай\n*фонарики*", "pos": "right"}] }, { "src": "garden", "in": 12.4, "out": 15.5, "frame": {"fit": "crop", "focus": [0.5, 0.43], "push": 0.12}, "transition": "fadewhite", "tdur": 0.3, "captions": [{"text": "Комбо *ЯРКО ×3*!", "pos": "top", "style": "hook", "pop": true, "from": 1.1}] }, { "src": "garden", "in": 15.5, "out": 18.9, "frame": {"fit": "blur", "place": 0.68}, "transition": "fade", "tdur": 0.3, "captions": [{"text": "Сад засиял —\nидём *дальше*", "pos": "left", "from": 0.4}] }, { "src": "pond", "in": 0.0, "out": 2.4, "frame": {"fit": "blur", "place": 0.32}, "transition": "fadeblack", "tdur": 0.5, "captions": [{"text": "Новое место —\n*новые фонарики*", "pos": "right", "from": 0.3}] }, { "src": "pond", "in": 2.4, "out": 6.6, "frame": {"fit": "crop", "focus": [0.5, 0.4], "push": 0.08}, "transition": "fade", "tdur": 0.35, "captions": [{"text": "*Шесть* волшебных мест", "pos": "top", "style": "hook", "pop": true}] }, { "src": "aurora", "in": 0.0, "out": 4.9, "frame": {"fit": "blur", "place": 0.68}, "transition": "fade", "tdur": 0.35, "captions": [{"text": "От пруда\nдо *северного\nсияния*", "pos": "left", "from": 0.3}] }, { "src": "pond", "in": 13.4, "out": 17.2, "frame": {"fit": "blur", "place": 0.32}, "transition": "slideleft", "tdur": 0.35, "sfx": [{"file": "sfx/whoosh.wav", "at": -0.25, "volume": -12}], "captions": [{"text": "Выводи\n*светящихся\nдрузей*", "pos": "right", "from": 0.3}] }, { "src": "pond", "in": 18.6, "out": 23.0, "frame": {"fit": "blur", "place": 0.68}, "transition": "fade", "tdur": 0.35, "captions": [{"text": "Наряжай\nгероя", "pos": "left", "from": 0.3}] }, { "src": "aurora", "in": 5.6, "out": 9.6, "frame": {"fit": "crop", "focus": [0.5, 0.4], "push": 0.1}, "transition": "fade", "tdur": 0.4, "captions": [{"text": "Звёздный причал *ждёт*", "pos": "top", "style": "hook", "pop": true, "from": 1.9}] }, { "type": "end", "dur": 4.2, "bg": {"src": "pond", "at": 6.2, "blur": 36, "dim": 0.42}, "title": "Светляндия", "sub": "Айдл-кликер для детей", "cta": "Играй в браузере телефона", "transition": "fade", "tdur": 0.5, "sfx": [ {"file": "sfx/impact.wav", "at": 0.15, "volume": -6}, {"file": "sfx/sparkle.wav", "at": 0.9, "volume": -8} ], "fade_out": 0.6 } ] }, "verticals": [ { "file": "out/vertical_1_luchshiy_moment.mp4", "hook": { "type": "best_moment", "src": "pond", "in": 5.95, "out": 7.55, "text": "Весь пруд\n*сияет!*", "pos": "upper", "focus": [0.5, 0.32], "push": 0.14, "sfx": "sfx/impact.wav", "sfx_volume": -8 }, "segments": [ { "src": "garden", "in": 2.1, "out": 5.2, "transition": "fadewhite", "tdur": 0.25, "captions": [{"text": "Тапай и лови\n*светлячков*", "pos": "scene"}] }, { "src": "garden", "in": 5.4, "out": 8.4, "transition": "fade", "tdur": 0.3, "captions": [{"text": "Фонарик разгоняет\n*темноту*", "pos": "scene"}] }, { "src": "garden", "in": 12.4, "out": 16.4, "transition": "fade", "tdur": 0.3, "captions": [ { "text": "Комбо *ЯРКО ×3*!", "pos": "scene", "style": "hook", "pop": true, "from": 1.1, "to": 3.2 } ] }, { "src": "aurora", "in": 0.6, "out": 4.9, "transition": "fadeblack", "tdur": 0.4, "captions": [{"text": "*6 мест* — от сада\nдо северного сияния", "pos": "scene", "from": 0.2, "to": 2.1}] }, { "type": "end", "dur": 3.6, "bg": {"src": "pond", "at": 6.2, "blur": 36, "dim": 0.42}, "title": "Светляндия", "sub": "Айдл-кликер для детей", "cta": "Играй в браузере телефона", "transition": "fade", "tdur": 0.5, "sfx": [ {"file": "sfx/impact.wav", "at": 0.15, "volume": -6}, {"file": "sfx/sparkle.wav", "at": 0.9, "volume": -8} ], "fade_out": 0.6 } ] }, { "file": "out/vertical_2_vopros.mp4", "hook": { "type": "question", "src": "garden", "in": 2.2, "out": 3.9, "text": "Зажжёшь\n*все фонарики?*", "dim": 0.5, "sfx": "sfx/pop.wav", "sfx_volume": -4 }, "segments": [ { "src": "garden", "in": 3.0, "out": 8.4, "transition": "fade", "tdur": 0.25, "captions": [ {"text": "Тапай — свет копится", "pos": "scene", "to": 2.6}, {"text": "Хватило — *зажигай!*", "pos": "scene", "from": 2.8} ] }, { "src": "garden", "in": 10.4, "out": 15.5, "transition": "fade", "tdur": 0.3, "captions": [{"text": "Ещё быстрее —\nкомбо *ЯРКО ×3*", "pos": "scene", "pop": true, "from": 2.9}] }, { "src": "garden", "in": 15.5, "out": 19.0, "transition": "fade", "tdur": 0.3, "captions": [{"text": "Получилось! *Сад сияет*", "pos": "panel", "box": true, "pop": true, "from": 1.2}] }, { "src": "pond", "in": 0.2, "out": 3.4, "transition": "fadeblack", "tdur": 0.4, "captions": [{"text": "А впереди —\n*Кувшинковый пруд*", "pos": "scene", "from": 0.3}] }, { "type": "end", "dur": 3.6, "bg": {"src": "pond", "at": 6.2, "blur": 36, "dim": 0.42}, "title": "Светляндия", "sub": "Айдл-кликер для детей", "cta": "Играй в браузере телефона", "transition": "fade", "tdur": 0.5, "sfx": [ {"file": "sfx/impact.wav", "at": 0.15, "volume": -6}, {"file": "sfx/sparkle.wav", "at": 0.9, "volume": -8} ], "fade_out": 0.6 } ] }, { "file": "out/vertical_3_do_posle.mp4", "hook": { "type": "before_after", "dur": 2.0, "labels": ["ДО", "ПОСЛЕ"], "before": {"src": "garden", "at": 2.3, "roi": [0, 0.12, 1, 0.5]}, "after": {"src": "garden", "at": 15.45, "roi": [0, 0.12, 1, 0.5]}, "sfx": "sfx/whoosh.wav", "sfx_at": 0.0, "sfx_volume": -8 }, "segments": [ { "src": "garden", "in": 13.0, "out": 15.6, "transition": "fadewhite", "tdur": 0.25, "captions": [{"text": "Зажги весь сад", "pos": "scene"}] }, { "src": "pond", "in": 13.4, "out": 17.3, "transition": "fade", "tdur": 0.3, "captions": [ {"text": "Открывай коконы —\nтам *новые друзья*", "pos": "scene", "to": 1.6}, {"text": "Новый друг!", "pos": "scene", "style": "hook", "pop": true, "from": 2.1} ] }, { "src": "pond", "in": 18.6, "out": 23.2, "transition": "fade", "tdur": 0.3, "captions": [{"text": "Пижама, узор —\n*наряжай героя*", "pos": "scene"}] }, { "src": "aurora", "in": 5.6, "out": 9.4, "transition": "fadeblack", "tdur": 0.4, "captions": [{"text": "И зажигай\n*новые места*", "pos": "scene"}] }, { "type": "end", "dur": 3.6, "bg": {"src": "pond", "at": 6.2, "blur": 36, "dim": 0.42}, "title": "Светляндия", "sub": "Айдл-кликер для детей", "cta": "Играй в браузере телефона", "transition": "fade", "tdur": 0.5, "sfx": [ {"file": "sfx/impact.wav", "at": 0.15, "volume": -6}, {"file": "sfx/sparkle.wav", "at": 0.9, "volume": -8} ], "fade_out": 0.6 } ] } ] } }
node capture.mjs capture_garden.json — Chromium без звука проходит игру: тапы, покупки, вкладки. Время в игре идёт ровно по 1/30 с на кадр.python3 montage.py scenario.json — трейлер, 3 вертикальных, листы кадров и журнал.Правка 1: что поменяли в scenario.json
outputs.trailer.segments.0.captions.0.text:
было: "Ночь опустилась\nна бабушкин сад…"
стало: "Помоги бабушке\nзажечь *сад*"
outputs.trailer.segments.10.captions.0.from:
было: 0.4
стало: 1.9
outputs.verticals.1.hook.text:
было: "Сможешь зажечь\n*все фонарики?*"
стало: "Зажжёшь\n*все фонарики?*"
$ python3 montage.py scenario.json
Монтажёр трейлеров 1.0 · сценарий scenario.json (1c8f4eb845825405) · шрифт Inter
▶ trailer: 12 сегментов, 38.60 с, 1920×1080
сегменты готовы (из кэша 12, заново 0)
звук: -14.0 LUFS, пик -1.4 dBTP, эффектов 147
✓ out/trailer_16x9_1080p.mp4: 38.60 с, 1920×1080, h264/aac, -14.0 LUFS, 19.2 МБ, 146.8 с работы
▶ v1: 6 сегментов, 17.85 с, 1080×1920
сегменты готовы (из кэша 6, заново 0)
= out/vertical_1_luchshiy_moment.mp4: без изменений, не пересобираю (0.0 с)
▶ v2: 6 сегментов, 20.75 с, 1080×1920
сегменты готовы (из кэша 6, заново 0)
звук: -14.0 LUFS, пик -1.5 dBTP, эффектов 95
✓ out/vertical_2_vopros.mp4: 20.77 с, 1080×1920, h264/aac, -14.0 LUFS, 8.5 МБ, 23.1 с работы
▶ v3: 6 сегментов, 18.75 с, 1080×1920
сегменты готовы (из кэша 6, заново 0)
= out/vertical_3_do_posle.mp4: без изменений, не пересобираю (0.0 с)
Готово за 176 с. Журнал: out/montage_log.json
Кадр каждые 2 с (трейлер) и 1,5 с (вертикальные) с отметкой времени — для согласования с заказчиком без просмотра всего ролика.
$ node capture.mjs capture_garden.json $ node capture.mjs capture_pond.json $ node capture.mjs capture_aurora.json ✓ capture/garden_portrait.mp4 — 1080×1920, 24.567 с, 737 кадров, событий игры 128, работа 157.5 с ✓ capture/garden_landscape.mp4 — 1920×1080, 24.567 с, 737 кадров, событий игры 128, работа 85.3 с ✓ capture/pond_portrait.mp4 — 1080×1920, 26.733 с, 802 кадров, событий игры 104, работа 176.7 с ✓ capture/aurora_portrait.mp4 — 1080×1920, 12.6 с, 378 кадров, событий игры 55, работа 81.2 с $ python3 synth.py sfx sfx/ ✓ 19 эффектов в sfx/ $ python3 montage.py scenario.json Монтажёр трейлеров 1.0 · сценарий scenario.json (1c8f4eb845825405) · шрифт Inter ▶ trailer: 12 сегментов, 38.60 с, 1920×1080 сегменты готовы (из кэша 0, заново 12) звук: -14.0 LUFS, пик -1.4 dBTP, эффектов 147 ✓ out/trailer_16x9_1080p.mp4: 38.60 с, 1920×1080, h264/aac, -14.0 LUFS, 19.2 МБ, 216.9 с работы ▶ v1: 6 сегментов, 17.85 с, 1080×1920 сегменты готовы (из кэша 0, заново 6) звук: -14.0 LUFS, пик -1.5 dBTP, эффектов 82 ✓ out/vertical_1_luchshiy_moment.mp4: 17.87 с, 1080×1920, h264/aac, -14.0 LUFS, 7.9 МБ, 88.0 с работы ▶ v2: 6 сегментов, 20.75 с, 1080×1920 сегменты готовы (из кэша 0, заново 6) звук: -14.0 LUFS, пик -1.5 dBTP, эффектов 95 ✓ out/vertical_2_vopros.mp4: 20.77 с, 1080×1920, h264/aac, -14.0 LUFS, 8.5 МБ, 77.7 с работы ▶ v3: 6 сегментов, 18.75 с, 1080×1920 сегменты готовы (из кэша 0, заново 6) звук: -13.9 LUFS, пик -1.5 dBTP, эффектов 68 ✓ out/vertical_3_do_posle.mp4: 18.77 с, 1080×1920, h264/aac, -13.9 LUFS, 6.9 МБ, 72.8 с работы Готово за 473 с. Журнал: out/montage_log.json Весь путь (сборка → запись → звуки → монтаж): 16 мин 20 с
| Файл | Длит. | Кадр | Звук |
|---|---|---|---|
| Трейлер | 38.6 с | 1920×1080, H.264 High | -14.0 LUFS |
| Вертикальный 1 | 17.9 с | 1080×1920 | -14.0 LUFS |
| Вертикальный 2 | 20.8 с | 1080×1920 | -14.0 LUFS |
| Вертикальный 3 | 18.8 с | 1080×1920 | -13.9 LUFS |
Музыка и звуки рассчитаны нашим кодом (мелодия — из самой игры), чужих сэмплов нет. Громкость выровнена двухпроходным loudnorm.