NUGANUGA Web-SDK
Je game draait in een sandbox-iframe op https://play.nuganuga.com. De SDK is het enige kanaal naar het platform — je bouwt zelf nooit authenticatie, ranglijsten, delen, advertenties of analytics.
1. Laad de SDK
Altijd via precies dit absolute pad. Het platform serveert en verversiet het.
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. De vier aanroepen
const ctx = await Nuga.ready(); // wacht op het platform
await Nuga.game.start(); // wanneer de speler echt een potje start
await Nuga.score.submit({ score }); // precies één numerieke score per potje
await Nuga.game.finish(); // het platform tekent het resultaatschermTeken geen eigen resultaatscherm, opnieuw-knop, deelknop of ranglijst — het platform rendert die na finish(), identiek voor elke game.
3. Al het andere
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. Het manifest
nuga.json in de hoofdmap van je bundel:
{
"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개의 타겟을 빠르게 클릭하세요." }
}
}Ranglijsttypes: HIGH_SCORE, LOW_SCORE, LOW_TIME, HIGH_TIME, CUSTOM. Categorieën: REACTION, TIMING, ACCURACY, MEMORY, PUZZLE, LUCK, ARCADE.
5. Sandboxregels
De statische validatie weigert een bundel die hier één van breekt, nog voordat die een speler bereikt:
- Geen externe URL’s — geen CDN, webfont of externe afbeelding. Stop alles in je bundel.
- Geen
eval,new Function,document.writeofdocument.cookie. - Geen eigen netwerk:
fetchnaar een absolute URL,XMLHttpRequest,WebSocketen service workers worden zowel door de CSP als door de validatie geblokkeerd. - Geen navigatie op topniveau en geen pop-ups.
- Bundel onder 5 MB; microgames blijven het best onder 1 MB.
- Minstens één
Nuga.score.submit()-aanroep — een game zonder score kan niet meetellen. - De platformschil ligt vast: index.html, het schil-stylesheet en de harness in game.js moeten ongewijzigd blijven. Alleen de run()-body en #field-stijlen zijn van jou.
6. Scores worden geverifieerd
Elk potje krijgt een sessie aan de serverkant. Je game ziet het sessietoken nooit — de platformschil houdt het vast en verstuurt namens jou — en de server toetst de score aan de werkelijke duur en de in het manifest opgegeven grenzen voordat hij in een ranglijst komt.
Het kan beter. Haal willekeur uit de door de server uitgegeven seed en leg vast wat er echt gebeurde: dan berekent de server het potje opnieuw uit jouw gebeurtenissen in plaats van het getal te geloven. Een score die je replay niet ondersteunt wordt botweg geweigerd.
const rng = Nuga.random(); // geseed door de server — reproduceerbaar, anders dan Math.random()
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // één score-relevante uitkomst, tot 400 per potjeDeclareer de mechaniek in nuga.json om het aan te zetten. Zonder dat telt je game nog steeds mee, alleen op duur- en grenscontroles.
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. Uitbrengen
Zip de hoofdmap van de bundel (niet de map) en upload die in de makersconsole. Statische validatie, build en de runtime-, responsive-, gameplay- en beveiligingssuites draaien automatisch; publiceren gaat open zodra ze slagen.