Let’s create

02Case study / Games

Gacha Lab

An economy design tool that shows what a gacha banner's rules really do, to revenue and to the players who never pay.

Role
Economy design, interface, and build
Year
2026
Status
Live and public
Stack
JavaScript, Canvas, SVG, Cloudflare Pages
Scope
0 to 1: the model, the interface, and the live site

Open Gacha Lab (opens in a new tab)Read the code (opens in a new tab)

01

Introduction

Gacha Lab is an economy design tool that plays a gacha season out across up to a million pretend players.

New to gacha? A quick dictionary
Gachagah·chuhnoun
A game mechanic where players spend currency on random draws for characters or items, and the games built around it. The name comes from gachapon, Japan's capsule-toy machines.
Bannernoun
A limited-time event built around a featured legendary with boosted odds. Its rules set the odds, the pity, and the 50/50.
Seasonnoun
The days a simulation runs, 30 by default. Each day, the players who log in collect their free gems, buy if they pay, and pull.
Pullnoun, verb
One try on a banner, paid for with gems. Genshin Impact calls it a wish; Honkai: Star Rail, a warp.
Legendarynoun
The rarest prize, usually a 5-star character or item.
Pitynoun
The rule that raises the odds the longer a player goes without a legendary. Soft pity is where the odds start climbing; hard pity is where a legendary is certain.
The 50/50noun
The chance a legendary is the featured one rather than a different one, often 50%. With a guarantee, losing it makes the next legendary the featured one.
Whales + dolphinsnouns
The biggest spenders, a tiny share of players (0.2% in Gacha Lab), and the mid-size spenders who pay far less (1.1%).

The goal: show what a banner's rules really do, to revenue and to the players who never pay. You set the rules, the store, and the player mix, then watch the season play out. It's live, free, and open to anyone.

Most economy tuning happens in a spreadsheet, one number at a time. But a spreadsheet can't show you the trade. Make pity kinder and free players finally get their character, but the whales who were going to spend anyway spend less. I built Gacha Lab to put both halves of that trade on one screen.

Economy design
The model is mine, and so is everything built around it: the interface, the motion, and the published tool.
Public
Live and free, with no sign-in and no tracking beyond anonymous daily counts.
Sourced
Banner rates come from the games' own disclosures and large public pull datasets. The money comes from the only gacha publisher that has ever released per-player spending.
Published carefully
The model covers more banners than the site shows. I only publish games I know well enough to vouch for. The rest stay behind a flag until someone who plays them has checked them.
9
Real banners on the live site
Genshin Impact, Honkai: Star Rail, and Zenless Zone Zero, each with its character and weapon banner, plus Honkai Impact 3rd and both of League of Legends' Sanctum banners. Each has its own rules. The 3 HoYoverse games share HoYoverse's US store prices, as they do in the games.
1,000,000
Players a season
The biggest sample the tool offers. A season plays out in about 5 seconds.
6 of 6
Published figures matched
Spend per payer, spend per player, paying share, revenue concentration, and both band averages all land inside the bands set around the published figures. A test fails if any of them drifts out.
02

The Problem + Solution

How do you let someone change one rule and see, honestly, what it costs in money and in players?

Problem
Gacha rules are public. What they do isn't. The rates, the pity, and the 50/50 are all published. Players argue about whether a banner is generous. Designers argue about whether a change will cost revenue. Both sides are guessing, because the only people with the data are the ones who can't publish it.
Solution
A simulator, not a calculator. A calculator gives you the odds of one pull. A simulator gives you a season: 10,000 people with different budgets and appetites, logging in on different days, running out of gems at different moments, and the money that falls out of all of it.
The whole tool at a million players: the money across the top, and the field below packed with them
A million players on one screen. The money sits on top because it's what you're trading against. The players sit below because they're what you're trading.
03

Accuracy + Transparency

Clear about how sure it is

A tool like this is only worth using if you can trust it. So I documented exactly how sure it is of each part, and the tool itself says to treat its results as a starting point, not a forecast.

  1. Verified

    Every banner rule

    Checked against the exact math with a million legendaries per rule set. The pity curves, the 50/50, the guarantee, sparks, and free copies are right to the decimal.

  2. Fitted

    The money

    Tuned to 6 published per-player figures at once, with a test that fails if any of them drifts out of range.

  3. Not checkable

    A season's total revenue

    No publisher has released revenue for a single banner, so there's nothing to check it against. The tool lands each per-player figure inside its band, with the right shape across payers, and claims nothing beyond that.

Saying the third one out loud is worth more than a number that quietly overclaims.
The banner rules panel: base chance 0.6%, soft pity from pull 74, hard pity at pull 90 marked 'almost never reached (<0.01%)', featured chance 50%, the guarantee, and extra copies

Settings that explain themselves

On HoYoverse's character rules, soft pity nearly always lands the legendary before hard pity is ever reached. Moving hard pity to pull 85, 95, or 100 changes revenue by exactly 0.00%.

So instead of a setting that seems to do nothing, the tool tells you why: “almost never reached (<0.01%).” Bring it down into the climb, and the label shows how many legendaries it now settles.

The three outcomes as a proportional bar: got the featured legendary, got one but lost the 50/50, or got none

Outcomes in proportion

The 3 counts were hard to weigh against each other on their own, so I drew them in proportion, in the field's own colors, each with its share.

04

Key Decisions

Getting the money right

The banner math was verified early and never moved. The money was the hard part, because that's where public data runs out. I pushed the model the way designers and players would and traced each surprising result to its cause. 3 of the fixes that came out of it:

Decision 01

Making prices matter

<0.1%
Revenue moved when any of the 5 smaller packs doubled in price
+32.7%
Revenue when the $99.99 pack doubled
19 of 23
Presets unchanged by the fix, with calibration held to the cent

What testing showed

Testing across 20,000 players and 8 sets of dice showed that changing a pack's price barely moved revenue, except on the biggest pack.

The options

  1. Assume the prices weren't reaching the model. Measuring showed they were. (ruled out)
  2. Look at how buyers choose. They picked packs by how many gems a pack held, never by what it cost. (taken)

The fix

Buyers now spend as little money as they can for the gems they need: the cheapest pack that finishes the job, or else the best price per gem they can afford.

The cause

A whale needs more gems than any single pack holds, so the choice always fell through to “the most gems I can afford,” and price was ignored outright. In a unit test, it would buy a $500 pack for 8,080 gems over a $50 pack for 3,880.

The result

Real stores already make the biggest pack the best value, so calibration held to the cent. Where a store's ladder is out of order, the model now shops the way players do. In a banner I haven't published yet, Umamusume's $69.99 pack costs more than two $33.99 packs, so it skips it.

Decision 02

Measuring what a giveaway really costs

$80,930
Free gems priced at store rates
$180
Their real cost in revenue, measured at the time
450×
The overstatement the fix removed

What testing showed

The “free gems given away” tile read $80,930 beside $3,391 of revenue, and it never moved when the rules changed. It was pricing every free gem at store rates, counting currency handed to players who would never have bought any.

The options

  1. Price every free gem at what the store charges, as the tile did. (ruled out)
  2. Run the same season with nothing given away, same players and same dice, and take the difference. (taken)

The fix

The tile now reports what the giveaway costs in revenue, in dollars, averaged over several sets of dice.

The result

The tile now measures the giveaway instead of pricing it. At the time, the real cost was $180, not $80,930, and on Honkai Impact 3rd, $25, not $91,032.

The tradeoff

Measured on one season, the cost could land anywhere from $5 to $360. Averaging over several sets of dice narrowed that to $64 to $189, at the price of a figure that deliberately doesn't move when you re-roll the luck.

Decision 03

Reconciling 2 sources that seemed to disagree

86.6%
Revenue from the top tenth of payers in a cross-genre study
80.1%
From the top tenth in a publisher's filing
83%
From the top tenth in Gacha Lab, at a million players

The challenge

The money had to match what little spending data has been published, and 2 sources seemed to disagree about the biggest spenders. A publisher's filing put the top 0.2% of players at about $750 a month. A cross-genre study put whales at 86.6% of all revenue.

The options

  1. Pick one source as the anchor and fit the model to it. (ruled out)
  2. Put both on the same population first, then fit the model to every published figure at once. (taken)

The fix

The defaults are fitted against all 6 published per-player figures at once, and the money panel shows the one share that can be compared with research: the biggest tenth of payers.

The insight

On the same footing, the 2 sources agree. The study's whales are 0.20% of players in data where only 2.09% pay, which makes them the top tenth of payers, the same group as the filing's top 10.4% of payers. Both put that group at 80 to 87% of revenue.

The result

Every per-player figure now lands inside the band set around its published value, with a test that fails if any of them drifts.

The money panel at a million players: $4M of revenue, whales at 53%, dolphins at 37%, and the line reading 'the biggest tenth of payers brings 83% of revenue'
The line under the split is the one to compare with published data: the biggest tenth of payers brings 83% of revenue, inside the 80 to 87% that mobile studies report.
05

The Craft

Spending paced across the season

Players pace their spending across the season, funding roughly what's left divided by the days left. Free daily gems can stand in for a purchase. And because each day's share sizes the purchase, the whole price ladder sells.

  • Pack money spent on day 1

    Before100%AfterPaced across the season

  • Money through a single pack

    Before91%AfterSpread across the ladder

The gems and store panel: 300 free gems a day, 160 gems a pull, and the gem pack ladder with each pack's share of revenue: under 1%, 11% and 40% for the first three packs

Every pack shows its share

Each pack shows its share of the season's money, so the answer to “why didn't this price change move revenue?” is right there on screen, not left to be guessed at.

A million players as a thinned field, with a chip reading 'Each dot is 84 players'

Each dot is 84 players

One dot per player stops working fast. At 100,000 players, dots small enough to fit turn the field into gray mush, and at a million they'd be smaller than a pixel. So past about 12,000 players, the field draws one player in N, with the same stride for every type so the proportions hold. At a million, that's 1 in 84.

The label had to change with it. A label that silently stops being true is worse than a less ambitious one that is.

A single player's card: copies, money spent, pulls, days played, and where their gems came from

Every dot opens a player

Any dot opens the player behind it. The model is only trustworthy if you can pull one person out of it and check that their season made sense.

06

Learnings

Every surprising result had a real cause, and the model is more accurate for having chased them down. What I'd carry into any economy work:

  1. 01

    Put 2 sources on the same population before you let them disagree.

  2. 02

    Measure before changing anything. Twice, measuring first showed the real cause was somewhere else.

  3. 03

    Break the code to test the test. That's how I found that no test would have caught a change that silently zeroed a visitor's setting. Now one does.

  4. 04

    Re-measure the calibration every time the model changes. A stale figure in the docs is a quiet lie.