Docs
How Capo City is built, what the numbers actually are, and how to run your own copy. For the player-facing guide see How to play.
Overview
Capo City is a real-time isometric city rendered on a single HTML canvas. The whole game — renderer,
pathfinding, economy, UI — lives in one self-contained file, city.html, with no build step and
no runtime dependencies. It works offline and from a file:// URL.
- Grid: 48 × 48 tiles, 2:1 isometric projection (64 × 32 px tiles).
- Rendering: every static object is baked once into its own offscreen canvas and blitted;
the ground is a single pre-composited layer. A frame is a few dozen
drawImagecalls. - Pathfinding: 4-directional A* over the walkable mask, Manhattan heuristic.
- Depth: painter's algorithm sorted on
gx + gy, with entities merged into the same sorted list each frame. - Persistence:
localStorageunder the keycapocity.v1.
Economy reference
Every tunable number in one place.
| Constant | Value | Note |
|---|---|---|
| Starting CASH | 500 | Fresh save |
| Numbers route | 130 base · 6.5s · +4 heat | Pavement markers |
| Dock work | 190 base · 8.5s · +7 heat | Waterfront strip |
| Level bonus | +12% per level | Multiplies base pay |
| Payout variance | ×0.85 – ×1.25 | Uniform random |
| Daily cap | 25,000 CASH | Resets at local midnight |
| XP per job | 28 | Plus 6 $CAPO points |
| Heat decay | 0.22 / second | ≈13 per minute |
| Safehouse cooling | 7 / second | Plus loyalty top-up |
| Detectives spawn | heat ≥ 70 | Payouts halved at the same threshold |
| Detectives leave | heat < 35 | |
| Shakedown | 10% of CASH, max 600 | Resets heat to 38 |
| Need drain | 0.055 / second | All five needs, ≈30 min from full to empty |
| Station refill | 9 / second | While standing in the block |
| Level curve | 0, 300, 800, 1600, 2800, 4600, 7200, 11000, 16500, 24000, 34000 | XP thresholds |
City generation
The city is deterministic: the turf name is hashed (FNV-1a) into a seed for a mulberry32 PRNG, so the same turf always produces the same city on every device.
- Roads run every 6 tiles on both axes, giving an 8 × 8 grid of blocks.
- Each block is 5 × 5 inside the roads: a walkable pavement ring around a 3 × 3 buildable core.
- Building cores are filled from six footprint templates, heights 3–12 storeys, taller toward the centre.
- Tiles 18–29 on both axes are cleared for Vault Plaza; the 4 × 4 vault sits at its centre.
- Ten blocks in the ring around the plaza are reserved for boss towers, 14–32 storeys by rank.
- Rows 43+ are water, 41–42 are the dock strip, and one block is Lantern Park.
Seasons and the pot
A season runs 7 days from launch. The pot splits across the top ten by
rank weight (11 − rank)^1.45, normalised — so rank 1 takes roughly a quarter of the pot and
rank 10 takes a few percent.
Until a live trading-leaderboard feed is wired up, the board and pot are simulated from the turf seed. The sidebar shows a DEMO SEASON badge whenever that is the case, and the city never presents simulated figures as live data.
Token
| Field | Value |
|---|---|
| Ticker | $CAPO |
| Chain | Solana |
| Venue | pump.fun — standard bonding curve |
| Launch | 12 August, 5:00 PM UTC |
| Presale | None |
| Team allocation | None |
| Contract | SOON |
There is exactly one contract address and it does not exist before 12 August, 5:00 PM UTC. It will appear on this site and in the pinned post on X at the same moment. Any address circulating before then is a scam.
Architecture
frontend/ static, deploy anywhere
index.html landing page
how-to-play.html player guide
docs.html this page
city.html the game (self-contained, no build)
js/config.js single source of truth: name, launch, CA, API URL
js/site.js nav, countdown, CA copy
js/api.js backend client — no-ops when API_URL is empty
css/site.css shared site styles
assets/ wordmark, badge, banner, OG, favicons
backend/ optional — the city runs fully without it
src/server.js Express + WebSocket, server-authoritative payouts
supabase/schema.sql tables, indexes and row level security
Dockerfile Railway deploy target
The frontend degrades cleanly. With API_URL empty the city is single-player: local save,
simulated leaderboard, local wire. Set API_URL and the same build switches on live chat,
presence, a shared leaderboard and server-checked payouts — no code changes.
Backend setup
1. Supabase
Create a project, open the SQL editor and run backend/supabase/schema.sql. It creates the
tables, indexes and row level security policies. Copy the project URL, the anon key and the service role key.
2. Railway
Point Railway at backend/. It builds from the Dockerfile. Set these variables:
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_KEY=eyJ... # service role — server only, never ship to the browser
ALLOWED_ORIGINS=https://capocity.fun,https://www.capocity.fun
PORT=8080
The service role key bypasses row level security. It belongs only in Railway's environment. The browser gets the anon key, and only if you use Supabase directly from the client.
3. Point the frontend at it
Set API_URL in frontend/js/config.js to your Railway URL and redeploy the
frontend. That is the whole switch-over.
API reference
| Method | Path | Does |
|---|---|---|
| GET | /health | Liveness probe. |
| POST | /api/session | Creates or resumes a player by client id, returns their state. |
| GET | /api/leaderboard?turf= | Top ten for a turf, with pot and cuts. |
| POST | /api/job/start | Opens a server-side job window. Returns a job id. |
| POST | /api/job/claim | Claims a finished job. The server checks elapsed time, the daily cap and heat before paying. |
| POST | /api/market/buy | Buys an item. Checks balance and remaining supply in one transaction. |
| GET | /api/chat?turf= | Last 50 messages on a turf. |
| WS | /ws?turf= | Live chat, presence and player positions for a turf. |
Payouts are never trusted from the client. /api/job/start records a server timestamp and
/api/job/claim refuses anything that comes back faster than the job's real duration, or that
would push the player past the daily cap.
Run it yourself
# frontend — any static server
cd frontend
python3 -m http.server 4173
# backend — optional
cd backend
cp .env.example .env # fill in your Supabase keys
npm install
npm run dev
The frontend has no build step, so whatever is in frontend/ is exactly what ships. Deploy it to
Vercel, Netlify, Cloudflare Pages, GitHub Pages or an S3 bucket — set the output directory to
frontend and there is nothing else to configure.
Launch checklist
- Frontend deployed to
capocity.fun, DNS pointed, HTTPS live. - Open Graph images resolving — check with the X card validator before the day.
- X and Telegram bios pointing at
capocity.fun. - Mint on pump.fun at 5:00 PM UTC on 12 August.
- Paste the address into
CAinjs/config.jsand upload that one file. Every page loads it with a timestamp, so it is picked up immediately — no cache purge needed. - Pin the CA post on X. Confirm the site and the pinned post match, character for character.
Disclaimers
Capo City is a browser game and a memecoin. It is not an investment product, it is not a security, and nothing on this site is financial advice.
In-game CASH, XP and $CAPO points exist only inside the game. They have no monetary value, they are not tradeable, and they are not redeemable for the token or anything else.
Leaderboard figures, PnL and pot values shown while the DEMO SEASON badge is visible are simulated and do not describe any real trader or any real money.
Crypto assets are volatile and you can lose everything you put in. Only ever risk what you are happy to lose, and always verify the contract address against the pinned post on X before you buy.