Caputchin
Desarrollo de juegos del marketplace

Referencia del game SDK

@caputchin/game-sdk es el contrato contra el que escribe un autor de juegos: un helper register, un Bridge de solo empuje, el GameContext por ronda, y los tipos de TypeScript para los bloques de preset del manifiesto. Se publica por separado del widget de cara al usuario para que los juegos nunca empaqueten transitivamente el runtime del widget. Los juegos de primera parte usan esta misma API pública; no hay contrato privado.

Para un build guiado, mira Construye un juego del marketplace. Para el manifiesto que declara los presets que este SDK expone, mira El manifiesto caputchin.json.

register(factory)

El único punto de entrada de registro. Pasa tu factory de juego; no pasas el manifiesto (el servidor lee caputchin.json en tiempo de indexación y envía los presets resueltos como el contexto de la factory). Registrar dos veces emite un warning en consola y la última escritura gana; no hay imposición de la plataforma.

register(factory: GameFactory): void

La factory de juego

type GameFactory = (
  container: HTMLElement,
  bridge: Bridge,
  ctx?: GameContext,
) => (() => void) | void
ParámetroSignificado
containerUn elemento dentro del iframe en sandbox del juego. Renderiza aquí. El estilo queda naturalmente acotado, el iframe es su propio documento.
bridgeEl canal de solo empuje hacia el anfitrión (mira El bridge). El juego emite hacia arriba; no se suscribe. Que la factory sea llamada es la señal de inicio.
ctxEl contexto por ronda (semilla más presets resueltos). Opcional en el tipo porque el widget puede correr un juego fuera de una sesión verificada.
returnUna función de limpieza opcional que el widget llama si desmonta tu juego.

El bridge

El bridge es de solo empuje: el juego reporta eventos al anfitrión y nunca escucha. Sus miembros:

MiembroFormaEfecto
passpass(result: { trace: string }): voidSeñala que la ronda se aprobó, entregándole al anfitrión la trace opaca. El servidor vuelve a correr el run del juego bajo la semilla emitida para computar el veredicto autoritativo, así que el juego no reporta una puntuación aquí. La primera llamada libera la verificación retenida y bloquea el token; las llamadas posteriores se ignoran.
errorerror(err: { code: string; message?: string }): voidEl propio juego falló (carga de asset, excepción interna). Hace aflorar un evento error al usuario. Distinto de que un jugador pierda, que se señala llamando a nada.
setSizesetSize(width: number, height: number): voidRedimensiona explícitamente el iframe para ajustar el contenido. Llámalo tras el primer pintado; el widget también automide el primer hijo del juego, así que la mayoría de los juegos nunca lo necesitan.
layoutreadonly layout: 'inline' | 'modal' | 'fullscreen' | nullLa presentación resuelta bajo la que corre el juego, o null cuando se desconoce.

Deliberadamente no hay complete, ni listener start, ni método unmount (devuelve una función de limpieza en su lugar), ni señal de fallo más allá del silencio.

El contexto

interface GameContext {
  seed:   Seed          | null
  locale: ResolvedLocale | null
  skin:   ResolvedSkin   | null
  config: ResolvedConfig | null
}
CampoSignificado
seedLa semilla de repetición por ronda (un Seed del contrato de repetición). Siembra toda la aleatoriedad del juego de ella. null cuando el juego corre fuera de una sesión verificada.
localeEl objeto de idioma resuelto: _lang (BCP-47), _direction, más tus claves de texto aplanadas. null si tu manifiesto no publica ningún bloque locales.
skinEl skin resuelto: _theme más tus claves de color/asset aplanadas, las URLs de asset ya absolutas. _theme es siempre el modo concreto para el que se resolvió el skin, light o dark (nunca any), así que un preset agnóstico al tema reporta el modo real del visitante. null si no hay bloque skins.
configLa configuración resuelta: tus escalares tipados aplanados. null si no hay bloque configurations.

Cada uno es null cuando el bloque correspondiente del manifiesto está ausente, así que provee siempre un fallback integrado.

Tipos de preset

El SDK exporta tipos de TypeScript para crear caputchin.json (y los archivos divididos .caputchin/) con comprobación de tipos. Estos reflejan los bloques del manifiesto:

TipoDescribe
GameManifestEl caputchin.json entero. Fuente de verdad del autor + indexador; nunca se lee en el navegador.
LocalePreset / ResolvedLocaleUn preset de locale declarado / el objeto resuelto que el juego recibe.
SkinPreset / ResolvedSkin / SkinSchemaEntry / SkinValueTypePresets de skin, el skin resuelto, y el esquema de tipo por clave.
ConfigPreset / ResolvedConfig / ConfigSchemaEntry / ConfigValueTypePresets de configuración, la config resuelta, y el esquema de tipo por clave.
LocalesFile / SkinsFile / ConfigurationsFileEl objeto de nivel superior de cada archivo dividido .caputchin/<axis>.json.
MarketplaceMetadata / PreferredPresentationEl bloque marketplace y la pista de huella preferred.

Crea un archivo dividido con un import satisfies para que el compilador lo compruebe:

import type { LocalesFile } from "@caputchin/game-sdk";
export default { schema: { /* ... */ }, presets: { /* ... */ } } satisfies LocalesFile;

Qué está ausente a propósito

  • Ningún sessionId ni identificadores de plataforma llegan al juego.
  • Ningún gancho de ciclo de vida start / pause / resume; la llamada a la factory es el inicio.
  • Ningún maxScore ni rango de puntuación de plataforma; la puntuación del veredicto es lo que tu run devuelva.

El contrato es deliberadamente diminuto para que se mantenga estable a través de años de crecimiento del catálogo.

Véase también

En esta página