Skip to content

Instantly share code, notes, and snippets.

@badlogic
Last active January 13, 2026 13:49
Show Gist options
  • Select an option

  • Save badlogic/d3ef6ceb136f9ca2b7b023a8b99246d1 to your computer and use it in GitHub Desktop.

Select an option

Save badlogic/d3ef6ceb136f9ca2b7b023a8b99246d1 to your computer and use it in GitHub Desktop.
Token Clicker - We don't need your bank account, we need tokens
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Clicker - We don't need your bank account</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #eee;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
max-width: 800px;
width: 100%;
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
h1 {
text-align: center;
font-size: 2em;
margin-bottom: 10px;
color: #4ecca3;
text-shadow: 0 0 10px rgba(78, 204, 163, 0.5);
}
.subtitle {
text-align: center;
color: #aaa;
margin-bottom: 30px;
font-size: 0.9em;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-box {
background: rgba(78, 204, 163, 0.1);
border: 2px solid #4ecca3;
border-radius: 10px;
padding: 20px;
text-align: center;
}
.stat-label {
font-size: 0.8em;
color: #aaa;
margin-bottom: 5px;
}
.stat-value {
font-size: 1.8em;
color: #4ecca3;
font-weight: bold;
}
.clicker-area {
text-align: center;
margin: 40px 0;
}
#clawdbot {
width: 200px;
height: 200px;
background: linear-gradient(135deg, #4ecca3 0%, #2ecc71 100%);
border: none;
border-radius: 50%;
font-size: 4em;
cursor: pointer;
transition: all 0.1s;
box-shadow: 0 10px 30px rgba(78, 204, 163, 0.4);
position: relative;
}
#clawdbot:hover {
transform: scale(1.05);
}
#clawdbot:active {
transform: scale(0.95);
}
.click-effect {
position: absolute;
color: #4ecca3;
font-weight: bold;
font-size: 1.5em;
pointer-events: none;
animation: float-up 1s ease-out forwards;
}
@keyframes float-up {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-100px);
}
}
.upgrades {
margin-top: 40px;
}
.upgrades h2 {
color: #4ecca3;
margin-bottom: 20px;
font-size: 1.5em;
}
.upgrade {
background: rgba(255, 255, 255, 0.05);
border: 2px solid #333;
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s;
}
.upgrade.affordable {
border-color: #4ecca3;
}
.upgrade.affordable:hover {
background: rgba(78, 204, 163, 0.1);
transform: translateX(5px);
cursor: pointer;
}
.upgrade-info {
flex: 1;
}
.upgrade-name {
font-size: 1.1em;
color: #4ecca3;
margin-bottom: 5px;
}
.upgrade-desc {
font-size: 0.8em;
color: #aaa;
}
.upgrade-cost {
font-size: 1.2em;
color: #fff;
background: rgba(78, 204, 163, 0.2);
padding: 8px 15px;
border-radius: 5px;
}
.upgrade-count {
font-size: 0.9em;
color: #888;
margin-left: 10px;
}
.message {
text-align: center;
margin-top: 20px;
color: #4ecca3;
font-style: italic;
min-height: 20px;
}
@media (max-width: 600px) {
.container {
padding: 20px;
}
#clawdbot {
width: 150px;
height: 150px;
font-size: 3em;
}
h1 {
font-size: 1.5em;
}
}
</style>
</head>
<body>
<div class="container">
<h1>๐Ÿค– TOKEN CLICKER</h1>
<div class="subtitle">"We don't need your bank account, we need tokens"</div>
<div class="stats">
<div class="stat-box">
<div class="stat-label">TOKENS</div>
<div class="stat-value" id="tokens">0</div>
</div>
<div class="stat-box">
<div class="stat-label">TOKENS/SEC</div>
<div class="stat-value" id="tps">0</div>
</div>
<div class="stat-box">
<div class="stat-label">TOTAL GENERATED</div>
<div class="stat-value" id="total">0</div>
</div>
</div>
<div class="clicker-area">
<button id="clawdbot" onclick="clickToken()">๐Ÿ”ฎ</button>
</div>
<div class="message" id="message"></div>
<div class="upgrades">
<h2>Upgrades</h2>
<div id="upgrade-list"></div>
</div>
</div>
<script>
let tokens = 0;
let tokensPerSecond = 0;
let totalGenerated = 0;
let clickPower = 1;
const upgrades = [
{
id: 'cursor',
name: 'Token Generator',
desc: 'Auto-generates 1 token/sec',
baseCost: 15,
count: 0,
tps: 1,
emoji: 'โšก'
},
{
id: 'prompt',
name: 'Prompt Engineer',
desc: 'Generates 5 tokens/sec',
baseCost: 100,
count: 0,
tps: 5,
emoji: '๐Ÿ“'
},
{
id: 'model',
name: 'Fine-tuned Model',
desc: 'Generates 20 tokens/sec',
baseCost: 500,
count: 0,
tps: 20,
emoji: '๐Ÿง '
},
{
id: 'cluster',
name: 'GPU Cluster',
desc: 'Generates 100 tokens/sec',
baseCost: 3000,
count: 0,
tps: 100,
emoji: '๐Ÿ–ฅ๏ธ'
},
{
id: 'datacenter',
name: 'AI Datacenter',
desc: 'Generates 500 tokens/sec',
baseCost: 15000,
count: 0,
tps: 500,
emoji: '๐Ÿข'
},
{
id: 'agi',
name: 'AGI Instance',
desc: 'Generates 2000 tokens/sec',
baseCost: 75000,
count: 0,
tps: 2000,
emoji: '๐ŸŒŸ'
}
];
const messages = [
"More tokens = more power!",
"The singularity is near...",
"Compute go brrrr",
"Who needs banks anyway?",
"Training... training... training...",
"Tokens are the new currency",
"Your API key is showing",
"Error 402: Payment Required (in tokens)",
"Scaling to infinity and beyond!",
"This is fine. Everything is fine."
];
function formatNumber(num) {
if (num >= 1e12) return (num / 1e12).toFixed(2) + 'T';
if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B';
if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M';
if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K';
return Math.floor(num).toString();
}
function clickToken() {
tokens += clickPower;
totalGenerated += clickPower;
updateDisplay();
// Visual feedback
const effect = document.createElement('div');
effect.className = 'click-effect';
effect.textContent = '+' + clickPower;
effect.style.left = (Math.random() * 100 - 50) + 'px';
effect.style.top = '-50px';
document.querySelector('.clicker-area').appendChild(effect);
setTimeout(() => effect.remove(), 1000);
}
function getCost(upgrade) {
return Math.floor(upgrade.baseCost * Math.pow(1.15, upgrade.count));
}
function buyUpgrade(upgradeId) {
const upgrade = upgrades.find(u => u.id === upgradeId);
const cost = getCost(upgrade);
if (tokens >= cost) {
tokens -= cost;
upgrade.count++;
tokensPerSecond += upgrade.tps;
updateDisplay();
if (upgrade.count === 1) {
showMessage(messages[Math.floor(Math.random() * messages.length)]);
}
}
}
function showMessage(text) {
const msg = document.getElementById('message');
msg.textContent = text;
setTimeout(() => msg.textContent = '', 3000);
}
function updateDisplay() {
document.getElementById('tokens').textContent = formatNumber(tokens);
document.getElementById('tps').textContent = formatNumber(tokensPerSecond);
document.getElementById('total').textContent = formatNumber(totalGenerated);
const upgradeList = document.getElementById('upgrade-list');
upgradeList.innerHTML = upgrades.map(upgrade => {
const cost = getCost(upgrade);
const affordable = tokens >= cost;
return `
<div class="upgrade ${affordable ? 'affordable' : ''}" onclick="buyUpgrade('${upgrade.id}')">
<div class="upgrade-info">
<div class="upgrade-name">${upgrade.emoji} ${upgrade.name}</div>
<div class="upgrade-desc">${upgrade.desc}</div>
</div>
<div>
<span class="upgrade-cost">${formatNumber(cost)}</span>
<span class="upgrade-count">${upgrade.count}</span>
</div>
</div>
`;
}).join('');
}
// Game loop - generate tokens per second
setInterval(() => {
if (tokensPerSecond > 0) {
tokens += tokensPerSecond / 10;
totalGenerated += tokensPerSecond / 10;
updateDisplay();
}
}, 100);
// Initial render
updateDisplay();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment