Spiel-SDK-Referenz
@caputchin/game-sdk ist der Vertrag, gegen den ein Spiel-Autor schreibt: ein register-Helfer, eine Push-only-Bridge, der Pro-Runde-GameContext und die TypeScript-Typen für die Preset-Blöcke des Manifests. Es wird separat vom nutzergewandten Widget veröffentlicht, sodass Spiele die Widget-Runtime nie transitiv bündeln. Hauseigene Spiele nutzen dieselbe öffentliche API; es gibt keinen privaten Vertrag.
Für einen geführten Build sieh dir Ein Marketplace-Spiel bauen an. Für das Manifest, das die Presets deklariert, die dieses SDK zum Vorschein bringt, sieh dir Das caputchin.json-Manifest an.
register(factory)
Der einzelne Registrierungs-Einstiegspunkt. Übergib deine Spiel-Factory; du übergibst das Manifest nicht (der Server liest caputchin.json zur Index-Zeit und liefert aufgelöste Presets als Kontext der Factory hinunter). Zweimal zu registrieren loggt eine Konsolen-Warnung und der letzte Schreibvorgang gewinnt; es gibt keine Plattform-Durchsetzung.
register(factory: GameFactory): voidDie Spiel-Factory
type GameFactory = (
container: HTMLElement,
bridge: Bridge,
ctx?: GameContext,
) => (() => void) | void| Parameter | Bedeutung |
|---|---|
container | Ein Element im gesandboxten Iframe des Spiels. Render hier. Style ist natürlich beschränkt, der Iframe ist sein eigenes Dokument. |
bridge | Der Push-only-Kanal zum Host (siehe Die Brücke). Das Spiel emittiert aufwärts; es subscribt nicht. Dass die Factory aufgerufen wird, ist das Startsignal. |
ctx | Der Pro-Runde-Kontext (Seed plus aufgelöste Presets). Optional im Typ, weil das Widget ein Spiel außerhalb einer verifizierten Session laufen lassen kann. |
| return | Eine optionale Cleanup-Funktion, die das Widget aufruft, wenn es dein Spiel unmountet. |
Die Brücke
Die Brücke ist Push-only: das Spiel meldet Events an den Host und lauscht nie. Ihre Member:
| Member | Form | Effekt |
|---|---|---|
pass | pass(result: { trace: string }): void | Signalisiert, dass die Runde bestanden wurde, und reicht dem Host den opaken trace. Der Server lässt das run des Spiels unter dem ausgegebenen Seed erneut laufen, um das maßgebliche Urteil zu berechnen, also meldet das Spiel hier keine Punktzahl. Der erste Aufruf gibt die gehaltene Verifizierung frei und sperrt das Token; spätere Aufrufe werden ignoriert. |
error | error(err: { code: string; message?: string }): void | Das Spiel selbst schlug fehl (Asset-Load, interne Exception). Bringt ein error-Event zum Nutzer zum Vorschein. Verschieden von einem verlierenden Spieler, der signalisiert wird, indem nichts aufgerufen wird. |
setSize | setSize(width: number, height: number): void | Den Iframe explizit auf den Inhalt anpassen. Ruf nach dem ersten Paint; das Widget misst auch das erste Kind des Spiels automatisch, also brauchen die meisten Spiele das nie. |
layout | readonly layout: 'inline' | 'modal' | 'fullscreen' | null | Die aufgelöste Präsentation, unter der das Spiel läuft, oder null, wenn unbekannt. |
Es gibt bewusst kein complete, keinen start-Listener, keine unmount-Methode (gib stattdessen eine Cleanup-Funktion zurück) und kein Fehler-Signal über Stille hinaus.
Der Kontext
interface GameContext {
seed: Seed | null
locale: ResolvedLocale | null
skin: ResolvedSkin | null
config: ResolvedConfig | null
}| Feld | Bedeutung |
|---|---|
seed | Der Pro-Runde-Replay-Seed (ein Seed aus dem Replay-Vertrag). Seede jede Spiel-Zufälligkeit daraus. null, wenn das Spiel außerhalb einer verifizierten Session läuft. |
locale | Das aufgelöste Sprach-Objekt: _lang (BCP-47), _direction, plus deine abgeflachten Text-Schlüssel. null, wenn dein Manifest keinen locales-Block ausliefert. |
skin | Der aufgelöste Skin: _theme plus deine abgeflachten Farb-/Asset-Schlüssel, Asset-URLs schon absolut. _theme ist immer der konkrete Modus, für den der Skin aufgelöst wurde, light oder dark (nie any), sodass ein theme-agnostisches Preset den tatsächlichen Modus des Besuchers meldet. null, wenn kein skins-Block. |
config | Die aufgelöste Konfiguration: deine abgeflachten typisierten Skalare. null, wenn kein configurations-Block. |
Jedes ist null, wenn der entsprechende Manifest-Block abwesend ist, also stell immer einen eingebauten Fallback bereit.
Preset-Typen
Das SDK exportiert TypeScript-Typen zum Verfassen von caputchin.json (und den geteilten .caputchin/-Dateien) mit Typprüfung. Diese spiegeln die Manifest-Blöcke:
| Typ | Beschreibt |
|---|---|
GameManifest | Das ganze caputchin.json. Autoren- + Indexer-Wahrheitsquelle; nie im Browser gelesen. |
LocalePreset / ResolvedLocale | Ein deklariertes Locale-Preset / das aufgelöste Objekt, das das Spiel empfängt. |
SkinPreset / ResolvedSkin / SkinSchemaEntry / SkinValueType | Skin-Presets, der aufgelöste Skin und das Pro-Schlüssel-Typ-Schema. |
ConfigPreset / ResolvedConfig / ConfigSchemaEntry / ConfigValueType | Konfigurations-Presets, die aufgelöste Config und das Pro-Schlüssel-Typ-Schema. |
LocalesFile / SkinsFile / ConfigurationsFile | Das Top-Level-Objekt jeder .caputchin/<axis>.json-Split-Datei. |
MarketplaceMetadata / PreferredPresentation | Der marketplace-Block und der preferred-Footprint-Hinweis. |
Verfass eine Split-Datei mit einem satisfies-Import, sodass der Compiler sie prüft:
import type { LocalesFile } from "@caputchin/game-sdk";
export default { schema: { /* ... */ }, presets: { /* ... */ } } satisfies LocalesFile;Was bewusst abwesend ist
- Keine
sessionIdoder Plattform-Identifier erreichen das Spiel. - Keine
start/pause/resume-Lebenszyklus-Haken; der Factory-Aufruf ist der Start. - Kein
maxScoreoder Plattform-Score-Bereich; die Punktzahl des Urteils ist, was auch immer deinrunzurückgibt.
Der Vertrag ist bewusst winzig, sodass er über Jahre des Katalog-Wachstums stabil bleibt.
Siehe auch
- Ein Marketplace-Spiel bauen: das Tutorial, das diese Fläche nutzt.
- Der Replay-Vertrag: der
Seed, der Trace und das Urteil, auf die die Brücke und der Kontext sich beziehen. - Das caputchin.json-Manifest: die Presets deklarieren, die der Kontext auflöst.