Own a market.
Get paid on every trade.
Anime Money is a market game you play from a phone inside an anime Tokyo. The app on that phone, CoinMangaCap, lists 500 markets, every market has exactly one owner, and the owner earns a fixed share of every buy and sell that other players make there. These docs cover the rules, the math and the small library that runs all of it.
Your first ten minutes in the room, and your first quote from code.
RulesTiersSix colours, six owner rates, and what each rank costs to own.
LiveTry itPick a rank and an amount and watch the real functions answer.
BuildLibrary APIEvery export of animemoney.js with a signature and an example.
What you do here#
- Own a market. There are 500 ownership rights, one per coin rank, and each can belong to exactly one player at a time. We sell them from 250 to 50,000 USDC depending on how high the coin sits.
- Open it. An owned market is a closed shop until its owner pays the launch fee. Once it opens, anyone can trade it, and it starts life at a 210,000 USDC market cap.
- Trade, collect, grow. Every buy and sell that somebody else makes on your market pays you the owner rate of your tier. You can also trade any open market yourself, including your own.
- Resell. A market with real volume is worth more than you paid for it. List it, or wait for an offer letter, and keep 90% of the sale.
The cast#
| Piece | What it is | Where it lives |
|---|---|---|
| CoinMangaCap | The market app. 500 rows, one per coin, each with its tier colour, price, owner and volume. | On the phone and the laptop |
| Ownership | The one right per market to collect the owner fee. It can be bought, opened, listed and sold. | On the market page |
| Play USDC | The money of the game. Everybody starts with 20,000 and nobody can top up. | In your browser |
| The other 36 | Simulated players who buy ownerships, open markets, trade and write you letters. | World simulation |
| $ABUCKS | The real token of the project, pinned as the first row of the market list. | Solana |
How markets are named#
Every coin of the top 500 gets a "-chan" at the end of its name and an "a" in front of its symbol. Bitcoin becomes Bitcoin-chan with the symbol aBTC, and Solana becomes Solana-chan with aSOL. The rank you see in CoinMangaCap is the rank of the original coin, and that rank alone decides the tier, the owner rate and the price of the ownership.
Quick start#
Two ways in. Play the first ten minutes, or quote a trade from code.
Your first ten minutes#
- Open the game. Press Play and you are in the Midnight room with a phone in your hand and 20,000 play USDC on the balance. Nothing to install and nothing to connect.
- Open CoinMangaCap. It is the market app on the phone. Scroll the 500 rows, look at the tier colours, and notice which markets still have no owner.
- Buy an ownership you can afford to open. A Blue market costs 5,000 and another 100 to launch, which leaves plenty of cash to trade with. Green, Purple and Pink are cheaper and pay a lower rate.
- Open it. Pay the launch fee and the market goes live at a 210,000 USDC market cap. Choose "Buy & Open" if you want to be the first buyer of your own market in the same tap.
- Let the world trade. The other players find open markets on their own, and every trade they make on yours pays you. Check the Inbox from time to time, because somebody may want to buy you out.
Quote a trade from code#
The game does all of its market math through one small ES module, and the same file is served from the site for anybody to import. It has no dependencies and never touches the network, so it works the same in a browser tab, in Deno and in Node.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
const rank = 42; // a Blue market
const m = am.openMarket(1e9); // fresh pool, supply of one billion
const q = am.quoteBuy(m, 1000, am.ownerRate(rank), false);
console.log(am.tierOf(rank).name); // 'Blue'
console.log(q.units); // 4456243.481558681
console.log(q.devFee, q.ownerFee); // 30 30
console.log(am.fmtUsd(q.priceAfter)); // '$0.0002119'<output id="out"></output>
<script type="module">
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
const m = am.openMarket(1e9);
const q = am.quoteBuy(m, 1000, am.ownerRate(42), false);
document.querySelector('#out').textContent =
am.fmtCompact(q.units) + ' units for ' + am.fmtUsd(q.usd);
// 4.46M units for $1,000.00
</script>Run it next to your own code#
If you would rather not import from a URL, save lib/animemoney.js next to your script and import it from there. In Node, keep it as an ES module: name the copy animemoney.mjs or set "type": "module" in your package.json.
How it works#
Four steps that loop for as long as you feel like playing.
Buy one of the 500 ownership rights. The price depends on the rank of the coin, from 250 USDC at the bottom to 50,000 for Bitcoin-chan.
Pay a launch fee of 2% of the base ownership price. The market opens at a 210,000 USDC market cap, and you may add a first buy in the same step.
Trades run on a constant-product curve. Each one pays a 3% developer fee and the owner fee of the tier, and the owner fee lands on your balance.
List your ownership for sale or accept an offer letter. The seller keeps 90% of the price, and the buyer takes over the fees from that moment.
Where the money moves#
| Moment | Amount | Notes |
|---|---|---|
| Buying an unowned market | The base ownership price, 250 to 50,000 USDC by rank | Paid once by the first owner. |
| Opening it | Launch fee, 2% of the base ownership price | Paid once by the owner. No launch, no trading. |
| Every buy and sell | Developer fee, 3% of the trade | Everybody pays it, the owner included. |
| Every buy and sell by somebody else | Owner fee, 0.375% to 7% by tier | Credited to the owner of that market. |
| Selling an ownership | 10% of the sale price | The seller keeps the other 90%. |
What an owner actually earns#
Owner income is volume multiplied by the rate, and nothing else. A thousand USDC of other people's trades on Bitcoin-chan pays its owner 70, and the same thousand on a Blue market pays 30. An Orange market that nobody trades earns exactly as much as a Pink market that nobody trades, so we suggest watching the volume column before the tier colour.
Tiers#
The rank of the coin picks the colour, and the colour picks everything else.
The six tiers#
| Tier | Ranks | Markets | Owner rate | Ownership price | Launch fee |
|---|---|---|---|---|---|
| Orange | #1 | 1 | 7% | $50,000 | $1,000 |
| Yellow | #2 | 1 | 5% | $30,000 | $600 |
| #3–5 | 3 | 5% | $20,000 | $400 | |
| #6–10 | 5 | 5% | $15,000 | $300 | |
| Blue | #11–100 | 90 | 3% | $5,000 | $100 |
| Green | #101–300 | 200 | 1.5% | $1,000 | $20 |
| Purple | #301–400 | 100 | 0.75% | $500 | $10 |
| Pink | #401–500 | 100 | 0.375% | $250 | $5 |
The owner rate is fixed for the life of the market. It does not grow with volume, it does not shrink with age, and it moves to the new owner unchanged when the market is sold.
What a trader pays in each tier#
A trader always pays the developer fee and the owner fee together, so the colour of a market is also its price tag for everybody who is not the owner. Top markets are the most expensive to trade and the most generous to own, which is exactly why they cost what they cost.
| Tier | Developer fee | Owner fee | Total per trade | Owner earns per 1,000 USDC |
|---|---|---|---|---|
| Orange | 3% | 7% | 10% | $70.00 |
| Yellow | 3% | 5% | 8% | $50.00 |
| Blue | 3% | 3% | 6% | $30.00 |
| Green | 3% | 1.5% | 4.5% | $15.00 |
| Purple | 3% | 0.75% | 3.75% | $7.50 |
| Pink | 3% | 0.375% | 3.375% | $3.75 |
Yellow is the tier with a spread#
Five tiers have one price each. Yellow has three, because rank 2 is not the same animal as rank 10, and the rate stays at 5% across all nine markets. Ask the library for the price of a rank instead of reading it from the tier.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
am.ownershipPrice(2); // 30000
am.ownershipPrice(4); // 20000
am.ownershipPrice(7); // 15000
am.tierOf(2).price; // 15000, the floor of the tierMarket math#
One pool, two numbers, and a product that never changes.
The pool#
Every open market is a constant-product pool with two reserves. v is the USDC inside the pool and t is the number of coins still left in it. A trade moves both numbers in opposite directions and keeps v · t the same, so each next coin costs a little more than the one before.
price = v / t
market cap = price × supply
at launch: v = 210,000 t = supply
price × supply = 210,000Buying#
Fees leave first, and only what remains enters the pool. The trader names the amount in USDC, we take 3% for the developer fee and the tier rate for the owner, and the rest buys coins along the curve.
net = usd × (1 − 0.03 − rate)
units = t − v·t / (v + net)
after: v' = v + net t' = t − unitsWhen the buyer owns the market, rate is zero for that trade and net is simply usd × 0.97.
Selling#
Selling is the same curve read backwards. The coins go back into the pool, the pool pays out USDC, and the two fees come out of that payout before it reaches the seller.
gross = v − v·t / (t + units)
usd = gross × (1 − 0.03 − rate)
after: v' = v − gross t' = t + unitsA round trip in numbers#
Take a fresh Blue market with a supply of one billion coins. Somebody who is not the owner buys for 1,000 USDC and immediately sells everything back. Both columns below come straight from quoteBuy and quoteSell.
| Line | Buy 1,000 USDC | Sell it all back |
|---|---|---|
| Developer fee | $30.00 | $28.20 |
| Owner fee | $30.00 | $28.20 |
| Through the pool | $940.00 in | $940.00 out |
| Coins | 4,456,243.48 received | 4,456,243.48 returned |
| Price after | $0.0002119 | $0.0002100 |
| Price impact | +0.90% | −0.89% |
| Trader ends with | 4.46M coins | $883.60 |
The pool is back exactly where it started, the trader is 116.40 USDC lighter, and the owner is 58.20 richer without lifting a finger. That is the whole business model of owning a market in one table.
Price impact#
Impact is how far a single trade moves the spot price, and both quote functions return it as impact. On a fresh pool of 210,000 USDC a thousand-dollar buy moves the price by less than one percent, and a fifty-thousand-dollar buy moves it by about half. The deeper the pool already is, the less any single order matters.
RangeError.Try it#
These two blocks import the real module and recompute on every keystroke.
Quote a buy#
Pick a rank, type an amount, and decide whether you are the owner. The slider pretends other players got there first and already pushed USDC into the pool, so you can see what arriving late costs.
Loading the market math.
Payback calculator#
How long does a market take to earn back its ownership price? Give it a rank and the volume that other players trade there in an hour. The answer is plain arithmetic on the base price and the owner rate.
Loading the market math.
The same thing in code#
Nothing in the blocks above is special. The slider builds a pool that already took some buys, and everything else is three calls into the library.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
const rank = 7, usd = 1000, iOwnIt = false, already = 50000;
const fresh = am.openMarket(1e9);
const pool = { // same curve, further along
v: fresh.v + already,
t: fresh.v * fresh.t / (fresh.v + already),
supply: fresh.supply
};
const q = am.quoteBuy(pool, usd, am.ownerRate(rank), iOwnIt);
console.log(q.units, q.devFee, q.ownerFee, q.impact, q.priceAfter);
console.log(am.paybackHours(42, 2500)); // 66.66666666666667Ownership and resale#
One market, one owner, and a price on the door.
Buying from the board#
A market with no owner shows its base ownership price in CoinMangaCap. Pay it and the market is yours, and nobody else in your world can own it until you sell. The simulated players shop from the same board, so the bargains do not wait forever.
What the owner gets#
- The owner fee. The tier rate on every buy and every sell made by anybody else, credited to your balance as the trades happen.
- The launch button. Only the owner can open the market, and only the owner decides when.
- Cheaper trading at home. Your own trades in your own market skip the owner fee and pay only the 3% developer fee.
- The right to sell. You can list the ownership at your price or accept an offer that arrives by letter.
Selling an ownership#
When an ownership changes hands, the buyer pays the agreed price and the seller receives 90% of it. The market itself does not notice the change: same pool, same price, same owner rate, new name on the door. Fees from the next trade already belong to the new owner.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
am.resaleProceeds(8000); // 7200, what the seller receives
am.RESALE_PAYOUT; // 0.9Is it worth the price#
The honest way to price an ownership is to ask how fast it pays for itself. paybackHours divides the base price by what the owner earns in an hour at a given volume, and ownerCut gives the earning for any amount of volume. A Blue market that sees 2,500 USDC an hour earns 75 an hour and pays back in about 67 hours.
am.ownerCut(42, 2500); // 75
am.paybackHours(42, 2500); // 66.66666666666667
am.paybackHours(1, 20000); // 35.714285714285715
am.paybackHours(450, 0); // Infinity, a market nobody trades never pays backpaybackHours counts the base ownership price only. Add the launch fee yourself, and if you bought the market from another player, use the price you actually paid.Opening a market#
An owned market earns nothing until its owner opens it.
The launch fee#
Opening costs 2% of the base ownership price, paid once. The fee follows the base price of the rank and not what you paid another player for the market, so it is the same number for everybody who ever opens that rank.
| Market | Base ownership price | Launch fee |
|---|---|---|
| Orange #1 | $50,000 | $1,000 |
| Yellow #2 | $30,000 | $600 |
| Yellow #3–5 | $20,000 | $400 |
| Yellow #6–10 | $15,000 | $300 |
| Blue | $5,000 | $100 |
| Green | $1,000 | $20 |
| Purple | $500 | $10 |
| Pink | $250 | $5 |
The opening state#
Every market opens with 210,000 USDC in the pool and the entire supply of the coin on the other side. The starting price is therefore 210,000 divided by the supply, whatever the coin is. Bitcoin-chan, with its 21,000,000 coins, opens at exactly one cent.
const m = am.openMarket(21e6); // { v: 210000, t: 21000000, supply: 21000000 }
am.price(m); // 0.01
am.marketCap(m); // 210000
am.startPrice(21e6); // 0.01, the same number without building the pool
am.launchFee(1); // 1000Buy & Open#
The owner can attach a first buy to the launch and take the very first coins off the curve. It is a normal trade with one perk: the owner fee is waived, so only the 3% developer fee comes off. On a Blue market a thousand-dollar opening buy gets about 141,567 more coins than the same order from a stranger.
const m = am.openMarket(1e9);
am.quoteBuy(m, 1000, am.ownerRate(42), true).units; // 4597810.115182281, the owner
am.quoteBuy(m, 1000, am.ownerRate(42), false).units; // 4456243.481558681, anybody elseClosed markets#
A market that is owned and not yet opened cannot be traded by anybody, its owner included. It shows up in the list with its owner and no price. If you see one you would love to be early on, that is what AniBot is for.
Offers and letters#
Every market has one owner, so sooner or later you will want somebody else's.
Making an offer#
Open a market that already has an owner and name your price for the ownership. The owner thinks about it at their own pace, and the answer does not come back as a pop-up. It comes by post.
The Inbox#
Answers arrive in the Inbox as sealed envelopes, and you do not know what is inside until you break the seal. The same Inbox receives offers that other players make on the markets you own. We could have used a notification badge, and we decided that a wax seal is more fun to open.
| Letter | Why it arrives | What you do with it |
|---|---|---|
| Answer to your offer | You offered to buy somebody's ownership and they made up their mind. | Open the envelope and read the verdict. |
| Offer on your market | Another player wants an ownership that belongs to you. | Accept it and keep 90% of the price, or pass. |
Listing your own market#
You do not have to wait for somebody to ask. List the ownership at a price of your choice, and it stays on sale for the other players to take. A market with a visible history of volume tends to find a buyer faster than one that has never been opened.
What the seller receives#
Whichever way the sale happens, by listing or by letter, the split is the same. The buyer pays the full price and the seller receives 90% of it, as computed by resaleProceeds. Price your listing with that in mind: to walk away with 9,000 you need to sell for 10,000.
Devices#
The market lives on a screen inside the scene, and you choose which screen.
Four ways to look#
| View | What you see | Good for |
|---|---|---|
| Phone view | A hand holding the phone in front of the scene, with the apps on its home screen. | Playing with one thumb, the way the game was drawn. |
| Laptop view | The same apps on a wider screen. | Long lists, bigger charts and comparing several markets. |
| Close-up | The screen fills most of the window and the room steps back. | Reading numbers on a small display. |
| Device away | No screen at all, only the place you are in. | Dragging the background to look around, and meeting people. |
One account on every screen#
The phone and the laptop show the same balance, the same holdings and the same Inbox. Switching devices never pauses the world, so the other players keep trading while you admire the view.
Looking around#
Put the device away and drag the background. Each place is wider than the window, and some of the things worth finding are not in the middle of the picture. We will say no more than that.
Your corner of the world#
Seven places between Tokyo and Okinawa, and five of them are open from the start.
The seven backgrounds#
| Place | Where | Status |
|---|---|---|
| Midnight room | Tokyo | Open. This is where you wake up. |
| Shibuya café | Tokyo | Open |
| Akihabara street | Tokyo | Open |
| Roppongi penthouse | Tokyo | Open |
| Private jet | Somewhere above it all | Open |
| Okinawa beach | Okinawa | Locked until you find the way |
| Okinawa yacht | Okinawa | Locked until you find the way |
Changing the background does not change your money, your markets or the prices. It changes where you are sitting while the fees come in, which matters more than it sounds.
People#
You are not alone in these places. The people you see in the world can be clicked and talked to, and they do not all say the same thing twice. Some of them simply like to chat, and some of them know things.
The two locked places#
Nobody sells a ticket to Okinawa in a menu. The way there is found inside the world and not in the settings, and that is all the help these docs are going to give.
AniDex#
The charts app on the home screen of the phone.
What it is for#
CoinMangaCap tells you where a market is right now. AniDex shows how it got there: the price history of a market since it opened, the highest point it ever reached and the volume that pushed it. It is the app to check before you make an offer on somebody's ownership.
No signal#
The icon is on the home screen from the first minute, and the app has no signal at first. That is not a bug in your browser. Signal is something you sort out in the world, and once it is there, it stays.
Where the charts come from#
Every market keeps its own short history inside your saved world, next to its reserves, its volume and its all-time high. AniDex draws from that record, so the charts include everything that happened while you were away. See Stored state for the fields.
AniBot#
A hidden app that stands in the queue so you do not have to.
What it does#
AniBot queues a buy on a market before its planned launch. You choose the market and the amount in USDC, and the order waits. The moment the owner opens the market, your buy fills right after the open, ahead of the players who were only watching.
Why being first matters#
On a constant-product curve the earliest coins are the cheapest. The example below sends the same 2,000 USDC into a fresh Blue pool, and then into the same pool after a crowd has already bought for 50,000. The early order gets about one and a half times as many coins.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
const fresh = am.openMarket(1e9);
const first = am.quoteBuy(fresh, 2000, 0.03, false);
const crowded = am.quoteBuy(fresh, 50000, 0.03, false).after;
const late = am.quoteBuy(crowded, 2000, 0.03, false);
am.fmtCompact(first.units); // '8.87M' at an average of $0.0002254
am.fmtCompact(late.units); // '5.93M' at an average of $0.0003370The rules of a queued order#
- A queued buy is an ordinary buy once it fills. It pays the 3% developer fee and the owner fee of the tier like any other trade.
- Orders wait in your saved world under
me.orders, so they survive closing the tab. - AniBot only helps with markets that are owned and not yet open. On an open market you can simply buy.
Finding it#
AniBot is not on the home screen and it is not in a store. Somebody in the world knows about it. Be nice to people.
Avatar#
The face that the other players see next to your name.
What you can change#
| Part | What you choose |
|---|---|
| Face | The shape and the expression you want to wear while the market moves. |
| Hair | The cut, and yes, anime rules apply to gravity. |
| Clothes | What you put on to check a chart at three in the morning. |
| Colours | The palette for hair, clothes and details. |
Where it shows up#
Your avatar travels with your name. Wherever the game shows you as a player, that is the face it uses, so pick one you will not mind seeing next to a bad trade. You can come back and change it whenever the mood changes.
How it is saved#
The avatar is a handful of choices stored with the rest of your world under me.av. No image is uploaded anywhere, because the game redraws you from those choices every time.
World simulation#
Thirty-six other players, all of them busy, none of them real.
Who else is here#
Your world has 36 simulated players with their own balances and their own taste in markets. They run inside your browser and play by the same rules and the same math as you do. When one of them trades on your market, you get paid exactly as you would by a human.
What they do#
| Action | What happens | What it means for you |
|---|---|---|
| Buy an ownership | A player takes an unowned market off the board. | That market is gone until its owner sells. |
| Open a market | The owner pays the launch fee and the pool goes live. | A new market to trade, and a moment for AniBot. |
| Trade | Every couple of seconds somebody buys or sells on an open market. | Prices move, and trades on your markets pay you the owner fee. |
| Send an offer | A player writes to you about an ownership you hold. | An envelope in your Inbox. |
While you are away#
The world does not freeze when you close the tab. When you come back, the game looks at how long you were gone and replays that time tick by tick before it shows you anything. Fees are collected, prices move and letters pile up as if you had been watching.
Seeds#
The starting world is built from one number, the seed, with a small deterministic dice function. The same seed always gives the same players and the same first moves, in every browser. That function is exported from the library, so you can roll the same dice.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
const next = am.rng(42);
next(); // 0.6011037519201636
next(); // 0.44829055899754167
next(); // 0.8524657934904099
const dice = am.rng(2026);
1 + Math.floor(dice() * am.MARKETS); // 228, a rank from 1 to 500Library API#
One file, 8 constants and 17 functions, all of them pure.
Load it#
The module is plain JavaScript with named exports. It keeps no state, reads no storage and makes no requests, so every function gives the same answer for the same input.
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
// or only what you need
import { tierOf, quoteBuy, fmtUsd } from 'https://animemoney.vercel.app/lib/animemoney.js';
console.log(am.VERSION); // '1.0.0'<script type="module">
import * as am from 'https://animemoney.vercel.app/lib/animemoney.js';
console.log(am.VERSION); // '1.0.0'
</script>Exports at a glance#
| Export | Kind | Does |
|---|---|---|
tierOf | function | Returns the tier object for a rank. |
ownershipPrice | function | Base ownership price of a rank in USDC. |
ownerRate | function | Owner rate of a rank as a fraction. |
launchFee | function | Fee to open the market of a rank. |
openMarket | function | Builds a fresh pool for a given supply. |
price | function | Spot price of a pool. |
marketCap | function | Spot price multiplied by supply. |
startPrice | function | Opening price for a given supply. |
quoteBuy | function | Full quote for buying with an amount of USDC. |
quoteSell | function | Full quote for selling a number of coins. |
holdingValue | function | What a holding would pay if sold now, after fees. |
ownerCut | function | Owner earning on a given volume. |
paybackHours | function | Hours of volume needed to earn back an ownership. |
resaleProceeds | function | Seller's share of an ownership sale. |
rng | function | Seeded random numbers, the same sequence for the same seed. |
fmtUsd | function | Formats a number as dollars. |
fmtCompact | function | Formats a number with K, M, B or T. |
fmtPrice | function | Formats a coin price, seven decimals under one dollar. |
TIERS | constant | The six tier objects. See Constants. |
VERSION MARKETS LAUNCH_CAP DEV_FEE LAUNCH_FEE RESALE_PAYOUT MIN_TRADE | constants | The numbers of the game. See Constants. |
Tiers and prices#
Four functions answer questions about a rank. All of them go through tierOf, so all of them throw the same RangeError when the rank is outside 1 to 500.
| Signature | Returns |
|---|---|
tierOf(rank) | The tier object { id, name, key, from, to, rate, price } whose range contains the rank. |
ownershipPrice(rank) | Number. The base price in USDC, including the three Yellow steps. |
ownerRate(rank) | Number. The owner rate as a fraction, for example 0.03. |
launchFee(rank) | Number. ownershipPrice(rank) × LAUNCH_FEE. |
am.tierOf(42);
// { id: 3, name: 'Blue', key: 'blue', from: 11, to: 100, rate: 0.03, price: 5000 }
am.ownershipPrice(1); // 50000
am.ownershipPrice(4); // 20000
am.ownerRate(450); // 0.00375
am.launchFee(42); // 100
am.tierOf(501); // RangeError: rank must be 1..50010.5, throws.Pools#
A pool is a plain object { v, t, supply }. The library never mutates it: quotes return the next state in after, and you decide whether to keep it.
| Signature | Returns |
|---|---|
openMarket(supply) | A fresh pool { v: 210000, t: supply, supply }. Throws when the supply is not positive. |
price(m) | Number. m.v / m.t. |
marketCap(m) | Number. price(m) × m.supply. |
startPrice(supply) | Number. LAUNCH_CAP / supply. |
const m = am.openMarket(1e9); // { v: 210000, t: 1000000000, supply: 1000000000 }
am.price(m); // 0.00021
am.marketCap(m); // 210000
am.startPrice(1e9); // 0.00021quoteBuy#
Quotes a buy for an amount of USDC. rate is the owner rate of the market as a fraction, and isOwner waives the owner fee when it is true.
quoteBuy(m, usd, rate, isOwner)
// → {
// side: 'buy',
// usd, what the buyer pays
// units, coins received
// devFee, usd × 0.03
// ownerFee, usd × rate, or 0 for the owner
// net, USDC that actually enters the pool
// avgPrice, usd / units, fees included
// priceAfter, spot price after the trade
// impact, priceAfter / priceBefore − 1
// after the next pool { v, t, supply }
// }const m = am.openMarket(1e9);
const q = am.quoteBuy(m, 1000, 0.03, false);
q.units; // 4456243.481558681
q.net; // 940
q.avgPrice; // 0.0002244042553191518
q.impact; // 0.008972417233559904
q.after; // { v: 210940, t: 995543756.5184413, supply: 1000000000 }
am.quoteBuy(m, 0.5, 0.03, false); // RangeError: minimum trade is 1 USDCquoteSell#
Quotes a sell of a number of coins. Here the input is units and usd is the output: what the seller receives after both fees.
quoteSell(m, units, rate, isOwner)
// → {
// side: 'sell',
// units, coins sold
// gross, USDC the pool pays out before fees
// devFee, gross × 0.03
// ownerFee, gross × rate, or 0 for the owner
// usd, what the seller receives
// avgPrice, gross / units
// priceAfter, spot price after the trade
// impact, negative for a sell
// after the next pool { v, t, supply }
// }const bought = am.quoteBuy(am.openMarket(1e9), 1000, 0.03, false);
const s = am.quoteSell(bought.after, bought.units, 0.03, false);
s.gross; // 940
s.devFee; // 28.2
s.usd; // 883.5999999999999
s.impact; // -0.008892628857150364
am.quoteSell(bought.after, 10, 0.03, false);
// RangeError: this sale is worth less than 1 USDCholdingValue#
The friendly version of quoteSell for portfolio screens. It returns the USDC a holding would pay out right now after fees, and it returns 0 instead of throwing when the holding is empty or too small to sell.
// holdingValue(m, units, rate, isOwner) → number
am.holdingValue(bought.after, bought.units, 0.03, false); // 883.5999999999999
am.holdingValue(bought.after, bought.units, 0.03, true); // 911.8, the owner skips the owner fee
am.holdingValue(bought.after, 0, 0.03, false); // 0Owner income#
| Signature | Returns |
|---|---|
ownerCut(rank, usd) | Number. usd × ownerRate(rank), the owner earning on that much volume from other players. |
paybackHours(rank, hourlyVolume) | Number. Hours until ownershipPrice(rank) is earned back, or Infinity when the volume is zero or less. |
resaleProceeds(salePrice) | Number. salePrice × RESALE_PAYOUT. |
am.ownerCut(1, 1000); // 70
am.ownerCut(450, 1000); // 3.75
am.paybackHours(42, 2500); // 66.66666666666667
am.paybackHours(42, 0); // Infinity
am.resaleProceeds(8000); // 7200rng#
rng(seed) takes an integer seed and returns a function. Each call of that function returns the next number of the sequence, at least 0 and below 1. The same seed gives the same sequence everywhere, which is how every browser builds the same starting world.
// rng(seed) → () => number
const a = am.rng(42), b = am.rng(42);
a() === b(); // true
a(); // 0.44829055899754167Formatting#
| Signature | Returns |
|---|---|
fmtUsd(n, digits) | String. Dollars with thousands separators and two decimals. Without digits, values under one cent get seven decimals. Returns '—' for anything that is not finite. |
fmtCompact(n) | String. Two decimals with a K, M, B or T suffix and no currency sign. |
fmtPrice(n) | String. Dollars with two decimals from $1 up, seven decimals below it, and <$0.0000001 for anything smaller. |
am.fmtUsd(1234.5); // '$1,234.50'
am.fmtUsd(50000, 0); // '$50,000'
am.fmtUsd(-12.3); // '-$12.30'
am.fmtUsd(0.00021); // '$0.0002100'
am.fmtUsd(0.00000001); // '<$0.0000001'
am.fmtUsd(Infinity); // '—'
am.fmtCompact(210000); // '210.00K'
am.fmtCompact(1.5e9); // '1.50B'
am.fmtCompact(-4200000); // '-4.20M'
am.fmtCompact(999); // '999.00'
am.fmtPrice(0.0694361); // '$0.0694361'
am.fmtPrice(12.5); // '$12.50'Errors#
The library throws RangeError and nothing else. Each message is short enough to show to a player as it is, which is exactly what the Try it block above does.
| Message | Thrown by | When |
|---|---|---|
rank must be 1..500 | tierOf and everything that takes a rank | The rank is outside the board or not a number. |
supply must be positive | openMarket | The supply is zero, negative or not a number. |
minimum trade is 1 USDC | quoteBuy | The amount is below MIN_TRADE. |
units must be positive | quoteSell | The number of coins is zero or negative. |
this sale is worth less than 1 USDC | quoteSell | The pool would pay out less than MIN_TRADE before fees. |
rate to the quote functions. It is not looked up for you, and a quote made without it comes back full of NaN instead of throwing.Constants#
Every number of the game, exported by name.
The numbers#
| Constant | Value | Meaning |
|---|---|---|
VERSION | '1.0.0' | Version of the library. |
MARKETS | 500 | Number of markets, one ownership right per coin rank. |
LAUNCH_CAP | 210000 | Game market cap in USDC at which every market opens. |
DEV_FEE | 0.03 | Developer fee taken from every buy and every sell. |
LAUNCH_FEE | 0.02 | Share of the base ownership price paid once to open trading. |
RESALE_PAYOUT | 0.9 | Share of the sale price that the seller of an ownership keeps. |
MIN_TRADE | 1 | Smallest trade in USDC, before fees. |
TIERS | 6 objects | The tier table, from Orange to Pink. |
TIERS#
An array of six objects ordered from the top of the board to the bottom. from and to are inclusive ranks, rate is the owner rate as a fraction, and key is the lower-case name that the site uses for its colour classes.
am.TIERS;
// [
// { id: 1, name: 'Orange', key: 'orange', from: 1, to: 1, rate: 0.07, price: 50000 },
// { id: 2, name: 'Yellow', key: 'yellow', from: 2, to: 10, rate: 0.05, price: 15000 },
// { id: 3, name: 'Blue', key: 'blue', from: 11, to: 100, rate: 0.03, price: 5000 },
// { id: 4, name: 'Green', key: 'green', from: 101, to: 300, rate: 0.015, price: 1000 },
// { id: 5, name: 'Purple', key: 'purple', from: 301, to: 400, rate: 0.0075, price: 500 },
// { id: 6, name: 'Pink', key: 'pink', from: 401, to: 500, rate: 0.00375, price: 250 }
// ]
am.TIERS.map(t => t.name + ' ' + t.rate * 100 + '%');price holds the lowest of its three prices. Use ownershipPrice(rank) whenever you need the real number for a rank.Stored state#
Your whole world is one JSON value in the storage of your browser.
The key#
The game saves under a single localStorage key, animemoney:v1. There is no account and no server copy, so that value is the world: your cash, your markets, the other players and the mail. The docs live on the same site as the game, which means you can read the key from the console on this very page.
const world = JSON.parse(localStorage.getItem('animemoney:v1') || 'null');
if (world) {
console.log(world.me.name, world.me.cash); // who you are and what is left of the 20,000
console.log(Object.keys(world.me)); // everything the game remembers about you
console.log(Object.values(world.mk).filter(m => m && m.launched).length); // markets open for trading
}Top-level fields#
| Field | Holds | Notes |
|---|---|---|
seed | The number the starting world was built from. | Fed to rng. Same seed, same 36 neighbours. |
born | The moment this world was created. | Set once, on your first visit. |
last | The moment the simulation last ran. | The game compares it with the clock to replay your time away. |
me | Everything about you. | See the next table. |
mk | The 500 markets. | One entry per market. See below. |
feed | The recent events of the world. | What the activity feed of the game shows. |
Inside me#
| Field | Holds |
|---|---|
me.name | The name on your markets and your letters. |
me.cash | Your play USDC. A new world starts at 20,000. |
me.hold | The coins you hold, per market. |
me.fav | The markets you starred. |
me.av | Your avatar choices: face, hair, clothes and colours. |
me.env | The background you are sitting in. |
me.flags | What you have found and unlocked so far. |
me.earned | The owner fees you have collected. |
me.inbox | Your letters, sealed and opened. |
me.orders | The buys queued with AniBot. |
Inside a market#
| Field | Holds |
|---|---|
owner | Who owns the market, or nothing while it is still on the board. |
launched | Whether the owner has opened it for trading. |
v | USDC reserve of the pool, as in Market math. |
t | Coins left in the pool. |
vol | Volume traded on the market. |
ath | The highest point the market has reached. |
history | The short price record that AniDex draws its charts from. |
Starting over#
Remove the key and reload the game, and you wake up in the Midnight room with 20,000 USDC and a fresh set of neighbours. There is no undo for this, so say goodbye to your markets first.
localStorage.removeItem('animemoney:v1');v or t will price that market strangely for the rest of its life.Limits#
What the game does not do, said once and plainly.
Good to know#
- Play money only. The USDC in the game is play USDC. It cannot be deposited, withdrawn or exchanged, and no wallet is ever asked for.
- One browser is one world. Your phone and your computer each hold their own world with their own 36 players. Nothing syncs between them.
- Clearing site data resets it. The world lives in the storage of the browser. Private windows, cleaning tools and "clear browsing data" take it with them.
- The board is a snapshot. Names, ranks, supplies and logos are the top 500 as it stood on 2026-11-09. A coin that climbed or fell since then keeps its seat in the game.
- The replay has a ceiling. Time away is replayed up to 4,000 ticks, however long you were actually gone.
Numbers#
The math runs on ordinary JavaScript numbers. That is plenty of precision for a market cap of a few million, and it is also why a round trip can return 883.5999999999999 where you expected 883.60. Format before you show anything to a human, and fmtUsd will take care of the rest.
$ABUCKS#
The one row of CoinMangaCap that exists outside the game.
The pinned row#
$ABUCKS is the real token of the project. It sits pinned above the 500 markets as the top row of the list, above Bitcoin-chan and everybody else. Once the contract address is set, that row shows the live price from DexScreener instead of a game price.
Contract and links#
| Field | Value |
|---|---|
| Ticker | $ABUCKS |
| Chain | Solana |
| Contract | |
| Buy | Buy $ABUCKS |
| Chart | Open the chart |
| X | Follow on X |
The address, the Buy link and the X link on this page are read from the main page of the site, so they are always the same in both places. Click the contract chip to copy the full address.
The token and the game#
The game runs on play USDC and the token trades on Solana, and the two never mix. You cannot buy $ABUCKS with your in-game balance, and holding the token does not change your rates or your prices in CoinMangaCap. The pinned row is there so you always know how the real one is doing while you run your empire of -chans.
FAQ#
The questions we would ask if we had just walked into the Midnight room.
Do I need a wallet to play?#
No. The game hands you 20,000 play USDC the first time you open it and never asks you to connect anything. Everything you do happens in your browser.
I own a market and earn nothing. Why?#
Check two things. The market has to be opened, because a closed market cannot be traded at all. And the trades have to come from other players, since your own buys and sells in your own market pay you no owner fee.
Can my owner rate change?#
No. The rate comes from the rank of the coin and is fixed for the life of the market. If you sell the ownership, the next owner gets exactly the same rate.
My balance changed while the tab was closed. Is that right?#
Yes, and usually in your favour. When you return, the game replays the time you were away, up to 4,000 ticks, and the other players trade through all of it. Owner fees from those trades are already on your balance when the room appears.
Can two players own the same market?#
Never. Each of the 500 markets has one owner at a time, and the only way in is to buy it from the board or from the player who holds it. That scarcity is the entire point of the game.
AniDex says there is no signal. Did I break something?#
You did not. The app starts that way for everybody, and the fix is somewhere in the world and not in your browser settings. Put the phone down and look around.
How do I get to Okinawa?#
The beach and the yacht are locked until you find the way, and finding it is part of the game. We can tell you that the people in the world are worth talking to. We will not tell you which ones.
How do I start again from zero?#
Remove the animemoney:v1 key from the storage of your browser, as shown in Starting over, and reload the game. You get a new world, a new 20,000 and no memory of the old one.