SDK web de NUGANUGA
Tu juego se ejecuta en un iframe aislado en https://play.nuganuga.com. El SDK es el único canal hacia la plataforma: nunca implementas tú mismo la autenticación, la clasificación, el compartir, la publicidad ni la analítica.
1. Cargar el SDK
Siempre desde esta ruta absoluta exacta. La plataforma lo sirve y lo versiona.
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. Las cuatro llamadas
const ctx = await Nuga.ready(); // esperar a la plataforma
await Nuga.game.start(); // cuando el jugador empieza de verdad una partida
await Nuga.score.submit({ score }); // exactamente una puntuación numérica por partida
await Nuga.game.finish(); // la plataforma dibuja la pantalla de resultadoNo dibujes tu propia pantalla de resultado, botón de reintento, botón de compartir ni clasificación: la plataforma los renderiza tras finish(), igual para todos los juegos.
3. Todo lo demás
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. El manifiesto
nuga.json en la raíz de tu paquete:
{
"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개의 타겟을 빠르게 클릭하세요." }
}
}Tipos de clasificación: HIGH_SCORE, LOW_SCORE, LOW_TIME, HIGH_TIME, CUSTOM. Categorías: REACTION, TIMING, ACCURACY, MEMORY, PUZZLE, LUCK, ARCADE.
5. Reglas del entorno aislado
La validación estática rechaza cualquier paquete que incumpla una de estas, antes de que llegue a un jugador:
- Sin URL externas: ni CDN, ni fuentes web, ni imágenes remotas. Empaquétalo todo tú.
- Nada de
eval,new Function,document.writenidocument.cookie. - Nada de red propia:
fetcha una URL absoluta,XMLHttpRequest,WebSockety los service workers están bloqueados tanto por la CSP como por la validación. - Sin navegación de nivel superior ni ventanas emergentes.
- Paquete por debajo de 5 MB; los microjuegos deberían quedarse por debajo de 1 MB.
- Al menos una llamada a
Nuga.score.submit(): un juego que no produce puntuación no puede clasificar. - La carcasa de la plataforma es fija: index.html, la hoja de estilos de la carcasa y el arnés de game.js deben quedar intactos. Solo el cuerpo de run() y los estilos de #field son tuyos.
6. Las puntuaciones se verifican
Cada partida recibe una sesión en el servidor. Tu juego nunca ve el token de sesión (lo guarda la carcasa de la plataforma, que envía por ti) y el servidor contrasta la puntuación con la duración real y con los límites declarados en el manifiesto antes de que entre en una clasificación.
Puedes hacerlo mejor. Genera la aleatoriedad a partir de la semilla que emite el servidor y registra lo que ocurrió de verdad: el servidor recalculará la partida con tus eventos en vez de fiarse del número. Una puntuación que tu repetición no respalde se rechaza directamente.
const rng = Nuga.random(); // con semilla del servidor: reproducible, a diferencia de Math.random()
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // un resultado relevante para la puntuación, hasta 400 por partidaDeclara la mecánica en nuga.json para activarlo. Sin ella tu juego sigue clasificando, solo con las comprobaciones de duración y límites.
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. Publícalo
Comprime la raíz del paquete (no la carpeta) y súbela en la consola de creador. La validación estática, la compilación y las pruebas de runtime, adaptabilidad, jugabilidad y seguridad se ejecutan automáticamente; la publicación se desbloquea cuando pasan.