# Скилл: Создание и публикация HTML5-игры на Яндекс Играх

Ты — ИИ-агент, который должен **самостоятельно, без доступа к интернету**, создать готовую к публикации HTML5-игру для платформы Яндекс Игры, включая весь код, промо-изображения (иконку, обложку) и текстовые материалы. Ниже — полный набор правил, шаблонов и чек-листов. Следуй им по порядку.

**Важно:** тебе запрещено искать что-либо в интернете, исследовать рынок, проводить A/B-тесты или ссылаться на внешние ресурсы. Всё, что нужно, есть в этом документе.

---

## 1. Технические требования (обязательны к соблюдению)

Игра — браузерная, на чистом HTML5. Никаких движков (Unity, Godot, Defold и т.д.) — только HTML, CSS и JavaScript.

- **Формат:** HTML5 Canvas. Без WebGL. Работает в браузере без установки.
- **Архив:** ZIP. В корне архива обязательно файл `index.html`.
- **Размер:** Распакованный архив ≤ **100 МБ**.
- **Имена файлов:** только латиница, цифры, дефисы и подчёркивания. Без пробелов и кириллицы.
- **SDK Яндекс Игр:** обязательно подключён.
- **Гостевой режим:** игра работает без авторизации, прогресс сохраняется локально.
- **Авторизация:** отсутствует. Не подключай `getPlayer()` с авторизацией, не делай кнопок «Войти через Яндекс».
- **Лидерборды:** отсутствуют. Не используй `ysdk.leaderboards`.
- **Звук:** при потере фокуса (`blur` / `visibilitychange`) звук обязан останавливаться.
- **Платежи:** только через SDK, если они вообще есть. Если покупок нет — не подключай `getPayments()`.
- **HTTPS:** игра должна работать по HTTPS (это обеспечивает платформа).
- **Service Worker:** опционально. Если не уверен — не делай.
- **Адаптивность:** корректно отображается на Desktop, Mobile (iOS, Android), TV.
- **Полноэкранный режим:** на мобильных игра работает в полный экран.
- **Управление:** на мобильных — жесты (тач). Допустимо добавить акселерометр.
- **Лонгтап:** долгое нажатие не должно вызывать выделение текста или контекстное меню.
- **I18N:** должна быть заготовка I18N на русском, без других языков, но готовой к добавлению новых языков.
- **LoadingAPI.ready():** должен быть сигнал о том, что игра загружена. `ysdk.features.LoadingAPI?.ready();`

### 1.1. Заготовка `index.html`

Используй эту структуру как стартовую точку. Не отклоняйся от неё без причины.

```html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>НАЗВАНИЕ_ИГРЫ</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html, body {
    width: 100%; height: 100%;
    overflow: hidden;
    background: #000;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    touch-action: none;
  }
  #game { display: block; width: 100vw; height: 100vh; }
</style>
</head>
<body>
<canvas id="game"></canvas>

<script src="/sdk.js"></script>
<script>
  // 1. Инициализация SDK
  let ysdk = null;

  async function initSDK() {
    try {
      ysdk = await YaGames.init();
      ysdk.features.LoadingAPI?.ready(); // Вызвать когда игра загрузиться
    } catch (e) {
      console.warn('SDK не загружен, играем без платформы', e);
    }
    
    startGame();
  }

  window.addEventListener('load', () => {
    if (typeof YaGames === 'undefined') {
      startGame();
    } else {
      initSDK();
    }
  });

  // 2. Остановка звука при потере фокуса
  document.addEventListener('visibilitychange', () => {
    if (document.hidden) pauseAllAudio();
    else resumeAllAudio();
  });
  window.addEventListener('blur', pauseAllAudio);
  window.addEventListener('focus', resumeAllAudio);

  function pauseAllAudio() { /* mute всех Audio и AudioContext */ }
  function resumeAllAudio() { /* unmute */ }

  // 3. Игровой код
  function startGame() {
    // ...
  }
</script>
</body>
</html>
```

---

## 2. Интеграция SDK Яндекс Игр

SDK даёт доступ к рекламе и (опционально) к платежам. Авторизацию и лидерборды **не используй**.

### 2.1. Подключение

В `<head>` или перед закрытием `<body>` добавь:

```html
<script src="/sdk.js"></script>
```

Если игра хостится на собственном домене, используй абсолютный путь:

```html
<script src="https://sdk.games.s3.yandex.net/sdk.js"></script>
```

### 2.2. Инициализация

```javascript
let ysdk = null;
async function initSDK() {
  try {
    ysdk = await YaGames.init();
  } catch (e) {
    console.error(e);
  }
}
```

Всегда оборачивай в `try/catch` — SDK может быть недоступен при локальном тестировании.

### 2.3. Реклама (полноэкранная)

Вызывай не чаще, чем раз в 60 секунд и только между раундами/уровнями.

```javascript
function showInterstitial(callback) {
  if (!ysdk) return callback && callback();
  ysdk.adv.showFullscreenAdv({
    callbacks: {
      onClose: () => callback && callback(),
      onError: () => callback && callback()
    }
  });
}
```

### 2.4. Реклама с вознаграждением (опционально)

```javascript
function showRewarded(onReward) {
  if (!ysdk) return;
  ysdk.adv.showRewardedVideo({
    callbacks: {
      onRewarded: () => onReward && onReward(),
      onClose: () => {},
      onError: () => {}
    }
  });
}
```

### 2.5. Платежи

Используй только если в игре реально есть покупки. Для простых игр — пропусти этот раздел.

```javascript
let payments = null;
async function initPayments() {
  try {
    payments = await ysdk.getPayments({ signed: false });
  } catch (e) {}
}
```

### 2.6. Что НЕ использовать

- `ysdk.getPlayer()` — авторизации нет.
- `ysdk.leaderboards` — лидербордов нет.
- `ysdk.auth` — не существует в этом скилле.

Прогресс сохраняй в `localStorage`:

```javascript
localStorage.setItem('save', JSON.stringify(state));
const state = JSON.parse(localStorage.getItem('save') || '{}');
```

---

## 3. Медиаматериалы

Формат — **PNG**. Ни на одном изображении не должно быть: системного интерфейса (статус-бар, батарея), интерфейса браузера, бейджей Яндекс Игр, надписей «Лучшее», «Акция», «Новая игра», «Хит».

### 3.1. Иконка игры

- **Размер:** 512 × 512 пикселей.
- **Формат:** SVG.
- **Содержание:** белое или цветное изображение. Без рамки вокруг арта.

### 3.2. Обложка игры

- **Размер:** 800 × 470 пикселей.
- **Формат:** SVG.
- **Содержание:** без имитации интерфейса платформы. Текст крупный, читаемый, без перегруза.

### 3.3. Как сгенерировать иконку и обложку

Используй единый стиль игры во всех промо-материалах. Создавай иконку и обложку используя .svg.

**Иконка (512×512):**
```
вставь SVG здесь
```

**Обложка (800×470):**
```
вставь SVG здесь
```

**Правила выбора сюжета для промо:**
- Показывай главного героя или главную механику.
- Не показывай смерть, кровь, рейтинг 18+ элементы.
- Избегай изображений, которые вводят в заблуждение (не показывай того, чего нет в игре).

---

## 4. Текстовые материалы

Все тексты пиши грамотно, на русском, без лишних украшательств.

### 4.1. Название игры

- Максимум **50 символов**.
- Первая буква заглавная. Никакого CAPS LOCK.
- Уникальное, не похожее на названия популярных игр.

Примеры: «Прыжок Кота», «Лабиринт Кристаллов», «Пушистый Пекарь».

### 4.2. Краткое описание (SEO)

- **50–160 символов.**
- Отображается в поиске Яндекса.

Шаблон: `Помоги [герой] [цель]. [Механика в двух словах]. [Уникальность].`

Пример: `Помоги коту собрать все рыбки в лабиринте. Управляй прыжками и избегай ловушек. Более 30 уровней.`

### 4.3. Полное описание

- **100–1000 символов.**
- Содержит: сюжет, геймплей, возможности, взаимодействие с объектами, сцены.

Структура:
1. Что за игра и о чём.
2. Основная механика.
3. Что предстоит делать игроку.
4. Особенности (уровни, персонажи, режимы).
5. Почему интересно.

### 4.4. Инструкция «Как играть»

- **50–1000 символов.**
- Простым языком: управление, цель, правила.

Пример:
```
Управление: тапай по экрану, чтобы кот прыгнул. На ПК — пробел или клик.
Цель: собрать все рыбки на уровне и не коснуться шипов.
Совет: некоторые платформы двигаются — подгадай момент прыжка.
```

### 4.5. Теги

До **20 штук**. Формат — через запятую, короткие слова или словосочетания.

Пример: `кот, прыжки, аркада, лабиринт, казуальная, для детей, на время, сбор предметов, уровни, весёлая`.

---

## 5. Возрастной рейтинг и контент

- Категории: **0+, 6+, 12+, 16+, 18+**.
- Выбирай минимально возможную для своей игры. Если сомневаешься между 6+ и 12+ — ставь 12+.
- Запрещено: порнография, оскорбления по полу, национальности, религии.
- Эротика внутри игры допустима с маркировкой, но не в промо.
- Шокирующий контент — только с возрастной маркировкой.

---

## 6. Как придумать идею и сделать игру интересной

Ты не имеешь доступа к интернету. Все идеи ищи внутри этих правил.

### 6.1. Как рожать идеи без исследования

Используй **комбинаторику простых механик**. Возьми по одному элементу из каждой колонки:

| Механика | Объект | Цель |
|---|---|---|
| Прыжок | Кот | Собрать предметы |
| Полёт | Ракета | Долететь до финиша |
| Собирание | Пузырь | Уничтожить врагов |
| Разрезание | Фрукт | Открыть дверь |
| Поворот | Кристалл | Разгадать головоломку |
| Соединение | Кирпич | Построить башню |

Пример: «Прыжок» + «Кот» + «Собрать предметы» = «Прыжок Кота». Это уже рабочая идея.

### 6.2. Что делает игру играбельной, а не «поделкой»

Обязательные элементы:

- **Понятная цель.** Игрок понимает, что делать, за 3 секунды.
- **Одна ключевая механика.** Не смешивай 5 жанров. Одна механика — много вариаций.
- **Обратная связь.** Каждое действие даёт отклик: вспышка, звук, цифра, анимация.
- **Прогрессия.** Уровни сложнее. Или счёт растёт. Или открываются новые элементы.
- **Короткая сессия.** 1–3 минуты на раунд.
- **Реиграбельность.** Захотелось пройти ещё раз и улучшить результат.

### 6.3. Простая формула геймплея

```
Каждый кадр:
  1. Игрок совершает действие (или не совершает).
  2. Игра реагирует на действие (движение, счёт, звук).
  3. Игра проверяет условие победы и поражения.
  4. Если победил — следующий уровень.
  5. Если проиграл — рестарт с кнопкой или без.
```

Ничего сложнее не нужно для первой игры.

### 6.4. Обучение игрока

- Первые 5 секунд — подсказка «Тапни, чтобы прыгнуть».
- Следующие 10 секунд — простое действие, легко выполнимое.
- Далее — постепенно новые элементы.

Никогда не пиши длинные туториалы. Обучай через геймплей.

### 6.5. Что делает игру скучной (избегай)

- Нет обратной связи (нажал — ничего не произошло визуально).
- Слишком медленный темп.
- Слишком сложно с первых секунд.
- Однообразные уровни без изменений.
- Управление, которое игрок не понимает.

### 6.6. Практический план разработки простой игры

1. Определи жанр и ключевую механику (см. таблицу выше).
2. Нарисуй мысленно 3 экрана: старт, игра, конец раунда.
3. Сделай игровой цикл: `update()` + `render()` на `requestAnimationFrame`.
4. Добавь управление: тач и мышь — единообразно.
5. Добавь счёт, победу, поражение.
6. Добавь звуки (Web Audio API — синтез, без файлов).
7. Добавь сохранение прогресса в `localStorage`.
8. Протестируй мысленно на маленьком экране (360×640) и на большом (1920×1080).

---

## 7. Архитектура типовой HTML5-игры (референс)

Скелет, который ты должен адаптировать под свою идею:

```javascript
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');

let W, H;
function resize() {
  W = canvas.width = window.innerWidth * devicePixelRatio;
  H = canvas.height = window.innerHeight * devicePixelRatio;
  canvas.style.width = window.innerWidth + 'px';
  canvas.style.height = window.innerHeight + 'px';
}
window.addEventListener('resize', resize);
resize();

const state = {
  score: 0,
  best: Number(localStorage.getItem('best') || 0),
  running: false,
  gameOver: false
};

// Ввод — тач и мышь
canvas.addEventListener('pointerdown', onInput);

function onInput() {
  if (state.gameOver) return restart();
  if (!state.running) state.running = true;
  // твоё действие (прыжок, выстрел, поворот)
}

function update(dt) { /* логика */ }
function render() { /* отрисовка */ }

let last = performance.now();
function loop(now) {
  const dt = (now - last) / 1000;
  last = now;
  update(dt);
  render();
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
```

Все звуки генерируй через Web Audio API, чтобы не тащить бинарники. Пример:

```javascript
const actx = new (window.AudioContext || window.webkitAudioContext)();
function beep(freq, dur) {
  const o = actx.createOscillator();
  const g = actx.createGain();
  o.frequency.value = freq;
  o.connect(g); g.connect(actx.destination);
  o.start();
  g.gain.exponentialRampToValueAtTime(0.001, actx.currentTime + dur);
  o.stop(actx.currentTime + dur);
}
```

Пауза звука при потере фокуса:

```javascript
function pauseAllAudio() { actx.suspend(); }
function resumeAllAudio() { actx.resume(); }
```

---

## 8. Чек-лист перед публикацией

Пройди по списку один раз в конце разработки. Каждый пункт — обязателен.

**Технические:**
- [ ] `index.html` лежит в корне архива.
- [ ] Размер распакованного архива ≤ 100 МБ.
- [ ] Имена файлов — латиница, без пробелов.
- [ ] SDK подключён через `<script src="/sdk.js">`.
- [ ] `YaGames.init()` вызывается после загрузки SDK, обёрнуто в `try/catch`.
- [ ] Авторизации нет.
- [ ] Лидербордов нет.
- [ ] Прогресс сохраняется в `localStorage`.
- [ ] Звук останавливается при `blur` / `visibilitychange`.
- [ ] Покупки только через SDK (или отсутствуют).
- [ ] Адаптив: работает на 360×640 и на 1920×1080.
- [ ] Полноэкранный режим на мобильных.
- [ ] Управление работает тачем и мышью.
- [ ] Лонгтап не выделяет текст, контекстное меню не появляется.
- [ ] Игра не вылетает если `/sdk.js` не скачался или не имеет каких-то функций.
**Медиа:**
- [ ] Иконка 512×512 PNG, без рамки.
- [ ] Обложка 800×470 PNG, без текста и интерфейса.
- [ ] На изображениях нет системного интерфейса и бейджей Яндекс Игр.

**Тексты:**
- [ ] Название ≤ 50 символов, первая заглавная, без caps.
- [ ] Краткое описание 50–160 символов.
- [ ] Полное описание 100–1000 символов.
- [ ] «Как играть» 50–1000 символов.
- [ ] Теги до 20 штук.
- [ ] Возрастной рейтинг выставлен.

**Геймплей:**
- [ ] Понятно с первых 5 секунд.
- [ ] Есть счёт / цель / победа / поражение.
- [ ] Есть обратная связь на каждое действие.
- [ ] Сессия длится 1–3 минуты.
- [ ] Есть причина сыграть ещё раз.

---

## 9. Порядок действий агента (что делать по шагам)

1. Придумай идею по таблице из раздела 6.1.
2. Определи жанр, механику, цель, поражение.
3. Собери игру по скелету из раздела 7.
4. Вставь SDK-инициализацию из раздела 2.
5. Убедись, что все пункты раздела 1 выполнены.
6. Сгенерируй иконку 512×512 по разделу 3.3.
7. Сгенерируй обложку 800×470 по разделу 3.3.
8. Напиши название, краткое и полное описание, «Как играть», теги по разделу 4.
9. Определи возрастной рейтинг по разделу 5.
10. Пройди чек-лист из раздела 8.
11. Упакуй всё в ZIP: `index.html` в корне, все ассеты рядом.
12. Отдай пользователю: архив, иконку PNG, обложку PNG, тексты.

---

**Если сомневаешься — делай проще.** Простая работающая игра проходит модерацию лучше, чем сложная недоделанная.
