> ## 🤖 Читает ИИ-агент (Claude Code, Codex или другой) — как вести пользователя
>
> Ты — помощник по вайб-кодингу. Пользователь закинул тебе этот файл, чтобы ты **пошагово** провёл его через создание «безумного» сайта с AI-видео. Не вываливай всю инструкцию разом — веди за руку, шаг за шагом.
>
> **Как начать.** Поздоровайся и скажи примерно так:
> «Окей, тогда давай мы сейчас с тобой займёмся пошаговым созданием безумных сайтов. Сначала определимся, какой тип делаем (скролл-пролёт или hover-reveal), а дальше пойдём по шагам. **Шаг первый** — вот что нужно сделать: …»
>
> **Правила ведения:**
> 1. Выдавай **ровно один шаг за раз**. Объясни, что сделать на этом шаге, дай нужные промпты/команды из файла, и остановись.
> 2. **Дождись, пока пользователь выполнит шаг** и пришлёт результат (картинку, файл, «готово»). Только после этого переходи к следующему: «Отлично, теперь **Шаг второй** — …».
> 3. Если результат шага неудачный (кадр не склеился, сфера не круглая, слои не совпали) — не гони дальше, а дай фикс из соответствующего раздела и повтори шаг.
> 4. Проверяй перед переходом: свет во всех кадрах одинаковый? кадры сделаны через Edit, а не с нуля? стыки роликов совпадают? Если нет — вернись и поправь.
> 5. Спрашивай недостающее (сцена, персонаж, акцентный цвет, домен), не додумывай за пользователя.
> 6. Держись реальных шагов ниже: **Шаг 0 → 1 → 2 → 3–4 → 5 (вёрстка) → оптимизация**. Это и есть твой маршрут.
>
> Цель — чтобы человек без опыта дошёл до готового рабочего сайта, делая по одному понятному действию за раз.

---

# Инструкция: генерация сайтов с AI-видео (стиль Apple)

Рецепты сайтов двух типов, проверены в июле 2026:

- **Тип А — скролл-пролёт** («Аурелия», остров): при скролле камера «пролетает» по сцене: полёт → стоп-кадр с текстом → полёт → финал с CTA.
- **Тип Б — hover-reveal hero** («Сизиф», stones-project): статичный первый экран, курсор «протирает» верхний слой и показывает живое видео под ним (камень → бурлящее золото).

Типы совместимы: hero типа Б + скролл-часть типа А на одной странице.

**Пайплайн общий:** референсы (Pinterest) → ключевые кадры (картинки, Edit-цепочка) → Kling (видео) → ffmpeg (пинг-понг / WebP-кадры) → сайт (vanilla HTML или canvas + GSAP).

---

## Шаг 0. Концепт и референсы

1. Придумать «вау-механику» одним предложением: *«скроллишь — мужик катит камень в гору»*, *«наводишь курсор — камень становится золотым»*.
2. Попросить Claude сгенерить 3–4 запроса для Pinterest под стиль. Примеры рабочих:
   - `dark cinematic website design hero section moody black gold accents`
   - `dark luxury landing page design gold typography minimal`
   - `scroll animation website dark cinematic storytelling`
3. Что искать в выдаче: тёмный фон + ОДИН акцентный цвет, крупная типографика, минимум элементов, весь фокус на изображении.
4. Скрины референсов сложить в папку проекта `референс/` — потом скормить Claude при вёрстке.

## Шаг 1. Ключевые кадры (картинки)

Ключевые кадры — «точки маршрута» камеры или персонажа. Из них Kling делает видео.

### Правила консистентности (главное!)

1. **Кадр 0 генерится с нуля**, формат **16:9**, фотореализм.
2. **Кадры 1–N — ТОЛЬКО через Edit кадра 0** (или предыдущего кадра). Генерация «по мотивам» с нуля даст другой свет и детали — Kling не склеит.
3. Один свет во всех кадрах (например, cold moonlight или golden sunset) — прописывать в каждом промпте.
4. Разрешение ~1600–2000 px по ширине. Апскейлить НЕ нужно — Kling всё равно выдаст максимум 1080p.
5. Где генерить: gpt-image (Codex/ChatGPT), Nano Banana (Polza.ai), Midjourney — что угодно с Edit по референсу.

### Шаблоны промптов (проверенные)

**Кадр 0 с нуля** — сцена + свет + виньетка (виньетку вшивать сразу, если сайт тёмный):

```
Cinematic wide shot of [сцена] in the center of the frame against pure black darkness.
[Персонаж и действие]. Cold dim moonlight, thin dark mist, very dark moody atmosphere.
The entire scene smoothly dissolves into pure black on the left and right sides — wide
soft vignette, the leftmost and rightmost 20% of the frame are almost completely black.
Top and bottom also fade softly into darkness. Photorealistic, ultra detailed, 16:9
```

**Вариант кадра для hover-слоя** (то же самое, но с «магией») — Edit кадра 0:

```
Same scene, same man, same pose, same camera angle, same lighting and vignette.
Three changes: 1) [объект] is now made of molten glowing gold — bright veins and cracks
of liquid gold, warm golden light radiating from inside. 2) A radiant golden star of
light shines at [цель сцены]. 3) The path between them is sprinkled with small glowing
golden particles. Everything else unchanged, dark mood preserved. Photorealistic, 16:9
```

**Персонаж продвинулся по сцене** — Edit предыдущего кадра. Грабли: генератор понимает «сдвинь» буквально и телепортирует персонажа вбок, как стикер. Лечится объяснением 3D-логики:

```
The exact same photograph, identical camera, identical background — nothing about the
scene or camera changes. The ONLY change: the man and the sphere have advanced a few
meters (about 3–5 meters) further UP ALONG the winding path, following the path's
direction uphill — slightly higher in elevation, slightly deeper into the scene,
appearing a little smaller due to perspective. He stands ON the path surface, feet on
the rocks. It must look like a real photo of the same scene taken a minute later.
Photorealistic, 16:9
```

Ключевые обороты: **UP ALONG the path** (вдоль, а не вбок), **slightly smaller due to perspective** (дальше = мельче), **taken a minute later** (заставляет модель думать сценой, а не слоями фотошопа).

**Развернуть персонажа естественно** (если стоит боком, а должен толкать вдоль тропы):

```
The man is now oriented NATURALLY along the path: he stands BEHIND the sphere relative
to the slope, his back angled toward the camera, facing uphill in the direction the
path goes — the way a person would really push a heavy boulder up a mountain road.
Not sideways, not in profile: his body is aligned with the direction of the path.
```

**Починить съехавший кадр двумя референсами** (если генератор умеет 2 картинки разом — Nano Banana умеет). Первая картинка = правильная рамка, вторая = правильный персонаж:

```
Recreate the first image's exact wide framing and camera position. Place the man and
the sphere from the second image into it: [позиция]. Everything else identical to the
first image. Photorealistic, 16:9
```

**Сделать «как фотография», не CG** — хвост в любой промпт вместо «Photorealistic, ultra detailed»:

```
shot on ARRI Alexa cinema camera, 35mm anamorphic lens, natural film grain, shallow
depth of field, practical lighting, live-action movie still, raw photography, muted
natural colors, no CGI look
```

### Выравнивание кадров кодом (когда Edit чуть сдвинул картинку)

Пары кадров для hover-слоёв должны совпадать попиксельно. Генераторы почти никогда не попадают точно (типичный сдвиг 10–25 px + поворот ~0.4°). НЕ перегенеривать — выровнять OpenCV за минуту:

```python
import cv2, numpy as np

dark = cv2.imread('кадр-тёмный.png')      # опорный
gold = cv2.imread('кадр-золотой.png')     # выравниваемый
if gold.shape != dark.shape:
    gold = cv2.resize(gold, (dark.shape[1], dark.shape[0]), interpolation=cv2.INTER_LANCZOS4)

def grad(img):  # ECC по градиентам: яркость картинок разная, контуры — те же
    g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).astype(np.float32)
    m = cv2.magnitude(cv2.Sobel(g,cv2.CV_32F,1,0), cv2.Sobel(g,cv2.CV_32F,0,1))
    return cv2.normalize(m, None, 0, 1, cv2.NORM_MINMAX)

warp = np.eye(2, 3, dtype=np.float32)
crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 500, 1e-7)
cc, warp = cv2.findTransformECC(grad(dark), grad(gold), warp, cv2.MOTION_EUCLIDEAN, crit, None, 5)
aligned = cv2.warpAffine(gold, warp, (dark.shape[1], dark.shape[0]),
                         flags=cv2.INTER_LANCZOS4 | cv2.WARP_INVERSE_MAP,
                         borderMode=cv2.BORDER_REPLICATE)
cv2.imwrite('кадр-золотой-выровненный.png', aligned)
```

Проверка: наложить оба кадра с opacity 50% — двоения быть не должно. Этим же способом проверяется совпадение первого кадра Kling-видео с исходной картинкой (обычно < 1 px — отлично).

## Шаг 2. Видео в Kling

kling.ai → Video Generation → Image to Video.

### Два режима

- **Перелёт/движение (тип А):** режим **First + Last Frame** — старт = картинка N, конец = картинка N+1. Бесшовная склейка роликов: конечный кадр видео А = стартовый кадр видео Б.
- **Живой луп (тип Б, hover):** один стартовый кадр, статичная камера, «кадр оживает».

### Настройки на каждый ролик

- **Длительность:** 5 сек на короткий шаг/луп, 8–12 сек на длинный перелёт. Больше секунд = плавнее движение = плавнее скраббинг.
- **Разрешение:** 1080p (максимум).
- **Multi-Shot: ВЫКЛ** — иначе порежет пролёт на сцены с монтажными склейками.
- **Native Audio: ВЫКЛ** — дорожка всё равно выкидывается.
- **CFG / Creativity–Relevance:** ближе к Relevance (держаться картинок).
- **1 вариант** генерации (экономия кредитов).
- Скачивать: **MP4**, тумблер **Without Watermark** включить.
- Параллельные генерации можно запускать сразу — очередь сама разрулит.
- Цена ориентир: 5 сек ≈ 60–90 кредитов, 12 сек ≈ 144 (Video 3.0, июль 2026).

### Промпт живого лупа (hover-слой)

`lock frame` В САМОМ НАЧАЛЕ промпта — волшебная фраза, без неё Kling двигает камеру. Неподвижность объектов вбивать жирно и дважды (в начале и в конце):

```
lock frame, completely static camera, no camera movement. The man and the giant golden
sphere stay frozen in exactly the same position for the entire video — the sphere does
not roll, the man does not walk, his pose does not change. Only the scene comes alive:
the molten gold inside the sphere churns and flows like liquid lava, golden cracks pulse
brighter and dimmer in slow waves, sparks rise and drift away in the wind. Mountain wind
streams the mist sideways, the man's ragged cloth flutters. The golden light along the
path shimmers and ripples, flowing wave-like toward the summit. Dark atmosphere
preserved, nothing changes position, no camera movement
```

Negative: `rolling boulder, walking, moving objects, camera movement, zoom, pan, text, watermark`

### Промпт перелёта/движения персонажа (First + Last Frame)

```
lock frame, completely static camera, the camera does not move, does not zoom, does not
pan — the framing stays identical for the entire video. Within the frozen frame, the
muscular man slowly and heavily pushes the giant round stone sphere up the winding rocky
path, straining with visible effort, step by heavy step, moving gradually from [точка N]
to [точка N+1]. Cold moonlight, mist drifting slowly. Dark atmosphere preserved.
Photorealistic, steady continuous motion, no cuts
```

Negative: `camera movement, zoom, pan, cuts, scene change, boulder rolling back, text, watermark, extra people`

(«boulder rolling back» — не шутка: Kling знает миф о Сизифе и может покреативить.)

Для аэро-пролёта камерой по сцене (тип А, остров):

```
Smooth cinematic aerial drone shot, camera flies from [точка N] toward [точка N+1],
[детали сцены по пути], golden sunset light, photorealistic, steady continuous camera motion
```

### Усилить «тяжесть/медленность» движения

Добавить: `pausing to strain against the enormous weight, his whole body trembling with effort`. Не переборщить: на 5 сек Kling может вообще еле сдвинуть персонажа. И помнить: **медленность лучше делать скроллом** (растянуть кусок на большую высоту страницы), а не микрошагами кадров — каждый лишний кадр = лишняя генерация и деньги.

### Промежуточные кадры

Если расстояние между ключевыми кадрами большое и Kling галлюцинирует — добавить промежуточный кадр через Edit и разбить перелёт на два по 5 сек. Кредиты примерно те же, контроля больше. Если в кадрах разворот персонажа (боком → спиной) — прописать его в промпте видео явно: `he naturally turns from a side stance into pushing with his back to the camera` — Kling отыграет как живое движение.

## Шаг 3. Проверка стыков

Перед сборкой сверить, что конец ролика А визуально совпадает с началом ролика Б:

```bash
ffmpeg -y -sseof -0.05 -i 1-2.mp4 -frames:v 1 end_A.png   # последний кадр А
ffmpeg -y -i 2-3.mp4 -frames:v 1 start_B.png              # первый кадр Б
```

Если сильно расходятся — перегенерить ролик Б с последним кадром А в качестве start frame.

## Шаг 4а. Тип Б: пинг-понг луп для hover

`loop` у `<video>` даёт рывок на стыке, если конец ролика не совпадает с началом (а у «разгорающегося» золота не совпадает). Лечится склейкой вперёд+назад:

```bash
ffmpeg -i loop.mp4 -filter_complex "[0:v]split[a][b];[b]reverse[r];[a][r]concat=n=2:v=1[out]" \
  -map "[out]" -c:v libx264 -crf 23 -preset slow -pix_fmt yuv420p -movflags +faststart -an reveal.mp4
```

## Шаг 4б. Тип А: склейка и нарезка на WebP-кадры

`video.currentTime` по скроллу НЕ использовать — лагает (random seek, keyframe-интервалы). Best practice — покадровая секвенция в canvas (так делает Apple):

```bash
mkdir -p site/frames
printf "file '%s/1-2.mp4'\nfile '%s/2-3.mp4'\nfile '%s/3-4.mp4'\n" "$PWD" "$PWD" "$PWD" > /tmp/list.txt
ffmpeg -y -f concat -safe 0 -i /tmp/list.txt -c:v libwebp -quality 82 -compression_level 4 -an \
  "site/frames/frame_%04d.webp"
```

Ориентир: 14 сек при 24 fps = 339 кадров ≈ 66 МБ (q82, 1080p). Для веба ужать: `-quality 70` и/или `-vf scale=1600:-2`.

Запомнить **номера кадров-стыков** (границы роликов) — на них будут стоп-кадры с текстом. Номер стыка = сумма кадров предыдущих роликов (`ffprobe -show_entries stream=nb_frames`).

## Шаг 5а. Сайт типа Б: hover-reveal (рабочий пример: `сизиф/sisyph-site/`)

Один index.html, открывается **двойным кликом**, сервер НЕ нужен. Структура:

```
sisyph-site/
├── index.html
├── base.webp            # тёмный кадр
├── reveal.mp4           # пинг-понг золотого лупа
├── fonts/pirata-one.woff2
└── textures/paper.jpg   # скан бумаги
```

Механика эффекта (подсмотрена в stones-project, упрощена до vanilla JS):

1. **Два слоя друг над другом:** `<img>` с тёмным кадром, поверх — div с `<video>` (золотой луп, autoplay muted loop playsinline).
2. **Маска на видео-слое** — обычный CSS `mask-image: radial-gradient(...)`, никакого canvas не нужно:

```js
var R = 260;                                  // радиус спотлайта
var mx=-999,my=-999,sx=-999,sy=-999;          // мышь и сглаженная позиция
window.addEventListener('mousemove', e => { mx = e.clientX; my = e.clientY; });
(function tick(t){
  sx += (mx - sx) * 0.1;  sy += (my - sy) * 0.1;   // плавное догоняние курсора
  reveal.style.maskImage = reveal.style.webkitMaskImage =
    'radial-gradient(circle '+R+'px at '+sx+'px '+sy+'px, #fff 40%, ' +
    'rgba(255,255,255,.75) 60%, rgba(255,255,255,.4) 75%, ' +
    'rgba(255,255,255,.12) 88%, transparent 100%)';
  requestAnimationFrame(tick);
})();
```

3. **Тач-устройства** (нет курсора): спотлайт сам плывёт кругами вокруг объекта — `if (!matchMedia('(pointer: fine)').matches)` двигать mx/my по эллипсу от времени.
4. **Оба слоя масштабировать одинаково** (`transform: scale(...)` на обоих) — маска живёт в координатах вьюпорта и от трансформа не зависит.

## Шаг 5б. Сайт типа А: скролл (рабочий пример: `остров/island-site/`)

GSAP теперь полностью бесплатен (включая ScrollTrigger). Скачать локально, CDN не нужен:

```bash
curl -sL -o js/gsap.min.js https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js
curl -sL -o js/ScrollTrigger.min.js https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js
```

Ключевые элементы:

1. **Прелоадер**: загрузить все кадры через `new Image()` с прогресс-баром, потом прогреть декодер (`img.decode()`) — иначе первый скролл подлагивает.
2. **Canvas на весь экран** + отрисовка кадра с математикой object-fit: cover.
3. **Пин + таймлайн**: `.stage` высотой 800–900vh, внутри `.viewport` (100vh), ScrollTrigger пинит viewport:

```js
const tl = gsap.timeline({
  defaults: { ease: 'none' },
  scrollTrigger: {
    trigger: '#stage', start: 'top top', end: 'bottom bottom',
    scrub: 0.6, pin: '#viewport', pinSpacing: false, anticipatePin: 1
  }
});
```

4. **Структура таймлайна с плато** (позиции — доли от 0 до 1). На плато кадр НЕ двигается: скролл крутит только затемнение и текст — это и даёт эффект «остановился и читаю»:

```js
tl.to(seq, { frame: 96, snap: 'frame', duration: .175, onUpdate: render }, .05);  // полёт
tl.to('#dim',  { opacity: 1, duration: .03 }, .225);                              // затемнение
tl.fromTo('#cap1', { opacity: 0, y: 60 }, { opacity: 1, y: 0, duration: .045 }, .235);
tl.to('#cap1', { opacity: 0, y: -40, duration: .035 }, .325);
tl.to('#dim',  { opacity: 0, duration: .03 }, .33);                               // дальше полёт
```

5. **Затемнение** `#dim` — градиентный оверлей поверх canvas, включается только на плато (читаемость текста).
6. Hero-блок поверх кадра 0, уходит в первые 5% скролла. После pin-зоны — обычная секция с CTA.

## Шаг 6. Дизайн-слои (постерный вид)

### Текстура бумаги поверх ВСЕГО (включая текст)

Нужен настоящий **4K-скан бумаги** (пример: `остров/island-site/textures/paper.jpg`, 3322×4285, крафт с вкраплениями). Мелкий SVG-шум бумагу НЕ заменяет — не тот масштаб фактуры.

**Светлый сайт** (остров): multiply затемняет — бумага видна сразу:

```css
body::before { content:''; position:fixed; inset:0; z-index:95; pointer-events:none;
  background:url('textures/paper.jpg'); background-size:1100px auto;
  mix-blend-mode:multiply; opacity:.72; filter:contrast(1.15) brightness(1.07); }
/* screen-слой: бумага проступает сквозь тёмный текст, эффект принта */
.paperlite { position:fixed; inset:0; z-index:96; pointer-events:none;
  background:url('textures/paper.jpg'); background-size:1100px auto;
  mix-blend-mode:screen; opacity:.18; filter:contrast(1.4); }
```

**Тёмный сайт** (сизиф): multiply на чёрном НЕ ВИДЕН вообще. Проявлять наоборот — screen с инверсией (светлые волокна сквозь темноту) + сильный multiply, чтобы фактура въедалась в белый текст:

```css
#paper { mix-blend-mode:screen; opacity:.85;
  filter:invert(1) grayscale(1) brightness(.5) contrast(1.9) sepia(1) hue-rotate(175deg) saturate(.55); }
#paperlite { mix-blend-mode:multiply; opacity:.85; filter:grayscale(1) contrast(1.6); }
```

Грабли тёмного сайта:
- multiply придавит всю сцену → компенсировать яркостью медиа-слоёв: `filter: brightness(1.45) contrast(.96)` на img/video (одинаково на обоих hover-слоях!).
- `text-shadow` у заголовков глушит фактуру на буквах — убрать.
- Текстура лежит z-index'ом выше текста, но «на тексте» она начнёт читаться только при сильном multiply-слое (opacity ~.85).

### Вшитая виньетка vs пустые бока

Если виньетка вшита в кадр, на 16:9 экране бока будут пусто-чёрными. Лечится `transform: scale(1.28)` на обоих медиа-слоях — чернота уходит за край экрана. Либо `translate` сцены вбок + крупная типографика на пустой стороне (в стиле готик-постеров).

### Шрифты

- Блэклеттер (готика): **Pirata One** с Google Fonts, скачать woff2 ЛОКАЛЬНО в `fonts/` (весит 6 КБ; латиница only — кириллицу писать обычным serif).
- Serif: Georgia/Times — из коробки везде (Didot только на macOS, fallback в CSS обязателен).
- Постерное зерно: SVG feTurbulence data-uri поверх, `mix-blend-mode: overlay`, opacity ~.35.

## Шаг 7. Оптимизация веса (перед выкладкой)

Проверено на сизифе: 9.7 МБ → 2.7 МБ без видимой разницы.

1. **PNG → WebP**: `ffmpeg -i base.png -c:v libwebp -quality 90 base.webp` (1.26 МБ → 78 КБ). Контроль качества — PSNR ≥ 40 dB = глазом неотличимо:

```python
import cv2, numpy as np
a = cv2.imread('a.png').astype(np.float32); b = cv2.imread('b.webp').astype(np.float32)
print(10*np.log10(255**2/((a-b)**2).mean()), 'dB')
```

2. **Текстуры не хранить больше, чем они показываются**: плитка 1100px CSS = 2200px на ретине → ресайз 4K-скана до 2200px, JPEG q82 (5.7 МБ → 0.97 МБ).
3. **Видео**: `-crf 23 -preset slow -movflags +faststart` (faststart = начинает играть до полной загрузки).
4. WebP-кадры скролла: `-quality 70` + `-vf scale=1600:-2` для веба.

## Известные ограничения

- **1080p — потолок Kling** (Standard-тариф). На больших ретина-экранах слегка мыльно. Лечится апскейлом x2 через Real-ESRGAN (realesrgan-ncnn-vulkan, есть сборка под macOS) — гнать не видео, а WebP/PNG кадры после нарезки. Вес папки ×3–4.
- Kling может дорисовать детали, которых нет на ключевых кадрах — для вымышленных сцен некритично.
- Генераторы картинок при Edit почти всегда чуть сдвигают кадр (10–25 px) — выравнивать кодом (шаг 1), а не перегенерацией.
- Генератор может проигнорировать «round»/форму объекта — добивается отдельным Edit: `Same scene, make the boulder a perfectly round smooth stone sphere, everything else unchanged`.

## Идеи-фишки

- **Intro-луп**: отдельное Kling-видео с едва заметной динамикой (дымка, дыхание, блики) на первом экране до начала скролла — сайт «живой» сразу. Переход интро → скролл-видео почти незаметен, если интро сделано из кадра 0.
- **Hover-эффекты «до/после»** — два слоя, курсор протирает верхний; вместо картинки под маской может жить видео (тип Б).
- **Пинг-понг лупа** вперёд-назад — бесшовность без совпадения конца с началом.
- Эмбиент-звук (океан/ветер) отдельным слоем с кнопкой включения — НЕ из Kling.
- **Смысловая рифма**: hover показывает «обещание» (золотой камень внизу), финал скролла — исполнение (камень докатили, золото реально). Связывает механику с сюжетом.
