# Card Data Editor

> Describe a card game to DiceyTable — fields, roles, filters, columns, deck stats and partitions — so the deck builder works for your mod without any code.

- Source: https://diceytable.com/docs/editor/item-editors/card-data
- Last verified: 2026-08-25

To start, choose **New ▾ ▸ Card Data** in the asset explorer's toolbar (or **Mod ▸ New ▸ Card
Data** on the menu bar). That creates `data/cardSchema.json` and opens this tab. A mod has one
card data document, so the entry disappears once the file exists — from then on, double-click
`data/cardSchema.json` in the explorer to open the same tab.

This document is what makes the deck builder generic: **every filter, column and statistic on the
deck-building page comes from here**, so one page serves a trading card game, a collectible card
game or a wargame army list without a line of game-specific code.

See [the tab strip conventions](https://diceytable.com/docs/editor/item-editors/model#the-tab-strip) — dirty dots,
closing, cycling and mounted-but-hidden tabs apply here too.

## Two files, not one

Card data is stored as **two** documents, and this tab edits both:

```
data/cardSchema.json               the configuration — fields, roles, filters, columns, formats
assets/cards/<slug>.cards.json     the catalogue — the cards themselves
```

They are separate on purpose. The catalogue is bulk data that behaves like an asset, while the
schema is small configuration that the mod page and the deck builder read constantly without
needing a single card. Keeping them apart also means no part of DiceyTable ever holds a document
containing both, so card data cannot leak into the multiplayer table state by accident.

Saving the tab writes both files. If the schema is invalid, **nothing is written** — see
[Problems](https://diceytable.com/docs/editor/item-editors/card-data#problems).

## Source

Choose where cards come from.

- **This mod ships its own card list** — the cards live in the catalogue file named here, and you
  edit them in the [Cards](https://diceytable.com/docs/editor/item-editors/card-data#cards) section. No network access, nothing external.
- **A plugin supplies the cards** — a registered plugin fetches them from an external card
  database. DiceyTable itself does not integrate with any card site; plugins do that, and this
  setting names which one.

### Plugin sources

Four settings, only the first of which is required:

| Setting | Required | What it does |
| --- | --- | --- |
| **Plugin id** | yes | Names a registered plugin, e.g. `community.swtcg-deckdb`. Reverse-DNS, so the dots matter |
| **Endpoint** | no | Which of the plugin's card endpoints to read. Blank takes its first one |
| **Search parameter** | no | The endpoint parameter the deck builder's search box fills in |
| **Page parameter** | no | The endpoint parameter carrying the next-page token while the builder prefetches |

Switching the picker to a plugin fills the id in with `com.example.cards`. That is a placeholder,
not a default — replace it with a real plugin id, and until you do the source resolves to nothing.

The three optional settings are stored beside any query defaults the plugin declares, under names
beginning with `_` so they can never collide with a parameter the plugin defines itself. Clearing a
field removes it from the document rather than storing an empty value.

### Deck import plugin

Optional, and offered for **both** source kinds. It names the plugin whose deck-import block the
deck builder offers for this game — the **Import decklist** path, not where cards come from.

The two are separate because they genuinely differ in practice: a deck database can serve
decklists while supplying no card data at all, so a game commonly ships its own `static` catalogue
*and* imports decklists from `community.swtcg-deckdb`. Leave it blank if this game offers no deck
import; a plugin-sourced game importing from its own provider can leave it blank too, and the deck
builder falls back to the source's plugin.

Naming a plugin here is not the same as listing it in the manifest. The manifest's plugin list is
the **table script's** declared reach and carries the `plugin-call` capability with it; a deck
import is a person pressing a button in the deck builder and runs no mod code.

## Fields

The card data model — one row per piece of information a card carries (name, cost, type, power).
Each field has a **key** (how scripts read it, e.g. `data.power`), an optional **label** for
display, and a **type**: text, number, boolean or select.

Card **art** and card **identity** are ordinary `text` fields. An image URL is text and an id is
text, so there is no special field type for them — you point the roles at them instead.

> **Renaming a field updates everything that refers to it.** Filters, columns, stats, copy-limit
> exceptions and roles all follow the new key automatically. Renaming the identity field does
> **not** rewrite the catalogue, so existing cards keep their data under the old key — rename
> identity before you add cards, not after.

> **Removing a field also removes what referred to it**, and the editor tells you exactly what it
> took. A field backing the **Identity** or **Title** role cannot be removed at all: point that role
> at another field first.

## Roles

Which field plays each well-known part, so the generic UI knows what to show:

| Role | Required | Used for |
| --- | --- | --- |
| **Identity** | yes | The stable id a saved deck stores and a spawned card carries |
| **Title** | yes | The tile caption and decklist row label |
| **Card image** | no | The card art. Without it, cards render as name-only tiles |
| **Group by** | no | How a decklist is grouped (e.g. by card type). Without it, a flat list |
| **Card type** | no | The card's type — `Creature`, `Unit`, `Battle`. Lets layout templates pick types from a list |

**Card type** and **Group by** are separate on purpose, and pointing both at one field is normal.
Group by is a presentation choice — a Magic decklist often groups by mana value — while the type is
a property of the card. Binding the type role is what turns a layout template's match section into
a checklist of your game's actual types, counted against the catalogue, instead of a hand-typed
`contains` clause that fails silently when you misspell one. See
[Card Layouts](https://diceytable.com/docs/editor/item-editors/card-layouts#card-types).

> Removing the field a type role points at also clears every layout's type list, because a type
> list with nothing to evaluate against cannot be saved. The editor says so in the same notice that
> reports the filters and columns it took.

Roles only accept fields that can do the job — a number field cannot be the card image, and a text
field cannot be summed. Picking an unusable one is reported in [Problems](https://diceytable.com/docs/editor/item-editors/card-data#problems) rather than
silently rendering blank.

## Filters and columns

**Filters** appear in the deck builder's search pane. Each names a field and a control:

| Control | Widget | Field type |
| --- | --- | --- |
| `text` | search box | text |
| `enum-multi` | checkbox list | text, select |
| `enum-chips` | toggle chips | text, select |
| `range` | dual slider | number |
| `boolean` | switch | boolean |

Filters **compose**, and the player then presses Search — the builder does not re-query on every
keystroke.

**Columns** are the deck builder's table view. Each names a field and an optional header; leave the
header blank to use the field's label.

A mod that declares no filters gets just the text search box. That is intended, not broken.

## Deck stats

Aggregates shown beside a deck:

- **histogram** — buckets a number field (a mana curve)
- **sum** — totals a number field (an army's points, a deck's price)
- **breakdown** — counts by value of a text, select or boolean field (card types)

`sum` is what lets a wargame army list render through the same page as a card deck: "2000 pts" is
just a sum where a card game shows a card count.

## Partitions

Named sections of a deck — `commander` / `maindeck` / `sideboard`, or `hq` / `troops` / `elites`.

Once you have two or more, exactly one must be marked **Default**: it is where a decklist entry
lands when it does not name a partition. This is explicit rather than "the first one" so that
reordering the list never silently re-files existing decks.

How many cards each partition holds is a property of a *format*, not of the partition, because the
same partition holds different amounts in different formats.

## Cards

The catalogue. Each row is one card, with a cell per declared field.

Every card needs a value for the **Identity** field, and those values must be unique — copies are
expressed by a deck listing the same card more than once, never by duplicating the row. Duplicates
and missing ids are reported in [Problems](https://diceytable.com/docs/editor/item-editors/card-data#problems).

Large catalogues render the first 200 matching rows; use **Find** to narrow the list. The footer
always states how many matched, so nothing is hidden without saying so.

## Problems

Live validation of both documents.

- **Schema problems** must be fixed before saving. The tab refuses to write a schema that would
  fail to load, and Publish aborts rather than shipping one.
- **Catalogue problems** (missing, over-long or duplicate card ids) are warnings. They save, but a
  deck referring to an affected card will not resolve until you fix them.

## Card layouts

Regions mapped onto a card face, live overlay values like current power or health, and counters
live in the [Card Layouts editor](https://diceytable.com/docs/editor/item-editors/card-layouts) — press **Open the layout
editor** here to open it on the same document.

It is a separate tab rather than a section because the region mapper is a direct-manipulation
canvas that wants the whole viewport. Both tabs edit `data/cardSchema.json` and neither overwrites
the other's work, but the layout editor reads the document **from disk**, so save here before you
open it or the fields you just added will not appear in its pickers. The section says so when it
applies.

## What is not here yet

**Formats** (deck-size and copy-limit rules, banned lists) are stored and preserved but are not yet
editable here; a document that already declares them keeps them when you save. So is
`breakingVersion`, the card-model version that scopes saved decks — bump it by hand, and only for
an incompatible change to your card model.

**Attachments** (equipment attached to a host card) have no home in the document at all yet; see
the [Card Layouts editor](https://diceytable.com/docs/editor/item-editors/card-layouts#attachments).
