| name | scroll-scrub-hero |
| description | Use when building a premium "wow" hero section where scrolling drives a video animation — object assembles or explodes as the user scrolls. Full end-to-end pipeline: generate start + end frames with Nano Banana 2, create a 7-second video with lumalabs.ai or Higsfield/Kling 3.0, then implement scroll-scrub with GSAP ScrollTrigger in Next.js (or vanilla HTML). Trigger on "вау эффект на скролле / wow scroll hero / scroll-driven video / привяжи видео к скроллу / сделай анимацию при скролле / 3D hero / scroll scrub / две картинки в видео / image to video hero / lumalabs / Kling hero". Also invoke after scroll-stop-prompter when the user has 2 images ready and asks "что дальше", or after website-intelligence when Build Brief mentions scroll-driven animation. |
Scroll-Scrub Hero
Полный пайплайн создания премиального hero-эффекта: скролл управляет video.currentTime, объект «разбирается» или «собирается» перед глазами пользователя. Паттерн из пайплайна Джека («$10K / $12K сайты»), применён на проекте ROCKMESH (сетка стеклопластиковая, Гален).
Результат: sticky-scroll секция на 300vh, внутри — <video> с GSAP ScrollTrigger scrub. На мобильном — autoplay loop fallback.
Требования
| Инструмент | Зачем | Ссылка |
|---|
| Nano Banana 2 (внутри Higsfield) | Генерировать START и END кадры | https://higsfield.ai → Nano Banana 2 |
| lumalabs.ai ИЛИ Higsfield + Kling 3.0 | Создать видео из 2 кадров | https://lumalabs.ai / https://higsfield.ai |
| GSAP + ScrollTrigger | Scroll-scrub в браузере | npm i gsap |
| @studio-freight/lenis | Плавный скролл | npm i @studio-freight/lenis |
| Next.js 16 ИЛИ vanilla HTML | Основа проекта | — |
Пайплайн — 5 шагов
ШАГ 1 — Генерация START кадра (Nano Banana 2)
Открыть Higsfield → Nano Banana 2.
Технические требования (ОБЯЗАТЕЛЬНО в каждом промпте):
- Aspect ratio:
16:9
- Resolution: минимум 2K (1K = «PowerPoint ребёнка»)
- Background:
clean white background
no objects touching the edges (нужен воздух вокруг)
- Запускай batch = 4 и выбирай лучший
Структура промпта START FRAME:
[описание объекта в исходном/целом/собранном состоянии].
Professional product photography style, soft directional studio lighting, gentle ground shadow.
Clean white seamless background. 16:9, 2K resolution. No objects touch the edges of the frame.
Пример (ROCKMESH — стеклопластиковая сетка):
Photorealistic top-down isometric view of a premium ROCKMESH fiberglass composite mesh panel,
showing the woven grid structure with visible resin-coated nodes, laid flat on a clean surface.
Professional product photography style, soft directional studio lighting, gentle ground shadow.
Clean white seamless background. 16:9, 2K resolution. No objects touch the edges of the frame.
Пример (AnyVan — переезды):
Photorealistic side view of an open-back moving van, parked. Friendly modern design, rounded edges.
Soft top-down studio lighting, gentle ground shadow.
Clean white seamless background. 16:9, 2K. No objects touch edges.
ШАГ 2 — Генерация END кадра (Nano Banana 2)
Правило: тот же объект, тот же ракурс/освещение — но трансформирован по твоей метафоре.
Метафоры:
- «Взорвано» → компоненты летят наружу
- «Разобрано» → части разложены по местам
- «Собрано из хаоса» → хаос → порядок
- «Переродилось» → старое → новое
Структура промпта END FRAME:
Same [объект], same angle and lighting — but now [описание трансформации].
[Детали компонентов видны, если нужно].
Same clean white seamless background, matching studio lighting. 16:9, 2K. No edges touched.
Пример (ROCKMESH — разборка на 4 компонента):
Same ROCKMESH mesh panel, same isometric angle — but now exploded into its four material components:
glass fiber rovings (top-left), epoxy resin matrix (top-right), quartz sand coating (bottom-left),
polymer binding nodes (bottom-right). Parts float mid-air in a dramatic product teardown layout.
Same clean white seamless background, identical studio lighting. 16:9, 2K. No edges touched.
Пример (AnyVan — вылетающая мебель):
Same van, same angle — but furniture, boxes, a houseplant and packing supplies are bursting out
of the open back in an explosive arc, frozen mid-air.
Clean white seamless background, soft studio lighting matching start frame. 16:9, 2K, no edges.
ШАГ 3 — Создание видео из 2 кадров
Два варианта — выбери один.
Вариант A: lumalabs.ai (рекомендую попробовать первым)
Что это: AI-видео сервис, умеет делать плавный переход между двумя изображениями.
Шаги:
- Открыть https://lumalabs.ai
- Выбрать режим «Image to Video» (или «Start/End Frame»)
- Загрузить START кадр как первый (start image)
- Загрузить END кадр как последний (end image)
- Промпт для движения:
Smooth product teardown animation, objects gently separate and float outward, cinematic slow motion, no text, no camera shake
- Длительность: 5–7 секунд
- Скачать .mp4
Когда лучше lumalabs:
- Нет аккаунта Higsfield
- Нужен быстрый тест
- Объекты статичные (не нужен кинематографический флоу)
Вариант B: Higsfield + Kling 3.0 (основной, даёт лучшее качество)
Шаги:
- Открыть Higsfield → «Create Video»
- Модель: Kling 3.0
- Загрузить START как первый кадр
- Загрузить END как последний кадр
- Промпт:
Smooth 7-second transition. [описание движения]. Cinematic, no text, no camera shake.
- Настройки:
multi-shot: OFF
enhance: OFF
- Длительность: 7 секунд, 1080p
- Скачать .mp4
ВАЖНО: multi-shot OFF и enhance OFF — это стандарт из пайплайна Джека. С ними лучше.
ШАГ 4 — Реализация scroll-scrub в Next.js
4.1 Структура секции
Паттерн: sticky-scroll. Секция 300vh, внутри — sticky контейнер 100vh.
'use client'
import { useRef, useEffect } from 'react'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
export default function HeroSection() {
const sectionRef = useRef<HTMLElement>(null)
const videoRef = useRef<HTMLVideoElement>(null)
const textRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const video = videoRef.current
const section = sectionRef.current
if (!video || !section) return
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
video.autoplay = true
video.loop = true
return
}
const isMobile = window.matchMedia('(max-width: 768px)').matches
if (isMobile) {
video.autoplay = true
video.loop = true
return
}
ScrollTrigger.create({
trigger: section,
start: 'top top',
end: 'bottom bottom',
scrub: 0.5,
onUpdate: (self) => {
if (video.duration) {
video.currentTime = self.progress * video.duration
}
},
})
gsap.to(textRef.current, {
opacity: 0,
y: -40,
scrollTrigger: {
trigger: section,
start: 'top top',
end: '30% top',
scrub: true,
},
})
return () => ScrollTrigger.getAll().forEach(t => t.kill())
}, [])
return (
<section ref={sectionRef} style={{ height: '300vh' }}>
<div className="sticky top-0 h-screen overflow-hidden bg-white">
{/* Видео — занимает весь экран */}
<video
ref={videoRef}
src="/video/hero.mp4"
muted
playsInline
preload="auto"
className="absolute inset-0 w-full h-full object-contain"
/>
{/* Тёмный градиент слева для читаемости текста */}
<div className="absolute inset-y-0 left-0 w-1/2
bg-gradient-to-r from-[#0F0F0F] to-transparent" />
{/* Текст + CTA */}
<div ref={textRef}
className="absolute left-8 top-1/2 -translate-y-1/2 z-10 max-w-lg">
<span className="text-green-500 text-sm font-semibold uppercase
tracking-widest mb-4 block">
● В наличии — отгрузка сегодня
</span>
<h1 className="font-display font-extrabold
text-[clamp(28px,4vw,56px)] leading-[1.1] text-white mb-4">
Название бренда<br/>
<span className="text-[#FF6B00]">Tagline</span>
</h1>
<div className="flex gap-4 flex-wrap">
<a href="tel:+7XXXXXXXXXX"
className="bg-[#FF6B00] text-white px-6 py-3 rounded-lg
font-semibold hover:bg-[#FFB280] transition-colors">
Позвонить
</a>
<a href="https://wa.me/79XXXXXXXXX"
className="border border-white/20 text-white px-6 py-3 rounded-lg
font-semibold hover:border-white/60 transition-colors">
WhatsApp
</a>
</div>
</div>
</div>
</section>
)
}
4.2 Тултипы компонентов (опционально)
Показываются по мере «разборки» — каждый в свой момент скролла.
function Tooltip({ label, detail, className, appearAt }: {
label: string; detail: string; className: string; appearAt: number
}) {
const ref = useRef<HTMLDivElement>(null)
const sectionRef = useRef<HTMLElement | null>(null)
useEffect(() => {
gsap.fromTo(ref.current,
{ opacity: 0, y: 10 },
{
opacity: 1, y: 0,
scrollTrigger: {
trigger: sectionRef.current,
start: `${appearAt * 100}% bottom`,
end: `${(appearAt + 0.08) * 100}% bottom`,
scrub: true,
},
}
)
}, [])
return (
<div ref={ref} className={`opacity-0 pointer-events-none absolute z-20 ${className}`}>
<div className="bg-white/10 backdrop-blur-md border border-white/20
rounded-xl px-4 py-3 text-sm">
<div className="text-[#FF6B00] font-semibold mb-0.5">{label}</div>
<div className="text-white/70 text-xs">{detail}</div>
</div>
<div className="absolute w-px h-8 bg-white/30 left-1/2 -bottom-8" />
</div>
)
}
Пример расстановки тултипов (ROCKMESH):
| Позиция | label | detail | appearAt |
|---|
top-[15%] left-[38%] | Эпоксидная смола | Связующее: аминный отвердитель | 0.35 |
top-[10%] right-[15%] | Стеклянные нити | Высокомодульный ровинг | 0.45 |
bottom-[15%] left-[30%] | Кварцевый песок | Покрытие для адгезии в бетоне | 0.55 |
top-[45%] right-[10%] | Узел вязки | Полимерный фиксатор | 0.65 |
4.3 Lenis — плавный скролл (инициализация)
'use client'
import { useEffect } from 'react'
import Lenis from '@studio-freight/lenis'
export function SmoothScroll({ children }: { children: React.ReactNode }) {
useEffect(() => {
const lenis = new Lenis()
function raf(time: number) {
lenis.raf(time)
requestAnimationFrame(raf)
}
requestAnimationFrame(raf)
return () => lenis.destroy()
}, [])
return <>{children}</>
}
4.4 Разместить видео
cp ~/Downloads/hero-video.mp4 ./public/video/hero.mp4
Видео в public/video/hero.mp4 → src="/video/hero.mp4" в компоненте.
ШАГ 5 — Vanilla HTML (альтернатива Next.js)
Если не нужен фреймворк — использовать скилл 3d-website-builder для vanilla HTML. Он генерирует готовый index.html + js/scroll.js с тем же паттерном.
Или сделать вручную:
<section id="hero" style="height: 300vh; position: relative;">
<div style="position: sticky; top: 0; height: 100vh; overflow: hidden; background: white;">
<video id="hero-video" src="assets/hero.mp4"
muted playsinline preload="auto"
style="width:100%; height:100%; object-fit:contain;">
</video>
</div>
</section>
<script>
const video = document.getElementById('hero-video')
const section = document.getElementById('hero')
window.addEventListener('scroll', () => {
const rect = section.getBoundingClientRect()
const total = section.offsetHeight - window.innerHeight
const scrolled = Math.max(0, -rect.top)
const progress = Math.min(1, scrolled / total)
if (video.duration) video.currentTime = progress * video.duration
}, { passive: true })
</script>
Порядок действий (чеклист)
Anti-patterns
- ❌ 1K разрешение — «ребёнок добрался до PowerPoint». Только 2K+
- ❌ Разные ракурсы на START и END — видео не склеится
- ❌ Текст в промпте для Kling — замыливается в анимации
- ❌ multi-shot ON / enhance ON в Higsfield — портит результат
- ❌ Без
preload="auto" — видео не загружается заранее, scrub лагает
- ❌ ScrollTrigger на мобильном без fallback — scroll-scrub работает плохо на touch
- ❌
<img> вместо <video> — для scroll-scrub нужно именно <video> с currentTime
- ❌ Объекты у краёв кадра — нужен воздух, иначе веб-вёрстка обрезает
Связанные скиллы
scroll-stop-prompter — только генерация промптов для Nano Banana 2 (шаги 1–2 этого скилла)
3d-website-builder — берёт готовое видео и собирает vanilla HTML MVP (альтернатива шагу 4)
ship-to-vercel — деплой готового Next.js проекта
imagegen-frontend-web — генерация ассетов для остальных секций лендинга