---
type: reference
title: 游戏 SDK 参考
summary: 一个游戏作者对着写的完整 @caputchin/game-sdk 面、register 函数、仅推送的 bridge、逐回合上下文，以及预设类型。
---

`@caputchin/game-sdk` 是一个游戏作者对着写的那个契约：一个 `register` 助手、一个仅推送的 `Bridge`、逐回合的 `GameContext`，以及清单预设块的 TypeScript 类型。它和面向用户的组件分开发布，于是游戏绝不传递性地捆绑组件运行时。第一方游戏用这同一个公开 API；没有私有契约。

一个有引导的构建，见 [构建一个应用市场游戏](/docs/marketplace-game-development/build-a-marketplace-game)。声明这个 SDK 所暴露预设的那个清单，见 [caputchin.json 清单](/docs/marketplace-game-development/the-caputchin-json-manifest)。

## `register(factory)`

那单一的注册入口点。传你的游戏工厂；你 **不** 传清单（服务器在索引时读 `caputchin.json`，并把解析出的预设作为工厂的上下文送下来）。注册两次会记一条控制台警告，且最后一次写入获胜；没有平台强制。

```ts
register(factory: GameFactory): void
```

## 游戏工厂

```ts
type GameFactory = (
  container: HTMLElement,
  bridge: Bridge,
  ctx?: GameContext,
) => (() => void) | void
```

| 参数 | 含义 |
|---|---|
| `container` | 游戏沙箱化 iframe 里面的一个元素。在这里渲染。样式天然被限定范围，iframe 是它自己的文档。 |
| `bridge` | 通往宿主的仅推送通道（见 [bridge](#the-bridge)）。游戏向上发出；它不订阅。工厂被调用就是那个开始信号。 |
| `ctx` | 逐回合的 [上下文](#the-context)（种子加上解析出的预设）。在类型里是可选的，因为组件可能在一个已核验会话之外跑一个游戏。 |
| return | 一个可选的清理函数，组件在卸载你的游戏时调用它。 |

## bridge [#the-bridge]

bridge 是仅推送的：游戏向宿主报告事件，而从不监听。它的成员：

| 成员 | 形状 | 作用 |
|---|---|---|
| `pass` | `pass(result: { trace: string }): void` | 示意这个回合 **被通过了**，把不透明的 `trace` 交给宿主。服务器在签发的种子下重跑游戏的 [`run`](/docs/marketplace-game-development/replay-contract) 来算出那个权威裁定，所以游戏在这里 **不** 报告一个分数。第一次调用释放被持有的验证并锁定令牌；之后的调用被忽略。 |
| `error` | `error(err: { code: string; message?: string }): void` | 游戏自己失败了（资源加载、内部异常）。向用户浮现一个 `error` 事件。区别于一次玩家落败，后者靠什么都不调用来示意。 |
| `setSize` | `setSize(width: number, height: number): void` | 明确地把 iframe 调整为适配内容。在第一次绘制之后调用；组件也会自动量测游戏的第一个子元素，所以大多数游戏从不需要这个。 |
| `layout` | `readonly layout: 'inline' \| 'modal' \| 'fullscreen' \| null` | 游戏所跑在的那个解析出的呈现方式，或在未知时为 `null`。 |

有意没有 `complete`、没有 `start` 监听器、没有 `unmount` 方法（改为返回一个清理函数）、也没有沉默之外的失败信号。

## 上下文 [#the-context]

```ts
interface GameContext {
  seed:   Seed          | null
  locale: ResolvedLocale | null
  skin:   ResolvedSkin   | null
  config: ResolvedConfig | null
}
```

| 字段 | 含义 |
|---|---|
| `seed` | 逐回合的回放种子（来自回放契约的一个 [`Seed`](/docs/marketplace-game-development/replay-contract)）。从它给所有游戏随机性播种。当游戏在一个已核验会话之外跑时为 `null`。 |
| `locale` | 解析出的语言对象：`_lang`（BCP-47）、`_direction`，加上你扁平化的文本键。如果你的清单不交付 `locales` 块则为 `null`。 |
| `skin` | 解析出的皮肤：`_theme` 加上你扁平化的颜色/资源键，资源 URL 已是绝对的。`_theme` 始终是皮肤为之解析的那个具体模式，`light` 或 `dark`（绝不是 `any`），所以一个与主题无关的预设报告访客的实际模式。如果没有 `skins` 块则为 `null`。 |
| `config` | 解析出的配置：你扁平化的带类型标量。如果没有 `configurations` 块则为 `null`。 |

当对应的清单块缺失时每一个都是 `null`，所以总是提供一个内置回退。

## 预设类型

SDK 导出用于撰写 `caputchin.json`（以及拆分的 `.caputchin/` 文件）并带类型检查的 TypeScript 类型。这些镜像 [清单](/docs/marketplace-game-development/the-caputchin-json-manifest) 块：

| 类型 | 描述 |
|---|---|
| `GameManifest` | 整个 `caputchin.json`。作者加索引器的真相来源；绝不在浏览器里读。 |
| `LocalePreset` / `ResolvedLocale` | 一个声明的 locale 预设 / 游戏收到的那个解析出的对象。 |
| `SkinPreset` / `ResolvedSkin` / `SkinSchemaEntry` / `SkinValueType` | 皮肤预设、解析出的皮肤，以及逐键的类型模式。 |
| `ConfigPreset` / `ResolvedConfig` / `ConfigSchemaEntry` / `ConfigValueType` | 配置预设、解析出的配置，以及逐键的类型模式。 |
| `LocalesFile` / `SkinsFile` / `ConfigurationsFile` | 每个 `.caputchin/<axis>.json` 拆分文件的顶层对象。 |
| `MarketplaceMetadata` / `PreferredPresentation` | `marketplace` 块和那个 `preferred` 占位提示。 |

用一个 `satisfies` 导入撰写一个拆分文件，好让编译器检查它：

```ts
import type { LocalesFile } from "@caputchin/game-sdk";
export default { schema: { /* ... */ }, presets: { /* ... */ } } satisfies LocalesFile;
```

## 什么被有意省去

- 没有 `sessionId` 或平台标识符到达游戏。
- 没有 `start` / `pause` / `resume` 生命周期钩子；工厂调用就是那个开始。
- 没有 `maxScore` 或平台分数范围；裁定的分数就是你的 `run` 返回什么。

这个契约有意做得极小，好让它跨多年的目录增长保持稳定。

## 另见

- [构建一个应用市场游戏](/docs/marketplace-game-development/build-a-marketplace-game)：用这个面的那篇教程。
- [回放契约](/docs/marketplace-game-development/replay-contract)：bridge 和上下文所指的那个 `Seed`、轨迹和裁定。
- [caputchin.json 清单](/docs/marketplace-game-development/the-caputchin-json-manifest)：声明上下文所解析的那些预设。
