NUGANUGA Web SDK
Играта ти работи в изолиран 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. Правила на пясъчната кутия
Статичната проверка отхвърля пакет, който нарушава което и да е от тях, още преди да стигне до играч:
- Никакви външни адреси — без CDN, уеб шрифт или отдалечено изображение. Опаковай всичко.
- Никакви
eval,new Function,document.writeилиdocument.cookie. - Никаква собствена мрежа:
fetchкъм абсолютен адрес,XMLHttpRequest,WebSocketи service worker се блокират и от CSP, и от проверката. - Никаква навигация на най-горно ниво и никакви изскачащи прозорци.
- Пакет под 5 MB; микроигрите е добре да останат под 1 MB.
- Поне едно извикване на
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, отзивчивост, геймплей и сигурност се изпълняват автоматично; публикуването се отключва, когато всички преминат.