Caputchin
Desenvolvimento de jogo de marketplace

O manifesto caputchin.json

O caputchin.json na raiz do seu repositório é a fonte de verdade do autor e do indexador para um jogo de marketplace. O indexador o lê no servidor para conhecer a identidade do jogo, onde seu bundle vive, quais presets ele oferece, e como reexecutá-lo. Ele nunca é lido no navegador; o SDK não o carrega em tempo de execução.

Esta página é a referência de campos. Para a construção, veja Construir um jogo de marketplace; para a publicação, veja Publicar no marketplace. Os tipos exatos são exportados do SDK como GameManifest (veja a referência do SDK).

Um jogo único mínimo

{
  "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"
}

Campos de nível superior

CampoObrigatórioPropósito
terms_acceptedpara indexarPrecisa ser o literal true para confirmar que você aceita os Termos de Submissão do Marketplace. Qualquer outro valor (ou ausente) tira o manifesto do índice. Manifestos só-auto-hospedados podem omiti-lo.
licensepara indexarUm identificador ou expressão SPDX cobrindo seu código e ativos empacotados. Precisa avaliar para um identificador aprovado (veja a referência de erros de publicação).
marketplacepara indexarA presença é o sinal de "me indexe". Ausente significa um jogo auto-hospedado válido que o marketplace ignora. Veja O bloco marketplace.
npmcom entryA coordenada de pacote npm que o indexador resolve para uma URL jsDelivr.
entrycom npmCaminho relativo ao repositório para o bundle construído. entry, npm, ou ambos precisam estar presentes para um jogo executável.
gamespara coleçõesCaminhos de submanifesto para um wrapper de coleção. Mutuamente exclusivo com entry / npm. Veja Coleções.
runopcionalUm artefato de replay headless dedicado. Veja O artefato run.
preferredopcionalDicas de apresentação que o anfitrião PODE honrar. Veja O bloco preferred.
locales / skins / configurationsopcionalBlocos de preset consumidos pelo SDK no iframe. Veja Blocos de preset.

Não há campo version: o indexador fixa o bundle em uma ref imutável ele mesmo (a versão npm publicada ou o SHA de commit resolvido).

O bloco marketplace

CampoPropósito
nameTítulo do card. Recai para o nome do repositório (único / wrapper) ou o nome do diretório folha (filho de coleção).
descriptionSubtítulo do card e corpo da página de detalhe.
previewCaminho de imagem (relativo à raiz do repositório) ou URL absoluta. Cerca de 600x315, com o sujeito centralizado.
versionString de versão só de exibição para a página de detalhe. Opcional.
supportFlags de compatibilidade declaradas pelo autor (responsive, touch, accessible, audio, ...), nunca verificadas pela plataforma; expostas como filtros e ícones de card.
author{ name?, url?, email? } opcional. name / url renderizam como uma assinatura de autor na página de detalhe; email nunca é mostrado e é a opção de adesão para os e-mails de falha de publicação. Os três subcampos são independentes.

O bloco é totalmente opcional. Omita name / url e a página de detalhe simplesmente não mostra assinatura de autor (o dono do GitHub mostrado em outro lugar da página é uma identidade separada, sempre presente, não um fallback para esta assinatura). Omita email e você não recebe notificações de falha de publicação. Defina só os subcampos que quiser.

Ponteiros de distribuição

O indexador fixa o bundle de cada jogo em uma ref imutável para que o hash de integridade armazenado continue válido, e re-resolve a cada execução (cron diário mais "Publicar ou atualizar" manual):

  • entry + npm resolvem para cdn.jsdelivr.net/npm/<npm>@<resolved-version>/<entry>.
  • entry sozinho resolve para cdn.jsdelivr.net/gh/<owner>/<repo>@<commit-sha>/<entry>.
  • npm sozinho resolve para a entrada padrão do pacote na versão fixada.

Não há fixação de versão do lado do usuário; para congelar uma build, um usuário a auto-hospeda pelo game-src do widget (jogo personalizado).

O artefato run

Por padrão a autoverificação de replay roda seu bundle entry ativo. Quando seu jogo é grande ou baseado em framework ou WASM, envie um artefato run headless enxuto e dedicado em vez disso:

{
  "run": {
    "entry": "dist/run.js",
    "modules": [
      { "name": "sim.wasm", "type": "wasm", "path": "dist/sim.wasm" }
    ]
  }
}
CampoSignificado
run.entryCaminho relativo ao repositório para o bundle run headless (o export run do contrato de replay).
run.modulesArray opcional de entradas de módulo que o run importa por name.

Restrições que o indexador impõe

Estas são validadas no momento da indexação; uma violação falha a publicação com um manifest-error (veja a referência de erros de publicação).

run.entry:

  • Precisa ser JavaScript: o basename precisa casar com [a-zA-Z0-9_-]+.js. O artefato run é sempre JS (o WASM é enviado como um módulo, abaixo).
  • Precisa ser um caminho limpo relativo ao repositório: sem barra inicial, sem travessia .., sem espaço em branco, sem ? / #, sem prefixo scheme://.

Cada entrada run.modules[] é { name, type, path }:

  • name precisa casar com [a-zA-Z0-9_-]+.(wasm|js), um módulo é ou JS ou WASM, nada mais. O name é o especificador de import que a entrada usa.
  • type precisa concordar com a extensão: wasm para um nome .wasm, js para um nome .js.
  • name não pode ser um nome reservado (entry.js, artifact.js) que o anfitrião de replay usa internamente.
  • name precisa ser único dentro do array (sem duplicatas).
  • path precisa ser um caminho limpo relativo ao repositório (mesmas regras de run.entry).
  • No máximo 16 módulos.

Omita run para reexecutar o entry ativo diretamente. Veja o contrato de replay para o que o artefato precisa exportar.

O bloco preferred

O bloco preferred opcional carrega dicas de apresentação. Toda chave é consultiva: o anfitrião PODE honrá-la, e ela nunca sobrescreve um atributo de embed explícito.

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

Um jogo responsivo que deve ocupar seu contêiner por padrão pode declarar "full" em qualquer eixo:

{
  "preferred": { "width": "full", "height": 480 }
}
CampoSignificado
width / heightUma pegada em pixels, ou o literal "full". O widget a aplica quando o embed deixa width / height sem definir (um valor de embed explícito, inclusive full, vence). Um valor em pixels dimensiona o iframe para essa contagem; "full" estica esse eixo para preencher o pai, o mesmo efeito que um width="full" de embed tem. Omita para recair na pegada padrão embutida do widget.
layoutO shell que o widget constrói ao redor do jogo: inline, modal ou fullscreen. Usado só quando o embed deixa layout sem definir (seu padrão auto). Ordem de resolução: o atributo layout do embed, depois este layout preferred, depois inline.

Estas dicas são honradas só para jogos que a plataforma resolve no servidor (jogos de marketplace, ou um id de jogo dado sem uma chave de site). Um bundle game-src auto-hospedado que a plataforma não consegue ler antes da montagem ignora tanto a pegada quanto a dica de layout.

Blocos de preset

locales, skins e configurations cada um declara um schema opcional (tipos por chave e documentação) mais presets (os bancos de opções nomeados). O widget resolve a escolha do visitante contra estes e entrega ao seu jogo o resultado achatado como ctx. O catálogo completo de tipos de campo é a referência de esquema de personalização compartilhada; os mesmos tipos alimentam o esquema do painel de um jogo personalizado.

Um campo skins.schema pode ser um color, um ativo (image / audio / video), ou um escalar (boolean, number, range, list) usando as mesmas formas de restrição que configurations ({ "type": "range", "min": 0, "max": 24 }, ["dots","stripes"], e assim por diante). Valores escalares de skin resolvem para seu valor tipado em ctx.skin (um number é um número de verdade), exatamente como um valor de configuração; valores de cor e ativo resolvem para strings.

O _theme de um preset de skin declara o modo em que funciona: light, dark, ou any (omiti-lo significa any). Um preset light ou dark aparece só naquele modo; um preset any lê em qualquer fundo e é elegível para os dois. Há um padrão por modo. Um preset marcado _default: true é o padrão para qualquer modo para o qual é elegível, então um padrão any cobre os dois; quando vários presets elegíveis são marcados como padrão para um modo, o primeiro na ordem de declaração o vence. Liste um preset específico de modo acima de um any para dar a esse modo um skin dedicado enquanto o preset any cai para o outro.

Os arquivos divididos .caputchin/

Blocos de preset (especialmente conjuntos completos de idioma) deixam o caputchin.json longo. Mova qualquer eixo para o seu próprio arquivo sob uma pasta .caputchin/, deixando o manifesto curto:

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

O objeto de nível superior de cada arquivo é aquele bloco de eixo ({ schema?, presets }). Os três são opcionais. A precedência é substituição de eixo inteiro, caputchin.json vence: se um eixo é declarado tanto inline quanto como arquivo, o bloco inline é usado e o arquivo é ignorado (a publicação avisa para você saber que ele ficou morto). Mantenha cada eixo em exatamente um lugar.

Coleções

Um repositório pode enviar vários jogos. Um wrapper de coleção declara caminhos de filho em vez de entry / npm:

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

Cada caminho aponta para um diretório filho que tem seu próprio caputchin.json. Os ids dos filhos são owner/repo/<leaf-dir>. Omita o bloco marketplace do wrapper para indexar os filhos sem uma página de coleção.

Veja também

Nesta página