Card Layouts Editor
Open the Card Data editor, scroll to Card layouts, and
press Open the layout editor. It opens as its own tab over the same data/cardSchema.json.
This is where a card stops being a picture and starts carrying values: a power box that shows
4/4 and can be changed to 6/6 during a fight, a damage counter, a stun marker.
<!-- screenshot: editor/item-editors/card-layouts.png -->
See the tab strip conventions — dirty dots, closing, cycling and mounted-but-hidden tabs apply here too.
Vocabulary#
| Term | Means |
|---|---|
| Region | A named rectangle on a card face |
| Overlay | A value drawn into a region |
| Counter | A small badge shown on a card |
None of these are engine Components in the sense the scene model uses that word. A region is not an entity and a counter is not a table object.
It edits the same file as the Card Data tab#
Both tabs write data/cardSchema.json. Having both open is safe and expected — this tab rewrites
only the layouts and counters sections, so it can never overwrite a field, filter or format
the other tab just saved, and the other tab keeps whatever you save here.
The one thing to know: this tab reads the document from disk when it opens. If the Card Data tab has unsaved changes, save them before opening this one, or the fields you just added will not be in the field pickers. The Card Data tab says so in place when it applies.
Layout templates#
A mod declares any number of templates. Each has a match predicate over the fields you mapped in the Card Data editor — the same fields, not a second mapping system.
Templates are evaluated top to bottom, and the first match wins:
card ──▶ [ Planeswalker? ] ─no─▶ [ Creature? ] ─no─▶ [ Default ]
│ yes │ yes │
4 regions 6 regions 3 regions
Drag a template by its ⋮⋮ handle, or use the ↑ / ↓ buttons, to change the order. Order is
meaning here, not presentation.
An unconditional template must be last. A template with no clauses matches every card, so everything below it can never be reached. The list strikes those rows through and the panel says which template is shadowing them. This is not a style preference — the document cannot be saved in that state, so the editor warns before you get there rather than after.
The match readout#
Under the clause list:
✓ matches 412 / 1104 sample cards
This is the most useful control on the screen. It is counted first-match-wins, exactly as the table will evaluate it, so the per-template numbers plus the unmatched count add up to your whole catalogue.
- 0 matched — either your predicate is too narrow, or a template above is swallowing everything. The readout turns amber so you cannot miss it.
- Everything matched — your predicate is probably too broad and later templates will starve.
Clauses are a flat AND-list: every clause must match. There are two operators, equals and
contains, and that is deliberate — a predicate you cannot write a loop or a side effect in is a
predicate the editor can count instantly across a 20,000-card catalogue.
Card types#
Above the clauses is a checklist of every card type in your game, each with the number of catalogue cards carrying it. Tick the types this template renders.
Types are an OR — a card matching any ticked type qualifies — which is the one thing the clause list cannot express, and the reason authors used to write one near-identical template per type. They combine with the clauses by AND, so "Instant or Sorcery, whose name contains bolt" is one template. Tick nothing for "any type".
The checklist needs a field bound to the Card type role in the
Card Data editor. Without one the section says so
instead of showing an empty picker. The vocabulary comes from that field's declared options when it
is a select, and is otherwise scanned out of the catalogue — so a type spelled differently in
your data shows up as its own entry with a count of 0, which is exactly the mistake you want to
see before you ship.
A template with ticked types is conditional, so it does not shadow the templates below it.
The canvas#
The preview shows one real card from the catalogue. Only cards this template actually claims are offered, and the shuffle button cycles through them — the fastest way to notice a region that fits one printing and overflows every other.
- Drag a region's body to move it; drag a handle to resize.
- Arrow keys nudge the selected region by one snap step. Hold Shift for ten.
- The snap step is a fraction of the card, not pixels. Set it to snap off for fine work.
Coordinates are normalised — 0 to 1 of the card face, origin top-left. That is why one layout fits a poker card, a tarot card and a mini-European card without editing. Nothing here is measured in pixels or in inches.
Landscape cards#
The preview takes its shape from the card in front of it, measured off the art. A set that mixes orientations — the Star Wars TCG prints Battle and Location cards landscape and Character cards portrait, from one catalogue — shows each card at its own proportions as you shuffle through the matching cards. Because region coordinates are normalised to the face, the same template still works on both; only the frame changes.
A card with no art falls back to the standard 5:7 portrait.
Corner rounding#
Corner rounding under the card is a property of the whole SET, not of this template: it is how your cards are printed. It is a percentage of the card's short edge, so a landscape and a portrait card in the same set round by the same visible amount, and 0 is square-cut.
It applies everywhere the game's cards are drawn — the table, the deck builder's card grid, a deck's page, and this preview — so there is one number to change rather than one per surface. Leave it at 8% for standard playing-card stock.
Two notes on precedence:
- A custom deck's own authored rounding still wins for that deck, because it is the number the deck editor previews.
- The set's value outranks the per-card corner-rounding control in the table inspector. That control's value is seeded on every card the moment it spawns, so it cannot tell "the author chose 8%" from "nobody touched it" — whereas a set that declares its rounding has said so deliberately. Declare nothing and nothing changes; the inspector behaves exactly as before.
Binding a region#
| Bind to | Draws | Replicates? |
|---|---|---|
| Static text | Fixed text from this document | Nothing |
| Card field | A mapped field's value, resolved locally | Nothing, unless it is live |
| Live counter | The current count of a declared counter, or a whole area of tokens | The counts only |
Tick Players may change this on a card field to make it live. A live value can be changed at the table, and it is the only part of the whole editor that travels over the network:
- Printed value ± change — the change is a delta on top of the catalogue's printed value.
Base power 4,
+2at the table, the card reads 6. - Replace the printed value — the live value stands in for the printed one.
Everything else here — rectangles, fonts, colours, counter art, anchors — resolves locally on every player's machine from your mod. It is never sent anywhere.
Visible when — the control that matters#
Visible when is not a rendering setting. It is the rule the host uses to decide what to send, and it is the difference between a hidden hand and a spoiled game.
| Setting | What an opponent receives while the card is face down |
|---|---|
| Face up only | Nothing. The value is stripped before it leaves the host. Default. |
| Count only | An anonymous tally — how many, never which |
| Always | The exact value, even though they cannot see the card |
Always is a real, useful setting — a face-down cost marker everyone is meant to see — and it is also how you leak an opponent's hand. The panel warns in place whenever you choose it.
Two values worth internalising:
- The default is the concealing one. Every new region and counter starts at face up only.
- The strictest declaration wins. If two templates both bind a live
powerand disagree, the host takes the more concealing answer. You cannot accidentally publish a value by adding one careless template.
Draw on face is the separate question of which side the region is painted on (front, back or both). It changes nothing about redaction — a region bound to the back face with Always visibility still sends its value to everyone.
Who may change it#
Per region and per counter: host only (the default), the seat that owns the card, any seated player, or scripts only.
This is enforced by the host when it receives the change, not by the buttons in front of a player. A modified client can always ask; what stops it is the host.
Counters#
A counter is a badge a player can add to a card: +1/+1, damage, stun. Only the count
replicates.
- Art — a built-in chip, or an image from your own mod repo (a repo-relative path, never a URL).
- Anchor and offset — where on the card face it sits.
- Stacking —
Single badge with a NUMBERis recommended and is the default. It is the only mode whose cost does not grow with the count; a row or column of twenty chips draws twenty sprites on every card that has them. - The count is always readable. From two up, the number rides in a small orange bubble on the badge's top-right corner — one bubble for the whole counter, on the right-most chip of a row or column rather than one per chip. It is deliberately not written across the middle of your art: a numeral stamped over a token defaces the thing you drew, and on a light token it disappears into it. At exactly one there is no bubble; a built-in chip shows its label instead, since a coloured dot has nothing else to identify it, and a token drawn from your own art is left alone.
- Max — the ceiling a player can raise it to.
- When the card flips — keep the count, clear the count, or move the count to another counter. Transfer is how a back-face resource carries onto the front face as something else; its target may not itself transfer, so a flip can never cascade.
Mapping the area where tokens go#
A counter region has a Draw as toggle. The count, as a number draws text, exactly like any other region. Tokens arranged in this area turns the rectangle into the counters' arrangement area: tokens wrap into it left-to-right, top-to-bottom, centred as a block, and a counter drawn this way is not also drawn at its own anchor.
Stacking still decides how many tokens a count is worth. A counter set to Single badge with a NUMBER — the default — takes exactly ONE token in the area and draws its count on it, so two
damage is one token reading 2 rather than two identical tokens. Set the counter to a row or a
column when you want the points laid out individually; that is what fills the area. A token drawn
from your own art is left unstamped at exactly one — the art already says what it is — and carries
the number from two up, in the same orange corner bubble the anchored badges use, sized to the
token; a built-in chip shows its label at one instead, written across it, since a coloured dot
has nothing else to identify it. Set the region's text colour to override what the bubble and
the label are written in.
Several counters can share one area. Tick each one in the region's list; damage and shields sharing one track is a single region, not two rectangles you have to keep from colliding.
- Order is the draw order. The ↑ / ↓ buttons beside each ticked counter set it, and the number beside them is the position the table honours. All the shields, then all the damage — the same sequence on every player's machine, because it comes from the document rather than from the order a player happened to add them in.
- Min / max token size bound how large a token may be, as a percentage of the card's height.
0means unset. The table picks the largest size between the bounds whose grid fits everything, so two tokens draw large and a dozen shrink rather than overflowing at the third. Only past the minimum does the area give up and show a+Nbadge — the count stays exact and visible either way. - The example area in the preview draws stand-in tokens of every counter you ticked, in order, at the size the bounds produce. Counts are per-card runtime state that this document does not hold, so it fills the area rather than inventing a number — except for a numbered counter, which gets one stand-in, because one token is all it will ever draw.
A region that draws a number must name exactly one counter — a number is one number — and it cannot carry the size bounds. Switching it to tokens is what unlocks both.
The three-way preview#
Three cells: your card face up, your card face down, and what other players see.
The third one is the point. It is the same face-down card after host-side redaction, so a counter you thought was private shows up there before your players find it. Hovering a cell explains every counter's outcome in the list beneath it — including why one is missing, which is otherwise indistinguishable from a bug.
Attachments#
No editor yet, and the tab says so rather than showing one that cannot save. The contract
exists: deckSchema now accepts a top-level attachments array, and the runtime honours it — so a
rule written by hand into data/cardSchema.json works today.
One rule declares which card may attach (match, a predicate over your mapped fields), which card
may host it (hostMatch), how many one host may carry (maxPerHost, default 4), what happens past
that (overflow: compress — the default, the fan tightens; hide; or refuse), the per-slot
offset as a fraction of the host card's face, and what a flip does (onHostFlip: keep or
detach). Rules are evaluated top-down, first match wins, exactly as layout templates are, and an
unconditional rule must be last.
Attachment is object parenting — transform and organisation only, with the attached card held kinematic so it cannot fight its host — and never a physics joint. What replicates is the parent link plus a slot ordinal; the matching, the arrangement and the overflow policy all resolve locally from this document. Dropping a card onto a card it may attach to attaches it instead of merging the two into a pile; a host picked up into a hand releases its attachments where they stand.
Saving#
Save card layouts writes data/cardSchema.json. The tab refuses to write a document that would
fail to load, and Save Draft / Publish flush it along with every other open editor.
If the rest of the document changed underneath you in a way these layouts contradict — a field they reference was renamed or removed in the Card Data tab — the save is refused with that explanation rather than writing a broken file. Reopen the tab to pick up the current card data.
