---
type: reference
title: caputchin.json 清单
summary: 描述一个应用市场游戏的 caputchin.json 清单的每一个字段、marketplace 块、分发指针、回放 run 工件、预设块，以及 .caputchin 拆分文件。
---

你仓库根部的 `caputchin.json` 是一个应用市场游戏的作者加索引器的真相来源。索引器在服务端读它，以得知这个游戏的身份、它的包住在哪里、它提供哪些预设、以及如何回放它。它 **绝不** 在浏览器里读；SDK 不在运行时加载它。

这一页是那个字段参考。构建见 [构建一个应用市场游戏](/docs/marketplace-game-development/build-a-marketplace-game)；发布见 [发布到应用市场](/docs/marketplace-game-development/publish-to-the-marketplace)。确切的类型由 SDK 作为 `GameManifest` 导出（见 [SDK 参考](/docs/marketplace-game-development/game-sdk-reference)）。

## 一个最小的单一游戏

```json
{
  "terms_accepted": true,
  "license": "MIT",
  "marketplace": {
    "name": "Leaf Memory",
    "description": "Match pairs of tropical leaves before the timer runs out.",
    "preview": "preview.png"
  },
  "npm": "@your-org/leaf-memory",
  "entry": "dist/leaf-memory.js"
}
```

## 顶层字段

| 字段 | 必需 | 用途 |
|---|---|---|
| `terms_accepted` | 索引时 | 必须是字面量 `true`，以确认你接受 [应用市场提交条款](/legal/submission-terms)。任何其他值（或缺失）都把这个清单从索引里剔除。仅自托管的清单可以省略它。 |
| `license` | 索引时 | 一个涵盖你代码和捆绑资源的 SPDX 标识符或表达式。必须求值为一个被批准的标识符（见 [发布错误参考](/docs/marketplace-game-development/publish-failed-reference#approved-licenses)）。 |
| `marketplace` | 索引时 | 它的存在就是那个“索引我”的信号。缺失意味着一个应用市场忽略的有效 [自托管](/docs/custom-game-development/overview) 游戏。见 [marketplace 块](#the-marketplace-block)。 |
| `npm` | 配 `entry` | 索引器解析成一个 jsDelivr URL 的 npm 包坐标。 |
| `entry` | 配 `npm` | 指向构建出的包的仓库相对路径。一个可运行的游戏必须有 `entry`、`npm` 或两者。 |
| `games` | 集合时 | 一个集合包装器的子清单路径。和 `entry` / `npm` 互斥。见 [集合](#collections)。 |
| `run` | 可选 | 一个专用的 headless 回放工件。见 [run 工件](#the-run-artifact)。 |
| `preferred` | 可选 | 宿主 **可以** 遵从的呈现提示。见 [preferred 块](#the-preferred-block)。 |
| `locales` / `skins` / `configurations` | 可选 | iframe 里 SDK 消费的预设块。见 [预设块](#preset-blocks)。 |

没有 `version` 字段：索引器自己把包钉到一个不可变的 ref（已发布的 npm 版本或解析出的提交 SHA）。

## marketplace 块 [#the-marketplace-block]

| 字段 | 用途 |
|---|---|
| `name` | 卡片标题。回退到仓库名（单一 / 包装器）或 leaf-dir 名（集合子项）。 |
| `description` | 卡片副标题和详情页正文。 |
| `preview` | 图像路径（相对于仓库根）或绝对 URL。大约 600x315，主体居中。 |
| `version` | 给详情页用的仅显示版本字符串。可选。 |
| `support` | 作者声明的兼容性标志（`responsive`、`touch`、`accessible`、`audio`、……），平台绝不核实；作为筛选器和卡片图标浮现。 |
| `author` | 可选的 `{ name?, url?, email? }`。`name` / `url` 作为详情页上的一行作者署名渲染；`email` 绝不显示，是 [发布失败邮件](/docs/marketplace-game-development/publish-to-the-marketplace#get-notified-when-a-publish-fails) 的 **选择加入**。这三个子字段相互独立。 |

这个块完全可选。省略 `name` / `url`，详情页就只是不显示作者署名（页面别处显示的 GitHub 所有者是一个独立的、始终存在的身份，不是这个署名的回退）。省略 `email`，你就收不到发布失败通知。只设你想要的那些子字段。

## 分发指针

索引器把每个游戏的包钉到一个不可变的 ref，好让存储的完整性哈希保持有效，并在每次运行时重新解析（每日 cron 加手动的“发布或更新”）：

- `entry` + `npm` 解析为 `cdn.jsdelivr.net/npm/<npm>@<resolved-version>/<entry>`。
- 仅 `entry` 解析为 `cdn.jsdelivr.net/gh/<owner>/<repo>@<commit-sha>/<entry>`。
- 仅 `npm` 解析为被钉版本上的包默认入口。

没有用户侧的版本固定；要冻结一个构建，用户通过组件的 `game-src`（[自定义游戏](/docs/custom-game-development/self-hosted-game)）自托管它。

## run 工件 [#the-run-artifact]

默认地，回放自检跑你实时的 `entry` 包。当你的游戏很大、或基于框架或 WASM 时，改为交付一个专用的精简 headless `run` 工件：

```json
{
  "run": {
    "entry": "dist/run.js",
    "modules": [
      { "name": "sim.wasm", "type": "wasm", "path": "dist/sim.wasm" }
    ]
  }
}
```

| 字段 | 含义 |
|---|---|
| `run.entry` | 指向 headless `run` 包的仓库相对路径（[回放契约](/docs/marketplace-game-development/replay-contract) 的 `run` 导出）。 |
| `run.modules` | run 按 `name` 导入的模块条目的可选数组。 |

### 索引器强制的约束

这些在索引时被校验；一处违反会让发布以一个 `manifest-error` 失败（见 [发布错误参考](/docs/marketplace-game-development/publish-failed-reference)）。

**`run.entry`：**

- 必须是 **JavaScript**：basename 必须匹配 `[a-zA-Z0-9_-]+.js`。run 工件始终是 JS（WASM 作为一个模块交付，见下文）。
- 必须是一个干净的仓库相对路径：没有前导斜杠、没有 `..` 穿越、没有空白、没有 `?` / `#`、没有 `scheme://` 前缀。

**每个 `run.modules[]` 条目** 是 `{ name, type, path }`：

- `name` 必须匹配 `[a-zA-Z0-9_-]+.(wasm|js)`：一个模块要么是 **JS 要么是 WASM**，别无其他。`name` 是 entry 所用的那个导入说明符。
- `type` 必须和扩展名一致：一个 `.wasm` 名用 `wasm`，一个 `.js` 名用 `js`。
- `name` 不能是回放宿主内部使用的一个 **保留** 名（`entry.js`、`artifact.js`）。
- `name` 在数组内必须 **唯一**（不重复）。
- `path` 必须是一个干净的仓库相对路径（和 `run.entry` 同样的规则）。
- 至多 **16** 个模块。

省略 `run` 以直接回放实时的 `entry`。这个工件必须导出什么，见 [回放契约](/docs/marketplace-game-development/replay-contract)。

## preferred 块 [#the-preferred-block]

可选的 `preferred` 块携带呈现提示。每个键都是建议性的：宿主 **可以** 遵从它，而它绝不覆盖一个明确的嵌入属性。

```json
{
  "preferred": { "width": 360, "height": 480, "layout": "modal" }
}
```

一个应该默认横跨它容器的响应式游戏，可以在任一轴上声明 `"full"`：

```json
{
  "preferred": { "width": "full", "height": 480 }
}
```

| 字段 | 含义 |
|---|---|
| `width` / `height` | 一个像素占位，或字面量 `"full"`。当嵌入把 `width` / `height` 留空时组件应用它（一个明确的嵌入值，包括 `full`，会改为获胜）。一个像素值把 iframe 调到那个数；`"full"` 把那个轴拉伸到填满父级，和一个嵌入 `width="full"` 同样的效果。省略以回退到组件的内置默认占位。 |
| `layout` | 组件围绕游戏构建的那个外壳：`inline`、`modal` 或 `fullscreen`。仅当嵌入把 `layout` 留空时使用（它的默认 `auto`）。解析顺序：嵌入的 `layout` 属性、然后这个 preferred layout、然后 `inline`。 |

这些提示只对平台在服务端解析的游戏（应用市场游戏，或一个不带站点密钥给出的游戏 id）被遵从。一个平台在挂载前读不到的自托管 `game-src` 包，把占位和 layout 提示都忽略。

## 预设块 [#preset-blocks]

`locales`、`skins` 和 `configurations` 各声明一个可选的 `schema`（逐键的类型和文档）加上 `presets`（那些命名的选项库）。组件对着这些解析访客的选择，并把扁平化的结果作为 [`ctx`](/docs/marketplace-game-development/game-sdk-reference) 交给你的游戏。完整的字段类型目录是那份共享的 [自定义模式参考](/docs/references/customization-schema)；同样的类型驱动一个 [自定义游戏的仪表盘模式](/docs/custom-game-development/dashboard-schema)。

一个 `skins.schema` 字段可以是一个 `color`、一个资源（`image` / `audio` / `video`），或一个标量（`boolean`、`number`、`range`、`list`），用和 `configurations` 同样的约束形式（`{ "type": "range", "min": 0, "max": 24 }`、`["dots","stripes"]`，等等）。标量皮肤值在 `ctx.skin` 里解析为它们的带类型值（一个 `number` 是一个真正的数），恰好像一个配置值；颜色和资源值解析为字符串。

一个皮肤预设的 `_theme` 声明它在哪种模式下工作：`light`、`dark` 或 `any`（省略它意味着 `any`）。一个 `light` 或 `dark` 预设只在那种模式里显示；一个 `any` 预设在任一背景上都好看且对两者都有资格。每种模式有一个默认。一个标了 `_default: true` 的预设是它有资格的那个/那些模式的默认，所以一个 `any` 默认覆盖两者；当几个有资格的预设为一种模式都被标为默认时，声明顺序里的第一个赢得它。把一个特定模式的预设列在一个 `any` 的之上，以给那种模式一个专属皮肤，而让那个 `any` 预设落到另一种。

## `.caputchin/` 拆分文件

预设块（尤其是完整的 locale 集）让 `caputchin.json` 变长。把任何一个维度移进 `.caputchin/` 文件夹下它自己的文件里，让清单保持短：

```
caputchin.json
.caputchin/locales.json
.caputchin/skins.json
.caputchin/configurations.json
```

每个文件的顶层对象 **就是** 那个维度块（`{ schema?, presets }`）。三者都可选。优先级是整维度替换、`caputchin.json` 获胜：如果一个维度同时内联和作为文件声明，就用内联块、忽略文件（发布会警告，好让你知道它是死的）。把每个维度恰好放在一个地方。

## 集合 [#collections]

一个仓库可以交付好几个游戏。一个集合包装器声明子路径而非 `entry` / `npm`：

```json
{
  "marketplace": { "name": "Caputchin Core Pack", "description": "The official pack." },
  "games": ["./packages/leaf-memory", "./packages/dino-runner"]
}
```

每个路径指向一个持有它自己 `caputchin.json` 的子目录。子项 id 是 `owner/repo/<leaf-dir>`。省略包装器的 `marketplace` 块，以索引这些子项而不带一个集合页面。

## 另见

- [构建一个应用市场游戏](/docs/marketplace-game-development/build-a-marketplace-game)：产出这个清单所指向的那个包。
- [回放契约](/docs/marketplace-game-development/replay-contract)：那个 `run` 工件必须导出什么。
- [发布错误参考](/docs/marketplace-game-development/publish-failed-reference)：每一个清单校验错误和那份被批准的许可证清单。
- [自定义模式参考](/docs/references/customization-schema)：预设块所用的那些字段类型。
