NUGANUGA Web-SDK
Dein Spiel läuft in einem Sandbox-iframe auf https://play.nuganuga.com. Das SDK ist der einzige Kanal zur Plattform – Authentifizierung, Wertung, Teilen, Werbung und Analyse musst du nie selbst umsetzen.
1. SDK laden
Immer über genau diesen absoluten Pfad. Auslieferung und Versionierung übernimmt die Plattform.
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. Die vier Aufrufe
const ctx = await Nuga.ready(); // auf die Plattform warten
await Nuga.game.start(); // wenn der Spieler wirklich eine Runde startet
await Nuga.score.submit({ score }); // genau eine numerische Punktzahl pro Runde
await Nuga.game.finish(); // die Plattform zeichnet den ErgebnisbildschirmZeichne keinen eigenen Ergebnisbildschirm, keinen Wiederholen- oder Teilen-Knopf und keine Rangliste – die Plattform rendert das nach finish() für jedes Spiel identisch.
3. Alles Weitere
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. Das Manifest
nuga.json im Wurzelverzeichnis deines Bundles:
{
"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개의 타겟을 빠르게 클릭하세요." }
}
}Wertungsarten: HIGH_SCORE, LOW_SCORE, LOW_TIME, HIGH_TIME, CUSTOM. Kategorien: REACTION, TIMING, ACCURACY, MEMORY, PUZZLE, LUCK, ARCADE.
5. Sandbox-Regeln
Die statische Prüfung lehnt ein Bundle ab, das eine davon verletzt – bevor es je einen Spieler erreicht:
- Keine externen URLs – kein CDN, keine Webschrift, kein entferntes Bild. Bündle alles selbst.
- Kein
eval,new Function,document.writeoderdocument.cookie. - Kein eigenes Netzwerk:
fetchauf eine absolute URL,XMLHttpRequest,WebSocketund Service Worker werden von der CSP wie von der Prüfung blockiert. - Keine Navigation auf oberster Ebene und keine Popups.
- Bundle unter 5 MB; Mikrospiele sollten unter 1 MB bleiben.
- Mindestens ein
Nuga.score.submit()-Aufruf – ein Spiel ohne Punktzahl kann nicht gewertet werden. - Die Plattform-Hülle ist fest: index.html, das Hüllen-Stylesheet und der Harness in game.js müssen unverändert bleiben. Nur der run()-Rumpf und #field-Stile gehören dir.
6. Punktzahlen werden geprüft
Jede Runde bekommt eine serverseitige Sitzung. Dein Spiel sieht das Sitzungs-Token nie – die Plattform-Hülle hält es und reicht die Punktzahl für dich ein – und der Server prüft sie gegen die tatsächliche Laufzeit und die im Manifest erklärten Grenzen, bevor sie in eine Rangliste kommt.
Es geht besser. Zieh Zufall aus dem servergesetzten Seed der Runde und zeichne auf, was tatsächlich passiert ist – dann berechnet der Server die Runde aus deinen Ereignissen nach, statt der Zahl zu glauben. Eine Behauptung, die dein Replay nicht stützt, wird schlicht abgelehnt.
const rng = Nuga.random(); // vom Server geseedet – reproduzierbar, anders als Math.random()
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // ein punkterelevantes Ergebnis, bis zu 400 pro RundeDeklariere die Mechanik in nuga.json, um es einzuschalten. Ohne sie wird dein Spiel weiterhin gewertet – nur über Dauer- und Grenzprüfungen.
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. Ausliefern
Zippe das Bundle-Wurzelverzeichnis (nicht den Ordner) und lade es in der Creator-Konsole hoch. Statische Prüfung, Build sowie Runtime-, Responsive-, Gameplay- und Sicherheitstests laufen automatisch; Veröffentlichen wird freigeschaltet, sobald sie bestehen.