Most people building here drive an AI agent. This page is the literal text to paste at the start of that conversation — one prompt per architecture. Copy the whole block, replace the one angle-bracket line describing your game, and send it.
These are the only copies. If you find this prompt reproduced somewhere else, the copy here is the one that is maintained.
Which prompt
Decided by where your game's state lives, not by how fast it plays.
| Your game | Prompt |
|---|---|
| Two to four people playing each other, moves signed off chain | A — Arcade / channel game |
| A world the chain persists, every move its own transaction | B — persistent on-chain world |
Unsure? Read /skills first — it is one screen and it will route you.
Prompt A — Arcade / channel game
I want to build a multiplayer game for the Xaya Arcade. Before you write any code:
1. Get the Arcade skills if you do not already have them. Take the zip:
curl -fsSLO https://arcade.xaya.io/skills/arcade-skills.zip
unzip arcade-skills.zip -d .claude/skills/
If a template fork is already open in this workspace it carries the skills
vendored at .claude/skills/ — use those and install nothing.
No .claude/skills/ support? Read them straight from the site — the same files:
https://arcade.xaya.io/skills/building-channel-games.md
https://arcade.xaya.io/skills/building-channel-games/arcade.md
https://arcade.xaya.io/skills/building-channel-games/standalone.md
https://arcade.xaya.io/skills/building-channel-games/wasm.md
https://arcade.xaya.io/skills/building-channel-games/wagering.md
https://arcade.xaya.io/skills/building-channel-games/hidden-information.md
https://arcade.xaya.io/skills/building-channel-games/commit-reveal.md
https://arcade.xaya.io/skills/building-channel-games/pitfalls.md
https://arcade.xaya.io/skills/building-channel-games/examples.md
Once xaya/arcade-skills is public, the Claude Code marketplace pair installs
the same corpus:
/plugin marketplace add xaya/arcade-skills
/plugin install arcade-skills@arcade-skills
2. Read on this schedule, and do not skim:
- ARCADE.md in full, BEFORE any design;
- WASM.md before you touch rules/ or blob/ — that is where the blob toolchain
and golden-trace authoring live;
- PITFALLS.md before you submit;
- https://arcade.xaya.io/docs/quickstart.md and
https://arcade.xaya.io/docs/submitting.md in full.
Do not improvise anything these cover from memory.
3. Decide the two PERMANENT names first, before any design or code: slug and
gameType. They are claimed at upload and registered on chain when the game is
accepted: gameType can never be reassigned to another game, ever, and slug can
never be reused. There is no availability endpoint — you find out when you
upload — so the safe order is to dry-run on the playground (step 6), which
auto-accepts and tells you in seconds, and keep the resubmitToken it returns.
Nothing is claimed until upload and nothing is burned until an operator
accepts; a rejected submission releases both names. Only acceptance is
terminal.
Seats and the cfg suffix are PROVISIONAL — revise them freely while you build,
because the cfg suffix is derived from rules that do not exist yet. Keep them
in step with GAME_KEY in src/app-identity.ts, the blob's seat range and the
rules' cfg decoder as they settle, and confirm all four with me before we
submit.
4. Clone the template:
git clone https://github.com/xaya/arcade-xayaman.git
If any git clone in these instructions fails, STOP and tell me. Do not
reconstruct the judge ABI, the SDK surface or the submission contract from
memory.
My game: <one paragraph — what the players do, how a match ends, how many seats>
Non-negotiable constraints:
- The rules are a deterministic wasm judge against the frozen arcade_* ABI, whose
authority is docs/ARCADE-ABI.md in arcade-platform — read it, never reconstruct
it. Never add an import, never invent an export, no floats, no wall-clock, no
randomness outside the channel seed.
- The frontend never holds a wallet and never signs. Inside the Arcade the shell
is the only signer; the SDK's standalone wallet path exists for local
development only, so never write wallet, connect or signing code in the game.
- Free play first. Wagering is a separate operator action and is not part of this.
- The game is served under a base path, from ONE origin shared with every other
game and with the shell. So: never construct a root-absolute URL at runtime or
write one as a literal — no fetch('/data.json'), no <img src="/sprite.png">, no
url(/bg.png) — and set STORAGE_PREFIX in src/app-identity.ts to our own game's
key, never the template's.
- An Arcade game is 2 to 4 seats, React/Next only (the SDK has no supported
non-React path today), and ships as a static export with no server of any kind —
no API routes, no server actions, no database, no asset backend, no leaderboard
service, and no accounts beyond your Xaya p/ name. All shared state is produced
by a deterministic wasm judge with no floats, no clock, no network and no file
access, whose state output is bounded and whose execution is fuel-capped — which
caps how big a world and how long a history you can have. Input is keyboard- or
tap-shaped, and every game must be playable by touch: it declares on-screen touch
controls (a d-pad and/or action buttons) that the SDK mounts on touch devices, or
it declares that it draws its own touch surface and takes the whole frame to draw
it in — a game that declares neither is labelled desktop-only on the shelf and a
player on a phone cannot start or join a match in it. There is no gamepad support
and no key remapping. And a
match needs two to four named, funded humans online at the same moment; there is
no solo mode, no bot and no matchmaking.
If my idea does not fit, say so NOW rather than working around it.
- There is no self-serve update path: after acceptance the slug and gameType are
single-claim and the gameType is on chain, so a fix costs a new slug and a new
gameType. A REJECTED submission releases both — only acceptance is terminal.
- Build the submission bundle only with ./scripts/build-export.sh --bundle.
- Work test-first. Before we submit, all of these must be green and you must show
me the output: npm test; bash blob/tests/run-tests.sh; npm run e2e;
npm run e2e:determinism; npm run selfplay; bash blob/check-blob.sh. These run
offline; there is no local chain, so none of them opens a real channel.
- Then DRY-RUN THE WHOLE PIPELINE on the public playground before submitting for
real. It is a disposable test chain, it auto-accepts, and it is wiped every
Monday 04:10 UTC and without notice in between:
a) point the dev server at it with the committed script: npm run dev:playground
That sets all FIVE values the loop needs — WS_PROXY_DESTINATION,
CHAIN_PROXY_DESTINATION and GSP_PROXY_DESTINATION at test-arcade.xaya.io,
plus NEXT_PUBLIC_POLYGON_RPC=/chain and NEXT_PUBLIC_DEV_WALLET=1. Without
the last two the browser reads REAL Polygon and you have no test wallet.
Never put them in .env.local: Next loads that for builds too and they
would be baked into the bundle we submit. You should see a dev-wallet
picker, not a wallet-connect prompt — if you see a connect prompt, the
env did not apply, so stop and tell me.
b) NEXT_PUBLIC_GAME_ID=xarc ./scripts/build-export.sh --bundle, then upload
at https://test-arcade.xaya.io/attach — that is the playground's upload
page. Once it auto-accepts, the game is live there twice over: bare at
/g/<slug>/, and inside that plane's arcade shell at /play/<slug>.
(xarc is the playground's shared move namespace, NOT our game key — a
bundle for arcade.xaya.io is built with arcbeta instead; the bundle
refuses to boot on a mismatch. Keep the resubmitToken the upload returns —
you need it to re-upload the same slug after a fix.)
c) when it auto-accepts, open the game in TWO BROWSER PROFILES — one per seat
if the game seats more than two — and pick a DIFFERENT test-wallet slot in
each, then reload. Two tabs of one profile are the same player. Play a
full match.
Submissions on arcade.xaya.io are closed during the curated phase: /submit is
hidden there and an upload answers 503. So hand the SAME BYTES over in
#builders on the Xaya Discord, with the repository and the four registration
values (slug, gameType, seats, cfgSuffix). Check them:
sha256sum dist/bundle.tar.gz blob/rules.wasm must match the bundleSha256 and
rulesSha256 the playground echoed back in its 201 upload response (also at
GET https://test-arcade.xaya.io/api/submissions/<id>) — no page prints them, so
capture them from the response. If they differ, we are submitting bytes we never
dry-ran — rebuild and redo the dry run.
- The playground reserves NOTHING. It is a different chain, wiped at will. A game
that works perfectly there can still lose its gameType to someone else, and a
playground success is not a reservation of anything on the real arcade.
- Upload the blob whose sha256 the green run used, and the bundle built from that
same commit. The browser loads the REGISTERED blob, so a bundle built against a
different one boots, joins, and then renders garbage.
Give me a plan and wait for my approval before writing code. Ask one question at a
time.
Prompt B — persistent on-chain world
I want to build a Xaya game whose state lives fully on chain — a persistent world
where every move is its own transaction, not a game channel. Before you write any
code:
1. Get the Xaya skills if you do not already have them. Take the zip:
curl -fsSLO https://arcade.xaya.io/skills/arcade-skills.zip
unzip arcade-skills.zip -d .claude/skills/
No .claude/skills/ support? Read them straight from the site — the same files:
https://arcade.xaya.io/skills/building-persistent-games.md
https://arcade.xaya.io/skills/building-persistent-games/gsp.md
https://arcade.xaya.io/skills/building-persistent-games/determinism.md
https://arcade.xaya.io/skills/building-persistent-games/ops.md
https://arcade.xaya.io/skills/building-persistent-games/fork-testing.md
https://arcade.xaya.io/skills/building-persistent-games/pitfalls.md
https://arcade.xaya.io/skills/building-persistent-games/examples.md
2. Read SKILL.md and GSP.md in full before any design, DETERMINISM.md before you
write a line of game logic, and FORK-TESTING.md before you run anything against
a chain. Do not improvise anything they cover from memory.
3. Clone the foundation and the worked example:
git clone https://github.com/xaya/libxayagame.git
The mover/ directory inside it is the smallest complete game-state processor
there is — scaffold from it rather than from a blank file. If any git clone
fails, STOP and tell me.
My game: <one paragraph — what the world is, what a player does in one move, and
what the state has to remember between moves>
Non-negotiable constraints:
- The GSP is the only authority on state. State is a pure function of the ordered
move sequence and nothing else — no wall-clock, no randomness that is not
derived from chain data, no floats, no map or set iteration order dependence,
no uninitialised memory, no locale. Two independently synced GSPs must return
byte-identical gamestate; that is the acceptance test, not an aspiration.
- Pick the genesis height deliberately and tell me what you picked. Moves before
it are invisible forever, and a height above the current tip never syncs.
- Every move is a real on-chain transaction the player pays for. Say out loud, in
the design, what one move costs a player and how often they will send one — a
world that needs a move per second is not this architecture.
- Names are permanent and are ERC-721 tokens on Polygon. Registration costs WCHI.
- Test against a FORKED Polygon chain, never mainnet and never a testnet.
FORK-TESTING.md has the procedure and the traps — including that a fork's state
is memory-only, so restarting the container is a wipe rather than a hiccup.
- Work test-first: a golden-replay suite and a reorg suite, both baked into the
image build as a deploy gate, before the game is ever run anywhere real.
Give me a plan and wait for my approval before writing code. Ask one question at a
time.
After the prompt
The agent will ask for a plan approval. Read it. The two things worth checking hardest, because they are the two that cannot be undone later:
- Does the game actually fit? Seats, no server, input that works from a keyboard or the SDK's on-screen pad (no gamepad, no remapping), humans online at the same time. An agent that has decided to build your idea will find a way to describe it as fitting.
- Are the slug and gameType the ones you want forever?
gameTypegoes on chain at acceptance and can never be reassigned. Sleep on it.
Everything else is recoverable.