# Playcade.game()

> Reference for Playcade.game(), the one call that registers a game, and every field of the game definition.

`Playcade.game(definition)` registers a game. The definition is one object, and only `id`, `title`, `inputs` and `round` are required.

| Field | Type | What it does |
|---|---|---|
| `id` | `string` | kebab-case, unique in the gallery |
| `title` | `string` | The name on stream and in the gallery |
| `tagline` | `string`, optional | One sentence for the gallery card |
| `inputs` | `('guess' \| 'vote' \| 'team')[]` | How players answer. The first one sets the "how to play" line |
| `players` | `string`, optional | Shown in the gallery. `"1+"` means fun with a single player |
| `rounds` | `number`, optional | Default 5, capped by how many questions there are. `Infinity` runs the game until the host presses End, for long and idle games |
| `roundLabel(index, total)` | `function`, optional | The round chip and scores card, like `() => 'Puzzle #47'`. Default "Round 2 of 5" |
| `content` | `Item[]`, optional | The built-in questions, one per round: the game's free starter set. A host's [question set](#question-sets) replaces them |
| `item` | `object`, optional | What one question looks like, field by field. Question sets are checked against it |
| `checkItem(item)` | `function`, optional | Rules across fields, after `item` passed. Return a problem as a string, or `null` |
| `sets` | `boolean`, optional | `false` when the game takes no question set, like a daily puzzle everyone plays the same |
| `saves` | `boolean`, optional | `true` keeps progress between streams with `load()` and `save()` in the round. The host keeps it per show |
| `layout` | `'wide' \| 'tall'`, optional | `'tall'` gives the game most of the stage (1792 by 690, no hint row), for maps, boards and long games. Default `'wide'` |
| `round(ctx)` | `async function` | One round. Resolve when the round is over |

```js
Playcade.game({
  id: 'higher-or-lower',
  title: 'Higher or Lower',
  tagline: 'Two things, one question. Vote 1 or 2.',
  inputs: ['vote'],
  players: '1+',
  rounds: 5,
  content: PAIRS,
  item: {
    q: { type: 'text', label: 'The question, like "Which is older?"', max: 60 },
    a: { type: 'list', label: 'First choice and its reveal line', min: 2, max: 2, each: 40 },
    b: { type: 'list', label: 'Second choice and its reveal line', min: 2, max: 2, each: 40 },
    answer: { type: 'number', label: 'The right choice: 0 or 1', options: [0, 1] },
  },
  async round(ctx) { /* see The round */ },
})
```

## Question sets

A host can play their own questions instead of a game's built-in ones. A question set is a list of questions, or `{ title, maker, items }`. The maker is a handle like `"@quizlab"` and is credited as "set by @quizlab" on the lobby and reveal cards. A set only swaps questions: it can never change scoring, rounds or timing. Any question may also carry an `id` (a stable key) and a `source` (an https link that backs the answer).

Each question is checked against the game's `item` description before it plays, and a question that fails is skipped with a reason. Fields are one of these types:

| Type | Options | A valid value |
|---|---|---|
| `text` | `max` length (default 120), `options` | Text without `<`, `>` or control characters. It goes through the safety filter |
| `number` | `min`, `max`, `options` | A number |
| `list` | `min` and `max` items, `each` length (default 60) | A list of text |
| `map` | `keys`, `min`, `each` | Text by key, like `{ "1": "ice cube" }` |
| `image` | | An https link or an image data URL |
| `object` | `fields` | An object, checked field by field |
| `any` | | Anything. `checkItem` looks at it |

Every field also takes a `label`, written for the host who fills it in, and `optional: true`. Optional fields default to `''`, `[]` or `{}`. A show never repeats itself: questions it has not played yet go first, then the ones played longest ago.

## Other calls

| Call | Returns |
|---|---|
| `Playcade.match(text, answers)` | `{ ok, close }`: the loose matcher, outside a round |
| `Playcade.asset(path)` | A URL for a file in the game's own folder |
| `Playcade.checkContent(gameId, set)` | `{ ok, items, problems, notes, title, maker, paid }`: a question set checked against a game, before anyone plays it |
| `Playcade.itemKey(item)` | A question's key: its `id`, or a hash of the question. A show stores the keys it played |
