scroll-world: скилл, который собирает лендинг-3D-мир, управляемый скроллом

· 2 мин чтения
agent-skills claude-code codex design prompt-engineering
📂 Исходный код на GitHub

Скилл, превращающий любой бренд в 3D-мир-лендинг, который прокручивается: связные изометрические диорамы, бесшовные перелёты камеры и scroll-scrub движок на vanilla JS, MIT-лицензия.

scroll-world: скилл, который собирает лендинг-3D-мир, управляемый скроллом

Сайт, который выглядит так, будто летишь сквозь мир: при прокрутке камера сначала висит над сценой снаружи, потом ныряет внутрь неё, вылетает и без единого монтажного склея уходит в следующую. Графика сгенерирована AI, видео тоже, а скролл не управляет объектами — он управляет временем. Именно так работают скролл-страницы продуктов Apple, и именно этот приём воспроизводит репозиторий scroll-world: 9,5 тысяч звёзд, MIT-лицензия, JavaScript.

Собственно говоря, scroll-world — не библиотека и не фреймворк, а агентный скилл: папка с файлом SKILL.md и несколькими reference-файлами, которые кладутся в skills-каталог Claude Code, Codex или любого агента, понимающего этот формат. Агент сам проводит интервью, сам генерирует ассеты и сам собирает страницу.

Что делает scroll-world

Скилл собирает лендинг-«мир» для любой отрасли или бренда. Механика жёстко зафиксирована: непрерывный полёт сквозь мир, без склеек. Визуальный слой состоит из двух частей:

  • Сцены-диорамы — изометрические миниатюры в стиле low-poly пластилина с тёплым светом и эффектом tilt-shift. По умолчанию генерируются моделью gpt_image_2 на Higgsfield (или через встроенный image_gen в CLI от OpenAI, если он есть — та же модель, но списывается с подписки ChatGPT, а не с кредитов).
  • Видеопролёты камеры — ролики, в которых камера ныряет в сцену, а потом улетает к следующей. Рендерятся моделью Seedance 2.0.

Дальше всё это склеивается в нечто вроде сайта логистической компании Emons, только про вашу тему.

Ключевая особенность: скилл framework-agnostic. Движок в references/scrub-engine.js — самодостаточный vanilla JS, который строит собственный DOM и подключает свой CSS в переданный контейнер. Он одинаково заезжает в статический HTML, Next.js, Vue или страницу, отдаваемую Python-сервером. Ценность скилла не в фреймворке, а в пайплайне, шаблонах промптов и методе сшивки швов.

Как проходит сборка

Вызов скилла разворачивается в три крупные фазы.

1. Интервью. Агент задаёт открытый вопрос о теме (без выдуманного списка отраслей — это смещает пользователя), уточняет бренд-кит (импорт с сайта, переданные вручную цвета или предложенные агентом), арт-дирекшн и стиль камеры. Стиль арт-дирекшна превращается в общий style preamble, который дословно повторяется в каждом промпте — именно он делает мир цельным. Отдельно и обязательно спрашиваются мобильная версия и бюджет: сметка показывается до того, как что-то сгенерировано.

2. Генерация ассетов. На каждую сцену — один стил, на каждую сцену — один ролик ныряния, плюс ролики-коннекторы, которые связывают соседние сцены. Коннекторы генерируются из реальных отрендеренных кадров соседей, а не из исходных картинок.

3. Сборка страницы. Конфигурационный скролл-движок играет всю цепочку как один полёт, а на телефонах автоматически отдаёт портретные версии и постеры.

Стиль камеры выбирается из трёх вариантов, и это не техническая деталь, а «характер» фильма: полёт сквозь мир с постоянной сменой ракурсов, один непрерывный проход вперёд без откатов или зафиксированное изометрическое скольжение.

Главное правило: швы должны совпадать кадр в кадр

Это единственное, что рушит или делает результат, и SKILL.md ставит его на первое место с формулировкой «прочитай раздел про бесшовную цепочку до того, как сгенерируешь хоть один коннектор».

Суть проблемы: каждая генерация рендерит сцену чуть иначе. Если коннектор заканчивается свежим рендером «кухонной диорамы», а следующий ролик ныряния начинается со своего собственного рендера той же кухни, кадры не совпадут — и на стыке будет щелчок. Лечится передачей точных пикселей:

Для каждого коннектора между dive_i и dive_{i+1}:
  start-image = ПОСЛЕДНИЙ кадр, извлечённый из dive_i
  end-image   = ПЕРВЫЙ кадр, извлечённый из dive_{i+1}

Кадры вытаскиваются из отрендеренного видео, а не из исходных стилов:

ffmpeg -sseof -0.15 -i dive_i.mp4      -frames:v 1 -q:v 2 dive_i_last.png
ffmpeg -ss 0      -i dive_next.mp4     -frames:v 1 -q:v 2 dive_next_first.png

Теперь dive_i.end == connector.start и connector.end == dive_{i+1}.start — шов совпадает с обеих сторон. Seedance при этом приземляется не пиксель в пиксель, а близко (замерено 27,5 dB против 31,6 dB на старте), поэтому движок дополнительно делает короткий кроссфейд в несколько кадров. Но полагаться только на кроссфайд нельзя: большой скачок контента им не спрячешь.

Две архитектуры камеры

A. Непрерывный проход вперёд. Одна камера, которая только скользит вперёд от первой сцены к последней. Ролики генерируются строго последовательно: --start-image следующего ролика — это реальный последний кадр предыдущего. Коннекторов нет вообще, ноги и есть маршрут. Минус — параллелить нельзя, работа идёт дольше.

B. Ныряние плюс воздушный коннектор. Камера ныряет в сцену, коннектор вытягивает её вверх и переносит к следующему острову. Выглядит эффектнее на карте-диораме, но разворачивает направление движения на каждом шве. На реалистичном «от первого лица» это читается как перемотка назад, поэтому такая архитектура рекомендована только для миниатюрной эстетики.

Отдельно SKILL.md описывает «грамматику камеры»: движение внутри одного ролика может быть любым — орбита, боковой трек, подъём коптера, — но каждый ролик обязан заканчиваться спокойным ровным дрейфом вперёд, а следующий — продолжать этот дрейф. Развороты фатальны только на швах, а не внутри клипа. И есть нюанс про скролл: посетитель может крутить вверх, поэтому каждое движение играется ещё и задом наперёд.

Модели, деньги и требования

Видео-модель выбирается не по вкусу, а по способности удержать шов: ролик должен принимать --start-image, а коннектор — ещё и --end-image. Всё, у чего вход только референсный, физически не может продолжить сцену.

Модель Start / End image Примечания
seedance_2_0 (по умолчанию) да / да Полная цепочка, 1080p, фильтр NSFW чувствительный
kling3_0 да / да 720p без параметра разрешения, звук выключать флагом, разрешённый запасной вариант при срабатывании фильтра
seedance_2_0_mini да / да Дешёвый черновик 720p, сохраняет frame-locking
minimax_hailuo да / нет Самый дешёвый пробник, но коннекторы не собрать

Правило одно на всю цепочку: одна модель на все ролики. Смена модели посередине сохраняет позиционную непрерывность, но сдвигает характер картинки, и это читается как едва заметный щелчок.

Про деньги автор пишет честно. Цепочка из N сцен — это N стилов плюс 2N−1 видео, плюс около 15% запаса на перегенерации, и мобильная цепочка удваивает число видео. При шести сценах в 1080p получается около 27 долларов на Monid — там Seedance 2.0 тарифицируется поклипово, токенами по формуле ширина × высота × 24 × секунды, и это без подписки и без сгорания баланса. На кредитах Higgsfield та же работа обошлась бы примерно в 32 доллара по помесячному плану. Замерено на живых деньгах: ролик 1080p на 8 секунд — около 2,99 доллара, коннектор на 5 секунд — около 1,87; на 720p — 1,21 и 0,76; на 480p — 0,28 и 0,35. Скилл сверяет баланс со сметкой и прямо говорит, если денег не хватит, а цену заменяет на кредиты Higgsfield.

Требования честно перечислены: CLI Monid с ключом и балансом как основной бэкенд видео, аутентифицированный CLI Higgsfield для картинок и как запасной биллер, ffmpeg и ffprobe, Python 3 с Pillow для мобильных холстов. CLI от OpenAI — опционально: если он есть, стили можно генерировать image_gen и платить подпиской ChatGPT.

Отдельная деталь про точность смет: CLI Higgsfield не отдаёт прайс, поэтому скилл не угадывает. Он сначала генерирует одну картинку и один ролик, сравнивает баланс до и после и экстраполирует на весь прогон.

Скролл-движок и мобильная версия

Движок конфигурационный, и монтируется одной функцией:

mountScrollWorld(document.getElementById('world'), {
  brand: { name: 'Pearl & Co.' },
  diveScroll: 1.3, connScroll: 0.9,
  sections: [
    { id:'farm', label:'The Farms', still:'assets/farm.webp',
      clip:'assets/vid/farm.mp4',
      clipMobile:'assets/vid/farm-m.mp4',
      stillMobile:'assets/farm-m.webp',
      scroll: 1.6, linger: 0.45,
      accent:'#8FB98A', eyebrow:'From leaf to last sip', title:'It starts in the hills.',
      body:'…', tags:['Single-origin','Hand-picked'] }
  ],
  connectors:       ['assets/vid/conn1.mp4','assets/vid/conn2.mp4'],
  connectorsMobile: ['assets/vid/conn1-m.mp4','assets/vid/conn2-m.mp4'],
});

Движок берёт на себя упорядоченную цепочку «ныряние + коннектор», сглаживание скролла через requestAnimationFrame, ленивую подгрузку соседних роликов, кроссфейды на совпавших кадрах, текст секций, рельс маршрута, prefers-reduced-motion и адаптацию под телефон. Настроение сцены задаётся двумя ручками: scroll задаёт, сколько экранов прокрутки длится сцена, а linger (0–1) замедляет камеру в середине ролика ровно в момент, когда читатель дочитывает заголовок, и потом разгоняет её к шву.

Два технических решения стоит знать, потому что на них чаще всего и ломается скролл-видео. Первое: работать надо не с частотой ключевых кадров, а с seekability. Многие статические хостинги и python -m http.server не отдают байтовые диапазоны, из-за чего video.seekable схлопывается в [0,0] и каждое seek упирается в нулевой кадр — видео выглядит замороженным. Надёжный способ — грузить каждый ролик как Blob и играть из in-memory object URL, что скилл и делает. Второе: качество ради плавности ухудшать не надо. Кодировать в нативном 1080p, crf около 20, короткий GOP вместо all-intra и faststart:

ffmpeg -i src.mp4 -an -vf "unsharp=5:5:0.8:5:5:0.0" \
  -c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p \
  -g 8 -keyint_min 8 -sc_threshold 0 -movflags +faststart out.mp4

Мобильная версия — не кроп десктопного ролика. Это вторая цепочка, отрендеренная нативно в 9:16 и склеенная по тем же законам, но уже под вертикальные холсты: 720 ширины, -g 4, crf 23. Отдав кроп вместо неё, вы получите обрезанные по бокам композиции, поэтому SKILL.md разрешает кроп только как явно оговорённую временную меру. Движок при этом телефон готовит всегда: склеивает seek-запросы, держит картинку-постер, пока ролик не отрисовал первый кадр, и игнорирует ресайз, вызванный появлением адресной строки.

Что внутри репозитория

skills/scroll-world/
├── SKILL.md                    процедура, правило шва и грабли
└── references/
    ├── prompts.md              чек-лист интервью и все шаблоны промптов
    ├── pipeline.md             готовые батч-скрипты: generate → frames → connectors → encode
    ├── scrub-engine.js         портативный движок: blob-seek, ленивая загрузка, кроссфейд швов
    ├── index-template.html     минимальная самостоятельная страница, которая монтирует движок
    └── knockout.py             вырезание фона для парящих сцен

Самый ценный файл, если собираетесь делать такое же руками, — SKILL.md. Это плотный документ про грабли, собранные в проде: щелчок на шве из-за использования исходной картинки вместо кадра, зависшее видео из-за отсутствия байтовых диапазонов, лёгкий кроссфейд вместо кадровой подгонки, «не тот объект», NSFW-ложняк на безобидных сценах вроде спальни или бассейна, белый фон из коробки gpt_image_2, параллельные вызовы codex exec, которые делят stdin и потому подвисают, bash 3.2 на macOS без ассоциативных массивов, и циклы по массивам, написанные в zsh, где индексация с единицы.

Как поставить

В Claude Code — как плагин, одной командой:

/plugin marketplace add oso95/scroll-world
/plugin install scroll-world@scroll-world

В Codex и двадцати других агентах — через skills CLI от Vercel:

npx skills add oso95/scroll-world
npx skills add oso95/scroll-world -a codex

Ну и вручную, если хочется просто скопировать папку:

git clone https://github.com/oso95/scroll-world
cp -R scroll-world/skills/scroll-world ~/.claude/skills/

Кому это пригодится

scroll-world — редкий случай, когда агентный скилл продаёт не «фичу в коде», а дизайн-артефакт: упакованный в промпты и скрипты способ сделать дорогую motion-графику, которую иначе пришлось бы заказывать аниматору. Он же честно называет свою цену — десятки долларов и десятки минут ожидания на батче, — что делает его инструментом для запуска, а не для фоновой работы.

Логичный кандидат: продукт, который сам по себе удобно показать как место. Логистика, доставка, производственная цепочка, ремонт, туризм, ресторанный бизнес. Скилл сам подсказывает структуру маршрута — сцены выводятся из цепочки создания ценности субъекта, пять-семь штук работают лучше всего, а последняя обычно отдана главному продукту и призыву к действию.

Лицензия MIT, код на JavaScript, генерируемые ролики в репозиторий не кладутся — они производятся под конкретный проект.

Источник: https://github.com/oso95/scroll-world