Balancing Esports Idle Against Simulated Players
Every system in my esports idle game was in place by the morning after the first commit. Balancing its economy has taken the ten days since, mostly by letting simulated players run it for hours and reading where the money went.
Esports Idle is an incremental game in the Cookie Clicker mould. You click your team’s crest to build hype, sign players, send them through 16-match seasons across 12 parody games, and pay for all of it with businesses that earn every second: ranked grinders and streamers at first, then bootcamp houses, arenas and eventually things in orbit. When the org is big enough you sell it and start again with Legacy Points to spend.
I played a lot of Cookie Clicker, and I wanted to make an idle game of my own. I had two questions going in. Could an active loop, where you click and make decisions, sit alongside a passive one, where the org earns while you are away, without one making the other pointless? And could every screen share one visual style, rather than looking like a spreadsheet with pictures bolted on?
Every system existed by 09:07 on 15 September, about ten hours after the first commit. The 63 commits since have mostly gone on the first question. An idle game’s numbers tend to go wrong hours into a run, well past where a quick test reaches. So as well as friends and family, scripts play the game, and most of this article is what they found.

What the first night built
The first seven commits are named M0 to M6, and each added a whole layer. A tick engine with offline earnings and compressed saves. Generated players with six attributes and 32 traits, a match engine, and ten gear slots per player. Staff, illness, injury and a Gaming House that grows from a garage into an orbital HQ. Hype Drops, which are the game’s golden cookies, along with tournament brackets and 23 world events. A pixel-art studio for designing the crest and the merch, and 36 parody sponsors. Finally, selling the org, a 37-node Legacy Tree and challenge runs.
Each of those systems had numbers, and most of the numbers multiplied other numbers. The next milestone, on 18 September, was the first to check what they did together over a long run.
A trillion dollars in the first hour
M7 added scripts/sim.ts, a headless player that plays the real engine and logs when each milestone happens. It has profiles for the different ways people leave an idle game open. The active player decides every 20 seconds and catches every drop. The semi-active player looks every two minutes, the passive one every ten with the automation switched on, and a later casual profile checks in four times a day and closes the game in between.
The first runs reached a trillion dollars within an hour. Two exponents were compounding with nothing to stop them: fame, which scales income with the size of the fanbase, and match prizes, which were multiplied by operations income. M7 capped the fame exponent at 0.12 and cut prizes loose from operations. That cap comes up again below.
The simulation found a second problem that no single play session would. A second run after selling the org was no faster than the first, because a Legacy Point was worth 1% more income. Selling gave you nothing to look forward to, so the first reset now also grants Founding Points to pick one of four permanent charters, and every run offers three mandates that trade one advantage for a cost.
What people playing it found
Friends and family tested the game alongside the simulations. Version 0.1.0 is dated 19 September, and the fixes that followed it, many prompted by their feedback, were about things a simulation does not notice or mind:
- Music started on the first visit, so it is now off by default.
- The front-office automation spent money while you were browsing the market for yourself. It now pauses on the Market, Gear and Lineup screens.
- It was possible to lose the founding player, which left the save broken. A migration on start-up now rebuilds a missing founder.
- The first sale needed $10¹⁵ in lifetime earnings, which felt impossibly far away. It now needs $10¹², which was meant to bring it within a two to three hour session.
Other reports were closer to exploits. Hype Drops could spawn behind the top navigation bar and be missed without anyone seeing them. Sponsor goals paid a percentage of the org’s income at that moment, so a late-game org could finish a contract almost instantly and collect a huge payout. Drops are now kept inside the visible area, and after two revisions a finished goal pays 25% of what the org actually earned while the contract ran.
Merch ate the economy
On 22 September my testers reported that merch “goes insane” late in the game and that scrolling misbehaved on some pages. The next step was an audit rather than another tweak. scripts/audit.ts simulates 12 hours of play for each of three playstyles, three seeds each, selling the org whenever a Legacy Point is waiting.
Merch earned between 78% and 100% of every run’s income for every playstyle. For the active player at its peak, it was earning 100,000 to 480,000 times as much as operations, which are meant to be the main engine.
The cause was a loop. Merch Designers multiplied merch sales with no ceiling, and designers were paid for with merch income. In the audit’s late-game save the designer multiplier was ×3 with no designers, ×27 at 100, ×61 at 300 and ×154 at 1,000. More merch bought more designers, which sold more merch.
It damaged prestige as well. Legacy Points are the cube root of all-time earnings divided by 10¹², so a single runaway run outweighed everything before it. The active players’ fourth runs ended with 1.3 to 1.8 million points waiting to be claimed, against four to seven points earned in all their earlier sales combined. Selling early was never worth it.
The fix changed what merch is for rather than just shrinking it. Designers now keep designs fresh for longer and make trends last longer, with only a small sales boost, and each of their bonuses levels off at a ceiling. Matching the current trend doubles a line’s sales, and the Studio has a button that generates a design briefed to the trend. Set-and-forget merch should earn less than operations, and trend-chasing merch should earn more. That is the active and passive balance I set out to find, applied to one system. The same harness afterwards:
| Merch income ÷ operations income | Passive | Semi-active | Active |
|---|---|---|---|
| Peak, before the fix | 55–400× | 2,200–44,000× | 100,000–480,000× |
| Median, after the fix | 0.04–0.08× | 0.34–0.50× | 2.0–3.1× |
The two rows measure different things, peak against median, because the audit reported the runaway at its peak. Peaks still happen after the fix: an active player who stacks a Frenzy, a Merch Spotlight and a Mania reaches a few hundred times operations income for about a minute.
The audit also timed the interface. A save 12 hours in took 85 to 180 milliseconds to draw a frame, and about a quarter of that time went on one HQ card that tested every transfer-market player against the roster on every update. Caching it and a few other changes took the late-game frame time from 84 to 10 milliseconds on the HQ, 95 to 15 on Teams and 178 to 12 in the Studio. The likeliest cause of the scrolling complaints was simpler. The phone top bar needed 422 pixels, so on any narrower phone the page slid sideways and pushed the bottom navigation off the screen.
The cap that fixed the first bug
The most recent fix, on 24 September, started with a report that the fame cap was swallowing most of the Fame upgrade line. It was, and it was worse than the report said.
The base fame exponent plus the first three upgrades reached 0.115. The fourth upgrade delivered 0.005 of its advertised 0.015. The eight after it, costing between 2×10¹¹ and 2×10²⁵, added nothing at all, while their cards promised more fame power. Two Legacy nodes reached the cap on their own, so an org that owned them got nothing from any of the 12 cash upgrades.
The cap from the first balance pass was still stopping runaway growth. It was doing it by quietly eating purchases, and the existing test only checked that the cap held. Now the first four upgrades raise the exponent, and the cap is 0.13, exactly their total. The later eight multiply the fame bonus instead, which does not compound with the fanbase the way an exponent does.
The new test buys every upgrade in the store in cost order and fails if any purchase leaves the game’s modifiers unchanged. The same sweep turned up two more wasted bonuses: a sponsor perk that added offline efficiency when three Legacy nodes could already have taken it to its 100% cap, and two staff cards that promised morale above the maximum.
Two black screens
On 23 September a returning player saw only a black screen on the live site, while a fresh browser loaded the game normally. GitHub Pages serves the page with Cache-Control: max-age=600, so a browser can keep a copy for ten minutes. A copy cached before a deploy points at script files that no longer exist. The page now carries a small inline safety net that does not depend on the game’s own code. If nothing has drawn, it shows a card with a reload button that skips the cache, and buttons to copy or download the save.
That card reported the second failure. A save crashed on load with Svelte’s each_key_duplicate error, because the recent-results list identified each match by its game and time. Offline catch-up runs in coarse steps, so it can finish two matches for the same team in the same tick. The bug had been there since M2 and only appeared after a long enough absence.
One visual style
The second question was harder to measure. The first night’s interface was a neon dashboard in one fixed navy and cyan, and each gear slot showed the same placeholder icon at every tier. Over the following week, gear, players and upgrades moved onto one six-step rarity ladder. Each of the 160 pieces of gear got its own drawing, 10 slots across 16 tiers, and every operation building was redrawn on the same 48-pixel grid, with outlines, lit and shaded faces, and a layered scene behind it.
By 22 September that look, layered pixel art with light, shadow and depth, was consistent enough to audit against. The same audit that found the merch loop reviewed every screen and listed eight that fell short. The Hype Drop, which is the game’s golden cookie, was a flat gold circle with a lightning bolt and had less art than a mousepad. The trophy shelf was 131 near-identical tiny cups in rows. The next pass redrew both, along with the event cards, the Legacy Tree and the Welcome Back screen, and a later one gave all of the store’s upgrades a drawing in the same style.
Keeping track of rules that keep changing
The repository’s patch notes keep every superseded rule, struck through, with a count of how many times that system has changed. The count shows where the churn went:
| System | Times changed |
|---|---|
| Sponsorship board | 5 |
| News ticker | 5 |
| Merch store | 4 |
| Selling the org | 3 |
| Player illness and injury | 3 |
The file opens with instructions for the AI coding agents that work on the repository, and keeping those strikethroughs is one of the rules. It means the history of the sponsor board can be read in one paragraph rather than reconstructed from five commits, and the entry for the original fame cap now points at the fix that replaced it.
Current state
The game is live on GitHub Pages with 12 parody games, 16 operations, 36 sponsors, 160 pieces of gear and the 37-node Legacy Tree. Saves stay in the browser, and there are no accounts. The repository has 40 test files.
I’m happy with the game up to the first sale of the org, when the first Legacy Points arrive. After that point it is less settled. Taking merch out of the lead has a cost the audit measured: passive players now reach their first sale after about 5 hours 20 minutes, later than the three to five hour target, because merch no longer carries them.
The late game is also where I think the idle genre as a whole has the most to gain from more work. That is the part of Esports Idle I most want to keep working on, and I’m looking forward to it.