SDK Web da NUGANUGA
O teu jogo corre num iframe isolado em https://play.nuganuga.com. O SDK é o único canal para a plataforma — nunca implementas tu a autenticação, a classificação, a partilha, a publicidade ou a analítica.
1. Carregar o SDK
Sempre a partir deste caminho absoluto exato. A plataforma serve-o e versiona-o.
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. As quatro chamadas
const ctx = await Nuga.ready(); // esperar pela plataforma
await Nuga.game.start(); // quando o jogador começa mesmo uma partida
await Nuga.score.submit({ score }); // exatamente uma pontuação numérica por partida
await Nuga.game.finish(); // a plataforma desenha o ecrã de resultadoNão desenhes o teu próprio ecrã de resultado, botão de repetir, botão de partilhar ou classificação — a plataforma desenha-os depois de finish(), igual para todos os jogos.
3. Tudo o resto
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. O manifesto
nuga.json na raiz do teu pacote:
{
"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 classificação: HIGH_SCORE, LOW_SCORE, LOW_TIME, HIGH_TIME, CUSTOM. Categorias: REACTION, TIMING, ACCURACY, MEMORY, PUZZLE, LUCK, ARCADE.
5. Regras do ambiente isolado
A validação estática rejeita qualquer pacote que quebre uma destas, antes de chegar a um jogador:
- Sem URL externos — sem CDN, sem tipos de letra web, sem imagens remotas. Inclui tudo no pacote.
- Nada de
eval,new Function,document.writeoudocument.cookie. - Sem rede própria:
fetchpara um URL absoluto,XMLHttpRequest,WebSockete service workers são bloqueados pela CSP e pela validação. - Sem navegação de nível superior e sem janelas pop-up.
- Pacote abaixo de 5 MB; os microjogos devem ficar abaixo de 1 MB.
- Pelo menos uma chamada a
Nuga.score.submit()— um jogo sem pontuação não pode classificar-se. - A shell da plataforma é fixa: index.html, a folha de estilos da shell e o harness em game.js têm de ficar inalterados. Só o corpo de run() e os estilos de #field são teus.
6. As pontuações são verificadas
Cada partida recebe uma sessão no servidor. O teu jogo nunca vê o token da sessão — a camada da plataforma guarda-o e submete por ti — e o servidor confronta a pontuação com a duração real e com os limites declarados no manifesto antes de entrar numa classificação.
Podes fazer melhor. Gera a aleatoriedade a partir da semente emitida pelo servidor e regista o que realmente aconteceu: o servidor recalcula a partida com os teus eventos em vez de confiar no número. Uma pontuação que a tua repetição não sustente é recusada de imediato.
const rng = Nuga.random(); // semeado pelo servidor — reproduzível, ao contrário de Math.random()
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // um resultado relevante para a pontuação, até 400 por partidaDeclara a mecânica em nuga.json para ativar. Sem isso o teu jogo continua a classificar-se, apenas com as verificações de duração e limites.
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. Publicar
Comprime a raiz do pacote (não a pasta) e carrega-a na consola de criador. A validação estática, a compilação e os testes de runtime, adaptabilidade, jogabilidade e segurança correm automaticamente; a publicação desbloqueia quando passarem.