# Views: how a game lies on the table

A game has three layers, each in its own file:

| Layer | File | Read by |
|---|---|---|
| Rules | the model | engine, validator, diagram, player |
| Players | a tactic | the engine, as a player (see [tactics](https://tabletwin.com/docs/tactics/)) |
| View | a view | the [player](https://tabletwin.com/play/): the Board tab of the table |

The engine never reads a view: it changes nothing about the rules or the results.

**Using a view with your model.** In the [workshop](https://tabletwin.com/workshop/), write the view
in the View tab: the Table pane draws it at once, with your own [images](#images), and the Check
pane says whether it fits the model. In the [validator](https://tabletwin.com/validate/), paste the
view into "View (optional YAML)" below the model and press Check. "Open in the player" then opens
your model with that view. The validator only checks that the view is readable YAML ("The view
cannot be read" otherwise); a slot that names a zone, variable or board the model does not have
shows up in the player (for example "board x not found"). The built-in games of the player come
with their own views; "Start from" in the validator loads an example together with its view.

Without a view the player lays out the table itself: shuffled or hidden zones as a deck, open
zones as a row, a meter for every per-player variable with a numeric `init`, and an area per
player for the zones with `owner: player`.

Cards are drawn as typographic cards (name, type, numbers, tokens); the site's own games never use
original artwork. A view of your own can use your own images: see [images](#images).
What a viewer sees follows the visibility in the model: in the player you can "view as player p",
and hidden zones and other players' hands then show only card backs.

## Structure

```yaml
view: my-card-game                  # label only; the view belongs to the model it is used with

card:
  lang: en                          # language of card names, for hyphenation (default en)
  type_field: type                  # field with the card type (small text in the colour band)
  type_names: {hero: Hero, ally: Ally}            # optional: display names of the types
  color:                            # colour band: the first entry that matches
    - {field: sphere, values: {leadership: "#6d4c9f", tactics: "#a53a2c"}}
    - {field: type, values: {enemy: "#6b4a32"}}
  corner: [cost, threat]            # number top right: the first of these fields the card has
  stats:                            # numbers at the bottom, with an icon
    - {field: willpower, icon: "✦", name: willpower}
    - {field: hp, icon: "♥", name: hit points}
  tokens:                           # numbers on the instance shown as tokens on the card
    damage: {color: "#c0392b", name: damage}
  sideways: exhausted               # turn the card sideways while this property is true

table:                              # the middle of the table, row by row
  - row:
      - {zone: encounter_deck, as: deck}
      - {zone: encounter_discard, as: discard}      # top card face up
      - {quest: {var: quest_card, catalogue: quests, progress: progress, goal: quest_points}}
      - {zone: staging, name: staging area, wide: true}

player:                             # the area of every player (per-player zones show that player's part)
  - row:
      - {meter: {var: threat, max: 50, name: threat}}
      - {zone: heroes, attachments: {zone: attachments, field: host}}
      - {zone: hand, small: true, wide: true}
```

### `card`

| Key | Type | Default | Meaning |
|---|---|---|---|
| `lang` | text | `en` | Language of the card names (the `lang` attribute, for hyphenation) |
| `type_field` | text | `type` | Field that holds the card type |
| `type_names` | `{type: name}` | | Display name per type; otherwise the type itself |
| `color` | list of `{field, values}` | | Colour band: the first entry whose `field` value is in `values`. No match: a colour derived from the type |
| `corner` | list of fields | | Number in the top right corner: the first listed field that holds a number |
| `stats` | list of `{field, icon, name}` | the first 4 numeric fields of the content item | Numbers along the bottom; `name` is the tooltip |
| `tokens` | `{property: {color, name}}` | | Numeric properties of the instance shown as coloured tokens. Without `tokens`, every positive number on the instance that the content item does not have is shown as a token |
| `sideways` | property | | The card is turned sideways while this property is true |
| `text` | field | | A field with a short text (the card's rules in a few words) printed under the name |

A card's fields are the content item's fields (looked up by `id`) overlaid with the current
properties of the instance. Properties that are `true` (other than `sideways`) show as tags.

### `table` and `player`

Both are lists of rows: `- row: [slot, slot, ...]`. `table` is drawn once; `player` once per
player, and a per-player zone in it shows that player's part.

| Slot | Key | Meaning |
|---|---|---|
| Zone | `zone` | Name of a zone in the model |
| | `as` | `row` (all cards side by side), `deck` (a face-down pile with a count) or `discard` (a pile with the top card face up, if the viewer may see it). Default: `deck` for shuffled or hidden zones, `row` otherwise |
| | `name` | Heading; default the zone name |
| | `wide` | Take the rest of the row |
| | `small` | Smaller cards |
| | `attachments: {zone, field}` | Cards from that zone whose `field` equals the `uid` of a card in this zone are shown under it |
| Meter | `meter: {var, max, name}` | A dial for a numeric variable; for a per-player variable, that player's value. `max` default: the larger of 10 and the value |
| Quest | `quest: {var, catalogue, progress, goal}` | A landscape card: the item `content[catalogue][<value of var>]` (or the content item with that `id`), with the variable `progress` against `goal` (a derived value or variable; default the card's `quest_points`) |
| Grid | `board: {zone \| var, columns}` | A grid of cells from a zone or a list variable, `columns` wide (default 3); `None` shows as empty |
| Board | `board: {geometry, ...}` | A board from the model's `boards` with pieces; see below |

Every slot may have a `name`. Cards that are new since the previous request get a highlight, and a
meter shows its change.

The smallest view, for a 3 × 3 grid kept in a zone `board`:

```yaml
view: tictactoe
table:
  - row:
      - {board: {zone: board, columns: 3}, name: board}
```

## Boards with geometry

A board from `boards` (see [board geometry](https://tabletwin.com/docs/board-geometry/)) is drawn with the same geometry as
the engine: square with coordinates, hex with gaps drawn as walls, walls between cells as lines.
Cells that changed since the previous request get a highlight (in chess: the from and to squares).

```yaml
table:
  - row:
      - name: chessboard
        board:
          geometry: board                 # name in the model's boards
          pieces: {var: pieces}           # a dict cell → piece
          checkered: true
          flip: true
          names: true
          icons:
            wK: {icon: "♚", color: white}
            bK: {icon: "♚", color: black}
      - name: dungeon
        board:
          geometry: map
          pieces: {zone: figures, field: cell}           # instances with a property cell
          color: {field: side, values: {hero: "#2f6fb3", monster: "#a53a2c"}}
          value: hp                                      # number on the token
          cells:                                         # highlighted cells (with a legend)
            - {const: OBSTACLES, color: "rgba(120, 100, 70, .65)", name: obstacle}
            - {const: TERRAIN, color: "rgba(110, 160, 80, .42)", name: difficult terrain}
```

| Key | Meaning |
|---|---|
| `geometry` | Name of the board in the model's `boards`. Unknown: a "board not found" notice |
| `pieces` | `{var}`: a dict cell → piece (text, or a dict whose `label` or `id` names it). `{zone, field}`: the instances in a global zone, placed on the cell in their property `field` (default `cell`); fixed fields come from the content item, or from a dict with that `id` in `constants` |
| `icons` | Piece label (or `id`) → icon text, or `{icon, color}` with `color: white`, `black` or a CSS colour. Without an icon: a round token with the first letters of the label |
| `color` | `{field, values}`: token colour from a property of the piece |
| `value` | Property shown as a number on the token |
| `cells` | List of `{const \| var, color, name}`: the cells in a constant or variable (a list of cell names, or a dict whose keys are cell names) get that colour; `name` goes into the legend |
| `checkered` | Alternate light and dark squares (square boards) |
| `flip` | Turn the board around when viewing as player 1 |
| `names` | Show cell names (square: `a–h` and `1–8` for `letters` boards, else numbers; hex: the cell name in each cell) |

Clicking a piece or card shows its properties. Complete views, used by the player for the
built-in games of the same name: [chess](https://tabletwin.com/models/views/chess.yaml),
[hex-skirmish](https://tabletwin.com/models/views/hex-skirmish.yaml) and
[tictactoe](https://tabletwin.com/models/views/tictactoe.yaml).

## Images

A view can use your own images: card fronts and backs, card sheets, a table surface, board images
and pieces, and 3D models for pieces. They work in the 2D table and on the 3D table. The images are
yours: add them in the [workshop](https://tabletwin.com/docs/workshop/)'s Images tab, where they stay in your browser and go
into the game's package when you download it. Tabletwin never stores or publishes them.

### References

Wherever a view takes an image, it takes one **reference**, a text:

| Reference | Means |
|---|---|
| `back.png` | A file in the game's images (the Images tab; `media/back.png` in a package) |
| `deck#12` | Card 12 of the sheet `deck` (see `sheets`): counted from 0, row by row |
| `https://…` | An image on the web, loaded by the viewer's browser from that address |
| `data:image/…` | An image written into the text itself |

PNG, JPG, WebP, GIF and SVG work for images; GLB (binary glTF) for 3D models. A reference to a file
that is not there shows nothing (the typographic card instead), and the workshop's Check pane lists
it under the images that are missing.

### Keys

```yaml
view: my-card-game
background: felt.jpg                  # the table surface (2D: behind the table; 3D: the cloth)

sheets:                               # card sheets: many cards in one image, in a grid
  deck: {image: deck.jpg, columns: 10, rows: 7}

card:
  images: {gandalf: "deck#0", aragorn: "deck#1"}   # front per content id
  image: art                          # or: the content field that names the front (default image)
  style: full                         # full: the image is the whole face; art: a typographic card
                                      #   with the image as its picture
  back: back.png                      # the back of every card
  backs: {orc: enemy-back.png}        # back per content id

table:
  - row:
      - {zone: encounter_deck, as: deck, back: encounter-back.png}   # back for this slot
      - name: dungeon
        board:
          geometry: map
          image: map.jpg              # under the cells, stretched over the board
          grid: false                 # no cell outlines (the image has its own)
          pieces: {zone: figures, field: cell}
          icons:
            warrior: {image: warrior.png}                  # a round token with the picture
            guard: {image: guard.png, shape: square}       # a square one
            boss: {image: boss.png, model: boss.glb}       # 3D: the model; 2D: the picture
```

| Key | Where | Meaning |
|---|---|---|
| `background` | top level | Image for the table surface |
| `sheets` | top level | `{name: {image, columns, rows}}`: a grid of equal cards in one image, as made for Tabletop Simulator. `name#n` is card n |
| `card.images` | `card` | `{content id: reference}`: the front of the cards with that id |
| `card.image` | `card` | The content field that holds a front reference, for models that keep it with the card (default `image`). `card.images` wins |
| `card.style` | `card` | `full` (default): the image is the whole face, with tokens and tags on top. `art`: the typographic card (band, name, numbers) with the image as its picture |
| `card.back` | `card` | The back of every card: shown for face-down piles and for cards the viewer may not see |
| `card.backs` | `card` | `{content id: reference}`: a different back for some cards |
| `back` | zone slot | The back for the cards in this slot; wins over `card.backs` and `card.back` |
| `image` | `board` | Image under the board's cells. It covers the cells' area (for hex boards including the gaps) and turns with the board when `flip` turns it |
| `grid` | `board` | `false`: draw no cell outlines or fills (marks from `cells` still show) |
| `icons.<piece>.image` | `board` | The piece as a token with this picture; the token keeps the colour from `color` as its rim and `value` as a badge |
| `icons.<piece>.shape` | `board` | `round` (default) or `square` |
| `icons.<piece>.model` | `board` | A 3D model (GLB) for the piece on the 3D table, scaled to its cell |

Fronts follow what the viewer may see: a card in a hidden zone, or another player's hand when you
view as one player, shows its back. Which back it shows (from `card.backs`) is public, as on a real
table, where the back of a card tells you its deck.

**Sharing.** A [share link](https://tabletwin.com/docs/workshop/#sharing-a-game) carries the view with its references, not the
images; a package carries both. References to web addresses keep working wherever the view goes.
