Project Plateau
Project Plateau: four glass plates, one living valley, and the road back to camp.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗BitLife for crypto degenerates. A browser life simulator where you discover memecoins on TikTok, buy shitcoins, get rugged, work at McDonald's, come back, and maybe become a legend.
npm install
npm run dev # http://localhost:3000 (landing), /play (the game)
npm test # engine tests + balance simulation (~2 min)
npm run build
Saves live in the browser (localStorage). Every life has a run seed (RUN #123456); entering the same seed in the character creator reproduces the same starting stats, money and world.
You live the whole life through your phone:
The phone UI lives in components/game/phone/; shared pieces (order ticket, charts, pop-ups, hotkeys) are in components/game/.
Everything runs client-side. The game engine is plain TypeScript in lib/game/ with no React:
| File | What it does |
|---|---|
config.ts | Every balance number: salary, expenses, coin fate odds, status thresholds, pacing, death curve. JOB.name renames the one job everywhere. |
coins.ts / market.ts | Procedural memecoins with hidden price paths, monthly market ticks, pump/crash/rug signals |
portfolio.ts | Buying, selling, liquidity caps, rugs, run stats |
life.ts | The monthly loop: salary, expenses, market, broke detection, death, retirement |
events/engine.ts | The generic event engine: requirements, weighting, outcomes, effects, templating |
events/data/*.ts | All event content (120+ events) |
reducer.ts | UI actions → engine calls. State is cloned per action; RNG state lives in the save, so runs are deterministic |
The UI is in components/game/.
Append an EventDef to any file in lib/game/events/data/. The engine never needs to change.
{
id: "life_lost_wallet",
category: "life", // crypto | trade | kol | life | mcd | social | legendary
weight: 6, // relative frequency
cooldown: 24, // months before it can repeat
req: { minCash: 200, maxStatus: "degen" },
emoji: "👛",
title: "LOST WALLET",
setup: [{ type: "spawnCoin", fate: "luck" }], // binds {coin}
text: "You find a wallet on the bus. There's a sticker for {coin} on it.",
choices: [
{ text: "Return it", outcomes: [{ text: "Good karma.", effects: [{ type: "stat", stat: "luck", delta: 3 }] }] },
{
text: "Ape the sticker coin",
req: { minCash: 20 },
outcomes: [
{ weight: 2, mods: { luck: 0.6 }, text: "{coin} {moved}!", effects: [{ type: "buy", size: "small" }, { type: "coinMove", mult: [2, 5] }] },
{ weight: 3, text: "It rugs. Karma.", effects: [{ type: "buy", size: "small" }, { type: "coinMove", mult: 0 }] },
],
},
],
}
req): age, cash, net worth, portfolio, status, stats, followers, employment, flags, previously seen events, rugs, wins, times broke, held positions, a recent big loss.cash, stat, followers, reputation, spawnCoin, pickKol, pickHeld, pickMarket, buy, sell, sellAll, wipePositions, coinMove, marketMove, research, flag, queue (event chains), job, history, runStat, kolIntel.{name}, {job}, {salary}, {cash}, {nw}, {coin}, {mc}, {kol}, {kolRead}, {amount}, {value}, {proceeds}, {pnl}, {moved}, {pct}, {multiple}, and so on.signal: "pump" | "bigpump" | "megapump" | "crash" | "rug" | "paperhand" | "diamond") fire when the market does that to a coin you hold.npm test validates all content: unique ids, every queued follow-up exists, and every template variable resolves.