Das caputchin.json-Manifest
caputchin.json im Root deines Repositorys ist die Autoren- und Indexer-Wahrheitsquelle für ein Marketplace-Spiel. Der Indexer liest es serverseitig, um die Identität des Spiels zu lernen, wo sein Bundle lebt, welche Presets es bietet und wie man es abspielt. Es wird nie im Browser gelesen; das SDK lädt es zur Laufzeit nicht.
Diese Seite ist die Feld-Referenz. Für den Build sieh dir Ein Marketplace-Spiel bauen an; fürs Veröffentlichen sieh dir An den Marketplace veröffentlichen an. Die genauen Typen werden aus dem SDK als GameManifest exportiert (siehe die SDK-Referenz).
Ein minimales einzelnes Spiel
{
"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"
}Felder auf oberster Ebene
| Feld | Pflicht | Zweck |
|---|---|---|
terms_accepted | für Indexierung | Muss das literale true sein, um zu bestätigen, dass du die Marketplace-Einreichungsbedingungen akzeptierst. Jeder andere Wert (oder fehlend) droppt das Manifest aus dem Index. Nur-selbst-gehostete Manifeste dürfen es weglassen. |
license | für Indexierung | Ein SPDX-Identifier oder -Ausdruck, der deinen Code und die gebündelten Assets abdeckt. Muss zu einem genehmigten Identifier auswerten (siehe die Publish-Fehler-Referenz). |
marketplace | für Indexierung | Anwesenheit ist das "indexier mich"-Signal. Abwesend bedeutet ein gültiges selbst gehostetes Spiel, das der Marketplace ignoriert. Sieh dir Der marketplace-Block an. |
npm | mit entry | npm-Paket-Koordinate, die der Indexer zu einer jsDelivr-URL auflöst. |
entry | mit npm | Repo-relativer Pfad zum gebauten Bundle. entry, npm oder beide müssen für ein lauffähiges Spiel vorhanden sein. |
games | für Sammlungen | Sub-Manifest-Pfade für einen Sammlungs-Wrapper. Gegenseitig ausschließend mit entry / npm. Sieh dir Sammlungen an. |
run | optional | Ein dediziertes Headless-Replay-Artefakt. Sieh dir Das run-Artefakt an. |
preferred | optional | Präsentations-Hinweise, die der Host honorieren KANN. Sieh dir Der preferred-Block an. |
locales / skins / configurations | optional | Preset-Blöcke, die das SDK im Iframe konsumiert. Sieh dir Preset-Blöcke an. |
Es gibt kein version-Feld: der Indexer pinnt das Bundle selbst auf eine unveränderliche Ref (die veröffentlichte npm-Version oder die aufgelöste Commit-SHA).
Der marketplace-Block
| Feld | Zweck |
|---|---|
name | Karten-Titel. Fällt auf den Repo-Namen (einzeln / Wrapper) oder den Leaf-Dir-Namen (Sammlungs-Kind) zurück. |
description | Karten-Untertitel und Detail-Seiten-Body. |
preview | Bild-Pfad (relativ zum Repo-Root) oder absolute URL. Etwa 600x315, Motiv zentriert. |
version | Nur-Anzeige-Versions-String für die Detail-Seite. Optional. |
support | Autor-deklarierte Kompatibilitäts-Flags (responsive, touch, accessible, audio, ...), nie von der Plattform verifiziert; als Filter und Karten-Icons zum Vorschein gebracht. |
author | Optionales { name?, url?, email? }. name / url rendern als Autoren-Byline auf der Detail-Seite; email wird nie gezeigt und ist das Opt-in für Publish-Fehler-E-Mails. Alle drei Unterfelder sind unabhängig. |
Der Block ist vollständig optional. Lass name / url weg, und die Detail-Seite zeigt einfach keine Autoren-Byline (der anderswo auf der Seite gezeigte GitHub-Besitzer ist eine separate, immer vorhandene Identität, kein Fallback für diese Byline). Lass email weg, und du empfängst keine Publish-Fehler-Benachrichtigungen. Setz nur die Unterfelder, die du willst.
Distributions-Zeiger
Der Indexer pinnt das Bundle jedes Spiels auf eine unveränderliche Ref, sodass der gespeicherte Integritäts-Hash gültig bleibt, und löst bei jedem Lauf neu auf (täglicher Cron plus manuelles "Veröffentlichen oder aktualisieren"):
entry+npmlösen zucdn.jsdelivr.net/npm/<npm>@<resolved-version>/<entry>auf.- Nur
entrylöst zucdn.jsdelivr.net/gh/<owner>/<repo>@<commit-sha>/<entry>auf. - Nur
npmlöst zum Paket-Standard-Entry bei der gepinnten Version auf.
Es gibt kein nutzerseitiges Versions-Pinning; um einen Build einzufrieren, hostet ein Nutzer ihn selbst über das game-src des Widgets (Custom-Spiel).
Das run-Artefakt
Standardmäßig lässt die Replay-Selbstprüfung dein Live-entry-Bundle laufen. Wenn dein Spiel groß oder framework- oder WASM-basiert ist, liefere stattdessen ein dediziertes schlankes Headless-run-Artefakt:
{
"run": {
"entry": "dist/run.js",
"modules": [
{ "name": "sim.wasm", "type": "wasm", "path": "dist/sim.wasm" }
]
}
}| Feld | Bedeutung |
|---|---|
run.entry | Repo-relativer Pfad zum Headless-run-Bundle (der Replay-Vertrag-run-Export). |
run.modules | Optionales Array von Modul-Einträgen, die der Run per name importiert. |
Beschränkungen, die der Indexer durchsetzt
Diese werden zur Index-Zeit validiert; ein Verstoß lässt das Veröffentlichen mit einem manifest-error fehlschlagen (siehe die Publish-Fehler-Referenz).
run.entry:
- Muss JavaScript sein: der Basename muss
[a-zA-Z0-9_-]+.jsmatchen. Das run-Artefakt ist immer JS (WASM wird als Modul ausgeliefert, unten). - Muss ein sauberer repo-relativer Pfad sein: kein führender Slash, keine
..-Traversierung, kein Whitespace, kein?/#, keinscheme://-Präfix.
Jeder run.modules[]-Eintrag ist { name, type, path }:
namemuss[a-zA-Z0-9_-]+.(wasm|js)matchen, ein Modul ist entweder JS oder WASM, nichts sonst. Dernameist der Import-Specifier, den der Entry nutzt.typemuss mit der Endung übereinstimmen:wasmfür einen.wasm-Namen,jsfür einen.js-Namen.namedarf kein reservierter Name (entry.js,artifact.js) sein, den der Replay-Host intern nutzt.namemuss eindeutig im Array sein (keine Duplikate).pathmuss ein sauberer repo-relativer Pfad sein (dieselben Regeln wierun.entry).- Höchstens 16 Module.
Lass run weg, um das Live-entry direkt abzuspielen. Sieh dir den Replay-Vertrag dafür an, was das Artefakt exportieren muss.
Der preferred-Block
Der optionale preferred-Block trägt Präsentations-Hinweise. Jeder Schlüssel ist beratend: der Host KANN ihn honorieren, und er überschreibt nie ein explizites Embed-Attribut.
{
"preferred": { "width": 360, "height": 480, "layout": "modal" }
}Ein responsives Spiel, das standardmäßig seinen Container überspannen soll, kann "full" auf einer der Achsen deklarieren:
{
"preferred": { "width": "full", "height": 480 }
}| Feld | Bedeutung |
|---|---|
width / height | Ein Pixel-Footprint oder das literale "full". Das Widget wendet es an, wenn das Embed width / height ungesetzt lässt (ein expliziter Embed-Wert, einschließlich full, gewinnt stattdessen). Ein Pixel-Wert dimensioniert den Iframe auf diese Anzahl; "full" streckt diese Achse, um das Eltern-Element zu füllen, derselbe Effekt, den ein Embed-width="full" hat. Weglassen, um auf den eingebauten Standard-Footprint des Widgets zurückzufallen. |
layout | Die Hülle, die das Widget um das Spiel baut: inline, modal oder fullscreen. Nur genutzt, wenn das Embed layout ungesetzt lässt (seinen Standard auto). Auflösungsreihenfolge: das layout-Attribut des Embeds, dann dieses preferred-Layout, dann inline. |
Diese Hinweise werden nur für Spiele honoriert, die die Plattform serverseitig auflöst (Marketplace-Spiele, oder eine ohne Site-Key gegebene Spiel-id). Ein selbst gehostetes game-src-Bundle, das die Plattform vor dem Mount nicht lesen kann, ignoriert sowohl den Footprint als auch den Layout-Hinweis.
Preset-Blöcke
locales, skins und configurations deklarieren jeweils ein optionales schema (Pro-Schlüssel-Typen und Dokumentation) plus presets (die benannten Options-Banken). Das Widget löst die Wahl des Besuchers dagegen auf und reicht deinem Spiel das abgeflachte Ergebnis als ctx. Der vollständige Feldtyp-Katalog ist die geteilte Anpassungs-Schema-Referenz; dieselben Typen treiben das Dashboard-Schema eines Custom-Spiels.
Ein skins.schema-Feld kann ein color, ein Asset (image / audio / video) oder ein Skalar (boolean, number, range, list) sein, mit denselben Constraint-Formen wie configurations ({ "type": "range", "min": 0, "max": 24 }, ["dots","stripes"] und so weiter). Skalare Skin-Werte lösen sich zu ihrem typisierten Wert in ctx.skin auf (eine number ist eine echte Zahl), genau wie ein Konfigurationswert; Farb- und Asset-Werte lösen sich zu Strings auf.
Das _theme eines Skin-Presets deklariert den Modus, in dem es funktioniert: light, dark oder any (es wegzulassen bedeutet any). Ein light- oder dark-Preset zeigt sich nur in diesem Modus; ein any-Preset liest sich auf beiden Hintergründen und ist für beide berechtigt. Es gibt einen Standard pro Modus. Ein als _default: true markiertes Preset ist der Standard für die Modi, für die es berechtigt ist, also deckt ein any-Standard beide ab; wenn mehrere berechtigte Presets als Standard für einen Modus geflaggt sind, gewinnt das erste in Deklarationsreihenfolge ihn. Liste ein modus-spezifisches Preset über einem any, um diesem Modus einen dedizierten Skin zu geben, während das any-Preset auf den anderen durchfällt.
Die .caputchin/-Split-Dateien
Preset-Blöcke (besonders volle Locale-Sätze) machen caputchin.json lang. Verschieb jede Achse in ihre eigene Datei unter einem .caputchin/-Ordner, sodass das Manifest kurz bleibt:
caputchin.json
.caputchin/locales.json
.caputchin/skins.json
.caputchin/configurations.jsonDas Top-Level-Objekt jeder Datei ist dieser Achsen-Block ({ schema?, presets }). Alle drei sind optional. Vorrang ist Ganz-Achsen-Ersetzung, caputchin.json gewinnt: ist eine Achse sowohl inline als auch als Datei deklariert, wird der Inline-Block genutzt und die Datei ignoriert (das Veröffentlichen warnt, sodass du weißt, dass sie tot war). Halt jede Achse an genau einem Ort.
Sammlungen
Ein Repo kann mehrere Spiele ausliefern. Ein Sammlungs-Wrapper deklariert Kind-Pfade statt entry / npm:
{
"marketplace": { "name": "Caputchin Core Pack", "description": "The official pack." },
"games": ["./packages/leaf-memory", "./packages/dino-runner"]
}Jeder Pfad zeigt auf ein Kind-Verzeichnis, das seine eigene caputchin.json hält. Kind-ids sind owner/repo/<leaf-dir>. Lass den marketplace-Block des Wrappers weg, um die Kinder ohne Sammlungs-Seite zu indexieren.
Siehe auch
- Ein Marketplace-Spiel bauen: das Bundle produzieren, auf das dieses Manifest zeigt.
- Der Replay-Vertrag: was das
run-Artefakt exportieren muss. - Publish-Fehler-Referenz: jeder Manifest-Validierungsfehler und die genehmigte Lizenz-Liste.
- Anpassungs-Schema-Referenz: die Feldtypen, die die Preset-Blöcke nutzen.