Skip to content

Riftbound card data ​

Ruleset and calculator scripts get Riftbound 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 cardsById as their second argument.

See the ruleset script API and the calculator script API for the full function signatures.

Card keys and deck refs ​

A Riftbound card in the catalog is a card identity: one playable card with all of its printings (showcase, signature and alternate-art prints, reprints in later sets) listed under printings. Two kinds of id matter:

  • The identity id, card.id: rb- plus a hash, like rb-34ece2975dc9e4adcb5e.
  • A printing id: set, collector number and set size, like ogn-030-298. Treatments add a suffix: ogn-030a-298 is the alternate art.

Decks store printing ids (decks saved before printing refs existed may still use identity ids). cardsById is keyed by the deck's refs, and each one points to its identity, so two printings of the same card in one deck resolve to the same object:

  • Count copies of "the same card" by card.id, not by ref.
  • To read the printing a ref points to, find it in the list: card.printings.find((p) => p.id === ref).
  • ctx.globals.aliases[ref] gives the identity id for any printing or variant id, when globals are available.

A card rule gets the identity card itself, so card.id is always the identity id.

The game fields describe the card's default printing, the first entry of printings (game.defaultPrintingId). That matters for per-printing fields such as rarity, variant and artistName.

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:

PropertyTypeDescription
idstringCatalog id of the card identity ("01DE012" in LoR, "pikachu-ex--1f29b66b68bc" in Pokémon).
namestringDisplay name in the catalog locale.
setCodestringSet of the card, or of its default printing ("set1", "sv2", "OGN").
collectible?booleanFalse 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?booleanFalse when none of the card's printings has an image in this language. Absent means it has one.
game?TGameDataGame-specific fields; see the per-game *CardGameData type.

Printings ​

Each entry of printings (CardPrintingContract):

PropertyTypeDescription
idstringPrinting id; deck refs use it ("sv2-11" for Pokémon, "ogn-030-298" for Riftbound).
setCodestringSet the printing belongs to ("sv2", "OGN").
number?stringCollector number within the set.
language?stringLanguage of the printing, when it is not the catalog's own.
releaseDate?stringRelease 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?JsonObjectExtra per-printing data (rarity, artist, store ids); game-specific.

Each entry of a printing's variants:

PropertyTypeDescription
idstringVariant id, usually <printing id>:<kind> ("ogn-030-298:normal").
kind?stringTreatment kind ("normal", "foil", "alternate_art"); values are per game.
label?stringDisplay label, when the kind alone is not enough.
metadata?JsonObjectExtra per-variant data; game-specific.

Each entry of assets (on the card and on each printing):

PropertyTypeDescription
kindCardAssetKindWhat the image shows: "card" (framed render), "full" (full art), "icon", "banner", "slice", "portrait", …
urlstringImage URL.
format?CardAssetFormatImage format ("webp"), when known.
width?numberWidth in pixels, when known.
height?numberHeight in pixels, when known.
metadata?JsonObjectExtra per-asset data; game-specific.

Game fields (card.game) ​

Everything specific to Riftbound lives on card.game. Riftbound is English only, so classification values (type, rarity, domains) are lower-case tokens you can compare directly; look them up in the globals for display names.

PropertyTypeDescription
type?RiftboundCardTypeCard type: "unit", "spell", "gear", "battlefield", "rune" or "legend". Champions are units with supertype: "Champion".
supertype?stringPrinted supertype when there is one: "Champion", "Signature", "Basic", "Token".
rarity?RiftboundRarityRarity of the default printing: "common", "uncommon", "rare", "epic", "showcase", …
domains?RiftboundDomain[]Domains (colors): ["fury"], ["calm", "mind"]. A card with no domain carries ["colorless"].
tags?string[]Printed tags such as champion names and factions (["Jinx", "Zaun"]).
energy?numberEnergy cost.
might?numberMight (combat strength); units only.
power?numberPower cost: the domain-rune part of the cost, paid on top of energy.
collectorNumber?stringCollector number of the default printing within its set, without leading zeros ("30").
defaultPrintingId?stringId of the default printing ("ogn-030-298"): the first regular printing, from the earliest set, with the normal treatment. Always the first entry of printings.
legalities?RiftboundCardLegalitiesLegality per format ({ standard: "legal" } or "banned"). A missing format counts as legal.
text?stringRules text as HTML, with [Keyword] markers and :rb_…: symbol tokens.
textPlain?stringRules text without HTML tags; [Keyword] markers and :rb_…: tokens stay.
flavorText?stringFlavor text.
keywordRefs?string[]Keywords in the rules text, as globals.keywords keys (["accelerate", "assault"]); [Assault 2] becomes "assault".
orientation?RiftboundCardOrientation"portrait", or "landscape" for battlefields.
variant?stringTreatment of the default printing: "normal", "foil", "showcase", "ultimate", "alternate_art" or "signature".
foil?booleanTrue when the default printing is foil.
alternateArt?booleanTrue when the default printing is an alternate-art print.
signature?booleanTrue when the default printing is a signature print.
artistName?stringArtist of the default printing.

Globals (ctx.globals) ​

The catalog's globals are lookup tables for the values on a card (domains: ["fury"] resolves through ctx.globals.domains.fury), the keyword glossary, the rules-text symbols and the printing alias map.

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 and fall back to the raw value.

PropertyTypeDescription
domains?Record<string, RiftboundCatalogDomainLookupEntry>Domains by domains value ("fury" → Fury).
rarities?Record<string, RiftboundCatalogRarityLookupEntry>Rarities by rarity value ("epic" → Epic).
types?Record<string, RiftboundCatalogTypeLookupEntry>Card types by type value ("unit" → Unit).
sets?Record<string, RiftboundCatalogSetLookupEntry>Sets by the card's setCode ("OGN" → Origins).
formats?Record<string, RiftboundCatalogFormatLookupEntry>Formats by legalities key ("standard").
keywords?Record<string, RiftboundCatalogKeywordEntry>Keyword glossary, keyed by normalized keyword id; filtered to keywords the ingested catalog actually references.
symbols?Record<string, RiftboundCatalogSymbolEntry>Inline symbol-token lexicon (:rb_...:), keyed by token key.
aliases?Record<string, string>Printing or variant id → owning card identity id ("ogn-030-298" → "rb-34ece2975dc9e4adcb5e"); identity ids map to themselves. Deck refs may be either.

Lookup entries ​

domains, rarities, types, sets, formats and keywords map a key to an entry with these fields:

PropertyTypeDescription
labelstringDisplay name ("Fury", "Origins").
color?stringDisplay color set by an operator override; usually absent.
icon?string | nullIcon image URL set by an operator override; usually absent.
order?numberSort position in filters and lists, lowest first.
showInFilter?booleanWhether the entry is offered as a filter option; absent means shown.
metadataRef?RiftboundCatalogMetadataReferenceAnchor an operator override is matched on.

Keyword entries ​

keywords entries also have:

PropertyTypeDescription
description?stringReminder text; may contain :rb_…: symbol tokens.

Symbol entries ​

Each entry of symbols:

PropertyTypeDescription
tokenstringThe full inline token as it appears in rich text, e.g. ":rb_energy_1:".

Example card ​

Jinx, Demolitionist, trimmed to two printings with one image each:

json
{
  "id": "rb-34ece2975dc9e4adcb5e",
  "name": "Jinx - Demolitionist",
  "setCode": "OGN",
  "collectible": true,
  "assets": [
    {
      "kind": "card",
      "url": "https://cdn.turny.gg/cards/riftbound/assets/ogn-030-298-card-80a26a1b25235660a480721f141f212244485ad006bbd2602247425901e8b11e.webp"
    }
  ],
  "printings": [
    {
      "id": "ogn-030-298",
      "setCode": "OGN",
      "number": "30",
      "assets": [
        {
          "kind": "card",
          "url": "https://cdn.turny.gg/cards/riftbound/assets/ogn-030-298-card-80a26a1b25235660a480721f141f212244485ad006bbd2602247425901e8b11e.webp"
        }
      ],
      "variants": [{ "id": "ogn-030-298:normal", "kind": "normal" }],
      "metadata": { "tcgplayerId": "652802" }
    },
    {
      "id": "ogn-030a-298",
      "setCode": "OGN",
      "number": "30",
      "assets": [
        {
          "kind": "card",
          "url": "https://cdn.turny.gg/cards/riftbound/assets/ogn-030a-298-card-03360e2876cef6388860f6cd8445bd352c6a95eea244e015019869cd5d693365.webp"
        }
      ],
      "variants": [
        { "id": "ogn-030a-298:alternate_art", "kind": "alternate_art" }
      ],
      "metadata": { "tcgplayerId": "652803" }
    }
  ],
  "hasImage": true,
  "game": {
    "type": "unit",
    "supertype": "Champion",
    "rarity": "rare",
    "domains": ["fury"],
    "tags": ["Jinx", "Zaun"],
    "energy": 3,
    "might": 4,
    "power": 1,
    "collectorNumber": "30",
    "defaultPrintingId": "ogn-030-298",
    "legalities": { "standard": "legal" },
    "text": "<p>[Accelerate] (You may pay :rb_energy_1::rb_rune_fury: as an additional cost to have me enter ready.)<br />[Assault 2] (+2 :rb_might: while I'm an attacker.)<br />When you play me, discard 2.</p>",
    "textPlain": "[Accelerate] (You may pay :rb_energy_1::rb_rune_fury: as an additional cost to have me enter ready.)[Assault 2] (+2 :rb_might: while I'm an attacker.)When you play me, discard 2.",
    "keywordRefs": ["accelerate", "assault"],
    "flavorText": "I really need a new gun. But don't tell my other guns.",
    "orientation": "portrait",
    "variant": "normal",
    "artistName": "Kudos Productions"
  }
}

Common recipes ​

js
// Calculator: cards per type, with champions split out.
export default function compute(pile, cardsById) {
  const counts = {};

  Object.keys(pile).forEach((ref) => {
    const game = (cardsById[ref] && cardsById[ref].game) || {};
    const type =
      game.supertype === "Champion" ? "champion" : game.type || "other";

    counts[type] = (counts[type] || 0) + pile[ref];
  });

  return {
    widgets: [
      {
        kind: "donut",
        label: "Card types",
        segments: Object.keys(counts).map((type) => ({
          label: type,
          value: counts[type],
        })),
      },
    ],
  };
}
js
// Calculator: main-deck copies at each energy cost, 7+ grouped.
export default function compute(pile, cardsById) {
  const buckets = [0, 0, 0, 0, 0, 0, 0, 0];

  Object.keys(pile).forEach((ref) => {
    const game = (cardsById[ref] && cardsById[ref].game) || {};

    if (typeof game.energy !== "number") {
      return; // Legends, runes and battlefields have no energy cost.
    }

    buckets[Math.min(game.energy, 7)] += pile[ref];
  });

  return {
    widgets: [
      {
        kind: "histogram",
        label: "Energy curve",
        buckets: buckets,
        labels: ["0", "1", "2", "3", "4", "5", "6", "7+"],
      },
    ],
  };
}
js
// Card rule: commons and uncommons only. Legends, runes and battlefields pass.
export default function validateCard(card) {
  const game = card.game || {};
  const exempt = ["legend", "rune", "battlefield"];

  if (exempt.indexOf(game.type) !== -1) {
    return true;
  }

  if (game.rarity === "common" || game.rarity === "uncommon") {
    return true;
  }

  return {
    valid: false,
    issues: [{ message: card.name + " is " + game.rarity + "." }],
  };
}
js
// Card rule: not banned in Standard. A card with no entry counts as legal.
export default function validateCard(card) {
  const legalities = (card.game && card.game.legalities) || {};

  if (legalities.standard !== "banned") {
    return true;
  }

  return {
    valid: false,
    issues: [{ message: card.name + " is banned in Standard." }],
  };
}
js
// Card rule: Fury cards only. Uses the domain's display name when globals exist.
export default function validateCard(card, ctx) {
  const domains = (card.game && card.game.domains) || [];

  if (domains.indexOf("fury") !== -1) {
    return true;
  }

  const globals = ctx && ctx.globals;
  const fury =
    globals && globals.domains && globals.domains.fury
      ? globals.domains.fury.label
      : "fury";

  return {
    valid: false,
    issues: [{ message: card.name + " is not a " + fury + " card." }],
  };
}

Turny.gg documentation