- TypeScript 63.8%
- Vue 28.6%
- CSS 6.4%
- HTML 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Full English README for the project: - brand logo, shields.io badges (Vue, TypeScript, Vite, Pinia, Tailwind, Vitest, license, save target) and a gameplay screenshot above the fold - feature overview of the Phase 1 vertical slice - tech stack table and getting-started guide with a script reference - project structure tree with per-directory intent - architecture notes: pure engine layer vs. Pinia stores, fully derived persisted state, acyclic store graph, ticks vs. away-time handling, versioned save envelope with sanitising imports - the core game math (geometric costs, thermal throttling, offline progress) and a pointer to the tuning constants - phased roadmap (operations/hyperscale) noting that the TechUpgrade schema and later-phase hardware already exist in the catalog - screenshot pair contrasting the overheated and cooled basement states |
||
| .vscode | ||
| docs | ||
| public | ||
| src | ||
| .gitignore | ||
| index.html | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
ServerFarm Architect
An idle tycoon game about building a basement rack into a hyperscale data center.
Start with one 42U rack, a modest grid hookup and an open window for cooling — buy servers, keep them powered and cooled, automate the chaos, and scale all the way to an IPO.
About
ServerFarm Architect is a browser-based incremental/idle game. You earn cash by fulfilling compute workloads; every dollar can be reinvested into more servers, better cooling, or beefier power infrastructure. The simulation is honest: nodes draw real watts, dump real heat, and go offline when the grid runs dry.
Phase 1 (this repository) is a playable vertical slice: one 42U rack, the full power → heat → cooling → throttle → income loop, buy-max economics, and a versioned save system with offline progress.
Features (Phase 1)
- Live 42U rack — servers slot in bottom-up with blinking status LEDs: 🟢 online · 🟡 heat-throttled · 🔴 unpowered. Multi-U chassis span their rows correctly.
- Coupled resource simulation — compute (TFLOPS) earns cash, but every node draws power (W) and dumps heat (Wt). Cooling hardware competes with compute for the same grid.
- Thermal throttling — saturate your cooling and revenue efficiency falls
to
max(0.2, cooling / heat)while the room temperature gauge climbs. - Geometric cost scaling — every purchase gets 15% pricier, with closed-form bulk pricing powering the ×1 / ×10 / Max buttons at O(1).
- Fixed-step tick engine — 10 simulation ticks per second on
requestAnimationFrame, decoupled from render rate; identical game speed on a 60 Hz and a 144 Hz monitor. - Offline progress — close the tab, come back tomorrow: away time is credited at 50% efficiency, capped at 24 h, and reported in a welcome-back dialog. Hidden-tab gaps are caught up automatically.
- Robust saves — versioned localStorage envelope, autosave every 10 s plus saves on purchase/tab-hide/unload, and sanitising imports that survive corrupt or partially invalid save data.
- Unit-tested math — the entire formula layer (cost scaling, efficiency, offline earnings, save round-trips) is covered by Vitest.
Tech stack
| Layer | Choice |
|---|---|
| Framework | Vue 3 — Composition API, <script setup> |
| Bundler / dev server | Vite 8 |
| Language | TypeScript 5.9 (strict, verbatimModuleSyntax) |
| State | Pinia 4 (setup stores, hand-rolled versioned persistence) |
| Styling | Tailwind CSS 4 (CSS-first @theme, dark cyberpunk design system) |
| Icons | lucide-vue-next |
| Tests | Vitest |
Getting started
# Prerequisites: Node.js 22+ (20.19+ works) and npm
npm install
npm run dev # → http://localhost:5173
| Script | What it does |
|---|---|
npm run dev |
Start the Vite dev server with HMR |
npm run build |
Type-check (vue-tsc) then bundle for production |
npm run preview |
Serve the production build locally |
npm run typecheck |
Run vue-tsc --noEmit only |
npm run test |
Run the unit test suite once |
npm run test:watch |
Run Vitest in watch mode |
The game autosaves to localStorage under the key
serverfarm-architect:save. The footer's Wipe save button (guarded by a
confirm dialog) resets to a fresh basement.
Project structure
src/
├── engine/ # Pure TypeScript — no Vue, no Pinia, fully unit-tested
│ ├── constants.ts # every tunable balance value in one commented table
│ ├── formulas.ts # cost scaling, thermal efficiency, offline earnings
│ ├── ticker.ts # fixed-timestep GameTicker on requestAnimationFrame
│ ├── save.ts # versioned save envelope + SaveManager
│ ├── format.ts # number/money/watts/duration formatting
│ └── *.test.ts # Vitest suites for the formula and save layers
├── types/
│ └── models.ts # Strict schemas: ServerNode, Rack, CoolingUnit,
│ # PowerSource, TechUpgrade, reports
├── data/
│ └── hardware.ts # Static hardware catalog (servers/cooling/power)
├── stores/ # Pinia
│ ├── datacenter.ts # infrastructure state + all derived metrics
│ └── economy.ts # money ledger (leaf store, dependency-acyclic)
├── composables/
│ └── useGameLoop.ts # Boot conductor: hydrate → offline audit → tick → save
├── components/
│ ├── MetricsDashboard.vue
│ ├── RackView.vue
│ ├── ShopPanel.vue
│ ├── OfflineProgressModal.vue
│ └── ui/CapacityBar.vue
├── App.vue
├── main.ts
└── style.css # Tailwind v4 theme + dark data-center design system
Architecture notes
- The engine is pure.
src/engine/imports nothing from Vue or Pinia. Every formula is a side-effect-free function, which makes the balance math trivially testable and portable (e.g. into a Web Worker later). - Stores derive everything. Only instance lists (racks, servers, cooling units, power sources) are persisted. Power allocation, heat load, slot occupancy, income — all are computed getters, so the save file can never contradict the simulation.
- Acyclic store graph.
economyis a leaf;datacenter → economyis the only cross-store edge. The game loop injects the income rate into the economy tick. - Ticks vs. away-time. The
GameTickersimulates fixed 100 ms steps while the page is visible. Frame gaps beyond 5 s (hidden tab, suspended laptop) are routed through the same offline calculator used at boot — no tick storms, no double simulation. - Saves are versioned.
SaveManagerwraps contributors in a{ version, savedAt, contributors }envelope; unknown versions are discarded with a warning, ready for future migrations. Store imports sanitise aggressively (unknown catalog ids, slot collisions, junk numbers).
The core math
Hardware cost (per stack, N = units already owned):
cost(next) = baseCost × growth^N (growth = 1.15 by default)
cost(count) = baseCost × growth^N × (growth^count − 1) / (growth − 1)
maxAffordable(N) = ⌊ log( budget × (growth − 1) / baseCost×growth^N + 1 ) / log growth ⌋
Thermal throttling (from the design spec):
efficiency = heat ≤ cooling ? 1 : max(0.2, cooling / heat)
income = Σ powered nodes' TFLOPS × $5/TFLOPS × efficiency
Offline progress (boot-time audit and hidden-tab catch-up):
credited = min(elapsed, 24 h)
earned = incomePerSec × credited × 0.5
All constants (tick rate, offline cap, baseline grid/cooling/bandwidth, market
rate, throttle floor, starting cash) live in
src/engine/constants.ts with commentary.
Roadmap
| Phase | Scope |
|---|---|
| 1 — Basement ✅ | Single 42U rack, power/heat/cooling loop, offline progress, saves |
| 2 — Operations | Tech tree & research points, sysadmin/NOC staff, random incidents (drive failure, DDoS, power spike) with manual → automated resolution, additional racks & halls, redundancy mechanics for UPS/generators, bandwidth as a real bottleneck |
| 3 — Hyperscale | Prestige "Data Center Relocation / IPO" trading infrastructure for permanent Venture Capital multipliers, GPU/immersion endgame hardware, longevity & wear |
The TechUpgrade schema and phase-2/3 hardware entries already exist in the
catalog and type layer — later phases plug into them.
Screenshots
| Overheated basement | Cooled & healthy |
|---|---|
![]() |
![]() |
License
MIT © 2026 Tronax

