---
type: tutorial
title: マーケットプレイスゲームを作る
summary: "空のフォルダーから Caputchin のゲームを作ります：SDK をインストールし、ファクトリーを登録し、ラウンドごとのコンテキストからレンダリングし、トレースを記録し、サンドボックス化された iframe のためにバンドルします。"
---

このチュートリアルの終わりまでに、1 つの JavaScript のバンドルに、完全で遊べる Caputchin のゲームを持ち、リプレイ可能にして公開する準備ができていることでしょう。これは退屈な、すべてのステップをやる版です。どこに合うかは先に [マーケットプレイスにゲームを出荷する](/docs/marketplace-game-development/overview) を読んでください。

Node とバンドラー（esbuild、rollup、vite、webpack。どれでも）が要ります。作るのに Caputchin のアカウントは要りません。公開するときだけです。

## 1. SDK をインストールする

```bash
npm install @caputchin/game-sdk
```

SDK は小さいです。`register` ヘルパーに TypeScript の型を足したものです。ウィジェットのランタイムをバンドルしないので、あなたのゲームは小さいままです。

## 2. ゲームファクトリーを登録する

ゲームは、**ファクトリー関数** を伴う `register` への単一の呼び出しです。ウィジェットはサンドボックス化された iframe の中であなたのファクトリーを呼びます。その呼び出し自体が開始のシグナルです（待つべき別の開始イベントはありません）。

```js
import { register } from "@caputchin/game-sdk";

register((container, bridge, ctx) => {
  // container - a DOM element inside the sandboxed iframe; render into it.
  // bridge    - push-only channel to the host (pass / error / setSize).
  // ctx       - the per-round context (seed + resolved locale/skin/config).

  const cleanup = startGame(container, bridge, ctx);

  // Return an optional cleanup function; the widget calls it on unmount.
  return cleanup;
});
```

マニフェストは `register` に渡し **ません**。サーバーがインデックス時に `caputchin.json` を読み、解決済みのプリセットを `ctx` としてあなたのファクトリーに送り下ろします。完全な面は [SDK リファレンス](/docs/marketplace-game-development/game-sdk-reference) を参照してください。

## 3. ラウンドごとのコンテキストからレンダリングする

ファクトリーの 3 つ目の引数 `ctx` は、訪問者ごとに変わるすべてを運びます：

- `ctx.seed` - ラウンドごとのシード。**すべてのランダム性をこれから導きます**（ステップ 5 参照）。検証済みのセッションの外では `null`。
- `ctx.locale` - 解決済みの言語の文字列（`ctx.locale._lang` に加えてあなたのキー）、または `null`。
- `ctx.skin` - 解決済みの色とアセットの URL（`ctx.skin._theme`、常に `light` か `dark`、に加えてあなたのキー）、または `null`。
- `ctx.config` - 解決済みのゲームプレイの構成、または `null`。

あなた自身のキーをこれらから読みます。あなた自身はプリセットを決して解決しません。マニフェストが合致するブロックを宣言しないとき、それぞれが `null` なので、常に組み込みの既定にフォールバックしてください：

```js
function startGame(container, bridge, ctx) {
  const title = ctx.locale?.title ?? "Tap the targets";
  const accent = ctx.skin?.accent_color ?? "#2da44e";
  const targetCount = ctx.config?.target_count ?? 5;
  // ...render with these...
}
```

レイアウトに明示的なサイズが要るなら、最初の描画の後に一度 `bridge.setSize(width, height)` を呼びます。

## 4. 勝ち、負け、エラー

あなたのゲームが、プレイヤーがいつ勝つかを決め、ブリッジを通じてホストに伝えます：

- 勝ちでは、ラウンドの [トレース](#5-record-a-trace)（ステップ 5）とともに `bridge.pass({ trace })` を呼びます。
- 負けまたは放棄では、**何も** 呼びません。沈黙が失敗のシグナルです。
- ゲーム自体が壊れたら（アセットが失敗、例外）、`bridge.error({ code, message })` を呼びます。それは、プレイヤーの負けではなく、ゲーム内部の失敗のためです。

```js
function onWin(traceString) {
  bridge.pass({ trace: traceString });
}
function onAssetFailure(err) {
  bridge.error({ code: "asset-load-failed", message: String(err) });
}
```

## 5. トレースを記録する [#5-record-a-trace]

これが、ゲームを **リプレイ可能** にするステップです。プレイヤーが動くにつれて、結果を駆動する入力（どのターゲットを、どの順で当てたか、関係するならタイミングつき）を記録し、その記録を文字列かバイト配列にシリアライズします。それがあなたの **トレース** です。シードと組み合わさって、トレースはあなたのロジックに正確な結果を再現させなければなりません。サーバーがそれを再実行するからです。

2 つのルールがそれを可能にします：

1. **すべてのランダムな選択を `ctx.seed` から導きます。** 結果に影響する何かのために `Math.random()` を呼んだり、壁時計を読んだりしないでください。
2. **リプレイに十分を記録します。** トレースにシードを足したものが、あなたのゲームロジックへの完全な入力です。

```js
function makeRng(seed) {
  // seed is ctx.seed; feed it so the server reproduces the same sequence.
  let s = hashSeed(seed);
  return () => (s = (s * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff;
}
```

`seed`、トレース、判定の形は [リプレイ契約](/docs/marketplace-game-development/replay-contract) が定義します。そのページは、この記録されたプレイを、サーバーがリプレイするヘッドレスの `run` アーティファクトに変えることを扱います。決定論的なロジックを手で書くのが面倒に聞こえるなら、[エンジンキット](/docs/marketplace-game-development/engine-kit) が、任意で、あなたのためにそれをします。

## 6. サンドボックスのためにバンドルする

ウィジェットはちょうど 1 つのスクリプト URL を読み込むので、すべてがその 1 つのファイルに入っていなければなりません。1 つの自己完結した出力のために、バンドラーを設定してください：

- アセット（スプライト、音、フォント）をデータ URL としてインライン化する。
- コード分割を無効にする。
- WASM を使うなら、base64 として埋め込み、バイトからインスタンス化する。

不透明オリジンで厳格 CSP の iframe の中で **動かない** パターン：

- パス相対の `fetch('./sprite.png')` - 取得する元のパスがありません。
- 動的な `import('./chunk.js')` - 2 つ目の URL がブロックされます。
- `new Worker('./worker.js')` - 代わりにインラインの `Blob` URL から worker を生成してください。
- 実行時の外部 CDN のフェッチ - `connect-src` がそれらをブロックします。

## 7. ローカルでテストする

特別なハーネスはありません。静的な HTML ページにウィジェットを埋め込み、`game-src` をあなたのローカルのバンドル出力に向け、ブラウザでそれを遊びます：

```html
<caputchin-game sitekey="cpt_pub_..." game-src="http://localhost:8080/game.js"></caputchin-game>
```

これは [カスタムゲーム](/docs/custom-game-development/self-hosted-game) が使うのと同じ `game-src` のパスです。マーケットプレイスでは、代わりにリポジトリを公開して、プラットフォームがあなたのためにバンドルを固定します。

## 次のステップ

- [リプレイ契約](/docs/marketplace-game-development/replay-contract)：記録されたプレイを、ゲームをリプレイ可能にする `run` アーティファクトに変える。
- [caputchin.json マニフェスト](/docs/marketplace-game-development/the-caputchin-json-manifest)：ゲーム、そのプリセット、そのバンドルを記述する。
- [マーケットプレイスに公開する](/docs/marketplace-game-development/publish-to-the-marketplace)：リポジトリにタグを付けて本番にする。

## あわせて読む

- [ゲーム SDK リファレンス](/docs/marketplace-game-development/game-sdk-reference)：すべてのエクスポートを完全に。
- [engine-kit](/docs/marketplace-game-development/engine-kit)：無料で決定論を得る任意の方法。
