Два дня назад мы рассказали, как рендерим рекламу AI Budżet кодом: ролики из скриншотов на Python и 30-секундные фильмы на Canvas 2D с синтезированной музыкой, которые пишут агенты Claude Code. Это продолжение, и оно про две перемены. У фильмов появился второй фирменный стиль — карандаш на бумаге вместо мультфильма тушью, — а у фильма о долгах сменился состав: вместо двух выдуманных парней в баре теперь в кадре шаржи на реальных людей, и первый из них — я. Ниже: что к этому подтолкнуло, что мы взяли из чужой методички, чего стоит карандашный вид в коде, как HyperFrames показал себя на ноутбуке с Windows и почему один ребёнок в кадре вывел всю сцену из бара.
Зачем вторая часть
Сначала — откуда вообще эта идея. Рисованные кодом мультфильмы пошли от поста Кевина Нго (Kevin Ngo) «The life of a fruit fly» в X 15 сентября 2026 года: короткий фильм о жизни плодовой мушки, где каждый кадр нарисован программой. По его мотивам Дин Кун (Dean Kuhn) собрал открытый скилл для агентов procedural-film (лицензия MIT) — на нём и стоит наш конвейер фильмов из первой части.
Сразу после первой части к нам попала методичка «Мультики кодом на Opus 5.5» — её написал канал «Продуктивный Совет» к своему ролику «Мой личный аниматор на Opus 5.5: мультики без единого кадра от руки». Хороший повод проверить свой процесс по чужому чек-листу, а не по собственной памяти.
Первая половина проверки успокоила. Большая часть методички — это то, как мы уже работаем: рисунок — это код (JavaScript на canvas), рисунки держатся «на двойках» — 12 рисунков в секунду при 24 fps, — линии «кипят» от генератора случайных чисел с сидом, есть штриховка и строительные линии, звук синтезируется, а каждый его удар попадает в свой кадр, порядок работы — раскадровка → сцены → проверка кадров → звук → рендер, отрендеренные кадры смотрят агенты-критики, а стиль живёт в скилле.
| Практика из методички | У нас до этого | Что сделали |
|---|---|---|
| Рисунок как код (JavaScript, canvas) | Было | — |
| Рисунки «на двойках»: 12/с при 24 fps | Было | — |
| «Кипящие» линии от генератора с сидом | Было | — |
| Штриховка и строительные линии | Было | Выросли в карандашный набор |
| Синтезированный звук, события видны в кадре | Было | — |
| Раскадровка → сцены → кадры → звук → рендер | Было | — |
| Агенты-критики смотрят кадры; стиль в скилле | Было | — |
| Накопительный список граблей | Не было | PITFALLS.md, ~35 строк |
| Явные правила истории | Не было | Четыре правила в скилле |
| Карандашный вид, палитры как роли | Не было | pencil-film, шесть тем |
| Рендерер HyperFrames | Не было | Попробовали: хорошие инструменты, не быстрее |
Ещё три вещи мы делаем сверх методички. Гейт из шести проверок, включая детерминизм, который обязан пройти каждый фильм (о нём — в первой части). Общий модуль персонажей, чтобы герой, которого рисуют двенадцать параллельных агентов сцен, оставался одним и тем же героем в каждом плане. И фактчекинг: всё, что фильм утверждает на экране, сверяется с кодом и вики продукта.
Вторая половина была менее приятной. Не хватало четырёх вещей: накопительного списка граблей внутри скилла, явных правил истории, настоящего карандашного вида с палитрами, заданными как роли, и рендерера HyperFrames. Первые три мы взяли, четвёртый попробовали.
Файл граблей и четыре правила истории
За пять фильмов мы успели заплатить за некоторые уроки дважды, потому что они жили в транскриптах сессий, а не в скилле. Исправление (коммит ABA-632 в репозитории продукта) нарочито скучное: файл PITFALLS.md на 32 строки вида «симптом → причина и исправление», собранных со всех пяти фильмов. Агент читает его в начале каждого фильма и дописывает после сдачи. Несколько строк для примера.
События, которые не влезают в своё окно. Раскадровка просит N событий «на восьмые», и никто не проверяет, что N восьмых нот действительно помещаются во время, отведённое плану. Теперь это считается до того, как пишется сцена.
Ключевой чип высотой 13–16 px на телефоне. Статусный чип, ради которого существует весь план, прекрасно читается в кадре шириной 1080 пикселей и не читается на настоящем телефоне. Исправление — лупа над чипом.
Хвостик реплики через лицо. Хвостик указывает на говорящего, а прямая от облачка ко рту случайно проходит через лицо другого персонажа.
Пути Windows, съеденные экранированием. Путь D:\Work\tools\films, вставленный в строку JavaScript, превратился в D:\Work, табуляцию, «ools», перевод страницы и «ilms» — потому что \t и \f это escape-последовательности.
Пуш с текстом «50 PLN». Уведомление в фильме говорит «50 PLN», а не «50 zł». В польском фильме это выглядит странно, но именно это отправляет настоящее приложение, а фильм показывает продукт таким, какой он есть.
Правила истории — четыре строки. Один поворот, на 35–45 % длины. Последние ~3 секунды — статичный постер. Кадр 0 никогда не пустой. До 15 секунд — одна сцена, от 20 секунд — сцены цепочкой. Ничего нового для любого, кто монтирует видео, но записанное в скилл, это перестаёт быть делом вкуса в каждой отдельной сессии.
Карандашный набор
Второй фирменный стиль — отдельный набор, pencil-film. «Карандаш» оказался не текстурой, а списком маленьких конкретных привычек. Карандаш отрывается от бумаги. Замкнутый контур проскакивает собственное начало — так рука замыкает круг. Рядом с основной линией идёт второй, более тонкий эскизный проход. Сама линия — сужающаяся лента с зерном. Тени — штриховка по светлой бумаге, а не заливка. Есть следы ластика и полустёртые линии-призраки, а строительные линии гаснут, когда рисунок встал на место.
Цвет задаётся ролью, а не значением. Сцена никогда не просит «оранжевый» — она рисует «линией», «мягким», «акцентом» и «тёплым», а тема сопоставляет этим ролям цвета. Тем шесть — notebook, kraft, chalk, blueprint, neon и mystic, — и переключение между ними занимает один вызов.
Больше всего нам нравится почерк. Текст не набирается рукописным шрифтом, а пишется: штрих за штрихом, с видимым движением карандаша. Для этого нужны однострочные шрифты, где каждая буква — путь для пера, а не контур для заливки, поэтому мы взяли шрифты Hershey из общественного достояния, от Национального бюро стандартов США (NBS), — Script 1-stroke и Sans 1-stroke. Польских букв в них нет, поэтому ą ę ć ń ó ś ź ż ł собираются из базового глифа и штриха знака, который пишется в том же проходе. Одну букву мы нарисовали вручную: у оригинальной рукописной «z» есть петля вниз, и в «zł» она читалась как «ʒł». У новой «z» петли нет.
Для крупных заголовков постера мы оставили Caveat (шрифт под лицензией OFL) — там контурный шрифт просто смотрится лучше. В постер вклеивается настоящая PNG-иконка приложения, а не её нарисованная имитация. А новый проект — одна команда: new-film.cjs <slug> --theme notebook --seconds 12.
HyperFrames — честно
HyperFrames — консольный рендерер от HeyGen (npm-пакет hyperframes, версия закреплена на 0.8.111). Он покадрово перематывает остановленный таймлайн GSAP и делает скриншоты страницы, а наш canvas просто рисует по полученному времени — это ровно наш контракт сцены.
Методичка обещала 11–15 секунд рендера на 12 секунд видео на MacBook с M3. На нашем ноутбуке с Windows вышло около 80 секунд: захват скриншотов идёт примерно со скоростью 8 кадров в секунду, плюс кодирование. С -q standard -w 6 мы опустились до ~45 секунд; меньше воркеров — медленнее, а не быстрее. Так что быстрее нашего собственного рендерера на Playwright + ffmpeg он не оказался. Зато это хороший инструментарий: lint, check, снапшоты, контактные листы и сведение звука идут в комплекте.
Одну ловушку стоит знать. snapshot --at округляет время до 30 fps. Поэтому наше событие на 13,25 с требует --at 13.29, чтобы увидеть тот рисунок, который действительно стоит на экране в этот момент.
Свои лица
Первую настоящую работу карандашный стиль получил на фильме о долгах — «Oddam piętnastego» («Верну пятнадцатого»). Сюжет прежний: друг занимает 50 zł «до пятнадцатого», а приложение напоминает тому, кто дал в долг, за три дня до срока и на следующий день после. Только кредитору — никогда другу. Поменялось, кто в кадре. Кредитор теперь — шарж на меня, Михала, а подруга, которая занимает «до пятнадцатого», — Кася, шарж на мою жену. Есть и короткое камео — наш сын.
Метод — лист сходства: референсное фото рядом с рисунком плюс лицо в нескольких выражениях. Фото существует только на листе и никогда не попадает в фильм. Всё остальное — обратная связь от человека короткими раундами, и их стоит перечислить, потому что именно туда ушло время.
Борода прошла путь от пятнистой заливки «гравием» до карандашной штриховки по направлению роста волос. Потом стала короче и аккуратнее, с отдельными небольшими усами. Ширина лица ходила туда-обратно не один раз. Глаза стали карими, а потом чуть уже.
Дольше всего делались волосы Каси. Первая версия — плотный «парик» из локонов. Вторая — длинные волнистые ленты, которые читались как щупальца. Третья, та, что в фильме, — большая округлая масса кудрей-пружинок. Её кофту сделали холоднее и темнее, чтобы она не сливалась с моей кремовой рубашкой там, где мы стоим рядом.
Новый состав без переписывания сцен
В фильме двенадцать файлов сцен, и ни один не пришлось менять ради нового состава. Модуль персонажей сохранил имена функций и API — это интерфейс, через который две системы обмениваются данными автоматически, без выгрузок в Excel и копирования руками. Полное определение →: CAST.kuba по-прежнему рисует «друга» — просто теперь это Кася. Каждая сцена, которая его вызывает, подхватила её без изменений.
Поменялся текст на экране, потому что в польском есть грамматический род. «У каждого есть такой приятель» стало «Każdy ma taką kumpelę.» — в женском роде. «Напомнить ему?» стало «Przypomnieć jej?…», «Может, сам помнит…» — «Może sama pamięta…», а заголовок пуша — «Dług za 3 dni: Kasia». В её репликах теперь звучит моё имя: „Michał, pożycz 50 zł. Oddam piętnastego!”.
Ребёнок в кадре — значит, без пива
Как только рядом со стопкой монет появился ребёнок, бар перестал работать. Ребёнок рядом с алкоголем в рекламе выглядит плохо, а рекламные платформы проверяют такое сочетание строже. Поэтому бар стал кафе — кофе, лимонад, витрина с пирожными, — а мальчик получил розовое мороженое.
В кафе вылезла и ошибка рисунка в объятии. Рука Каси была нарисована перед мной, а не вокруг меня. Исправление — обрезать её руку моим силуэтом, чтобы рука проходила за моей спиной и на дальнем плече была видна только ладонь.
Сдача: громкость и две ложные тревоги
Однопроходный loudnorm с I=-14:TP=-1.5 дал −12,2 LUFS с пиком +0,7 dBFS — громко и с клиппингом. Двухпроходный loudnorm (сначала измерить, потом применить с linear=true) плюс alimiter попал ровно в −14,0 LUFS и −1,5 dBFS.
Проверка синхронизации пометила два события как сдвинутые: одно на 169 мс, другое на 45 мс. Обе тревоги ложные: карточка или рука начинают въезжать в зону измерения до удара, а сам удар приходится точно на кадр события. Все остальные события — в пределах 2 мс.
Результат и какой стиль когда
Версий две, польская и английская, обе по 30 секунд, 1080×1920 при 24 fps. Английская начинается с «Everyone has that one friend», в долг берут €50, монеты — биметаллические по 1 €, а пуш использует настоящий английский текст приложения: «You lent EUR 50 — repayment due soon». Саундтрек взят из версии тушью: границы планов те же, и все 51 событие совпадают.
Теперь у нас два стиля и простое правило выбора. Тушь — для 30-секундных историй с персонажами и экранами приложения. Карандаш — для коротких роликов «посчитай число», а с этого фильма — ещё и для комедии с персонажами и реальными лицами.
Всё это по-прежнему код в репозитории продукта: его можно просмотреть, воспроизвести и проверить на соответствие тому, что приложение делает на самом деле. Попробовать AI Budżet можно на ai-budget.pl или в Google Play. Если вам нужен такой же видеоконвейер для вашего продукта — ролики из скриншотов, процедурные фильмы или ваша собственная команда, нарисованная в рекламе, — напишите нам: development@mi-code.pl.
Частые вопросы
- Можно ли поместить реальных людей в рекламу, нарисованную кодом?
- Да, в виде шаржей и с согласия этих людей. Мы работаем по листу сходства: референсное фото рядом с рисунком и лицо в нескольких выражениях. Фото есть только на листе и никогда не попадает в фильм, а сходство доводится короткими раундами правок — борода, ширина лица, глаза, волосы.
- HyperFrames рендерит быстрее, чем Playwright и ffmpeg?
- У нас — нет. Методичка обещала 11–15 с на 12 с видео на MacBook с M3; на ноутбуке с Windows вышло около 80 с, после настройки (-q standard -w 6) — около 45 с. Это не быстрее нашего рендерера на Playwright и ffmpeg, зато HyperFrames даёт хорошие инструменты: lint, check, снапшоты, контактные листы и сведение звука.
- Как сохранить единство персонажей, если сцены пишут двенадцать параллельных агентов?
- Персонажей не рисует ни одна сцена — их рисует общий модуль персонажей, а сцены только вызывают его. Поэтому смена состава — это правка одного модуля: CAST.kuba сохранил имя и API, но теперь рисует Касю, и двенадцать файлов сцен подхватили её без изменений.
- Зачем агенту файл с граблями?
- Потому что уроки прошлых фильмов жили в транскриптах сессий, и мы платили за них снова. В PITFALLS.md 32 строки «симптом → причина и исправление» из пяти фильмов — от слишком мелкого чипа интерфейса до путей Windows, съеденных \t и \f. Агент читает его в начале каждого фильма и дописывает новые строки после сдачи.