Appearance
Pokémon TCG card data
Ruleset and calculator scripts get Pokémon TCG cards as plain objects straight from the card catalog. This page lists every field on those objects and in the catalog globals, with a real example and a few recipes.
Where the cards show up:
- Card rules receive one card as their first argument.
- Deck and deck set rules receive
cardsById, an object keyed by card ref that holds every card in the deck (it can hold more). - Calculators receive
cardsByIdas their second argument.
See the ruleset script API and the calculator script API for the full function signatures.
Card keys and deck refs
A Pokémon card in the catalog is a card identity: one playable card with all of its printings (reprints, alternate arts, promos) listed under printings. Two ids matter:
- The identity id,
card.id: a name slug plus a hash, likepikachu-ex--1f29b66b68bc. - A printing id:
<set code>-<collector number>, likesv2-11orsvp-106.
Decks store printing ids, so a deck is a map like { "me2pt5-276": 2, "svp-106": 2 }. cardsById is keyed by those same printing ids, and each one points to its identity. In that example both refs are Pikachu ex, so cardsById["me2pt5-276"] and cardsById["svp-106"] are the same card and share one card.id:
- Count copies of "the same card" by
card.id(orcard.name), not by ref. The deck above runs 4 Pikachu ex. - To read the printing a ref points to, find it in the list:
card.printings.find((p) => p.id === ref). ctx.globals.printings[ref]gives the identity id for any printing id, when globals are available.
A card rule gets the identity card itself, so card.id is always the identity id, never a printing id.
Guard against a missing card before reading from it: cardsById[ref] can be undefined when the catalog doesn't know a ref.
Card fields
Every card, in every game, has these top-level fields:
| Property | Type | Description |
|---|---|---|
id | string | Catalog id of the card identity ("01DE012" in LoR, "pikachu-ex--1f29b66b68bc" in Pokémon). |
name | string | Display name in the catalog locale. |
setCode | string | Set of the card, or of its default printing ("set1", "sv2", "OGN"). |
collectible? | boolean | False for cards that can't go in a deck (LoR tokens and level-ups). |
assets? | CardCatalogCardAssetContract[] | Images of the card's default printing. |
printings? | CardPrintingContract[] | Every printing of the identity, default printing first. Absent in LoR. |
hasImage? | boolean | False when none of the card's printings has an image in this language. Absent means it has one. |
game? | TGameData | Game-specific fields; see the per-game *CardGameData type. |
Printings
Each entry of printings (CardPrintingContract):
| Property | Type | Description |
|---|---|---|
id | string | Printing id; deck refs use it ("sv2-11" for Pokémon, "ogn-030-298" for Riftbound). |
setCode | string | Set the printing belongs to ("sv2", "OGN"). |
number? | string | Collector number within the set. |
language? | string | Language of the printing, when it is not the catalog's own. |
releaseDate? | string | Release date as the source gives it ("2023/06/09"). |
assets? | CardCatalogCardAssetContract[] | This printing's own images. |
variants? | CardVariantContract[] | Treatments of this printing (foil, alternate art, …). |
metadata? | JsonObject | Extra per-printing data (rarity, artist, store ids); game-specific. |
Each entry of a printing's variants:
| Property | Type | Description |
|---|---|---|
id | string | Variant id, usually <printing id>:<kind> ("ogn-030-298:normal"). |
kind? | string | Treatment kind ("normal", "foil", "alternate_art"); values are per game. |
label? | string | Display label, when the kind alone is not enough. |
metadata? | JsonObject | Extra per-variant data; game-specific. |
Each entry of assets (on the card and on each printing):
| Property | Type | Description |
|---|---|---|
kind | CardAssetKind | What the image shows: "card" (framed render), "full" (full art), "icon", "banner", "slice", "portrait", … |
url | string | Image URL. |
format? | CardAssetFormat | Image format ("webp"), when known. |
width? | number | Width in pixels, when known. |
height? | number | Height in pixels, when known. |
metadata? | JsonObject | Extra per-asset data; game-specific. |
Game fields (card.game)
Everything specific to the Pokémon TCG lives on card.game. The type tokens (supertype, subtypes, types, Energy costs, weakness types) are English in every language, so they are safe to compare. Names and text follow the viewer's language.
Watch for two things:
supertypeis"Pokemon", without the accent. Compare against both spellings if in doubt.hp,damageandlevelare strings, as printed ("60+"). Convert withNumber()before doing math.
| Property | Type | Description |
|---|---|---|
associatedCardRefs? | string[] | Reserved for related-card ids; not emitted by the catalog today. |
abilities? | PokemonAbilityPayload[] | Abilities, in printed order. |
artist? | string | Illustrator of the default printing. |
attacks? | PokemonAttackPayload[] | Attacks, in printed order. |
clientName? | string | Pokémon TCG Live display name when it differs from the printed name. |
convertedRetreatCost? | number | Number of Energy in the retreat cost (length of retreatCost). |
defaultPrintingId? | string | Printing id of the identity's representative (default art) printing. |
digitalOnly? | boolean | True when every printing exists only in Pokémon TCG Live. |
evolvesFrom? | string | Printed "Evolves from" name ("Pikachu"). |
evolvesFromIds? | string[] | Catalog ids of the identities this card evolves from. |
evolvesTo? | string[] | Printed "Evolves to" names. |
evolvesToIds? | string[] | Catalog ids of the identities this card evolves into. |
flavorText? | string | Flavor text, markup removed. |
hp? | string | Printed HP as a string ("120"); convert with Number() before comparing. |
identityAliases? | string[] | Older identity ids that now point to this card (ids it had before its Western release), so saved refs to them keep working. |
inMarket? | boolean | False when the card has no printing in this language's market (for example a Japan-only card in the English catalog). Absent means in-market. |
isProvisional? | boolean | True while the card is an unofficial pre-release entry, read off an official reveal before card data is published. Cleared when the official data lands. |
isLiveAvailable? | boolean | True when at least one printing is playable in Pokémon TCG Live. |
legalities? | JsonObject | Format key (standard, expanded, unlimited, standard-jp, expanded-jp, standard-future) to "Legal", "Illegal" or "Banned". Compare case-insensitively. |
level? | string | Printed level on older cards ("45"). |
liveCardId? | string | Pokémon TCG Live card id. |
nationalPokedexNumbers? | number[] | National Pokédex numbers of the Pokémon on the card ([25]); several for tag teams. |
number | string | Collector number of the default printing ("276"); the set is the card's setCode. |
rarity? | string | Rarity of the default printing as printed ("Rare", "Special Illustration Rare"). |
regulationMark? | string | Regulation mark letter ("G", "H"), which drives Standard rotation. |
resistances? | PokemonResistancePayload[] | Resistances, usually zero or one. |
retreatCost? | string[] | Energy type per retreat-cost Energy (["Colorless", "Colorless"]). |
rules? | string[] | Rule-box lines (Pokémon ex / V / Tera rules, Trainer rules). |
subtypes? | string[] | Stage and kind tokens (["Basic", "ex"], ["Stage 1"], ["Item"], ["Supporter"]). |
supertype | string | "Pokemon" (unaccented), "Trainer" or "Energy". |
types? | string[] | Energy types of a Pokémon (["Psychic"]); absent on Trainers and Energy. |
weaknesses? | PokemonWeaknessPayload[] | Weaknesses, usually zero or one. |
Abilities
Each entry of abilities:
| Property | Type | Description |
|---|---|---|
name | string | Ability name ("Quick Search"). |
text | string | Effect text. |
type | string | "Ability", "Poké-Power", "Poké-Body" etc., as printed. |
Attacks
Each entry of attacks:
| Property | Type | Description |
|---|---|---|
convertedEnergyCost? | number | Number of Energy the attack needs (length of cost). |
cost? | string[] | Energy type per required Energy (["Lightning", "Colorless"]). |
damage? | string | Printed damage as text ("30", "60+", "×"); absent when the attack does no printed damage. |
name | string | Attack name. |
text? | string | Effect text. |
Weaknesses
Each entry of weaknesses:
| Property | Type | Description |
|---|---|---|
type | string | Energy type the Pokémon is weak to ("Fighting"). |
value | string | Printed modifier ("×2", "+20"). |
Resistances
Each entry of resistances:
| Property | Type | Description |
|---|---|---|
type | string | Energy type the Pokémon resists ("Metal"). |
value | string | Printed modifier ("-30"). |
Globals (ctx.globals)
The catalog's globals hold set details and the printing index that maps every printing id to its identity.
When globals are available
Globals are passed to ruleset scripts as ctx.globals (the last argument). Calculators may not receive ctx at all, and a ruleset can run without it too. Always check ctx && ctx.globals before using them.
| Property | Type | Description |
|---|---|---|
printings? | Record<string, string> | Printing id → owning card identity id, covering every emitted printing. |
sets? | Record<string, PokemonCatalogSetLookupEntry> | Sets by set code ("sv2", "me2pt5"). |
Set entries
Each entry of sets:
| Property | Type | Description |
|---|---|---|
images? | PokemonSetImagesPayload | Set logo and symbol image URLs. |
label | string | Set name in the catalog locale ("Paldea Evolved"). |
printedTotal? | number | Card count printed on the cards (the /193 in 001/193). |
ptcgoCode? | string | PTCGO/PTCG Live set abbreviation (e.g. "PAL") used in text deck lists. |
releaseDate? | string | Release date as YYYY/MM/DD. |
series? | string | Series ("Scarlet & Violet"). |
total? | number | Total cards in the set, secret rares included. |
Set images
A set entry's images:
| Property | Type | Description |
|---|---|---|
logo? | string | Set logo image URL. |
symbol? | string | Set symbol image URL. |
Example card
Pikachu ex, trimmed to two printings, one image each and two identity aliases:
json
{
"id": "pikachu-ex--1f29b66b68bc",
"name": "Pikachu ex",
"setCode": "me2pt5",
"collectible": true,
"assets": [
{
"kind": "card",
"url": "https://cdn.turny.gg/cards/pokemon/assets/me2pt5-276-en-card-685c27781bd507cac386d4a882d063dedea2430e20472857fe1881360eae4777.webp"
}
],
"printings": [
{
"id": "me2pt5-276",
"setCode": "me2pt5",
"number": "276",
"releaseDate": "2026/01/30",
"assets": [
{
"kind": "card",
"url": "https://cdn.turny.gg/cards/pokemon/assets/me2pt5-276-en-card-685c27781bd507cac386d4a882d063dedea2430e20472857fe1881360eae4777.webp"
}
],
"variants": [],
"metadata": {
"rarity": "Special Illustration Rare",
"regulationMark": "H",
"artist": "booota"
}
},
{
"id": "svp-106",
"setCode": "svp",
"number": "106",
"releaseDate": "2023/01/01",
"assets": [
{
"kind": "card",
"url": "https://cdn.turny.gg/cards/pokemon/assets/svp-106-en-card-6834a96f03cf2394d164d4c948035eddc63428fcfd0c08d201e14064fe9b21dd.webp"
}
],
"variants": [],
"metadata": {
"rarity": "Promo",
"regulationMark": "H",
"artist": "takuyoa"
}
}
],
"game": {
"supertype": "Pokemon",
"subtypes": ["Basic", "ex"],
"hp": "200",
"types": ["Lightning"],
"rules": [
"Pokémon ex rule: When your Pokémon ex is Knocked Out, your opponent takes 2 Prize cards."
],
"attacks": [
{
"name": "Thunderbolt",
"cost": ["Lightning", "Lightning", "Colorless"],
"convertedEnergyCost": 3,
"damage": "120"
}
],
"weaknesses": [{ "type": "Fighting", "value": "×2" }],
"retreatCost": ["Colorless"],
"convertedRetreatCost": 1,
"number": "276",
"nationalPokedexNumbers": [25],
"rarity": "Special Illustration Rare",
"regulationMark": "H",
"artist": "booota",
"legalities": {
"expanded": "Legal",
"expanded-jp": "Legal",
"standard": "Legal",
"standard-future": "Legal",
"standard-jp": "Legal",
"unlimited": "Legal"
},
"identityAliases": ["pikachu-ex--1f4e7709a44c", "pikachu-ex--3f6f59171eb0"],
"defaultPrintingId": "me2pt5-276"
}
}Common recipes
js
// Calculator: Pokémon, Trainer and Energy counts.
export default function compute(pile, cardsById) {
const counts = { Pokémon: 0, Trainer: 0, Energy: 0 };
Object.keys(pile).forEach((ref) => {
const game = (cardsById[ref] && cardsById[ref].game) || {};
const supertype = game.supertype === "Pokemon" ? "Pokémon" : game.supertype;
if (counts[supertype] !== undefined) {
counts[supertype] += pile[ref];
}
});
return {
widgets: [
{
kind: "donut",
label: "Supertypes",
segments: Object.keys(counts).map((name) => ({
label: name,
value: counts[name],
})),
},
],
};
}js
// Card rule: legal in Standard. Legality text is compared case-insensitively.
export default function validateCard(card) {
const legalities = (card.game && card.game.legalities) || {};
const standard = String(legalities.standard || "").toLowerCase();
if (standard === "legal") {
return true;
}
return {
valid: false,
issues: [{ message: card.name + " is not legal in Standard." }],
};
}js
// Card rule: no Special Illustration Rares or Hyper Rares.
export default function validateCard(card) {
const rarity = (card.game && card.game.rarity) || "";
if (rarity !== "Special Illustration Rare" && rarity !== "Hyper Rare") {
return true;
}
return {
valid: false,
issues: [{ message: card.name + " is a " + rarity + "." }],
};
}js
// Calculator: copies per card identity, so reprints count together.
export default function compute(pile, cardsById) {
const copies = {};
const names = {};
Object.keys(pile).forEach((ref) => {
const card = cardsById[ref];
const id = card ? card.id : ref;
copies[id] = (copies[id] || 0) + pile[ref];
names[id] = card ? card.name : ref;
});
return {
widgets: [
{
kind: "table",
label: "Copies",
columns: ["Card", "Copies"],
rows: Object.keys(copies).map((id) => [names[id], copies[id]]),
},
],
};
}js
// Calculator: average HP of the Pokémon in the deck.
export default function compute(pile, cardsById) {
let total = 0;
let count = 0;
Object.keys(pile).forEach((ref) => {
const game = (cardsById[ref] && cardsById[ref].game) || {};
const hp = Number(game.hp);
if (hp > 0) {
total += hp * pile[ref];
count += pile[ref];
}
});
return {
widgets: [
{
kind: "stat",
label: "Average HP",
value: count > 0 ? Math.round(total / count) : 0,
},
],
};
}