The Modder's Manual
Everything the editor does, explained in plain language. New here? Read Quick Start, then come back to the rest when you need it. You can also replay the interactive walkthrough any time with the ? Tour button in the editor's top bar.
Quick Start
This tool builds a playable custom character for Slay the Spire 2 — their card pool, relics, custom statuses, and art — and compiles it into a mod you drop into the game. No coding required. Your work auto-saves to your browser as you go.
The flow, in 8 steps
- Character tab — name, HP, gold, energy per turn, and the character color (it tints every card frame in game).
- Cards — build your pool. Click a card in the sidebar to edit it; add effect blocks to define what it does.
- Upgrades — for each card, decide what its + version does at rest sites.
- Token cards — cards created mid-combat (like Shivs). Create these before referencing them from effects.
- Mechanics — your own buffs/debuffs (custom statuses). Same rule: create first, reference after.
- Relics — passive items with a trigger and effects. You need at least one.
- Balance — optional sanity check of your numbers.
- Export — fix any pre-flight issues, then Compile & Download and install (see Export & Install).
Minimum requirements
A mod must have at least 10 cards and 1 relic before the export buttons unlock. A new project starts with just Strike, Defend, and a starter relic — add at least 8 more cards of your own to reach the minimum.
Cards
Types, rarities, targeting
- Attack — deals damage; red frame. Most damage effects live here.
- Skill — everything that isn't an attack or a power — Block, draw, debuffs; blue frame.
- Power — a permanent effect for the rest of the combat; green frame. Power cards can use start-of-turn / end-of-turn timing on their effects.
Rarity controls how often a card shows up in rewards: Basic (starter deck only, never in rewards), Common, Uncommon, Rare, and Ancient — see the rarity rules before using Ancient.
Target decides who the card hits: Self, AnyEnemy (player picks one), AllEnemies, RandomEnemy, AnyAlly, or AllAllies (ally targets matter in co-op).
Effect blocks
A card is a stack of effect blocks, executed top to bottom when the card is played. Each block becomes real game code on export. The picker groups them by category:
- Damage — single hits, multi-hits, hit-all, random target, scaling damage.
- Defense — gain Block, heal, lose HP (for high-risk designs).
- Power — apply buffs/debuffs — vanilla ones like Strength, Weak, Poison, or your own custom statuses.
- Card — draw, discard, exhaust, upgrade cards mid-combat, and add token cards to hand / discard / draw pile.
- Utility — energy, gold, max HP, stances, Mantra, and other odds and ends.
- Orb — channel and evoke orbs (give your character orb slots in the Character tab first).
Conditions
Every effect block has a condition dropdown, defaulting to “Always (no condition)”. Pick a condition and the effect only fires when it's true — e.g. target has Poison, player HP below N, last card played was an Attack, in Wrath stance, enemy intends to attack. Some conditions take a number or a custom status to check for.
A conditional effect can also carry an Otherwise branch — effects that run only when the condition is false. That's the clean way to build “deal 7 damage; deal 14 instead if the enemy is Poisoned” cards. Otherwise-effects can have a condition of their own (one extra level), so “if A do X, otherwise if B do Y, otherwise Z” works too.
X-cost and other advanced options
- X-Cost — the card costs all your remaining energy and its effects scale with the amount spent (like Whirlwind).
- Playability condition — the card can only be played while a requirement holds — hand is all Attacks (Clash), exhaust pile is large enough, or no cards discarded this turn.
- Self-scaling — the card permanently grows (+N damage or Block) every time you play it — the Rampage pattern.
Keywords
- Exhaust — the card is removed for the rest of combat after being played once.
- Ethereal — if it's still in your hand at end of turn, it exhausts.
- Innate — always in your opening hand.
- Retain — not discarded at end of turn.
- Sly — when discarded, the card plays itself automatically.
- Eternal — the card can never be removed from your deck.
Card text
You never have to write card text: the description is auto-generated from your effect blocks (shown in italics under the effects list and on the card preview). If the auto text reads awkwardly — long conditional chains are the usual culprit — type your own in Description Override. Numbers in an override are up to you to keep in sync with the actual effect values. If an overridden card also upgrades, fill in the upgraded description too — a plain override freezes the shown numbers, so the + version needs its own text.
Complex Effects
Five things people get stuck on. Each one plays through in the editor’s own layout — hover to pause, or use the dots to step through at your own pace.
Conditions and layers
A layer holds up to three conditions, and you can nest three layers deep — nine conditions on a single effect. The joiner is per layer, so a layer is all AND or all OR, and any one condition can be negated.
1/5Every effect block starts unconditional. This one always fires.
One condition, several effects
When two effects share the same checks, put the checks once on an effect that does nothing and hang the real work off its Otherwise. The trick is to invert the conditions and flip AND to OR: you are aiming at the case where nothing should happen.
1/5Goal: if you have Block and your last card was an Attack, gain 8 Block and draw 1.
Numbers that stay live
A number you type into card text is frozen. The real damage moves with Strength, Weak, enchantments and the upgrade, and a typed number will not — so the card ends up lying. Use the {token} listed under the description box instead.
1/4A card with one damage effect writes its own text.
Deal {damage} damage.
What an upgrade can reach
Upgrade fields exist for top-level effects. An effect inside an Otherwise deliberately gets none, because both branches share one declared number — raising it would make the card advertise damage the other branch does not deal. Two ways around it below.
1/5The Upgrades panel offers a field per number the card declares.
A mechanic as a flag
Some cards are easiest to build as a status that does nothing, read by conditions on the cards it affects. Say what the card does, not how it is wired — and never describe an effect it does not have.
1/5Goal: a power that reads “Your Strikes hit all enemies.”
Your Strikes hit all enemies.
There is no effect for that. There is an effect for everything it is made of.
Discard Costs & Milling
Pay for a card by exhausting Discard
Under a card or token's Properties, enable Exhaust Discard to pay Energy beside its cost. Set the Energy paid per exhausted card; the default is 1. A card costing 3 can then be played with 1 Energy and 2 cards in Discard. The payment picker requires enough cards to cover any shortfall and lets you exhaust more to preserve Energy.
The normal cost still responds to upgrades and discounts. Free plays and automatic plays need no discard payment, and replays pay only once. Extra payment gives no Energy back. This option supports fixed Energy costs; X Energy and Unplayable cards cannot use it. Any Star cost still needs to be paid.
Give a bonus for what you milled or discarded
For an Escape Plan variant, add Move Top Draw Cards to Discard (Mill) with a count of 1. Below it, add Gain Block. Set that block's If to Last card milled was a type..., then choose Skill.
For a Survivor variant, add your discard effect first, then put Last card discarded was a type... → Attack on its bonus effect. Both checks also have a had a tag... version: enter the exact tag used on your cards.
These checks belong to the player who owns the effect. Discard checks read the most recent successful discard in the current combat, so discarding nothing leaves that previous result. Milling keeps its own result: an empty mill clears it, and milling several cards checks the last card successfully moved by that mill. Simply playing a card into Discard is not a discard event, and milling does not fire discard triggers.
Expressions & Formulas
Recent additions: use targetIntentDamage for the enemy’s intended attack damage across all hits, before Block. For example, targetIntentDamage / 2 grants half that amount in a scaled Block effect. It includes modifiers against the effect owner, returns zero for a non-attack, and reads the aimed enemy on targeted cards (the first opponent elsewhere).
For X-cost cards, use Increase X by beside the X-Cost setting, including a separate upgraded value. This changes resolved X without spending extra resources. The existing X-cost cards count X as +N passive applies to all your X-cost cards.
To enchant a discovered card, choose the enchantment inside Discover a Card → Enchant the chosen card. A separate Enchant effect targeting “That card” reads the trigger’s card, not the Discover selection. The chosen card must meet the enchantment’s compatibility rules.
Play This Card → Ignore Unplayable for this forced play bypasses that keyword for one automatic play and restores it afterward. Other play restrictions still apply. Whenever you die in Mechanics or Relics reacts to actual death; use death prevention separately if you want a resurrection effect.
An expression calculates a number when an effect runs. It can combine your HP, Gold, cards, or status stacks instead of scaling with just one value. You do not need to write code: start with a recipe below and change its numbers.
Your first formula
- Add Damage (Scaled) to a card.
- Set Base Damage to 0, Number of Hits to 1, and Scales With to expression.
- Set Per-Stack Multiplier to 1 and Multiplier when upgraded to 0 (same).
- Enter
max(0, selfMaxHp - selfCurrentHp)in Formula. - Leave But At Most on none and stack multiplication/repetition off. Leave the Strength/Weak damage option off while testing the arithmetic.
At 50 current HP out of 70 maximum HP, this calculates 20 damage. At full HP it calculates 0. The value updates when the effect runs; typing 20 into the description would only display a fixed number.
How the fields combine
For Damage (Scaled), with the extra options above off, each hit starts with base damage + formula × multiplier. Base Damage 5 with the formula handSize * 2 and multiplier 1 gives 11 damage if three cards remain in hand when the effect runs. The card being played has normally already left your hand. A multiplier of 2 makes that 17, not 22: it multiplies the formula contribution, not the base.
Keep the multiplier at 1 when the formula already says everything you want. A nonzero upgraded multiplier replaces the normal multiplier on an upgraded card; 0 keeps it unchanged. Upgrading the base amount is separate. Damage (Scaled) calculates damage per hit; Hits (Scaled) calculates how many hits to make. Read the base/minimum labels on other scaled effects: their extra fields do not all mean base damage.
min(handSize * 2, 10)adds at most 10 from the formula when the multiplier is 1. This does not impose a final damage ceiling after Strength or Vulnerable.Copyable recipes
Unless stated otherwise, use base amount 0, multiplier 1, no cap, and no stack multiplier.
| Goal | Formula | Example / setup |
|---|---|---|
| Your missing HP | max(0, selfMaxHp - selfCurrentHp) | 70 max HP − 50 current HP = 20. |
| Half your Block, rounded down | floor(currentBlock / 2) | 9 Block gives 4. |
| One point per 25 Gold | floor(currentGold / 25) | 124 Gold gives 4. Reading Gold does not spend it. |
| Two per card, up to 10 | min(handSize * 2, 10) | 3 cards gives 6; 7 cards gives 10. |
| 2 per complete 10 custom stacks, up to +10 | min(10, floor(selfCustomStatusStacks / 10) * 2) | Select the mechanic in Status. 9 stacks → 0; 27 → 4; 60 → 10. Set Base Damage to your starting damage. |
| X times (4 + a capped stack bonus) | energySpent * (4 + min(10, floor(selfCustomStatusStacks / 10) * 2)) | On an X-cost card, select the mechanic. X = 3 and 20 stacks gives 24. Leave the separate multiply-by-X option off. |
| Refund X − 2 from a played card | max(0, playedCardX - 2) | Use Energy (Scaled) in a Whenever you play a card trigger. X = 5 gives 3 Energy; X = 1 gives 0. |
| One third, rounded up | ceil(handSize / 3) | 4 cards gives 2. |
Names, arithmetic, and rounding
Write selfMaxHp, not {selfMaxHp}. Braces are for description text. Variable names are case-sensitive: selfMaxHP is not selfMaxHp. Use a dot for decimals (0.5), * for multiplication, and parentheses to group calculations. Multiplication and division happen before addition and subtraction: 2 + 3 * 4 is 14, while(2 + 3) * 4 is 20.
| Syntax | Meaning | Example |
|---|---|---|
| + − * / | Add, subtract, multiply, divide (type the ordinary minus key). | 10 / 4 |
| % | Remainder, not percentage. 7 % 3 gives 1. For 25%, multiply by 0.25. | floor(currentGold * 0.25) |
| min(a, b) | Take the smaller value; useful for a maximum. | min(handSize, 5) |
| max(a, b) | Take the larger value; useful for a minimum. | max(0, playedCardX - 2) |
| floor(n) | Round down: floor(2.9) = 2. | floor(currentBlock / 2) |
| ceil(n) | Round up: ceil(2.1) = 3. | ceil(currentBlock / 2) |
| round(n) | Round to nearest; exact halves go to the even integer: 2.5 → 2, 3.5 → 4. | round(currentBlock / 2) |
| abs(n) | Distance from zero: abs(-3) = 3. | abs(selfMaxHp - selfCurrentHp) |
Division can produce fractions. Use floor or ceilwhen your design needs a specific whole-number result. Division or remainder by zero returns 0. There is no if(), comparison, assignment, dice roll, or exponent operator in a formula. Put conditional behavior in the effect's If and Otherwisecontrols; use the chance condition for randomness.
Choose values that exist at that moment
| Values | What they read / where to use them |
|---|---|
selfCurrentHp, selfMaxHp, currentBlock | You on a card/relic; the status holder on a mechanic. |
handSize, handSpace, drawPileSize, discardPileSize, exhaustPileSize | The current combat piles; handSpace counts empty hand slots. |
deckSize | The permanent run deck, not the number of cards left to draw. |
currentGold, enemyCount | Current Gold and living opponents. |
selfCustomStatusStacks, targetCustomStatusStacks | Choose the custom mechanic in the effect's Status/scaling-status picker. Both names share that one selection; do not type your mechanic's name into the formula. |
energySpent, starsSpent | The current card's Energy X / Star X, including applicable X bonuses. These are for that X-cost card's own effects, not a generic trigger's last spend. |
playedCardCost, playedCardX | In a supported card-play trigger: actual Energy paid for that play, or that card's resolved Energy X. An ordinary non-X card has playedCardX = 0. A free X card can have a different X from Energy paid. |
pendingDamage | In a supported before-hit damage trigger: damage about to be dealt/taken for that hit. Not a prediction of an entire future multi-hit attack. |
hpChangeAmount | In an HP-change trigger: the HP amount just lost or healed. |
stacksApplied | In a supported stack-change trigger: the stack-change value carried by that event. |
An expression only reads values; it does not spend Gold, consume a mechanic, or remember the previous result. Add separate effects for those actions. Effects run in order, so gaining or spending a resource first can change the formula that runs next. Target values depend on the effect and trigger: a card can have a chosen target, while some non-card sources use the first opponent or a total across opponents. Do not assume every target… value means the last creature hit.
All recognized formula variable names
This list comes from the same supported-name registry as export validation. Recognition does not mean a value is available in every trigger. Export → Checks explains context restrictions. Other choices in Scales With that need extra filters, such as a card tag, are not automatically formula variables.
allCardsPlayedThisCombatallyHitsOnTargetThisTurnattacksPlayedThisTurncardsCreatedThisCombatcardsDiscardedThisPlaycardsDiscardedThisTurncardsDrawnThisCombatcardsExhaustedThisPlaycardsPlayedThisTurnchanneledOrbCountcurrentBlockcurrentGolddeckSizediscardPileSizedoomedCreaturesdrawPileSizeenemyCountenemyDoomStacksenemyFrailStacksenemyPoisonStacksenemyVulnerableStacksenergySpentenergySpentBeforeThisCardThisTurnetherealCardsPlayedThisCombatexhaustPileSizeextraCardsDrawnThisTurnforgeAmounthandSizehandSizeAtPlayhandSizeAtTurnEndhandSpacehpChangeAmountlastBlockGainedByThisCardostyAttacksThisTurnostyCurrentHpostyMaxHpotherCardsInHandotherOstyAttackCardsInCombatownHitsOnTargetThisTurnpendingDamageplayedCardCostplayedCardXrelicChargesretainCardsInDeckselfCurrentHpselfCustomStatusStacksselfMaxHpselfStrengthStacksskillsPlayedThisTurnstacksAppliedstacksAtPlayStartstarCostCardsInCombatstarsGainedThisTurnstarsSpentstarsSpentEventstatusCardsOutsideExhauststrikeCardsInCombattargetBlocktargetCurrentHptargetCustomStatusStackstargetIntentDamagetargetMaxHpthisCardBlockthisCardDamagetimesLostHpThisCombatturnNumberuniqueOrbTypesWhen a formula does not behave as expected
- Unknown value: check spelling/capitalization against the list above. Use
selfCustomStatusStacksand the picker, not a custom status name. - Formula ends early / expected a parenthesis: finish the calculation;
minandmaxneed exactly two comma-separated values. - Valid formula, wrong place: play-event and damage-event values need their matching triggers. Check Export → Checks before exporting.
- Too large or doubled: check the base amount, normal/upgraded multiplier, number of hits, multiply-by-X, stack multiplication, repeated triggers, and damage modifiers.
- Always zero: check that the selected mechanic is actually on the expected creature and that the event provides the value you are reading.
- Description looks unchanged: a formula is not a text placeholder. Use the description's supported tokens, or the effect's combat-only running-total option where offered. Test a fresh export in combat with known values.
Upgrades
At rest sites the player can upgrade a card once, turning it into its + version. The Upgrade section on each card decides what that means:
- Cost Reduction — the + version costs this much less energy (a 1-cost card with reduction 1 becomes free).
- +Damage / +Block / +Heal / +Draw / +Energy on Upgrade — one input appears per stat the card actually uses; the + version adds that amount. Two damage effects on one card share a single damage value, so one input upgrades both.
- +Stacks on Upgrade — for cards applying vanilla statuses (Strength, Weak, Poison...), the + version applies this many more stacks.
- Remove Exhaust on Upgrade — the + version no longer exhausts (shown only on Exhaust cards).
- Add Retain on Upgrade — the + version gains Retain.
Token Cards & Custom Statuses
Token cards
A token card is a card that other cards create during combat — think Shivs. Tokens never appear in card rewards or shops; they only exist when an effect puts them in your hand, discard, or draw pile. Create them under Token Cards in the sidebar; they get the same editor as normal cards (effects, keywords, art, upgrades).
Custom statuses (Mechanics tab)
A custom status is your own buff or debuff — a named icon with stacks that does something on a trigger (after a card is played, when damage is taken, at turn end...). Define them in the Mechanics tab, then apply them from cards or relics with the “apply custom status” effect.
Besides triggers, a status can have Passive Effects — always-on stat changes while it's active, the way Strength or Barricade work: extra attack damage, cheaper cards, more draw, keeping your hand or Block at end of turn, immunity rules, and dozens more. Most scale with the status's stack count.
Reskinning a base mechanic. Want Poison, but called Ether with your own icon? In the Mechanics tab open Templates and pick Poison-style or Regen-style — they rebuild the exact vanilla behavior (lose or heal HP equal to stacks each turn, fading by 1). Then just rename it and upload an icon. The behavior stays; only the skin changes.
Reacting to debuffs from anyone
In a mechanic, choose Whenever you change a status (any target or amount). Set Changed by → Anyone, Status change → Debuff changes, and Recipient → This status's holder / relic owner. This includes enemies, allies, self-inflicted debuffs, and changes with no applier. Losing Strength or Dexterity also counts as a debuff change.
To watch positive stacks of any debuff, choose For each stack gained of a status, set Status type → Any status, and choose Debuff changes. Use stacksApplied in a scaled effect for the number gained; a plain effect fires once per application. The gained-stack trigger does not include negative Strength changes; use the change trigger above for those. Equivalent filters are available on relics.
Stances
Stances are the Watcher's Wrath/Calm/Divinity system — you are in at most one at a time, and it changes how much damage you deal and take. The Stances panel at the top of the Mechanics tab lets you build your own: set Damage Dealt % and Damage Taken % (200 = double like Wrath, 50 = half), energy gained on enter or exit, and whether it auto-exits at the start of your turn (the Divinity pattern). Give it a name and icon, then enter it with the Enter Custom Stance effect on a card, relic, or status — and branch card logic on it with the In custom stance condition. The Exit Stance effect leaves whatever stance you're in.
Stack-scaled effects and streaks
Inside a status's triggers, several effects can scale with the status's own stack count. “× Stacks” checkboxes on Apply Status and Lose HP multiply the amount by the current stacks, and there are dedicated stack-scaled Damage and Block effects. The “Change Own Stacks” effect lets a status modify itself — a negative value is the classic poison decrement (the status disappears at zero).
For example, a poison-style debuff is: trigger at end of turn, effect Lose HP with × Stacks checked, then Change Own Stacks: -1. Whoever carries it loses HP equal to its stacks each turn, then it ticks down by one.
The after a card is played trigger also supports “In a Row” — fire only on every Nth consecutive matching play (playing a non-matching card resets the count). Combined with the card-type filter: “whenever you play two Attacks in a row”. Relics get the same pair of controls on their onCardPlay trigger, and their streak count resets at the start of each combat.
Stat manipulation, gold costs, and potions
Apply Status reaches every base-game status — search the dropdown for Vigor, Strength, Ritual, and the rest. Check “Reduce instead” to apply negative stacks: that's how you make an enemy lose Strength, exactly like the game's own debuff cards. Temporary this-turn-only versions exist as their own statuses (Coordinate for Strength, Anticipate for Dexterity, Dark Shackles for enemy Strength).
Cards that spend gold as a cost: add the Lose Gold effect next to the attack's damage. And “Obtain Random Potion” is the Alchemize effect — it rolls a random potion using the game's own generator (nothing happens if your potion slots are full).
Relics
For a Girya-style relic, enable Track charges (saved between combats) and set its starting charges. Choose a combat-start trigger and add Apply Status (Equal to X): select Strength, target Self, scale with This relic's charges, and set the multiplier to 1. Three charges give 3 Strength; five give 5. Use Add Charges to a Relic to change the counter. Expressions can read relicCharges, for example relicCharges * 2. This value is available only inside relic effects. Right-click effects read the remaining charges after their charge cost is paid.
Relic triggers include attack damage, HP lost from a card, mechanic threshold crossings, accumulated damage or Block, and alternating Attacks and Skills. Thresholds fire when stacks cross upward, including several thresholds crossed by one application. Damage/Block totals carry overflow within a combat and exclude the trigger's own effects to prevent loops.
Right click this relic (consumes charges) exposes initial charges and charge cost. It works during your combat turn. Charges survive saving; use Add Charges to a Relic to refill the selected relic. Cycle through effects runs one effect block per activation in order and loops; it resets after combat. A Power, Status, or Curse breaks Attack/Skill alternation.
On a card, Permanently Change This Card's Values changes values the card already applies and updates its permanent deck version. The change survives saving and loading. Non-X Energy cost is supported; a token without a deck copy only keeps changes while that token exists. Status changes use the chosen status's card value, rather than changing stacks currently on a creature.
A relic is a passive item: pick one trigger, attach effect blocks, and the effects fire every time the trigger happens. Relics can also carry Passive Effects — always-on stat changes with no trigger at all (extra draw every turn, cheaper cards, more gold from fights, and so on). Rarity (Starter, Common, Uncommon, Rare, Shop, Event) controls how the relic is found in a run. Your character begins every run with the Starter relic; if your configured starting relic is ever deleted, the first relic in your list is used instead.
Triggers
| Trigger | Fires |
|---|---|
onPickup | once, the moment the player obtains the relic. |
combatStart | at the start of every combat (the classic starter-relic trigger). |
combatEnd | when a combat is won. |
turnStart | at the start of each of your turns. |
turnEnd | at the end of each of your turns. |
onCardPlay | every time you play a card (powerful — keep the effect small). |
onDamageDealt | whenever you deal damage to an enemy. |
onDamageTaken | whenever you take damage. |
onBlock | whenever you gain Block. |
onHeal | whenever you heal. |
onRest | when you rest at a campfire. |
Events & Ancients
Chronicles → Epoch → Unlock requirement supports boss/elite encounter victories, completing an act or named area by defeating its boss, and winning at a minimum Ascension. Choose this character or any character. A multi-enemy boss fight counts once. Existing encounter statistics and available saved victory histories count; deleted histories cannot be recovered. Earning an Epoch makes it available to reveal on the Timeline, which unlocks its rewards.
To restrict an event to Underdocks instead of Overgrowth, open Can occur in / when, select Act 1, enable Only in named areas, and select Underdocks. Both filters must match. Leave the named-area restriction off to preserve ordinary act-number behavior.
In an event option, add Random potion, Random card, or Random relic. Choose custom content, base-game content, both, or selected candidates. A custom tag restricts the pool to your tagged items; base-game items do not carry creator tags. General card/relic rolls use ordinary reward rarities. Select candidates to include curses or special items. Potions open a reward screen, so a full belt can be managed or the reward skipped.
Add base-game card includes curses. Card grants offer Add upgraded. Upgrade cards can let the player choose or upgrade random eligible deck cards. Replace relic exchanges a custom relic only if the player owns it. Random enchantment rolls among enchantments compatible with at least one deck card, then chooses a compatible card; its amount is enchantment stacks.
For escalating fights, create follow-up pages, add a battle to each choice, and set that choice's After winning destination. Each fight can have a different destination. Rewards in a battle choice happen before combat; place victory rewards on the follow-up page.
For an Ancient, enable Replace Neow (Act 1) to offer it at the start of a run. Appearance chance (%) controls its forced appearance independently of the ordinary Ancient pool. A fixed run/act roll prevents repeated checks from rerolling. If multiple mods request a replacement, BaseLib takes its first successful candidate, so this percentage cannot guarantee precedence over another mod.
Under Events, select an event or Ancient. Beside Picture, choose Image fit: Fill screen crops the edges to cover the available area; Show entire image preserves every edge and may leave borders. Use a 2048 × 960 image and keep important details away from the edges when cropping.
Text size (%) adjusts description, dialogue, and option text from 60% to 120%. Long event descriptions and choices scroll; use the wheel or move focus to a lower choice. Smaller text can help, but is not required to reach the final option.
Custom Ancients also have Speaking portrait, a separate 256 × 256 upload for dialogue and run history. Transparent PNGs work well for a face or symbol. The large background stays unchanged. Remove the portrait to return to the background-image fallback.
If a random custom orb effect channels nothing, open Orbs and check Include in random orb rolls on at least one intended orb. Direct Channel Custom Orb effects do not need this checkbox. Checks warns when the random pool is empty.
Enemies & Battles
Open World → Enemies and add an enemy. Give it a name, HP, and a sprite or idle sheet. Optional attack, hit, and death sheets use the same frame/column controls as pets. Upload sounds for individual moves or death. The display height affects the sprite; the game places its health bar and intents.
In Move cycle, set damage per hit, number of hits, Block, healing, and mechanics. Moves execute damage, Block, healing, then mechanic applications. They run in listed order, skipping conditions that are false when choosing the next intent. Keep an Always move as a fallback. For example: Strike for 6 twice; Recover for 8 Block when HP is at or below 50%; repeat. A cycle completes when the move list wraps.
Starting mechanics applies your custom statuses to the enemy. Configure their passives and reactive behavior in Mechanics. Use holder/creature effects for enemies; player-only effects such as drawing cards still need a player recipient. On death, choose another enemy to summon before victory is checked. Circular death-summon chains are rejected.
Open World → Battles & bosses. Each roster row supplies a number of copies; each copy rolls from that row’s selected enemies or matching tag. Vanilla tags come from enemy-tag definitions; custom enemies have a comma-separated Tags field. Enter a higher wave number for enemies that arrive after the previous wave’s primary enemies die. Waves share the same combat, player resources, and final rewards. Use separate event fights if each stage should be a new combat.
Use a normal, early weak, elite, or boss battle type. HP overrides are final values for that row; leave them off to use each enemy’s native HP and multiplayer scaling. Extra mechanics apply only in this fight. Player mechanics apply at combat start. Bosses also need a 256 × 256 map icon.
Areas left unchecked make a battle event-only. Otherwise select its named areas, Ascension range, and character restriction. Pool inclusion chance rolls once consistently for the run and area: 25% means a 25% chance to enter that area’s encounter pool, not a 25% chance for every map node.
For selected rewards, choose this custom battle in an event option and set After winning to a reward page. Turn off the battle’s normal rewards if the page supplies everything. That page can offer another fight. The native encounter list offers complete original fights; use those when a vanilla enemy depends on companions or scene-specific setup.
Choose Use ordered effect sequence on a move to convert its existing effects. Add and reorder attacks, Block, healing, status application/removal, card creation, player draw/discard/Energy, and summons. Death effects use the same sequence editor. A status change before an attack gives that attack an unknown intent: arbitrary status hooks cannot safely be simulated for a damage preview. Put attacks first when you want a numerical intent.
For presentation, add Play custom visual (a PNG or a single horizontal row of frames), sound, Wait, screen shake, or radial blur. Visuals play once and remove themselves. Wait separates cues; it does not change a turn. Death effects finish before victory is evaluated. For a new event or a separate fight after combat, use an event’s victory page; changing rooms in the middle of death resolution is not supported.
Images
You can upload your own art anywhere the editor offers it. Uploads are automatically resized to the target dimensions, so close-enough source images are fine — but the aspect ratio should match or things get cropped.
| Asset | Size | Transparency | Where it shows up |
|---|---|---|---|
| Card art | 500 × 375 PNG/JPG | no | the picture in the top half of each card. |
| Relic icon | 256 × 256 PNG | supported | relic bar at the top of the screen, reward and shop screens. |
| Status (mechanic) icon | 256 × 256 PNG | supported | the buff/debuff icon row under a creature. |
| Character portrait | 256 × 256 PNG/JPG | no | character select screen and run UI — the default art for every character slot. |
| HUD icon (optional) | 88 × 88 PNG | supported | the small combat icon at the top-left; falls back to the portrait if not set. |
| Select screen art (optional) | 132 × 195 PNG/JPG | no | the tall character-select button image; falls back to the portrait if not set. |
| Energy counter layers (5) | 256 × 256 PNG | required | custom energy orb in combat, built from 5 stacked layers (2 and 3 rotate); all 5 or none. |
| Combat sprite | 512 × 512 PNG | required | your character standing in combat. |
| Pose images (5) | 512 × 512 PNG | required | idle / attack / cast / hit / dead poses, for the basic animation mode. |
| Spritesheets | 1–60 frames, up to 30 columns | required | full animation mode; one sheet per pose, played at 1–60 FPS. Columns describe the grid layout, not the total frame count. Large sheets may be resized on export. |
Shop & Rarity Rules
The Rare-card minimum
The in-game merchant stocks five cards from your pool, typed Attack / Attack / Skill / Skill / Power, and each slot can roll Rare. If a slot rolls Rare and your pool has no matching Rare card of that type, entering the shop crashes the run. A crash-proof pool therefore needs at least:
| Card type | Rare cards needed |
|---|---|
| Attack | 2 |
| Skill | 2 |
| Power | 1 |
The pre-flight check warns you when you're short, and the compiler auto-fills the gap with generic filler cards (Honed Edge, Reckless Cleave, Bulwark, Second Wind, Inner Fire) so your mod never bricks a run — but filler is boring. Replace it with your own Rare cards.
Ancient cards
Designing a Character
Everything below is measured from the 410 obtainable cards in the five shipped characters, not from a rule of thumb. The Balance tab grades against these same numbers.
Pool shape
The table below is for solo play (beta 0.111.0). Counts are identical across all five characters. The type splits are where they differ — that is where a character’s identity lives.
| Rarity | Cards | Attacks | Skills | Powers |
|---|---|---|---|---|
| Basic | 3–4 | 1–2 | 1–3 | 0 |
| Common | 20 | 9–13 | 7–11 | 0 |
| Uncommon | 35 | 8–14 | 12–18 | 7–10 |
| Rare | 25 | 4–9 | 7–12 | 8–9 |
| Ancient | 2 | 0–1 | 0–1 | 1 |
| Game version | Solo: uncommons / rares | Full pool: uncommons / rares |
|---|---|---|
| main 0.107.1 | 35 / 25 | 36 / 26 |
| beta 0.111.0 | 35 / 25 | 38 / 27 |
The full pool includes multiplayer cards; it is not the number available in a solo run. These counts are snapshots of the versions listed, not a requirement for your character.
What a card is worth
Measured from the main 0.107.1 reference set. Damage and Block per energy, median with the typical range. A 0-cost is charged as one energy.
| Cost | Damage / energy | Block / energy |
|---|---|---|
| 0 | 6 (3–17) | 7 (3–10) |
| 1 | 8 (4–10) | 6 (4–9) |
| 2 | 6.5 (2.5–9) | 5.5 (3–8) |
| 3 | 6 (5–10) | — |
Upgrades add about 3 damage or 3 block, which lands near a third more on a typical card.
The mix
- Cost curve — 18.3% free, 54.1% at 1, 18.8% at 2, 8.5% at 3. Far more 1-cost than people expect.
- Attacks — 36% of the pool. Skills outnumber attacks in most characters.
- Powers — 22.2% of the pool, all of them Uncommon or Rare.
- Card draw — 9% of cards draw. Every character has exactly one 1-cost draw-3.
- Hits all enemies — 16.3% of attacks. Enough to clear a room, not enough to ignore single targets.
What each rarity is for
- Common — No scaling of its own — it enables the rest. A small rider (draw 1, one stack of a debuff, an unusual cost) is the whole design. It has to feel playable with no support at all.
- Uncommon — Conditionals, scaling, or a real downside. The archetype starts to show, and card draw lives here. One X-cost card per character.
- Rare — The highest ramp or the biggest payoff — permanent buffs, complex effects, cards allowed past the usual damage band. Each character has one 3-cost Form power that can win a long fight alone.
- Ancient — the starter swap — Two Ancients per character, which is why the table shows one Power there. The first replaces a starting card (Orobas, Act 2). Aim for two to two and a half times the basic card, and fix a weakness the original had — Bash becomes Break, Neutralize becomes Suppress.
- Ancient — the Tome power — The second is the Dusty Tome power (Darv), and it arrives pre-upgraded, so design it as an upgraded card. Every shipped one but Regent’s pays for itself: Corruption makes skills exhaust, Wraith Form drops Dexterity, Biased Cognition drops Focus.
Translations
Open the editor's Translations tab and choose a target language. Under Mechanics, translate the name, general text, and separate combat tooltip. Keep {x} or {Amount} for the live stack count. Under Custom keywords, translate each keyword's name and tooltip. These are your mod's keywords; base-game keywords already use the game's language files. Blank translations keep the original text.
Export & Install
Three different downloads
- Export .json — your project file — a save you can back up, share, or re-import later. Not a mod. Your browser also auto-saves, but a .json export survives cleared browser data.
- Download C# Source — the generated code as one combined .cs file, for the curious or for compiling by hand. Most people don't need it.
- Compile & Download .zip — the real thing: sends your project to the compile service and returns a ready-to-install mod.
Pre-flight checks
Above the export buttons, the Export tab lists everything that would break or degrade your mod before any compiling happens: empty or non-English names, effects pointing at deleted statuses or token cards, a missing starting relic, and the Rare-card shop minimums. Red errors block compiling until fixed; gold warnings are handled automatically but worth reading.
Installing the mod
- Extract the downloaded
.zip— it contains two folders: your mod andBaseLib. - Copy both folders into your STS2 mods directory:Windows: Steam\steamapps\common\Slay the Spire 2\mods\Mac: ~/Library/Application Support/Steam/steamapps/common/Slay the Spire 2/mods/
- Launch STS2, open Mods in the main menu, enable both
BaseLiband your mod, then restart the game. - Your character appears on the character select screen.
BaseLib is required. It's the modding library your mod is built on; without it enabled, your mod won't load. If BaseLib is already installed from another mod, you can skip copying that folder.
If the compile fails
The Export tab translates compiler errors into plain language and names the card or relic responsible. The usual suspects:
| Error | What it means |
|---|---|
CS0101 | two items produce the same internal name — rename one of them. |
CS0246 | an effect references a custom status or token card that was deleted — re-link or remove the effect. |
CS1002 / CS1513 | a name or description contains characters that broke the generated code — usually quotes or unusual symbols. |
CS1503 / CS1061 | a bug in the mod creator itself; it is reported automatically — try removing the most recently added effect. |