NUGANUGA Web SDK
あなたのゲームは https://play.nuganuga.com のサンドボックス化されたiframe内で動きます。SDKがプラットフォームへの唯一の窓口で、認証・ランキング・共有・広告・分析を自前で実装する必要はありません。
1. SDKを読み込む
必ずこの絶対パスから読み込んでください。配信とバージョン管理はプラットフォームが行います。
<script src="/sdk/nuga-sdk.js"></script>
<script src="./game.js"></script>2. 4つの呼び出し
const ctx = await Nuga.ready(); // プラットフォームの準備を待つ
await Nuga.game.start(); // プレイヤーが実際に開始したとき
await Nuga.score.submit({ score }); // 1プレイにつき数値スコアを1つだけ
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. サンドボックス規則
以下に違反したバンドルは、プレイヤーに届く前に静的検証で拒否されます:
- 外部URL禁止 — CDN、Webフォント、リモート画像すべて不可。すべて同梱してください。
eval、new Function、document.write、document.cookieの使用禁止。- 独自の通信は禁止:絶対URLへの
fetch、XMLHttpRequest、WebSocket、Service Workerは静的検証とCSPの両方でブロックされます。 - トップレベルの画面遷移とポップアップは禁止。
- バンドルは5MB以下。マイクロゲームは1MB以下を推奨します。
Nuga.score.submit()を最低1回呼ぶこと — スコアを出せないゲームはランキングに載りません。- プラットフォームシェルは固定です。index.html、シェルのスタイルシート、game.jsのハーネスは変更不可で、run()本体と#fieldのスタイルだけが変更できます。
6. スコアはサーバーで検証されます
すべてのプレイにサーバー発行のセッションがあります。ゲームコードはセッショントークンを見られず、プラットフォームシェルが代わりに保持・送信します。サーバーは実際の経過時間とマニフェストの宣言範囲を照合してからランキングに反映します。
さらに一歩進められます。サーバー発行のシードから乱数を作り、実際に起きたことを記録すれば、サーバーは報告された数値ではなくその記録からスコアを再計算します。記録が裏付けない主張はそのまま拒否されます。
const rng = Nuga.random(); // サーバーのシード由来 — Math.random() と違い再現可能
const target = rng.int(0, 8);
Nuga.replay.record('hit', 172); // スコアに関わる結果1件、1プレイ最大400件nuga.json にメカニクスを宣言すると有効になります。宣言しなくてもランキングには載りますが、時間と範囲の検査のみが適用されます。
"verification": { "kind": "REPLAY_V1", "mechanic": "REACTION",
"params": { "rounds": 5 } }7. 公開する
フォルダではなくバンドルのルートを圧縮し、クリエイターコンソールでアップロードしてください。静的検証、ビルド、ランタイム、レスポンシブ、ゲームプレイ、セキュリティのテストが自動で実行され、すべて通ると公開できます。