Манифест 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 | Координата npm-пакета, которую индексатор разрешает в URL jsDelivr. |
entry | с npm | Путь к собранному бандлу относительно репозитория. entry, npm или оба должны присутствовать для запускаемой игры. |
games | для коллекций | Пути под-манифестов для обёртки коллекции. Взаимно исключающи с entry / npm. Смотри Коллекции. |
run | опционально | Выделенный headless-артефакт реплея. Смотри Артефакт run. |
preferred | опционально | Подсказки представления, которые хост МОЖЕТ учесть. Смотри Блок preferred. |
locales / skins / configurations | опционально | Блоки пресетов, потребляемые SDK в iframe. Смотри Блоки пресетов. |
Поля version нет: индексатор сам прибивает бандл к неизменному ref (опубликованная версия npm или разрешённый коммит SHA).
Блок marketplace
| Поле | Назначение |
|---|---|
name | Заголовок карточки. Откатывается на имя репозитория (одиночная / обёртка) или имя leaf-каталога (ребёнок коллекции). |
description | Подзаголовок карточки и тело страницы деталей. |
preview | Путь изображения (относительно корня репозитория) или абсолютный URL. Около 600x315, субъект по центру. |
version | Строка версии только для отображения на странице деталей. Опционально. |
support | Объявленные автором флаги совместимости (responsive, touch, accessible, audio, ...), никогда не проверяемые платформой; выводятся как фильтры и иконки карточки. |
author | Опциональный { name?, url?, email? }. name / url рендерятся как подпись автора на странице деталей; email никогда не показывается и является opt-in для писем о сбое публикации. Все три подполя независимы. |
Блок полностью опционален. Опусти 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: базовое имя должно совпадать с
[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 встраивания, затем эта предпочтительная раскладка, затем inline. |
Эти подсказки учитываются только для игр, которые платформа разрешает на сервере (игры маркетплейса или id игры, данный без ключа сайта). Самостоятельно размещённый бандл game-src, который платформа не может прочитать до монтирования, игнорирует и след, и подсказку раскладки.
Блоки пресетов
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/
Блоки пресетов (особенно полные наборы локалей) делают 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. - Справочник ошибок публикации: каждая ошибка валидации манифеста и список одобренных лицензий.
- Справочник схемы настройки: типы полей, которые используют блоки пресетов.