Caputchin
Разработка игры для маркетплейса

Манифест caputchin.json

Открыть как Markdown

caputchin.json в корне твоего репозитория является источником истины автора и индексатора для игры Marketplace. Индексатор читает его на сервере, чтобы узнать идентичность игры, где живёт её бандл, какие пресеты она предлагает и как её реплеить. Он никогда не читается в браузере; SDK не загружает его в рантайме.

Эта страница служит справочником полей. Для построения смотри Построй игру для Marketplace; для публикации смотри Опубликуй в Marketplace. Точные типы экспортируются из 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, чтобы подтвердить, что ты принимаешь Условия отправки в Marketplace. Любое другое значение (или отсутствие) выбрасывает манифест из индекса. Только-самостоятельно-размещаемые манифесты могут его опустить.
licenseдля индексацииИдентификатор или выражение SPDX, покрывающее твой код и встроенные ассеты. Должно вычисляться в одобренный идентификатор (смотри справочник ошибок публикации).
marketplaceдля индексацииПрисутствие служит сигналом «индексируй меня». Отсутствие означает валидную самостоятельно размещаемую игру, которую 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.

Эти подсказки учитываются только для игр, которые платформа разрешает на сервере (игры Marketplace или 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 обёртки, чтобы индексировать детей без страницы коллекции.

См. также

На этой странице