---
type: reference
title: Spiel-SDK-Referenz
summary: Die vollständige @caputchin/game-sdk-Fläche, gegen die ein Spiel-Autor schreibt, die register-Funktion, die Push-only-Brücke, der Pro-Runde-Kontext und die Preset-Typen.
---

`@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](/docs/marketplace-game-development/build-a-marketplace-game) an. Für das Manifest, das die Presets deklariert, die dieses SDK zum Vorschein bringt, sieh dir [Das caputchin.json-Manifest](/docs/marketplace-game-development/the-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.

```ts
register(factory: GameFactory): void
```

## Die Spiel-Factory

```ts
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](#the-bridge)). Das Spiel emittiert aufwärts; es subscribt nicht. Dass die Factory aufgerufen wird, ist das Startsignal. |
| `ctx` | Der Pro-Runde-[Kontext](#the-context) (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 [#the-bridge]

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`](/docs/marketplace-game-development/replay-contract) 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 [#the-context]

```ts
interface GameContext {
  seed:   Seed          | null
  locale: ResolvedLocale | null
  skin:   ResolvedSkin   | null
  config: ResolvedConfig | null
}
```

| Feld | Bedeutung |
|---|---|
| `seed` | Der Pro-Runde-Replay-Seed (ein [`Seed`](/docs/marketplace-game-development/replay-contract) 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](/docs/marketplace-game-development/the-caputchin-json-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:

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

## Was bewusst abwesend ist

- Keine `sessionId` oder Plattform-Identifier erreichen das Spiel.
- Keine `start` / `pause` / `resume`-Lebenszyklus-Haken; der Factory-Aufruf ist der Start.
- Kein `maxScore` oder Plattform-Score-Bereich; die Punktzahl des Urteils ist, was auch immer dein `run` zurückgibt.

Der Vertrag ist bewusst winzig, sodass er über Jahre des Katalog-Wachstums stabil bleibt.

## Siehe auch

- [Ein Marketplace-Spiel bauen](/docs/marketplace-game-development/build-a-marketplace-game): das Tutorial, das diese Fläche nutzt.
- [Der Replay-Vertrag](/docs/marketplace-game-development/replay-contract): der `Seed`, der Trace und das Urteil, auf die die Brücke und der Kontext sich beziehen.
- [Das caputchin.json-Manifest](/docs/marketplace-game-development/the-caputchin-json-manifest): die Presets deklarieren, die der Kontext auflöst.
