Skill #14 · Instagram multi-slide ads via Remotion

creative-carousel

Карусели для Instagram/Meta из 5-10 слайдов. Принципиально через Remotion (TSX-шаблоны), а не через Gemini Image — потому что в TSX баги с кириллицей, CTA-pill и softbox-in-frame невозможны by construction. 9 типов слайдов, 5 готовых шаблонов, $0 на рендеринг.

Путь
~/.claude/skills/creative-carousel/
Триггеры
сделай карусель, instagram carousel, многослайдовый пост, swipe-карусель, build carousel
Зависит от
Node 18+, npm, Remotion CLI, GOOGLE_API_KEY (только для planning)
Пэйрится с
creative-poster (брендбук + референсы), creative-orchestrator, copywriter

Что делает простыми словами

Карусель в Instagram — это серьёзный формат с большим количеством копирайта. 5-10 слайдов, человек свайпает, каждый слайд = одна мысль (хук → проблема → продукт → стата → процесс → доказательство → CTA). Конверсия выше чем у single-image.

Скилл делает ровно одну вещь: получает бриф, придумывает план карусели (через Gemini-текст), а потом рисует каждый слайд через Remotion CLI — никакой Gemini Image в боевом флоу. На выходе: PNG-секвенция, ZIP для аплоада в Ads Manager и multi-page PDF для клиентского ревью.

Почему Remotion, а не Gemini Image

Изначально (v1) карусели рисовались через Gemini Image. И там вылезали стабильные баги, которые QA-петля не всегда ловила:

БагЧто былоПочему Remotion решает
₸ → Т substitution Gemini подменял символ тенге на латинскую «Т» из-за токенизации В TSX — это просто Unicode-символ в CSS, он не подвергается image-генерации
CTA-pill Модель упорно дорисовывала кнопку «Подробнее» / «Купить» даже когда явно просили не делать В TSX-шаблонах кнопок-компонентов просто нет. Невозможно отрендерить то, чего нет
Softbox-in-frame На product-шотах ловила в кадр софтбоксы, штативы, аппаратуру В Product.tsx подгружается только заранее обработанное product-фото через <Img staticFile()/>
Brand logo random Дорисовывала левые лого или искажала бренд-марк TSX рисует только текст + бренд-цвета. Лого Meta добавит сам через page connection
Truncation Длинный headline обрезался посередине слова Строки приходят из JSON и рендерятся как есть через CSS
Главная мысль: в Remotion-роуте все эти классы багов невозможны by construction. Это не «снижение вероятности» — это полное устранение. QA-петля становится опциональной.

Per-project Remotion app

Каждый проект получает свою копию Remotion-приложения:

~/video-projects/<project>/carousel-remotion/
├── package.json
├── tsconfig.json
├── remotion.config.ts
├── src/
│   ├── index.ts
│   ├── Root.tsx               ← 3 композиции: 4:5, 1:1, 9:16
│   ├── CarouselSlide.tsx      ← dispatcher: type → нужный компонент
│   ├── slides/
│   │   ├── Hook.tsx
│   │   ├── Problem.tsx
│   │   ├── Product.tsx        ← <Img staticFile()/> для продуктового фото
│   │   ├── Stats.tsx
│   │   ├── List.tsx
│   │   ├── Process.tsx
│   │   ├── Comparison.tsx
│   │   ├── Proof.tsx
│   │   ├── Faq.tsx
│   │   └── CtaSwipe.tsx
│   └── lib/brand.ts           ← бренд-конфиг, автопатчится из brand.yaml
└── public/photos/             ← референсные фото, копируются на init

Зачем своя копия на проект: можешь менять TSX-шаблоны под конкретный бренд (например для apparatus сделать Product.tsx с другой раскладкой) — это не сломает другим проектам.

Workflow

init_project.py plan.py Approval gate render_slides.py pack.py present.py (auto)

init_project.py запускается ОДИН раз на проект. Дальше — только plan → render → pack.

Шаг 1 — bootstrap (один раз на проект)

python ~/.claude/skills/creative-carousel/scripts/init_project.py \
  --project apparatus

# Что происходит:
# 1. Копирует remotion_template/ → ~/video-projects/apparatus/carousel-remotion/
# 2. Копирует все references/*.{jpg,png} проекта в public/photos/
# 3. Читает project's brand.yaml и переписывает src/lib/brand.ts
# 4. npm install (~30-60 сек, ОДИН раз)

Шаг 2 — план карусели

python ~/.claude/skills/creative-carousel/scripts/plan.py \
  --project apparatus \
  --topic "Запусти УВТ-кабинет за 30 дней" \
  --template product_launch \
  --slide-count 7 \
  --output plan.json

# Один вызов gemini-2.5-flash, ~$0.0001, ~5 секунд
# На выходе — JSON с заполненными слайдами:
# { "slide_n": 3, "type": "stats", "headline": "30 дней",
#   "subhead": "до окупаемости", "visual_hint": "huge centered number" }

Шаг 3 — Approval gate

До рендера юзер видит план. Тут можно: (a) approve как есть, (b) поправить JSON руками, (c) перегенерить с другим брифом. Только после OK скрипт идёт рендерить.

Шаг 4 — рендер слайдов

python ~/.claude/skills/creative-carousel/scripts/render_slides.py \
  --project apparatus \
  --plan plan.json \
  --output-dir slides/ \
  --aspect 4:5 \
  --product-photo ref_eswt_t9.jpg

# Под капотом: на каждый слайд — `npx remotion still`
# ~5-10 секунд на слайд, 7 слайдов → под минуту
# По окончании авто-вызывает present.py (GR-1)

Шаг 5 — упаковка

python ~/.claude/skills/creative-carousel/scripts/pack.py \
  --output-dir slides/ \
  --zip ~/Desktop/apparatus_carousel.zip \
  --pdf ~/Desktop/apparatus_carousel_preview.pdf

# ZIP — для аплоада в Meta Ads Manager
# PDF — multi-page, по слайду на страницу, для клиентского ревью

9 типов слайдов

ТипUse caseВизуальный рецепт
hookСлайд 1 — scroll-stopperОгромный headline (80-100pt), один маленький визуал максимум
problemСлайд 2-3 — больЭмпатичная фраза, muted-палитра, ощущение «before»
productHero-шот аппарата/услугиПродукт 60-70% кадра, чистый градиент бренд-цвета
statsБольшая цифра (ROI/окупаемость/доход)ОДНА огромная цифра (200pt+), tiny label снизу
listFeatures/benefits01/02/03 нумерованный список, brief items
process3-4 шага «как работает»Горизонтальный stepper со стрелками и иконками
comparisonA/B (before/after, with/without)50/50 split с чётким контрастом
proofОтзыв с цифрамиБольшая кавычка, italic-quote, атрибуция
faqQ&A — снимает возражениеQuestion как headline + reassuring answer
cta_swipeПоследний слайд — invitationBold action text, НИКАКОЙ кнопки

Полный спек — в справочнике scene/slide-типов.

5 готовых шаблонов

ШаблонСлайдыКогда
product_launchhook → problem → product → stats → process → proof → cta_swipeЗапуск нового продукта/аппарата B2B (дефолт для медтехники)
sale_promohook → stats → comparison → list → cta_swipeАкция / спецпредложение / распродажа
case_studyhook → problem → process → stats → proof → cta_swipeКейс одного клиента — глубокий разбор
educationalhook → list → process → faq → cta_swipeОбразовательный пост — учим чему-то полезному
comparison_vshook → comparison → list → stats → cta_swipeСравнение: ваш продукт vs альтернативы

Можно либо --template product_launch, либо --slide-types hook,product,stats,cta_swipe руками.

Внутренности

Скрипты

ФайлЧто делает
scripts/init_project.pyOne-time bootstrap: копирует remotion_template/, фотки, патчит brand.ts, npm install
scripts/plan.pyБриф + topic + template → один вызов gemini-2.5-flash → JSON-план (слайд за слайдом)
scripts/render_slides.pyГлавный воркхорс: на каждый слайд из плана зовёт npx remotion still с props
scripts/pack.pyPNG-секвенция → ZIP + многостраничный PDF
scripts/present.pyHTML preview с scroll-snap, thumbnails, lightbox и payload-сайдбаром (GR-1)
scripts/db.pyCRUD по carousel_decks + carousel_slides

Hard constraints (невозможны by construction)

Что Remotion-роут гарантирует автоматически:
  • NO CTA button — в TSX нет компонентов кнопок
  • NO brand logo — рендерится только текст и бренд-цвета
  • NO photo equipment in frame — Product.tsx подгружает только подготовленное фото
  • NO ₸ → Т substitution — Unicode-символ через CSS
  • NO text truncation — строки из JSON, рендер as-is
  • NO PROFIT-pill/ribbon — каждый тип слайда имеет фиксированную раскладку
QA-ревью становится опциональным.

Стоимость и скорость

ОперацияЧто используетЦенаВремя
init_project (один раз на проект)npm install$030-60 сек
plan.pygemini-2.5-flash (text)$0.0001~5 сек
render_slides.pynpx remotion still (локально)$05-10 сек/слайд × 7 = ~под минуту
Итого на 7-слайдовую карусель:$0.0001~2 мин (или ~1 если init уже был)

Для сравнения: Gemini Image-роут был ~$0.28 на карусель + регулярные баги, которые QA приходилось ловить.

Output

~/video-projects/<project>/carousel/<deck>/
├── slide_01.png         ← 1080×1350 (4:5) или 1080×1080 (1:1)
├── slide_02.png
├── ...
├── slide_07.png
├── plan.json
├── manifest.json        ← порядок, типы, headlines, ген-метаданные
└── preview.html         ← GR-1 preview, авто-открывается

~/Desktop/apparatus_carousel.zip          ← для Meta Ads Manager
~/Desktop/apparatus_carousel_preview.pdf  ← для клиента

Multi-aspect

Передай --aspect 4:5,1:1 — оба формата отрендерятся параллельно (это две разные композиции в Root.tsx).

Gotchas и tips

init_project.py — обязательный первый шаг. Без него нет carousel-remotion/ папки, и render_slides.py упадёт с «no remotion app found». npm install запускается только при первом init.
Не редактируй remotion_template/ в скилл-папке. Это шаблон, с которого делаются копии. Если нужны проектные правки TSX — правь ~/video-projects/<project>/carousel-remotion/src/slides/....
Approval gate — это специально. Между plan.py и render_slides.py юзер видит JSON. Это даёт возможность поправить headlines/subheads до рендера. Без approval rendering пошёл бы автоматом.
Brand auto-injection. Цвета и шрифты brand.ts автогенерятся из brand.yaml при init. Меняешь палитру в brand.yaml → перезапускаешь init_project.py → все будущие карусели обновятся.
Никакой Gemini Image для слайдов. Это сознательное архитектурное решение. Если в коде где-то всплывает Gemini Image для рендера карусели — это регресс, нужно откатывать.

🎬 Примеры работы

Открой Showcase → carousel — там Полная T608-карусель (7 слайдов, scroll-snap, all slide types: hook/problem/product/stats/process/proof/cta_swipe). Все примеры — реальные production-runs, embedded локально (работают офлайн).

Место в пайплайне

copywriter plan.py (Gemini text) Approval render_slides.py (Remotion) pack.py Meta Ads Manager

Карусель — самостоятельный формат, не часть видео-пайплайна. Использует brand.yaml и референсы того же проекта.

Сверху над carousel может стоять creative-orchestrator с режимом carousel-orchestrate для батчей шаблонов × вариантов.