What is an Idle Game?
- Define the core loop of an idle game
- Recognize idle game patterns in popular titles
- Plan the entities for your first idle game
Definition
An idle game (also called clicker or incremental game) is a game where the player performs a simple action โ usually clicking โ to accumulate a resource, then spends that resource on upgrades that produce more resource over time, often automatically.
Examples
- Cookie Clicker (2013) โ the genre-defining game. Click cookie, buy grandmas, grandmas bake cookies.
- AdVenture Capitalist โ money instead of cookies, businesses instead of grandmas.
- Universal Paperclips โ start clicking to make paperclips, end up consuming the universe.
Why idle games are perfect first projects
- The core loop is tiny โ under 50 lines of code
- No physics, no animation, no asset generation needed
- All the interesting design is in the numbers (rates, costs, multipliers)
- You can ship a complete game in 30 minutes
Plan your entities
For our cookie clicker, we need:
- Score โ number of cookies the player owns
- Cookie button โ when clicked, adds 1 to score
- Upgrades โ items the player buys with cookies that auto-generate more cookies
- Game loop โ runs ~10 times per second, adds auto-generated cookies to score
The Clicker Loop
- Build a single-file HTML game with score tracking
- Use
setIntervalfor a tick-based game loop - Update the UI on every state change
The minimum viable clicker (12 lines)
<h1>๐ช <span id="score">0</span></h1>
<button id="btn">Click me</button>
<script>
let score = 0;
const scoreEl = document.getElementById('score');
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
score++;
scoreEl.textContent = score;
});
</script>
This is a complete working clicker. Save it as index.html and open it in any browser. Click the button โ the number goes up.
The game loop
To add auto-generation, run a function repeatedly using setInterval:
let cookiesPerSecond = 0;
setInterval(() => {
score += cookiesPerSecond / 10; // divide by 10 since we tick 10x/sec
render();
}, 100); // every 100ms = 10 ticks per second
Why 10 ticks per second instead of 1? Smoother number animation. The player sees the score climbing continuously instead of jumping by integers.
Rendering pattern: render-from-state
Don't update the UI in 12 different places. Have one function that reads the current state and updates the UI:
function render() {
document.getElementById('score').textContent = Math.floor(score);
document.getElementById('per-sec').textContent = cookiesPerSecond.toFixed(1);
// ... update all other UI elements
}
Then call render() after any state change. The UI never gets out of sync with the data.
Upgrades & Exponential Cost Scaling
- Implement purchasable upgrades that affect the game loop
- Apply exponential cost scaling for balanced progression
- Understand why idle games feel addictive (it's the math)
Defining upgrades as data
const upgrades = [
{ name: 'Auto-clicker', baseCost: 15, perSec: 0.1 },
{ name: 'Grandma', baseCost: 100, perSec: 1 },
{ name: 'Factory', baseCost: 500, perSec: 8 },
{ name: 'Bank', baseCost: 5000, perSec: 47 },
];
let owned = upgrades.map(() => 0);
Exponential cost scaling
The classic idle-game formula: each upgrade purchased increases the next purchase cost by 15%:
function costFor(upgradeIndex) {
const u = upgrades[upgradeIndex];
return Math.floor(u.baseCost * Math.pow(1.15, owned[upgradeIndex]));
}
Why 1.15? Empirically tuned to keep the player buying every ~30 seconds. Larger ratios (1.5, 2.0) feel grindy. Smaller (1.05) lets the player snowball too fast.
| Owned count | Cost (base 100, ratio 1.15) |
|---|---|
| 0 | 100 |
| 5 | 201 |
| 10 | 405 |
| 20 | 1,637 |
| 50 | 108,366 |
Computing total cookies-per-second
function perSec() {
return upgrades.reduce((sum, u, i) => sum + u.perSec * owned[i], 0);
}
Buy logic
function buy(upgradeIndex) {
const cost = costFor(upgradeIndex);
if (score >= cost) {
score -= cost;
owned[upgradeIndex]++;
render();
}
}
The addiction loop
Why do idle games hook players? The math: every upgrade purchase increases per-second income, which means the next upgrade is reachable faster, which gives a dopamine hit, which makes the next upgrade reachable even faster. The exponential cost prevents this from breaking โ it always feels like you're almost there.
Polish & Save Progress
- Add visual feedback to clicks (floating "+1" popups)
- Save and load game state with localStorage
- Calculate offline progress (cookies earned while away)
- Identify next-level features to add
Click feedback popups
btn.addEventListener('click', (e) => {
score += 1;
const popup = document.createElement('div');
popup.className = 'popup';
popup.textContent = '+1';
popup.style.left = e.clientX + 'px';
popup.style.top = e.clientY + 'px';
document.body.appendChild(popup);
setTimeout(() => popup.remove(), 1000);
render();
});
The popup is styled with CSS to float upward and fade out:
.popup {
position: fixed;
pointer-events: none;
font-size: 24px;
font-weight: 900;
color: #de6262;
animation: float 1s ease-out forwards;
}
@keyframes float {
to { transform: translateY(-80px); opacity: 0; }
}
Saving game state
function save() {
localStorage.setItem('clicker_save', JSON.stringify({
score: score,
owned: owned,
savedAt: Date.now()
}));
}
function load() {
const data = JSON.parse(localStorage.getItem('clicker_save') || 'null');
if (data) {
score = data.score;
owned = data.owned;
return data.savedAt;
}
return null;
}
// Auto-save every 5 seconds
setInterval(save, 5000);
// Load on page open
window.addEventListener('DOMContentLoaded', () => {
load();
render();
});
Offline progress
Calculate how many cookies the player would have earned while away:
const savedAt = load();
if (savedAt) {
const secondsAway = (Date.now() - savedAt) / 1000;
const earned = Math.floor(perSec() * secondsAway);
if (earned > 0) {
score += earned;
alert(`Welcome back! You earned ${earned} cookies while away.`);
}
}
Features to add next
- Achievements โ "First grandma!", "100 clicks!", "1 million cookies!"
- Click multipliers โ temporary boosts (golden cookies that randomly appear)
- Prestige system โ reset for a permanent multiplier (extends gameplay infinitely)
- Sound effects โ soft click on cookie press
- Visual upgrades โ the cookie gets bigger or fancier as you progress
๐ Course complete
Ready for a bigger project? Try the Monster Truck Game course next.
Next: Monster Truck Game โ Browse all courses