Веб-SDK NUGANUGA
Ваша игра работает в изолированном iframe на https://play.nuganuga.com. SDK — единственный канал к платформе: авторизацию, рейтинги, шеринг, рекламу и аналитику вам реализовывать не нужно.
1. Подключите SDK
Всегда по этому абсолютному пути. Раздачу и версии обеспечивает платформа.
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. Четыре вызова
const ctx = await Nuga.ready(); // дождаться платформы
await Nuga.game.start(); // когда игрок действительно начал партию
await Nuga.score.submit({ score }); // ровно один числовой результат за партию
await Nuga.game.finish(); // платформа рисует экран результатаНе рисуйте свой экран результата, кнопку повтора, кнопку «поделиться» или таблицу лидеров — платформа отрисует их после finish() одинаково для всех игр.
3. Всё остальное
Nuga.game.getContext();
Nuga.player.get();
Nuga.challenge.get();
Nuga.storage.get(key);
Nuga.storage.set(key, value);
Nuga.audio.setMuted(true);
Nuga.locale.get(); // 'en' | 'ko' | ...
Nuga.event.track('level_up', { level: 3 });
Nuga.on('pause', () => pauseLoop());4. Манифест
nuga.json в корне вашего пакета:
{
"schemaVersion": 1,
"name": "Reaction Hunter",
"slug": "reaction-hunter",
"description": "Click 10 targets as fast as possible.",
"rule": "Tap every target as fast as you can.",
"category": "REACTION",
"orientation": "PORTRAIT",
"duration": { "min": 5, "max": 30 },
"input": ["POINTER", "TOUCH"],
"ranking": { "type": "LOW_TIME", "unit": "ms" },
"entry": "index.html",
"locales": {
"ko": { "name": "리액션 헌터", "description": "10개의 타겟을 빠르게 클릭하세요." }
}
}Типы рейтинга: HIGH_SCORE, LOW_SCORE, LOW_TIME, HIGH_TIME, CUSTOM. Категории: REACTION, TIMING, ACCURACY, MEMORY, PUZZLE, LUCK, ARCADE.
5. Правила песочницы
Статическая проверка отклонит пакет, нарушающий любое из них, ещё до того, как он дойдёт до игрока:
- Никаких внешних URL — ни CDN, ни веб-шрифтов, ни удалённых изображений. Всё должно быть в пакете.
- Никаких
eval,new Function,document.writeиdocument.cookie. - Никакой своей сети:
fetchна абсолютный URL,XMLHttpRequest,WebSocketи service worker блокируются и CSP, и проверкой. - Никакой навигации верхнего уровня и никаких всплывающих окон.
- Пакет меньше 5 МБ; микроигры лучше держать в пределах 1 МБ.
- Хотя бы один вызов
Nuga.score.submit()— игра, которая не выдаёт результат, не может попасть в рейтинг. - Оболочка платформы фиксирована: index.html, таблица стилей оболочки и обвязка в game.js должны остаться без изменений. Вам принадлежат только тело run() и стили #field.
6. Результаты проверяются
Для каждой партии создаётся серверная сессия. Игра никогда не видит токен сессии — его хранит оболочка платформы и отправляет результат за вас, — а сервер сверяет результат с реальной длительностью и границами из манифеста, прежде чем он попадёт в рейтинг.
Можно сделать надёжнее. Берите случайность из выданного сервером зерна и записывайте, что произошло на самом деле: тогда сервер пересчитает партию по вашим событиям, а не поверит числу. Результат, который запись не подтверждает, отклоняется сразу.
const rng = Nuga.random(); // зерно от сервера — воспроизводимо, в отличие от Math.random()
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // одно значимое для результата событие, до 400 за партиюОбъявите механику в nuga.json, чтобы включить это. Без неё игра всё равно участвует в рейтинге — но только с проверками длительности и границ.
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. Публикация
Заархивируйте корень пакета (не папку) и загрузите в консоли автора. Статическая проверка, сборка, а также наборы runtime, адаптивности, геймплея и безопасности выполняются автоматически; публикация открывается после их прохождения.