The chain decides the card.
Every stat, every ability, every element on every OrdCard is read out of the SHA-256 of the inscription it belongs to. No card is authored, no card is edited, and no value in a match comes from anywhere else. This page is how you check that instead of believing it.
What the engine is
One pure function. In go the identifiers of six inscriptions and one match seed. Out come the winner and the log, action by action. There is no database read, no clock, no floating point and no randomness that is not derived from the seed.
simulate(teamA, teamB, seed, options) -> { winner, actions, log }The consequence of that signature is the whole product. Because the function is pure, the same inputs give the same output on any machine, forever, which is what makes a match something a stranger can recompute rather than something we assert. The database stores results so pages load quickly. It is a cache. The hash is the record.
- Inputs per card
- 2
- Bytes that matter
- 12
- Divisions per hit
- 1
- Action cap
- 60
The inscription id and its number. Nothing else.
Of the 32 the digest returns.
Every multiplication happens first, in integers.
A match cannot fail to end.
The eight rules
These came before the code and outrank it. Three separate times during design a good-sounding idea reintroduced buyable advantage, which is why the rules are written as prohibitions and why each one carries the measurement that justified it.
| Rule | In one line | What it costs to keep |
|---|---|---|
| INV-1 | Nothing outside the hash touches combat | Rarity, sat provenance, collection, market price, sold items, reputation, holding time and wallet balance are all forbidden inputs to resolution. |
| INV-2 | Money buys prestige, never win rate | Measured with a rarity bonus switched on, a wallet of mythics beat a wallet of commons 80% of the time. That is why the bonus is zero. |
| INV-3 | Wallet size does not decide the result | The hand is drawn, not picked. Once both hands come out of the same distribution, collection size stops being a variable at all. |
| INV-4 | Total reproducibility | Given an id and a number, any SHA-256 implementation produces the card. Given a seed, the teams and the engine version, anyone replays the match action by action. |
| INV-5 | Permissionless | The engine knows inscriptions, not collections. There is no approved list, and no collection has to integrate, ask or pay. |
| INV-6 | The backend is the authority | Simulation runs on the server. The client signs intents and animates a log it did not compute. |
| INV-7 | Reputation is not sellable | Career, wins, streaks and trophies cannot be bought, transferred between cards or edited. |
| INV-8 | Progression never touches combat | Level, streak, milestones and cosmetics change appearance and title. They never change a number the damage expression reads. |
Why progression is cosmetic, in one table
The eighth rule is the one that costs the most to keep, because a card game with no power progression gives up the easiest retention loop there is. It was measured before it was decided. A veteran carrying a flat stat bonus against a newcomer carrying none:
| Veteran bonus | Win rate | Reading |
|---|---|---|
| +0% | 49.7% | The control. No bonus, no advantage. |
| +5% | 63.1% | Five levels of five percent is already worth more than most abilities. |
| +10% | 78.4% | |
| +15% | 88.1% | |
| +25% | 97.5% | |
| +50% | 100.0% | Six months of play and the newcomer cannot win at all. |
In a small audience that closes the front door. So progression buys frames, titles, emblems and a public record, and never a point of attack.
The card generator
A card is not stored. It is computed, every time it is read, from two facts that are already public on Bitcoin. Delete our database and every card in the game comes back identical.
seed = sha256( utf8(inscription_id) || uint64BE(inscription_number) )
Why the number is in the hash
The inscription id alone would be enough to derive a card, and it would be a serious mistake. An id is chosen by the person inscribing: they can grind candidate transactions offline until one produces a card they like, and at that point stats stop being drawn and start being selected. The inscription number is assigned by the indexer at confirmation and cannot be picked, so mixing it in is what keeps the draw a draw. Negative numbers, the cursed inscriptions, encode as two’s complement so that two implementations cannot disagree about them.
One real card, byte by byte
Below is a genuine inscription, its genuine digest, and the card the engine derives from it. Nothing here is an example filled with plausible numbers: the stat line is recomputed on every request from the two values printed beside it.
- b[0..1]HP 75 + (u16 % 31)
- b[2..3]ATK 28 + (u16 % 15)
- b[4..5]DEF 15 + (u16 % 11)
- b[6]SPD 9 + (b % 8)
- b[7]CRT 8 + (b % 5)
- b[8]TIE queue tiebreak
- b[9]ELEM b % 5
- b[10]ABIL walks the weighted table
- b[11]MAG magnitude, budgeted
- b[12..31]RESERVED unread by combat
RunestoneAIR◆ COMMON SAT
NO EXOTIC PROVENANCE
- Number
- 63,140,674
- Element
- AIR
- Ability
- INITIATIVE
- Tier
- COMMON
The stat line
| Stat | Bytes | From the digest | Range | This card |
|---|---|---|---|---|
| Health | b[0..1] | 75 + (u16 % 31) | 75 to 105 | 83 |
| Attack | b[2..3] | 28 + (u16 % 15) | 28 to 42 | 29 |
| Defense | b[4..5] | 15 + (u16 % 11) | 15 to 25 | 15 |
| Speed | b[6] | 9 + (b % 8) | 9 to 16 | 16 |
| Crit | b[7] | 8 + (b % 5) | 8 to 12 | 10 |
The element, and the wheel it sits in
This is the most valuable decision in the game, and it is not close. Playing the wheel, which means putting each of your cards where it has the edge and away from the ones that have it over them, measures 91.6% against 54.3% for ignoring the element and pairing on the numbers alone. That is +37 points, against +12 for ordering well and +1.3 for choosing the right tool.
The tier does not come from the hash
Rarity is read off the inscription number directly, on a fixed ladder, and it never reaches resolution. This is the asymmetry worth understanding before anything else on the page: two cards with the same stats and different tiers are the same card in a match, and the engine has a test that proves it by running an identical match with every tier inverted and comparing the logs byte for byte.
| Tier | Inscription number | Cards that can ever exist |
|---|---|---|
| MYTHIC | below 1,000 | 1,000 |
| LEGENDARY | 1,000 to 9,999 | 9,000 |
| EPIC | 10,000 to 99,999 | 90,000 |
| RARE | 100,000 to 999,999 | 900,000 |
| UNCOMMON | 1,000,000 to 9,999,999 | 9,000,000 |
| COMMON | 10,000,000 and up | open |
| CURSED | negative numbers | closed |
The ability, and the budget it is drawn against
Byte 10 walks a weighted table to pick which of the sixteen abilities the card carries. Byte 11 sets the magnitude, but not on its own: the magnitude is scored against the stat line the same digest already produced, so a card that rolled well on stats lands lower in its ability’s range. The correlation is deliberately negative, around minus zero point three, with a hard cap. A card does not get to be both the strongest body and the strongest effect.
percentile = weighted_position_of(hp, atk, def, spd, crit) position = clamp( b[11]/255 * 0.6 + (1 - percentile) * 0.4 ) magnitude = lo + round( position * (hi - lo) )
Five of the sixteen abilities are binary. They have no magnitude at all, and the engine represents that absence explicitly rather than as a zero, so nothing downstream can accidentally read a missing value as a very weak one. This card holds INITIATIVE, which is one of them.
The strip across the foot of every card is not decoration. It is twenty-two linked pairs whose lengths are read straight off the same digest, so the figure below belongs to this inscription and to no other, permanently.
The sixteen abilities
Five families, one ability per card, drawn from a weighted table rather than a flat one. The weights sum to exactly 256, which is verified by a test, so the complicated abilities stay rare and a first match stays legible.
Byte 10 walks a weighted table whose weights sum to exactly 256, so a share here is a share of every card that will ever exist. A flat draw would put every bar at 6.25%.
- Barrier3011.7%
- Armor3011.7%
- Tenacity166.3%
- Riposte166.3%
- Rally2810.9%
- Formation62.3%
- Vengeance41.6%
- Initiative2810.9%
- Double Strike103.9%
- Charge83.1%
- Legacy166.3%
- Detonation166.3%
- Split62.3%
- Pierce145.5%
- Attrition145.5%
- Precision145.5%
A plain modulo would hand every ability 6.25% of all cards. That reads fair and plays badly: the effects that need reading, the ones that fire on death or change the queue, would be as common as the ones you can learn in a sentence, and the first match a new player watches would be a knot. Weighting is how the simple effects carry the introduction and the complicated ones stay worth finding.
| Family | The idea | Share of all cards |
|---|---|---|
| Defense | Absorb. Buy the exchange that would have ended you. | 35.9% |
| Support | Spend the ability on somebody else's numbers. | 14.8% |
| Tempo | Change when a thing happens instead of how big it is. | 18.0% |
| Sacrifice | The card is worth something the moment it dies. | 14.8% |
| Attack | Remove a term from the damage formula, or add one. | 16.4% |
Reference
| Ability | Family | Magnitude | Effect | Draw |
|---|---|---|---|---|
| BARRIER | defense | 51 to 61% | The first hit that would land arrives much weaker. Spent once, then gone. | 11.7% |
| ARMOR | defense | 9 to 19% | Every hit, and every splash, arrives reduced by the magnitude. | 11.7% |
| TENACITY | defense | 49 to 59% | The blow that would kill arrives weakened, once. If it still kills, it kills. | 6.3% |
| RIPOSTE | defense | 12 to 22% | A share of the damage taken goes straight back to the attacker. | 6.3% |
| RALLY | support | 2 to 3 | The whole side gains flat attack. Snapshot at setup, and it does not stack. | 10.9% |
| FORMATION | support | 3 to 4 | Attack and defense, but only while two allies are still standing. | 2.3% |
| VENGEANCE | support | 21 to 31 | Grows in attack each time an ally on its side dies. | 1.6% |
| INITIATIVE | tempo | none | Acts before everything else, in every round, without touching a single stat. | 10.9% |
| DOUBLE STRIKE | tempo | 67 to 71% | Two strikes instead of one, each at a reduced share of full force. | 3.9% |
| CHARGE | tempo | 53 to 63% | Nothing in round one. From round two on, a large attack multiplier. | 3.1% |
| LEGACY | sacrifice | 8 to 16 | On death, hands attack and health to the frontmost surviving ally. | 6.3% |
| DETONATION | sacrifice | 6 to 14 | On death, flat damage to every living enemy at once. | 6.3% |
| SPLIT | sacrifice | 42 to 52% | On death, leaves a copy of itself at a share of its own stats, with no ability. | 2.3% |
| PIERCE | attack | 49 to 59% | Cuts through most of the defense before the subtraction happens. | 5.5% |
| ATTRITION | attack | 4 to 13% | At setup, cuts the attack of the strongest enemy on the board. | 5.5% |
| PRECISION | attack | none | Carries +10 crit and rerolls the roll when it misses. | 5.5% |
The kit
Three tools, free, permanent and identical for everyone. One per card. They exist because a game whose only decision is a permutation of three does not hold anyone for a season, and they are the only shape of depth this product can accept.
| Tool | Effect | What it is for | Win rate alone |
|---|---|---|---|
| Whetstone | +1 attack | Always does something, never does anything surprising. The correct pick with no information. | 55.0% |
| Aegis | +4 health | Buys an action rather than damage. Worth most on a slow card that would die before its turn. | 55.5% |
| Lodestone | elemental penalty softened 50% | Worth nothing in a neutral matchup and more than either of the others against the wrong element. | 55.1% |
The store is locked out by structure, not by promise
A match takes a loadout, and the loadout is filtered against the kit before anything else happens. An item that is not one of these three is not a weaker item in resolution: it is discarded, silently, and the slot resolves empty. There is no argument, no configuration and no code path by which a sold item reaches the damage expression. The specification predicted that this rule would be pushed on every quarter revenue dipped, so it was made a test instead of a memo.
How much the kit is worth, measured
| Question | Measured | Reading |
|---|---|---|
| The whole kit against any two of the three | 50.3% | 95% interval 49.71 to 50.84, entirely inside the one point margin the gate requires. Breadth of catalogue is worth almost nothing. |
| Choosing the right tool against always the same one | 50.5% | Real and above chance, and thin. Playing the item system well is worth about two points. |
Those two numbers together are what licenses a shop to exist at all. Access to the kit matters; breadth of catalogue does not. So the kit is given away, and anything sold on top of it is decorative in fact rather than decorative in the marketing copy.
The match
Three cards a side. You do not pick your three best: the game deals you a hand and you choose inside it. That single rule is what keeps a wallet of five competitive against a wallet of five hundred, and it is measured rather than asserted.
- 01DrawUp to 5 cards come out of your eligible collection, by a published algorithm from a published seed.
- 02Keep threeYou choose the team out of what you were dealt, never out of the whole wallet.
- 03OrderYou arrange the three. Yours line up against theirs, position by position, so this is the decision the match turns on.
- 04ResolveThe server runs the engine. Integer arithmetic, no floating point, no roll that is not derived from the seed.
- 05PublishThe log, the seed and the teams come back together, which is everything a stranger needs to recompute it.
hand_size = max(3, min(5, collection - 1))
Draw from the collection, keep 3, order them. The subtraction is what stops a collection from ever dealing itself entirely, and the clamp is what stops a collection of three from being dealt a hand too small to field a team.
A wallet of 100 cards against a wallet of the size on the axis. 50% is symmetry: at 50% the bigger wallet has no advantage left. Left is the rule the game ships. Right is the same match if players simply picked their three best.
Cards in the opposing wallet, along the bottom of each plot.
The left plot is the mechanism the game ships and the right one is the same match if players simply picked their three strongest. Free choice never becomes fair: even fifty cards against a hundred, a difference of only two to one, still hands the bigger wallet 55.4%. The drawn hand arrives at symmetry at six cards and stays there no matter how large the other wallet grows.
What a small collection actually costs
| Your collection | You beat a wallet of 100 | |
|---|---|---|
| 3 cards | 37% | |
| 4 cards | 37% | The fourth card is worth nothing at all: the hand size formula returns three either way. |
| 5 cards | 45% | |
| 6 or more | 50% | From here the board is flat, and it stays flat however large the other wallet gets. |
A draw anyone can check
A shuffle you cannot verify is a shuffle the house could have dealt. So three things are published with every hand and all three are required together: the seed the draw came from, the eligible collection frozen and ordered at the moment of the draw, and the algorithm itself, which is a partial Fisher-Yates driven by a hash stream. With all three, anyone can redo the draw and confirm that nobody chose anybody’s hand.
Combat
Resolved on the server, in integers, with every tie broken by a rule rather than by a roll. Nothing in a match is decided by chance except the crit roll, and even that comes out of the seed.
The queue
Speed descending, then the tiebreak byte ascending, then the inscription id lexicographically, then the side. Four keys, and after the fourth there is nothing left that can tie, because two cards with the same id on the same side are the same card. The tempo ability is a partition of that queue rather than a bonus inside it: cards holding it form a block at the front, sorted among themselves by the same chain, in every round.
Who gets hit
Position against position. Your first card fights their first card, your second fights their second, and when a lane empties the next living card behind it steps across. This is the newest structural rule in the engine, and it is what lets the player work out who will face whom by looking, instead of by simulating.
| Rule | Skill ceiling | Mirror | |
|---|---|---|---|
| Lowest health | 50.6% | 49.9% | Version 1. Ordering was decoration: playing it perfectly was worth six tenths of a point. |
| Frontmost absorbs | 71.9% | 49.7% | Versions 2 and 3. Retired in version 4: alone it measures the same depth as lane, and it loses to lane once the stat ranges are compressed. |
| Lane against laneshipped | 73.7% | 50.1% | Shipped in version 4. Alone it ties the frontal rule; with compressed stat ranges it is what turns the reading into something inferable instead of simulable. |
Lane assignment measured higher and was not adopted. The click budget for a first match is six clicks and the replay runs twenty-five seconds, and “the front card takes the hits” is legible in one sentence and visible on screen as it happens, while lanes have to be taught before the first blow lands. Two points of ceiling do not pay that teaching debt.
The damage expression
Integer arithmetic with every multiplication before the single division. This is not fastidiousness: floating point would give different results on different architectures, and the reproducibility that makes the whole product checkable would quietly stop being true.
- 01Attackatk = floor(base * (100 + charge) / 100) + rally + vengeance + legacy + formationAttrition has already cut the base at setup. The multiplier resolves before the additive band, so an ability that adds attack is never multiplied by one that scales it.
- 02Rawraw = floor(atk * force * element * crit / 1000000)Four integers multiplied, then divided once. Force is the strike's share of full power, element is 118, 100 or 85, crit is 150 or 100.
- 03Defensedamage = raw - floor(defense / 2)Halved before it is subtracted, so defense slows a hit and never cancels one. Pierce skips this line entirely.
- 04Mitigationdamage = floor(damage * (100 - armor) / 100)Armor reduces attacks and splash damage alike. It is the only percentage applied after the division.
- 05Floordamage = max(1, damage)Applied after mitigation, not before. A card can never be immune by arithmetic, only by an ability that says so.
- 06Barrierif barrier and damage >= 1 then damage -= floor(damage * m / 100), barrier spentChecked last, so a barrier is spent on a hit that would have hurt rather than on one the floor had already reduced to nothing. Version 4 gave it a magnitude: it used to cancel the hit outright, which is binary and therefore impossible to tune.
Deaths, and the end of a match
Deaths are processed through a first-in-first-out queue, so effects that fire on death, and effects those effects trigger in turn, resolve in a defined order rather than in whatever order the interpreter happened to walk an array. A match ends when one side has no living cards, copies included. If it reaches 60actions it ends anyway, decided by the higher sum of remaining health as a percentage, then by the lower sum of tiebreak bytes, then by the ordered concatenation of the side’s inscription ids. Nothing is ever re-rolled.
r(i) = sha256( seed || uint32BE(i) ) // i is monotonic and never reused
Every roll the match makes comes out of that stream, and the counter only ever moves forward. The published log records the counter range each action consumed, so a replay that diverges by a single roll is visible rather than mysterious.
Balance, measured
An ability is acceptable when a card carrying it beats a card carrying nothing between 55% and 61% of the time. Strong enough to matter, weak enough to lose to a better draw. Every number below came out of the project's own simulator at 40,000 matches, paired seeds, sides alternated.
A card carrying the ability, on a team that is otherwise neutral, against a card carrying nothing. Everything between 55% and 61% is declared acceptable: strong enough to feel, weak enough to lose to a better draw.
- Rally
- Legacy
- Vengeance
- Charge
- Initiative
- Split
- Pierce
- Formation
- Double Strike
- Detonation
- Precision
- Armor
- Tenacity
- Attrition
- Barrier
- Riposte
- 58.8
- 57.5
- 57.4
- 57.1
- 56.9
- 56.9
- 56.8
- 56.7
- 56.7
- 56.5
- 56.3
- 56.2
- 56.2
- 56.1
- 56.0
- 55.9
The control run, no ability against no ability, measures 50.1% with no side bias, which is the zero the whole table is read against. All sixteen abilities sit inside the band, between 55.9% and 58.8%. The spread between the strongest and the weakest is 2.9 points, against 6.4 in version 3 and 16.1 immediately after version 4 changed the ranges and before the recalibration caught up.
How a balance change is actually made
Version 4 is not a patch, it is a reform, and it shipped as one version for the same reason every version does here: the frozen fixture is regenerated once instead of once per change. What drove it was a measurement nobody had taken. Under the old ranges, in 63% of matches either all six orderings won or none did, which means the result was already decided by the cards and the player's choice changed nothing in almost two thirds of the games.
Two changes fixed that and neither works alone. The stat ranges were halved around their own centres, so two teams are rarely far apart on raw numbers; and targeting became positional, so the player can see who will face whom. Together they take the share of matches where the ordering decides the result from 36.7% to 61.1%, and what playing well is worth from 62.9% to 70.1%. Compressing alone actually makes things worse under the old targeting, which is why the pair is the unit.
| Change | Before | After | Why this shape |
|---|---|---|---|
| Stat ranges halved, centres kept | 36.7% | 61.1% | Share of matches where the ordering actually decides the result. The single biggest lever found across eleven experiments, and five constants of code. |
| Targeting became positional | 62.9% | 70.1% | What playing well is worth. Alone it ties the frontal rule; it is the compression that makes the difference, because the player can now infer the matchup instead of simulating it. |
| Barrier, Tenacity and Pierce gained a magnitude | 3 stuck | 3 tunable | All three measured above the ceiling under the new ranges and had no dial at all. Each became the graded version of its own effect, so the maximum of the range reproduces the old behaviour exactly. |
| All sixteen magnitudes remeasured | 16.1 pts | 2.9 pts | Spread between the strongest and the weakest ability. Compressed stats make the effect matter more than the number, so every range had to move. |
Check it yourself
None of the above is worth anything if the only way to confirm it is to ask us. Here is how to reproduce a card with twelve lines of code and no dependency on this project at all.
import { createHash } from "node:crypto";
const id = "ed76bf35918948b8b78be0e6397ad4916d926dd3d65679a8b7e67d8699a672a0i0";
const number = 63140674;
const n = Buffer.alloc(8);
n.writeBigInt64BE(BigInt(number));
const b = createHash("sha256").update(id, "utf8").update(n).digest();
const u16 = (i) => (b[i] << 8) | b[i + 1];
console.log({
hp: 75 + (u16(0) % 31), // 83
atk: 28 + (u16(2) % 15), // 29
def: 15 + (u16(4) % 11), // 15
spd: 9 + (b[6] % 8), // 16
crit: 8 + (b[7] % 5), // 10
});The comments are the values this page derived for that inscription on this request. If your run disagrees with them, one of us has a bug, and the disagreement is the whole point of publishing the expression.
The regression the test suite used to allow
This is worth telling because it is what “deterministic” costs in practice. For a long time every test in the engine compared the engine to itself. One derived a card twice and checked the two results matched. Another ran the same match twice in the same process. A third checked stats fell between their minimum and maximum. All of them passed, and not one of them would have failed if somebody had swapped which bytes of the digest became which stat. An innocent refactor could have silently rewritten every card in the universe with the suite still green.
So the suite now holds a frozen fixture: 17 cards pinned with their exact hashes, stats, abilities and magnitudes, covering every rarity band, every element, binary and scaled abilities, the cursed case and a numeric edge, plus one entire 16 action match with the counter range of each action. The fix was validated by injecting a regression on purpose, swapping two bytes in the health calculation. Every older test still passed. Only the fixture broke, and it broke card by card.
- Tests
- 22
- Frozen cards
- 17
- Frozen match
- 16
- Engine version
- 4
All passing, in under two seconds.
Every tier, element and ability shape.
Actions, with the counter range of each.
Old matches replay under their own version.
What versioning means here
A card is never edited in a database, because a card was never in a database. When a rule changes, the version increments and matches that already ran stay valid and replayable under the version they ran on. That is the only honest way to change a deterministic engine, and it is also why changes are batched and measured first: every version is a promise that has to be kept forever.
The Genesis track publishes twenty-one fixed matches: the cards, the order, the kit and the seed. Recompute any claimed solution without us.
Paste any Bitcoin address and watch the engine derive its cards live. No wallet, no signature, no account.
The back of every printed card carries its full inscription id and a link to its page. Never trust the front. Recompute it. We would rather you did.
See the card system