---
type: reference
title: Customization schema reference
summary: The shared field-type and preset model behind every customizable surface, the field types each axis allows, the values each accepts, and how schemas and presets are defined and resolved.
---

This is the single reference for Caputchin's **field-type and preset model**, the shared foundation under every customizable surface:

- [Game customization](/docs/game-customization/overview): a marketplace game's language, skin, and configuration.
- [Custom game schemas](/docs/custom-game-development/dashboard-schema): the schema you author yourself for a custom game.
- [Marketplace game manifests](/docs/marketplace-game-development/the-caputchin-json-manifest): the `locales` / `skins` / `configurations` blocks a game author declares.
- [White-labeling the widget](/docs/widget-customization/white-label): the widget shell's built-in schema.

All four use the same field types and the same preset model described here. Customization is built from **presets**, and a preset is a bag of typed **fields**.

## Field types by axis

Each axis allows a fixed set of field types:

| Axis | Allowed field types |
|---|---|
| Configuration | `boolean`, `number`, `range`, `list`, `string`, `link` |
| Locale | `string` only |
| Skin | `color`, `image`, `audio`, `video`, `boolean`, `number`, `range`, `list` |

A skin is not only colors and assets: it can also expose the scalar knobs `boolean`,
`number`, `range`, and `list` (a "shadows" toggle, a corner-radius number, a "pattern" choice).
These behave exactly like their configuration counterparts and resolve to their typed value (a
`boolean` stays `true`, a `number` stays `8`); `color` and asset values resolve to strings.
Skin does not allow `string` or `link` (free text belongs to language; a link target is a
configuration).

## What each type accepts

| Type | Value | Rules |
|---|---|---|
| `string` | Free text | Any text. |
| `boolean` | A toggle | `true` or `false`. |
| `number` | A number | Any finite number. |
| `range` | A bounded number | A finite number within the field's minimum and maximum. The step is a slider convenience; off-step values are still accepted. |
| `list` | One choice | Must be one of the field's listed options. |
| `link` | A URL | An `http` or `https` URL. Embedded credentials are rejected. |
| `color` | A color | A hex color (`#rgb`, `#rgba`, `#rrggbb`, or `#rrggbbaa`) or an `rgb()` / `rgba()` value. Named colors and other color spaces are not accepted. |
| `image` | An image | An uploaded file or an `https` URL ending in `.png`, `.jpg`, `.jpeg`, `.webp`, `.svg`, or `.gif`. |
| `audio` | An audio clip | An uploaded file or an `https` URL ending in `.mp3`, `.ogg`, or `.wav`. |
| `video` | A video | An uploaded file or an `https` URL ending in `.mp4` or `.webm`. |

Caputchin validates every value when you save, so a value that does not fit its type is rejected before it can reach a visitor.

## Reserved keys

Alongside its content fields, a preset carries a few reserved **metadata keys** (each prefixed with an underscore) that control how it is selected and resolved, not what it displays. How you set them depends on the surface: a [marketplace game author](/docs/marketplace-game-development/the-caputchin-json-manifest) writes them literally in `caputchin.json`; in the dashboard editor (custom games, white-label) you set them through controls and never type the key. Either way the meaning is the same.

| Key | Axis | Meaning |
|---|---|---|
| `_lang` | Locale | The BCP-47 language tag a locale preset serves (`en`, `es`, and so on). Presets are grouped by it; several presets may share one `_lang` (e.g. two English variants). |
| `_direction` | Locale | `ltr` or `rtl`. Optional, auto-derived from `_lang` for right-to-left languages (`ar`, `he`, `fa`, `ur`, `yi`, `ps`, `sd`); rarely set by hand. |
| `_theme` | Skin | `light`, `dark`, or `any`. A `light` / `dark` preset shows only under that background; an `any` preset works under both and is eligible for either. Defaults to `light` when absent. |
| `_default` | All | Marks the preset the server picks for its group when the visitor does not select one. One default per group (per mode for skin); an `any` skin can be the default for light, dark, or both. |
| `_extends` | All | Names another preset to inherit from. See [Extending a preset](#extending-a-preset). |

Reserved metadata keys are **stripped during resolution**: `_extends` and `_default` never reach the game, and only the surviving metadata (`_lang`, `_direction`, `_theme`) plus the flattened content fields are delivered.

## Extending a preset [#extending-a-preset]

`_extends` lets one preset inherit every value from another, so you author only the fields that differ instead of repeating a whole preset. Set `_extends` to the **name of another preset in the same axis**; the extending preset starts from all of that preset's values and overrides the keys it sets itself.

```json
{
  "skins": {
    "presets": {
      "brand-light": { "_theme": "light", "accent": "#2da44e", "bg": "#ffffff" },
      "brand-light-warm": { "_extends": "brand-light", "accent": "#d97706" }
    }
  }
}
```

Here `brand-light-warm` inherits `bg` from `brand-light` and changes only `accent`.

Two details:

- **Skin theme shortcut.** On a skin preset, `_extends` may instead name a theme (`light` or `dark`) rather than a preset. That form resolves to whichever preset is the `_default` for that theme, a convenient way to base a variant on "the default light skin" without naming it.
- **It resolves away.** `_extends` is followed and then stripped; the game receives the fully merged result, never the `_extends` key itself.

## Where a schema comes from

The field set a preset can fill (its **schema**) has three sources, all using the same field types above:

- **Marketplace game**: the schema comes from the game author's manifest, fetched when you open the editor. You override the game's presets but do not change its schema.
- **Custom game**: you define the schema yourself in the dashboard, then author presets against it. See [custom games](/docs/game-customization/custom-games).
- **Widget shell (white-label)**: a fixed, built-in schema. You override its presets; the field set is not author-declared. See [white-label the widget](/docs/widget-customization/white-label).

## Presets and resolution

Within an axis, fields are grouped into named presets, and the server resolves one effective preset per group from the layered scopes, site key over troop over bundled default, computed per value. The selectors differ by axis: locale is chosen by the visitor's browser language, skin by the visitor's light or dark preference (a preset whose mode is `any` is eligible for either), and configuration is server-authoritative (the visitor cannot choose it). See the [overview](/docs/game-customization/overview#troop-and-site-key-scope) for the scope model.

## See also

- [Game customization overview](/docs/game-customization/overview): registering and managing games, plus the per-axis how-tos for [configurations](/docs/game-customization/configurations), [language](/docs/game-customization/locale), and [skin](/docs/game-customization/skin).
- [Custom game dashboard schema](/docs/custom-game-development/dashboard-schema): authoring a schema yourself for a custom game.
- [The caputchin.json manifest](/docs/marketplace-game-development/the-caputchin-json-manifest): declaring these blocks as a marketplace game author.
- [White-label the widget](/docs/widget-customization/white-label): the same types applied to the widget shell.
