After playing Balatro for several hours, most of the final scores you reach look something like "3.2e14". The odd part is that the player doesn't process that number as a huge figure, but as the feeling of "I'm winning big". That's strange. A game that shows scientific notation in its UI should feel unreadable, yet Balatro is one of the clearest scoring systems I've been able to play.
The obvious answer here is to think "the jokers are great". And that's true. But they have a problem: they don't explain anything. They don't help you understand where those huge scores come from. What actually holds up the whole system is a counterweight that balances the player's scoring capacity against each Ante's (blind's) requirements, which grow just as fast. The absolute number shown on screen never really measures anything; what matters is the relative number against the wall you need to clear, which moves along with the player.
1. The interface is the formula
Balatro does something almost no game with similar systems dares to do: it teaches the formula. It uses Chips × Mult (shown at the top of the screen), which updates every time a new card is played from your hand. There's no stats menu, no hidden panel to reveal them. The full calculation is always in plain sight.
This replaces an entire tutorial. You don't need to explain to the player what a "+4 Mult" joker does if they're already watching the number on the right jump from 8 to 12 in real time. The interface doesn't describe the system, it is the system. Any doubt about what a card does gets resolved by playing it once and watching which number changed.

Exposing the calculation on screen isn't an isolated UI decision. It's what lets the rest of the design (rare jokers, complex synergies, game-breaking builds...) stay legible without a single tutorial. If you need a tooltip to explain your calculations, the problem is probably the system.
2. Adding and multiplying aren't the same thing
Whether a joker adds to or multiplies Mult is Balatro's central distinction, and it's what separates a mediocre build from one that blows through the Ante.
A "+4 Mult" joker adds a constant. A joker that grants "×1.5 Mult" multiplies everything already calculated. The difference looks small, but the more jokers you stack, the more it starts to show.
| Jokers in play | Additive only (+4 Mult each) | Multiplicative only (×1.5 each) |
|---|---|---|
| 1 | Base Mult + 4 | Base Mult × 1.5 |
| 3 | Base Mult + 12 | Base Mult × 3.375 |
| 5 | Base Mult + 20 | Base Mult × 7.59 |
| 8 | Base Mult + 32 | Base Mult × 25.6 |
Each is the amount of Mult each joker contributes on its own: +4 in the additive case, ×1.5 in the multiplicative one.
With a base Mult of 4, eight additive jokers leave the value at 36. Eight multiplicative jokers, on the other hand, push that same value above 100. The additive curve is a straight line; the multiplicative one is an exponential. That asymmetry is why Balatro's "broken" builds don't depend on finding one special joker, but on finding enough multipliers in the right order. This is also what generates so much variety across runs and possible builds.
When designing a progression system, if the goal is for the player to feel like their build "breaks the game" at some point in the run, no special event needs to happen. It's enough for one part of the system to be additive and another multiplicative.
On top of that, letting the player discover for themselves when they cross the threshold where the second one starts to dominate is a genuinely satisfying moment (both for the developer who built it and the player who finds it).
What's interesting is that the base values of poker hands (before adding any joker value) only scale linearly. Leveling up a hand with a Planet card adds a fixed amount of chips and mult, always the same per level (for example, a Pair goes from 10 chips / 2 mult at level 1 to adding +15 chips / +1 mult per additional level). The game's base engine grows in a straight line. All of the system's exponentiality lives in the multiplicative jokers.

3. The counterweight: Ante
Score requirements per Ante don't grow linearly. Instead, they grow aggressively from the start and become super-exponential as soon as the player leaves the base content.
| Ante | Chips required (Small Blind, White Stake) |
|---|---|
| 1 | 300 |
| 2 | 800 |
| 3 | 2,000 |
| 4 | 5,000 |
| 5 | 11,000 |
| 6 | 20,000 |
| 7 | 35,000 |
| 8 | 50,000 |
Base Small Blind requirements on White Stake. The Big Blind multiplies this base by 1.5. Most Boss blinds multiply it by 2.
On top of that base, the Big Blind multiplies by 1.5 and most Boss blinds by 2 (with a few exceptions, like The Wall, which reaches ×4).
In Endless mode, the formula stops being a simple progression and starts depending on the ante number itself as an exponent. This produces what the community calls the "killscreen", around ante 39. The game doesn't break by accident; the run's requirements simply outgrow what any build can scale to.
This curve is what lets the jokers' multiplicative scaling avoid becoming a balance problem. It doesn't matter if the player pushes Mult to 4 digits before Ante 3, because that same ante won't demand 4 digits to clear. The design never compares power against a fixed number; it compares it against a number that grows with the player, so power is always relative to the current wall you're facing.

The trick isn't limiting how much the player can grow, but making sure whatever stands in their way grows just as fast. That way, the feeling of progress comes not from the finish line but from the race itself.
4. Evaluation order as a mechanic
Balatro makes a design decision most games would avoid for being awkward: it exposes evaluation order as a playable part of the system, not as a hidden implementation detail.
The sequence for how these values get evaluated is:
- Played cards resolve left to right. So which card gets played matters just as much as its value and multiplier. Each card contributes its base chips, then its modifiers (enhancement/seal/edition). After that, jokers fire (also left to right), reacting whenever a card scores.
- Retriggers, whether from jokers or red seals attached to cards, resolve right after that card's normal activation, repeating that card's entire sequence once more before moving to the next one.
- Once every played card has resolved, independent jokers kick in: those that don't depend on a specific card, like fixed
+Multor×Multjokers. Left-to-right order applies here too. - Finally, the cards left in hand activate, along with their own effects and whatever jokers trigger off them.
Left-to-right order holds throughout this entire interaction. So you always need to keep that order in mind when playing a hand. And that's why reordering the jokers on your board changes the final result even when you play the exact same cards.
A "+10 Mult" joker next to a "×2 Mult" one is the perfect example. In math, we always say the order of the factors changes the result. That's exactly this case. Adding 10 to a score of 2, getting 12, and then multiplying that by 2 gives 24. That's not the same as multiplying by 2 first, getting 4, and then adding 10 to reach 14. That small difference can determine whether the player hits the Ante's target or not.
Exposing evaluation order to the player is an awkward design decision because it literally reveals how the system is implemented under the hood. Most developers would be reluctant to show it, but in Balatro this becomes the gameplay mechanic itself. Managing joker order stops being cosmetic and becomes a fun strategic decision.
5. Designing for the player to break it
Balatro sets no visible design cap on score, only a technical one: the engine stores the score as a 64-bit double, which gives a theoretical limit around 1.7977 × 10³⁰⁸.
The game's community already found a bug from exceeding it, known as "NANEINF", literally the concatenation of "NaN" and "Infinity", the result of trying to compute the logarithm of infinity when formatting the number.
Some community builds combining Baron, Mime, and red-sealed Steel Kings have managed to reach scores on the order of 10^500,000, well past the point where the game starts showing scientific notation.
The most interesting part of this isn't the bug itself, but the design attitude behind it. Balatro doesn't defend against builds that break its own numeric system; it lets them through and turns them into the final goal of Endless mode. That score ceiling isn't a balance failure. Instead, it's the reward chased by the player who already finished the "normal game".
A system that allows overflow isn't automatically a badly designed one. It depends on whether it punishes the player or rewards them. The difference lies in whether the design accounted for that limit on purpose, or whether the developer just expected no one to reach it.
6. Implementing an ordered modifier pipeline
Implementing this system takes more than a simple chips × mult. You need an architecture that lets the order of a list of effects change the result in a way that's predictable for the player.
In C# you can build a scoring context that runs through an ordered list of modifiers, each with read and write access to the accumulated state:
1public class ScoreContext
2{
3 public double Chips { get; set; }
4 public double Mult { get; set; }
5
6 public double FinalScore => Chips * Mult;
7}
8
9public interface IScoreModifier
10{
11 void Apply(ScoreContext context);
12}
13
14public class AddMultModifier : IScoreModifier
15{
16 private readonly double _amount;
17
18 public AddMultModifier(double amount) => _amount = amount;
19
20 public void Apply(ScoreContext context)
21 {
22 context.Mult += _amount;
23 }
24}
25
26public class MultiplyMultModifier : IScoreModifier
27{
28 private readonly double _factor;
29
30 public MultiplyMultModifier(double factor) => _factor = factor;
31
32 public void Apply(ScoreContext context)
33 {
34 context.Mult *= _factor;
35 }
36}The pipeline is an ordered list of IScoreModifier, resolved in that same order sequentially. The order of that list mirrors the order on the board:
1public class ScoringPipeline
2{
3 private readonly List<IScoreModifier> _modifiers;
4
5 public ScoringPipeline(List<IScoreModifier> modifiers)
6 {
7 _modifiers = modifiers;
8 }
9
10 public ScoreContext Resolve(double baseChips, double baseMult)
11 {
12 var context = new ScoreContext { Chips = baseChips, Mult = baseMult };
13
14 foreach (var modifier in _modifiers)
15 {
16 modifier.Apply(context);
17 }
18
19 return context;
20 }
21}With this, [AddMultModifier(10), MultiplyMultModifier(2)] and [MultiplyMultModifier(2), AddMultModifier(10)] produce different results, as mentioned earlier. And the best part is you don't need to code any special logic; it's simply a direct consequence of the list's order carrying information.
The bug shows up when a buff or modifier system uses an unordered collection, like a HashSet or a dictionary iterated without a guaranteed order. If application order matters, that will cause problems. Better to follow Balatro's example and force that order to exist.
7. What to copy and what not to
Out of this whole system, there are three ideas I find worth keeping in mind:
- The additive/multiplicative split as an expressiveness tool. You don't need to invent new mechanics to create a sense of progression. It's enough to have two modifier categories with different growth curves, and let the player decide how much and when to invest in each.
- The counterweight. Explicit between the player's power and the demands of the system/level/challenge. A ceiling that scales with the player lets their growth stay sustainable indefinitely, or for as long as the developer wants it to.
- Exposing the calculation to the player. As long as the system allows it. Not every game can do this. Showing the core formula behind your system's calculations can be an advantage or a disadvantage. But when the system is the main mechanic, hiding it just adds friction to learning it.
Even so, it's worth stressing that relying on numeric-precision overflow as part of the design, without a deliberate decision behind it, is a game problem and an open door to bugs. And players will always have the patience to find it.
Screenshots: Balatro © LocalThunk / Playstack Ltd. Official images from Balatro's Steam page, used for analysis and commentary. Balatro is a registered trademark of LocalThunk LLC.


