caputchin.json 清单
你仓库根部的 caputchin.json 是一个应用市场游戏的作者加索引器的真相来源。索引器在服务端读它,以得知这个游戏的身份、它的包住在哪里、它提供哪些预设、以及如何回放它。它 绝不 在浏览器里读;SDK 不在运行时加载它。
这一页是那个字段参考。构建见 构建一个应用市场游戏;发布见 发布到应用市场。确切的类型由 SDK 作为 GameManifest 导出(见 SDK 参考)。
一个最小的单一游戏
{
"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,以确认你接受 应用市场提交条款。任何其他值(或缺失)都把这个清单从索引里剔除。仅自托管的清单可以省略它。 |
license | 索引时 | 一个涵盖你代码和捆绑资源的 SPDX 标识符或表达式。必须求值为一个被批准的标识符(见 发布错误参考)。 |
marketplace | 索引时 | 它的存在就是那个“索引我”的信号。缺失意味着一个应用市场忽略的有效 自托管 游戏。见 marketplace 块。 |
npm | 配 entry | 索引器解析成一个 jsDelivr URL 的 npm 包坐标。 |
entry | 配 npm | 指向构建出的包的仓库相对路径。一个可运行的游戏必须有 entry、npm 或两者。 |
games | 集合时 | 一个集合包装器的子清单路径。和 entry / npm 互斥。见 集合。 |
run | 可选 | 一个专用的 headless 回放工件。见 run 工件。 |
preferred | 可选 | 宿主 可以 遵从的呈现提示。见 preferred 块。 |
locales / skins / configurations | 可选 | iframe 里 SDK 消费的预设块。见 预设块。 |
没有 version 字段:索引器自己把包钉到一个不可变的 ref(已发布的 npm 版本或解析出的提交 SHA)。
marketplace 块
| 字段 | 用途 |
|---|---|
name | 卡片标题。回退到仓库名(单一 / 包装器)或 leaf-dir 名(集合子项)。 |
description | 卡片副标题和详情页正文。 |
preview | 图像路径(相对于仓库根)或绝对 URL。大约 600x315,主体居中。 |
version | 给详情页用的仅显示版本字符串。可选。 |
support | 作者声明的兼容性标志(responsive、touch、accessible、audio、……),平台绝不核实;作为筛选器和卡片图标浮现。 |
author | 可选的 { name?, url?, email? }。name / url 作为详情页上的一行作者署名渲染;email 绝不显示,是 发布失败邮件 的 选择加入。这三个子字段相互独立。 |
这个块完全可选。省略 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(自定义游戏)自托管它。
run 工件
默认地,回放自检跑你实时的 entry 包。当你的游戏很大、或基于框架或 WASM 时,改为交付一个专用的精简 headless run 工件:
{
"run": {
"entry": "dist/run.js",
"modules": [
{ "name": "sim.wasm", "type": "wasm", "path": "dist/sim.wasm" }
]
}
}| 字段 | 含义 |
|---|---|
run.entry | 指向 headless run 包的仓库相对路径(回放契约 的 run 导出)。 |
run.modules | run 按 name 导入的模块条目的可选数组。 |
索引器强制的约束
这些在索引时被校验;一处违反会让发布以一个 manifest-error 失败(见 发布错误参考)。
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。这个工件必须导出什么,见 回放契约。
preferred 块
可选的 preferred 块携带呈现提示。每个键都是建议性的:宿主 可以 遵从它,而它绝不覆盖一个明确的嵌入属性。
{
"preferred": { "width": 360, "height": 480, "layout": "modal" }
}一个应该默认横跨它容器的响应式游戏,可以在任一轴上声明 "full":
{
"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 提示都忽略。
预设块
locales、skins 和 configurations 各声明一个可选的 schema(逐键的类型和文档)加上 presets(那些命名的选项库)。组件对着这些解析访客的选择,并把扁平化的结果作为 ctx 交给你的游戏。完整的字段类型目录是那份共享的 自定义模式参考;同样的类型驱动一个 自定义游戏的仪表盘模式。
一个 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 获胜:如果一个维度同时内联和作为文件声明,就用内联块、忽略文件(发布会警告,好让你知道它是死的)。把每个维度恰好放在一个地方。
集合
一个仓库可以交付好几个游戏。一个集合包装器声明子路径而非 entry / npm:
{
"marketplace": { "name": "Caputchin Core Pack", "description": "The official pack." },
"games": ["./packages/leaf-memory", "./packages/dino-runner"]
}每个路径指向一个持有它自己 caputchin.json 的子目录。子项 id 是 owner/repo/<leaf-dir>。省略包装器的 marketplace 块,以索引这些子项而不带一个集合页面。
另见
- 构建一个应用市场游戏:产出这个清单所指向的那个包。
- 回放契约:那个
run工件必须导出什么。 - 发布错误参考:每一个清单校验错误和那份被批准的许可证清单。
- 自定义模式参考:预设块所用的那些字段类型。