29 Adding Cards
LunarTides edited this page 2026-01-12 09:01:58 +01:00

Warning

Most of this no longer applies as of 4.0.0. An updated version of this wiki is in progress: https://hs.lunartides.dev/guides/creating/cards/generators/custom/ (#447)

Adding cards can be difficult, if you're going to add a card with logic, you should have some experience with TypeScript.

In order to add a card. It is highly recommended to use the Card Creator Tool.

If you plan on adding a card that is already implemented in vanilla Hearthstone. Skip this section and go to "Adding a Vanilla card"

Adding a Custom card

  1. Open the Hearthstone.js Runner again by opening "run.bat" in the Hearthstone.js folder.
  2. Type "m" to enable Developer Mode.
  3. Type "c" to open the card creator.
  4. Type "c" again to make a custom card.

Making a card with the card creator

Making a Minion

hsjscccminion

  1. Type needs to be Minion.
  2. Name is the name of the card.
  3. Text can be whatever you want. In the picture above i use <b>Battlecry:</b> If.... The <b> means Bold and the </b> stops the bolding. There are a lot more tags like this, so keep that in mind. You don't have to use tags, it just makes it look better.
  4. Cost is how much the card should cost, usually in mana.
  5. Classes is the class the minion belongs to. Example: Priest, Hunter, Mage, etc... Use commas (,) to add multiple classes.
  6. Rarity is the rarity of the card. Keep your spelling in mind.
  7. Keywords is the keywords a minion has. Example: Taunt, Rush, Divine Spirit, etc... Your input should look like this: Keyword1, Keyword2, Keyword3, ....
  8. Attack is the amount of attack that the minion has.
  9. Health is the amount of health that the minion has.
  10. Tribes is the text in the middle of the attack and health of a minion in Hearthstone. This can be Dragon, Naga, Beast, etc... Your input should look like this: Tribe1, Tribe2, Tribe3, ....
  11. Uncollectible is if the card should not be allowed in a deck. Uncollectible cards can still be explicitly summoned by other minions.

After all this has been filled out, it will show you where the card file was created. If you have VSCode installed, it will open it to that location (You can change the default editor in the config.ts file under General > Editor). If not you need to navigate to the card file and open it with your favorite code editor.

Making a Spell

If a field isn't shown here, it means it works the same as in "Making a Minion".

hsjscccspell

  1. Type needs to be Spell.
  2. Spell Schools is a spells version of a Tribe. This can be Holy, Shadow, Fire, etc... Your input should look like this: SpellSchool1, SpellSchool2, SpellSchool3, ....

Adding a Vanilla card

hsjsvcc

  1. Open the Hearthstone.js Runner again by opening "run.bat" in the Hearthstone.js folder.
  2. Type "m" to enable Developer Mode.
  3. Type "c" to open the card creator.
  4. Type "v" to make a vanilla card.
  5. Type in the name or dbfID of the card as it is in Hearthstone.
  6. If there are multiple cards with the same name, it will ask you to choose one.
  7. Open the file created in your favorite code editor.
  8. Go to "Editing Logic"

Editing Logic

I would heavily recommend checking out the example cards at cards/Examples/. They have a lot more thought put into them than this wiki, and go into more detail about more specific things.

ccclogic

This picture is outdated and uses plr instead of owner and tribe instead of `tribes.

After you have the card open in your favorite code editor, it is time to work on the logic. The card creator should have been able to detect if you want a battlecry, deathrattle, cast, etc... from the description of the card.

The self variable is the actual card played, the owner variable is the player the card belongs to, and the global game variable is the entire game (you can also access the functions module from this). Look at the source code for different things you can do.

More accurately:

  1. The self variable is an instance of the Card class as defined in src/card.ts.
  2. The owner variable is an instance of the Player class as defined in src/player.ts, look in there for the different functions you can call.

Example

If you want more examples, there is an example folder in the cards folder that shows you some basics. I highly recommend checking that out. If there is anything you need that isn't shown in the example cards, consult the cards that are already implemented. You can also open an issue / discussion to ask me directly.

One

Lets say you have a minion with the description Battlecry: Draw a card. The code for that would be:

async battlecry(self, owner) {
    // Draw 1 card.
    await owner.drawCards(1);
}

Two

Lets say you have a minion with the description Battlecry: Deal 2 damage to a minion. The code for that would be:

async battlecry(self, owner) {
    // `game` is a global variable that you can always use.

    // targetCard(prompt, theCardThatCalledTheFunction, flags)
    const target = await game.prompt.targetCard("Deal 2 damage to a minion.", self);

    // If you didn't select a target (which means they cancelled the selection), refund the card.
    if (!target) {
        return Card.REFUND;
    }

    await game.attack(2, target); // Deal 2 damage to the target
}

Three

Lets say you have a spell with the description Discover a minion that costs (5) or more. The code for that would be:

async cast(self, owner) {
    // Discover needs a list to choose the 3 cards from.

    // This will get all the cards currently in the game, excluding uncollectible cards.
    let list = await Card.all();

    // Filter the cards so that only minions that cost 5 or more remains.
    list = list.filter(card => card.type === CardType.Minion && card.cost >= 5);

    // If there are no cards that meet this criteria, stop execution.
    if (list.length == 0) {
        return;
    }

    // Discover filters out cards that arent from the player's class. Example: If the player is a Priest, only include Priest and Neutral cards. You can disable this using the flag after `list`.
    // discover(prompt, listOfCardsToChooseFrom, filterOutCardsWithANonMatchingClass = true, amountOfCardsToChooseFrom = 3)
    let minion = await game.prompt.discover("Discover a minion that costs (5) or more", list);

    // Make a copy of the card. This is important to prevent "linking".
    minion = await minion.imperfectCopy();
    await owner.addToHand(minion);
}

In the 'Drakonid Operative' example i showed above, here's the working code: ccclogicworking

This picture is very outdated.