У Яндекса есть собственная таблица под названием «Частые причины отказа в публикации». Четырнадцать строк, каждая с номером нарушенного пункта и пояснением. Это самый полезный документ во всей документации: он показывает не абстрактные требования, а то, на чём реально спотыкаются игры, дошедшие до модерации.
Отдельная причина отнестись к нему серьёзно — механика кулдауна. Количество попыток не ограничено, но время ожидания перед повторной отправкой удваивается после каждого отказа. Три невнимательные попытки превращают неделю в месяц.
Ниже — весь список по категориям, с тем, как нарушение выглядит со стороны модератора и что именно чинить.
Интерфейс
Контекстное меню при взаимодействии (1.6.1.8, 1.6.2.7)
Самое частое нарушение и самое дешёвое в исправлении. При правом клике или долгом нажатии в игровой области появляется системное контекстное меню браузера — его необходимо отключить.
const canvas = document.getElementById('game');
canvas.addEventListener('contextmenu', (e) => e.preventDefault());Долгое нажатие на мобильных лечится не JS, а CSS:
#game, #game * {
-webkit-touch-callout: none; /* меню по лонгтапу в Safari */
-webkit-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
}Проверяется за пять секунд: правый клик по канвасу на десктопе, удержание пальца на картинке на телефоне.
Системный видеоплеер вместо игрового (1.6.1.6, 1.6.2.5)
Видеоконтент — заставки, катсцены, обучающие ролики — должен воспроизводиться встроенным в игру плеером, а не системным. Нативный <video controls> на мобильных разворачивается в полноэкранный плеер операционной системы: игрок вылетает из игры в чужой интерфейс с чужими кнопками, что нарушает целостность интерфейса.
Практически это значит: controls не ставить, playsinline ставить обязательно, элементы управления рисовать свои.
<video id="cutscene" playsinline muted preload="auto"></video>const video = document.getElementById('cutscene');
video.setAttribute('playsinline', ''); // без этого iOS откроет системный плеер
video.setAttribute('webkit-playsinline', '');
video.controls = false;Отдельно: встраивание YouTube-плеера не принимается (пункт 3.9).
Звук не ставится на паузу во время рекламы (4.7)
Во время показа рекламного ролика звук из игры продолжает играть. Требование 4.7 обязывает ставить на паузу и звук, и геймплей — на время interstitial и rewarded video.
Отдельно стоит помнить про стартовую рекламу: платформа показывает полноэкранный блок на старте всех игр автоматически, и колбэков у него нет. Единственный способ узнать о ней — события game_api_pause и game_api_resume.
ysdk.on('game_api_pause', () => { audioCtx.suspend(); pauseGame(); });
ysdk.on('game_api_resume', () => { audioCtx.resume(); resumeGame(); });Проверка модератора: открыть игру в наушниках и ничего не трогать.
Звук продолжается при переключении вкладки (1.3)
Методика проверки описана в документации буквально. Звук должен останавливаться:
- при сворачивании окна браузера на компьютере или приложения на телефоне;
- после переключения на другую вкладку в том же окне;
- в браузерном меню выбора вкладок.
Не считается нарушением задержка до 2 секунд, продолжение звука после клика по рекламному баннеру и переход в меню выбора вкладок на iOS.
document.addEventListener('visibilitychange', () => {
document.visibilityState === 'hidden' ? suspendAll() : resumeAll();
});
window.addEventListener('blur', suspendAll);
window.addEventListener('focus', resumeAll);SDK
Game Ready работает некорректно (1.19.2)
Метод ysdk.features.LoadingAPI.ready() подключён, но вызывается неправильно или не в тот момент жизненного цикла. Классические варианты: вызов сразу после YaGames.init(), когда ресурсы ещё грузятся; вызов после нажатия «Играть»; вызов внутри цикла загрузки.
Правильный момент один: все ресурсы загружены, все элементы интерактивны, загрузочных экранов не осталось.
const ysdk = await YaGames.init();
await loadAllAssets(); // картинки, звуки, шрифты
buildUI(); // интерфейс собран и кликабелен
ysdk.features.LoadingAPI?.ready();Game Ready не используется совсем (1.19.2)
Та же строка требования, отдельная строка в таблице отказов — настолько часто встречается. Метод обязателен для публикации в каталоге. На debug-панели индикатор Game Ready ждёт вызова 90 секунд, после чего краснеет и считается невызванным.
Автоопределение языка не реализовано (2.14)
«Язык интерфейса задаётся вручную вместо использования ysdk.environment.i18n.lang». Требование действует даже для игр с одним языком и вовсе без текстов, а определение должно происходить на старте, а не в процессе игры.
const lang = ysdk.environment.i18n.lang; // 'ru', 'en', 'tr' — ISO 639-1
applyLanguage(resolveLang(lang));Проверяется по индикатору 文 на debug-панели: он должен позеленеть во время загрузки.
SDK не встроен или встроен некорректно (1.1)
Три варианта нарушения: скрипт SDK отсутствует, подключён не из официального источника или инициализируется с ошибками.
Актуальное подключение — относительный путь для игры, залитой архивом в Консоль:
<!-- Yandex Games SDK -->
<script src="/sdk.js"></script>Для игры на собственном домене или в iframe — абсолютный https://sdk.games.s3.yandex.net/sdk.js.
Частая ошибка
Если ваше руководство, статья или ответ нейросети предлагают подключить SDK по адресу https://yandex.ru/games/sdk/v2 — это устаревший загрузчик. Игра будет работать: SDK инициализируется, реклама покажется, данные сохранятся. Но debug-панель покажет IF (Is loader: false), требование 1.19.1 будет не выполнено, и это отказ. Единственный способ убедиться — открыть игру с debug-mode=16 и увидеть IT.
Технические сбои
Прогресс не сохраняется (1.9)
Результаты, уровни или настройки не сохраняются между сессиями. Проверяется тривиально: пройти уровень и нажать F5.
Ключевая деталь, о которой забывают: сохранять нужно и гостю. Требование 1.2.2 разрешает играть без авторизации с сохранением прогресса, а setData() и getData() работают и для неавторизованного игрока.
Игра не запускается (1.14)
Загрузочный экран зависает или игра не доходит до геймплея. В пояснениях к пункту 1.14 перечислены реальные случаи: чёрный экран вместо игры, загрузка только после клика по экрану, необходимость перезагрузить страницу, вылет во время загрузки, ошибка загрузки на iOS.
Отдельная категория — «экраны-тупики»: экран после проигрыша, с которого нельзя вернуться в меню или начать заново. Это тоже 1.14.
Ошибки JS в консоли (1.14)
«В консоли браузера появляются JS-ошибки при запуске или в ходе игры, которые влияют на работоспособность». Модератор держит DevTools открытыми.
Практическое следствие: каждый вызов SDK оборачивается в try/catch, каждый промис — в .catch(). Необработанное отклонение промиса — это красная строка в консоли.
window.addEventListener('unhandledrejection', (e) => {
console.warn('[app] необработанный промис', e.reason);
e.preventDefault(); // не роняем игру из-за сетевой ошибки
});Заодно уберите из релизной сборки технические надписи и отладочные логи: в пояснениях к 1.14 есть примеры отказов из-за всплывающего технического текста и меню с неигровыми кнопками.
Игра зависает или тормозит (1.15)
«Заметные фризы или падение производительности делают игру некомфортной для пользователя». Формулировка самого пункта 1.15 при этом шире — про завершённость игры, а зависания и вылеты описаны в пункте 1.14. На практике обе строки означают одно: если на среднем устройстве игра дёргается, это отказ.
Что проверить: худший кадр в геймплее, поведение при повороте экрана и изменении размера окна, память после десяти минут игры.
Соответствие описанию
Игра не соответствует заявленному жанру (2.3)
Геймплей противоречит выбранной на вкладке «Черновик» категории. Возникает в двух случаях: категорию выбрали «пошире, чтобы охватить больше», или игра по ходу разработки превратилась во что-то другое, а черновик остался старым.
Правило: жанр должен быть очевиден модератору за первые тридцать секунд игры.
Вводящее в заблуждение название (8.2.2)
Название содержит слова, вводящие пользователя в заблуждение относительно условий игры: «free», «top», «best», «бесплатно», «бесплатный» и подобные. Все игры в каталоге бесплатные, поэтому «бесплатно» в названии — не информация, а обещание, которое ничего не обещает.
Само требование 8.2.2 шире запретного списка слов: тексты должны отражать реальную механику игры и её основной геймплей. Скриншот с механикой, которой в игре нет, — то же нарушение.
Кулдаун: почему вторая попытка дороже первой
Количество попыток не ограничено, но время ожидания перед повторной отправкой удваивается после каждого отклонения.
| Отклонение | Ожидание перед следующей отправкой |
|---|---|
| После 1-го | 24 часа |
| После 2-го | 2 дня |
| После 3-го | 4 дня |
| После 4-го | 8 дней |
| После 5-го | 16 дней |
Максимальное время ожидания — 384 часа (16 дней), дальше не растёт. Если исправление нужно внести экстренно, в Консоли есть кнопка Сброс кулдауна модерации — но воспользоваться ей можно не чаще, чем раз в 28 дней.
Важно
Арифметика простая: пять невнимательных отправок — это месяц ожидания плюс сроки самих проверок. Час, потраченный на прогон чек-листа в режиме черновика, стоит дешевле, чем любая из этих итераций. Особенно обидны отказы «пакетами»: модератор находит контекстное меню и останавливается, а звук во время рекламы вы почините только со следующей попытки.
Если вы не согласны с решением, у Яндекса есть форма обратной связи: нужно указать пункт требований, по которому игру отклонили ошибочно, и объяснить мотивацию. Перед отправкой формы документация просит прочитать пояснения к указанным пунктам — большая часть «ошибочных» отказов после чтения перестаёт быть ошибочными.
Чек-лист самопроверки
Прогоняется в режиме черновика с открытой debug-панелью и открытой консолью браузера. Порядок — от самого дешёвого к самому долгому.
- Лоадер на debug-панели показывает
IT, а неIF. - Индикатор Game Ready зелёный, время вызова разумное.
- Индикатор
文зелёный: I18N is used. - Правый клик и долгое нажатие по игровому полю не открывают контекстное меню.
- Видео (если есть) играет внутри игры, а не в системном плеере.
- Стартовая реклама платформы не перекрывается вашей музыкой.
- Во время interstitial и rewarded звук и геймплей на паузе.
- Переключение вкладки и сворачивание окна останавливают звук.
- Прогресс переживает F5 — и у авторизованного игрока, и у гостя.
- После «Clear cloud data» игра корректно запускается с нуля.
- В консоли нет ошибок ни при загрузке, ни после десяти минут игры.
- Нет технических надписей, отладочных меню и текста «в разработке».
- Игра не ломается при изменении размера окна и повороте экрана.
- Из любого экрана есть выход: нет экранов-тупиков.
- Категория соответствует тому, что видно в первые полминуты.
- В названии нет «бесплатно», «лучшая», «топ», «free», «best», капса.
- Скриншоты и видео показывают реальный геймплей этой игры.
Совет
Этот список удобно положить в CLAUDE.md проекта и попросить Claude Code проверить код по нему перед сборкой архива: часть пунктов (контекстное меню, playsinline, подписка на game_api_pause, обработка unhandledrejection, подключение /sdk.js) проверяется прямо по исходникам, без запуска игры.
Что дальше
Допустим, всё сошлось и статус сменился на «Опубликовано». Дальше начинается то, к чему разработчики обычно готовы хуже всего, — жизнь игры в каталоге: как она туда попадает, что происходит в первые дни, где смотреть цифры и почему трафик в первую неделю ничего не гарантирует. Об этом следующая глава.