# Правила сборки проектов

Документ для агентов, которые собирают проекты из `IDEAS.md`. Все пути ниже — от корня коллекции.

## 0. Цель

Каждый проект — витрина Opus 5.5. Человек открывает `index.html` и в первую же секунду думает «ого». Оценка по убыванию важности:

1. визуал;
2. работоспособность;
3. глубина механики;
4. непохожесть на остальные 99 проектов.

## 1. Что лежит в папке проекта

`NNN-slug/` (имя папки точно как в `IDEAS.md`, например `087-aurora-fjord`):

- `index.html` — точка входа. Код можно разнести по `app.js` и `style.css` рядом. Локальные скрипты подключаются обычным `<script src="app.js"></script>`, без `type="module"`.
- `README.md` — по шаблону ниже.
- `meta.json` — данные для общей галереи.
- `preview.jpg` — обложку создаёт `_tools/shot` при прогоне без `--tag` и `--actions`.

`meta.json`:

```json
{
  "n": 1,
  "slug": "001-aurora-fjord",
  "title": "Северное сияние над Териберкой",
  "tagline": "Одна фраза до 90 знаков: что это и чем цепляет",
  "category": "Шейдеры и генеративное искусство",
  "tech": ["WebGL2", "GLSL", "Web Audio"],
  "strength": "Какую силу Opus 5.5 показывает — короткой фразой",
  "controls": "Главные действия одной строкой",
  "accent": "#7CFFB2",
  "bg": "#05070D",
  "needsNetwork": false
}
```

`accent` и `bg` — ключевые цвета проекта, по ним галерея раскрасит карточку. `needsNetwork: true` ставится, только если без интернета пропадает суть (живые API, three.js с CDN).

Шаблон `README.md`:

```markdown
# NNN · Название

> Одна фраза о проекте.

![Превью](preview.jpg)

## Как запустить
Двойной клик по `index.html`. (Если нужен интернет — напиши, что именно без него не работает.)

## Что делать
- Управление и главные действия.

## Что внутри
3–6 пунктов про алгоритмы и устройство.

## Почему это про Opus 5.5
1–2 предложения.

## Ограничения
Честно: что упрощено и где приближение.
```

## 2. Технические правила (жёсткие)

1. **Проект работает по двойному клику через `file://`** — без сборки и без сервера. Отсюда следует:
   - никаких локальных ES-модулей: `<script type="module" src="./x.js">` и `import './x.js'` в `file://` не работают. Встроенный `<script type="module">` с импортом с CDN — можно;
   - никаких `fetch` и XHR к локальным файлам — данные лежат прямо в JS;
   - Web Worker создаётся только из Blob: `new Worker(URL.createObjectURL(new Blob([code], {type: 'text/javascript'})))`;
   - картинки не нужны: всё рисуется процедурно. Canvas, прочитавший локальную картинку, в `file://` становится «испорченным».
2. **Внешние зависимости — только когда без них правда хуже.**
   - Код: `https://cdn.jsdelivr.net/npm/<пакет>@<точная версия>/…`. three.js — `three@0.170.0` через importmap (`three` и `three/addons/` → `https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/`).
   - Шрифты — Google Fonts.
   - Никаких других доменов, кроме живых API, прямо названных в идее (USGS, Open-Meteo). У живых API обязателен запасной режим без сети.
3. **Без интернета нельзя показывать белый экран.** У шрифтов есть системный запасной вариант; если CDN не загрузился, проект показывает понятное сообщение в своём стиле.
4. **Шрифты только с кириллицей** — интерфейс на русском. Проверка любого шрифта Google:
   ```bash
   curl -s -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36' \
     'https://fonts.googleapis.com/css2?family=Font+Name' | grep -c '/\* cyrillic \*/'
   ```
   Результат должен быть ≥ 1. Кириллицы НЕТ, например, у Space Grotesk, Syne, Bebas Neue, Anton, Orbitron, Audiowide — проверяй каждый шрифт. Кириллица есть у Unbounded, Manrope, Onest, Geologica, Golos Text, Montserrat, Rubik (и всей семьи Rubik *), Russo One, Dela Gothic One, Oswald, Tektur, Handjet, Pixelify Sans, Press Start 2P, Exo 2, Jura, Play, Comfortaa, Cormorant (Garamond, SC, Infant), EB Garamond, Playfair Display, Lora, Literata, Spectral, PT Serif/Sans/Mono, Prata, Yeseva One, Oranienbaum, Ruslan Display, Alegreya, Vollkorn, Old Standard TT, JetBrains Mono, IBM Plex Sans/Serif/Mono, Fira Code, Martian Mono, Brygada 1918, Caveat, Neucha, Marck Script, Amatic SC.
5. **Холст учитывает `devicePixelRatio`**: для тяжёлых шейдеров DPR ограничен двумя или меньше. Изменение размера окна обрабатывается корректно.
6. **Анимация через `requestAnimationFrame`** и останавливается при `document.hidden`. У тяжёлых шейдеров разрешение подстраивается по времени кадра.
7. **Звук включается только после жеста пользователя** (этого требует политика автозапуска браузеров). Проект не должен шуметь при открытии. Громкость по умолчанию умеренная, есть кнопка звука.
8. Никаких `alert`, `prompt` и `confirm`. В финальной версии — ни мусорных `console.log`, ни одной ошибки в консоли.
9. `localStorage` — только внутри try/catch.
10. **Не трогать** чужие папки, `_tools/`, `IDEAS.md`, `BRIEF.md`. Не ставить глобальные пакеты, не поднимать серверы.

## 3. Планка визуала

Цель — вещь уровня главной страницы Codrops или Awwwards, подборки Shadertoy. Конкретно:

- **Первый кадр уже красив.** Обложка снимается через 2,5 с без всякого взаимодействия. К этому моменту на экране должна быть готовая живая композиция (автодемо, стартовая сцена, пример), а не пустой холст с надписью «нажмите, чтобы начать». Подсказка по управлению ненавязчивая.
- **Свой художественный язык** из описания идеи:
  - палитра из 3–5 цветов;
  - выверенный фон — не случайные #000 или #fff;
  - осмысленная гарнитура и шкала размеров;
  - ритм отступов.
  Проекты коллекции не должны выглядеть как один шаблон.
- **Композиция.** Главное — крупно. Интерфейс не перекрывает искусство: панели компактные и сворачиваются, края аккуратные. На мобильном своя раскладка (нижняя шторка, свёрнутые панели) и никакой горизонтальной прокрутки. Зоны нажатия — не меньше 40 px.
- **Детали.** Ползунки, кнопки и переключатели стилизованы — дефолтных контролов браузера нет. Состояния hover, active и focus-visible. Движение с easing, а не линейное. Микровзаимодействия. Курсор соответствует действию.
- **Иконки** — встроенный SVG или типографские символы. Эмодзи в роли иконок запрещены.
- **Русская типографика.**
  - Кавычки-«ёлочки».
  - Длинное тире — с пробелами.
  - Неразрывный пробел после коротких предлогов и союзов (в, к, с, и, а, но, на, по, за, от, до, из, не) и между числом и единицей: 4 Гц, 10 935 м.
  - Буква «ё».
  - Диапазоны через короткое тире: 5–10.
  - Никаких висячих предлогов в заголовках.
- **Запрещено — типичный «ИИ-вид»:**
  - фиолетово-синий градиент на всём;
  - стеклянные карточки сеткой;
  - Inter по умолчанию везде;
  - центрированный герой с тремя карточками под ним;
  - неоновое свечение на каждом элементе;
  - одинаковые скругления на всём;
  - лорем ипсум и заглушки «скоро».
- **Звук, если он есть,** — тоже часть дизайна: мягкие огибающие, без щелчков и резкости.

## 4. Тексты и факты

- Весь интерфейс и все тексты — на русском. Коротко, главное в начале.
- Факты — только те, в которых уверен. Сомневаешься — убери, не выдумывай. Иллюстративные данные подписаны как иллюстративные.
- Цитаты классиков — только те, что знаешь дословно. Иначе пиши собственный текст.
- Никаких реальных брендов и компаний в роли «своих» — только вымышленные или нейтральные названия.

## 5. Проверка обязательна

Зрение — сильная сторона Opus 5.5, им и проверяем. Команды запускаются из корня коллекции:

```bash
_tools/shot NNN-slug                 # десктоп 1440×900 и мобильный 390×844, ошибки консоли, обложка preview.jpg
_tools/shot NNN-slug --wait 6000     # для тяжёлой сцены, которой нужно больше времени
_tools/shot NNN-slug --tag play --actions '[{"click":[720,450]},{"wait":800},{"key":"Space"}]'
```

- **Действия:** `click` [x,y], `move` [x,y], `drag` [[x1,y1],[x2,y2]], `key` "Space", `down`/`up` (зажать или отпустить клавишу), `type` "текст", `scroll` 800, `wait` мс, `eval` "js" (выполнить JS и вывести результат), `selector` "css" (клик по элементу).
- **Скриншоты** сохраняются в `_shots/NNN-slug[-tag]-desktop.png` и `-mobile.png`. Смотри их инструментом Read — обе картинки, каждый раз.
- **Очередь.** Снимки делаются максимум в два браузера сразу, очередь общая с другими агентами, поэтому снимок может немного подождать. Запускай не больше одного снимка за раз.
- **Скорость на сервере не показательна.** WebGL здесь рендерится программно (SwiftShader, два ядра), кадров в секунду в разы меньше, чем на MacBook. По скриншоту можно судить о визуале, но не о скорости. При этом стартовая инициализация не должна занимать больше ~1 с процессорного времени.

**Цикл:** собрать → снять → критично посмотреть обе картинки глазами арт-директора («что здесь выглядит дёшево или сломано?») → исправить → снять снова. Минимум два круга. Главное взаимодействие хотя бы раз проверяется через `--actions`.

**Проект готов, когда:**

- 0 ошибок консоли;
- обе раскладки выглядят сильно;
- ключевая механика работает;
- `README.md` и `meta.json` на месте;
- `preview.jpg` снят финальным прогоном без `--tag`.

## 6. Порядок работы

1. Сначала ядро: минимальная рабочая версия главной механики и главного визуала. Потом полировка.
2. Не строить инфраструктуру ради инфраструктуры.
3. Распределять силы равномерно: пять сильных проектов лучше, чем три блестящих и два сырых.
4. Код читаемый: разделы с короткими комментариями, осмысленные имена, без минификации. Разумный размер — обычно 30–150 КБ.

## 7. Итоговый отчёт агента

По каждому проекту одной-двумя строками:

- статус: готов или частично;
- что работает;
- что упрощено;
- число ошибок в последнем прогоне `_tools/shot`;
- одна честная фраза о визуале.

## 8. Дополнение (разослано агентам после аудита первых файлов)

1. Функциональный текст — кнопки, подписи ползунков, значения, легенды, пункты меню, HUD — не меньше 11 px, лучше 12–13 px. Мельче допустимо только для декоративного текста без смысла. Лучше меньше контролов, но читаемых; второстепенное — в сворачиваемый раздел.
2. Контраст текста: не ниже 4,5:1 для мелкого и 3:1 для крупного.
3. Заголовки идут без пропуска уровней (h1 → h2 → h3), h1 на странице один.
4. Капсом набираются только короткие метки, не абзацы.
5. Цветное свечение (`box-shadow` или `text-shadow` цветом на тёмном фоне) на элементах интерфейса запрещено — только нейтральные тени. Свечение внутри сцены, где оно физически мотивировано (неон, люминофор, лампы, звёзды), допустимо.
6. Fixed-слой с `mix-blend-mode` (например, зерно с `overlay`) в программном рендере сервера после прокрутки «съедает» кадр. Для таких слоёв используй обычное смешивание с низкой прозрачностью.
7. **Режим съёмки.** `_tools/shot` до запуска скриптов страницы ставит `window.__SHOT__ = true` и отключает watchdog GPU. Если у проекта есть адаптивное разрешение или понижение качества для программного рендера, то при `window.__SHOT__` его нужно отключить: рендер в масштабе не ниже 0,75 от CSS-пикселей (DPR можно ограничить единицей). Иначе на SwiftShader обложка выйдет «в квадратиках», а на MacBook всё выглядит чётко. FPS в режиме съёмки неважен; если первый кадр тяжёлый, увеличь `--wait`.
8. **Очередь и стиль.**
   - Промежуточные снимки делай с `--no-mobile`, копи правки пачкой. Мобильный снимок по умолчанию идёт с DPR 1; `--mobile-dpr 2` — только когда нужно проверить чёткость мелкого текста.
   - Без толстых цветных полос на одной стороне карточек и плашек.
   - Анимируются только `transform` и `opacity`.
   - Текст абзацев — от 14 px, подписи — от 12 px.

## 9. Мультфильмы

Это не интерактивная игрушка, а **короткий фильм на 60–120 секунд**. Все пункты 1–8 действуют и здесь, плюс:

1. **История.** Оригинальный сюжет: завязка, препятствие, развязка, 3–6 сцен. Чужих персонажей и сюжетов не брать. Народная сказка — только в пересказе своими словами. Если есть реплики, то как интертитры или субтитры на русском; можно обойтись без слов.
2. **Режиссура.** Планы (общий, средний, крупный), движение камеры, монтажные переходы, ритм. Персонажи играют: 12 принципов анимации — сжатие и растяжение, упреждение, захлёст, дуги, вторичное действие, замедление в начале и в конце движения.
3. **Движок фильма.** Всё — функция от времени `t`: кадр однозначно определяется `t`, поэтому работает перемотка. Таймлайн сцен, ключевые кадры с easing, камера. Никаких `setTimeout`-цепочек, от которых зависит сюжет.
4. **Плеер** в стиле фильма:
   - кнопка «Смотреть» или «Пауза»;
   - шкала времени с метками сцен и перемоткой;
   - повтор и полноэкранный режим;
   - пробел — пауза, стрелки — ±5 с.
   Кадр 16:9 вписывается в экран с полями, на телефоне тоже.
5. **Звук и музыка** синтезируются на Web Audio: мелодия, гармония, ритм, шумы, синхронные с действием. По политике браузеров звук включается только после жеста. Поэтому при открытии фильм идёт без звука, а кнопка «Смотреть со звуком» перезапускает его с начала уже со звуком.
6. **Обложка.** Через 2,5 с после открытия на экране должен быть красивый кадр, а не чёрный экран и не титры. При `window.__SHOT__` сразу перематывай на самый выразительный кадр фильма и ставь паузу.
7. **Без картинок и аудиофайлов.** Всё рисуется кодом: SVG, Canvas 2D или WebGL/three.js — по технике из идеи.
8. **Проверка.** Помимо обложки сними 3–4 кадра из разных сцен через `--actions` с `eval`, который перематывает время. Так видно, что весь фильм, а не только первый кадр, выглядит сильно.

## 10. Игры с нейросетью

Все пункты 1–8 действуют и здесь, плюс:

1. **Подключение.** В `index.html`, до своего кода:
   ```html
   <script src="../_ai/ai.js"></script>
   ```
   Весь API описан в шапке `_ai/ai.js`: `AI.chat`, `AI.json`, потоковый вывод через `onToken`, `AI.ensureKey()`, флаги `AI.demo` и `AI.shot`, `AI.usage`. Свой клиент к OpenRouter не пиши. Ключ нигде не выводи и не логируй. Ключ — только от игрока (BYOK): встроенных ключей в коде быть не должно.
2. **Модель** — `deepseek/deepseek-v4.1-flash`, самая свежая DeepSeek. Рассуждение по умолчанию выключено, так ответ приходит за 1–3 с.
   - Для сложных решений передавай `think: true`: например, решение мастера игры в RPG или генерацию кода игры. Так медленнее, но умнее.
   - Первые токены при потоковом выводе приходят примерно через 0,9 с — используй поток для реплик.
3. **Задержка — часть дизайна.**
   - Пока нейросеть думает, персонаж «думает» анимацией: жест, «…», дым сигареты.
   - Реплики печатаются потоком.
   - Всё, что можно, готовь заранее и параллельно (очередь в клиенте — до 4 запросов одновременно).
   - Интерфейс никогда не замирает.
4. **Нейросеть видит правду.**
   - Скрытое состояние мира хранится в JS: преступление, рецепт напитка, список косяков ремонта. Оно передаётся модели в system-промпте, поэтому модель реагирует на то, что игрок реально сделал.
   - Решения, которые меняют игру, — только через `AI.json` со строгой схемой и проверкой в коде. Сломанный ответ не должен ломать игру: подставь разумное значение по умолчанию.
5. **Характер и язык.**
   - Персонажи говорят живым русским языком, коротко, с юмором, у каждого своя манера.
   - Промпты задают роль, цель, ограничения и длину реплики (обычно 1–3 предложения).
   - Никаких реальных людей и брендов.
   - Грубый юмор допустим, травля — нет.
   - Пиво и сигареты — игровые механики с последствиями: шатается камера, злится начальник. Это не реклама.
6. **Демо-режим обязателен.** Без ключа или без сети проект работает на заготовленных ответах. Играть в него хуже, но он живой и понятный. Вверху видна метка «демо-режим — нейросеть не подключена».
7. **Обложка и проверка.**
   - При `AI.shot` (флаг `__SHOT__`) нейросеть не вызывается: сразу покажи выразительную сцену с заготовленными репликами.
   - Живую работу с DeepSeek проверь сам: хотя бы одна настоящая сессия через `--actions` с ожиданием ответов. Сервер ходит в интернет; для проверки ключ передаётся в браузер тестовым скриптом, в файлах проекта его нет.
   - Трать разумно: `maxTokens` по делу, контекст сжимай.
8. **Стоимость.** Покажи в интерфейсе скромный счётчик потраченного: `AI.usage.costUSD`. Партия должна стоить центы.
