Examples: channel-game repos
One line per repo: the link, whether you can open it today, and the one thing it is worth reading
it for. /repos on the arcade site lists every public repository and your role for each.
The examples below are selected for implementation patterns, not an exhaustive catalogue.
Access marks. A row marked public clones anonymously. A row marked private will not: the row states what that repo demonstrates, and any path quoted from it describes its shape, not a file you can open. If a clone fails, stop and tell the human: never guess at a private repo's contents or invent its file layout. Questions go to the Xaya Discord (https://discord.gg/FdZWZj4), in #builders.
The Xaya foundation repos are deliberately not listed here: the GSP library, the XayaX Polygon
bridge and the mover worked example live in the building-persistent-games skill's
EXAMPLES.md: load that skill when you need them.
Arcade games: the hosted path
| Repo | Access | What it demonstrates |
|---|---|---|
| https://github.com/xaya/arcade-xayaman | public | THE copy-me template. A real-time simultaneous-move grid game, registered at 2..3 seats: reproducible zero-import rules blob, board UI on the arcade SDK, e2e + determinism harnesses. You fork this one repo and no other. |
| https://github.com/xaya/arcade-xayaships | public | Two seats, the born-packed codec, a freestanding SHA-256, and the commit-reveal coin flip for "who starts?": the pattern for unpredictability when the judge ABI hands you no entropy (below). Its rules carry their own SHA-256 (rules/ships_sha256.hpp) because a blob is freestanding, with no libcrypto to link. Also a worked example of a tap-native game on a phone: a shipped game that declares fullFrameOnTouch and mounts no pad: it gates a tap-to-aim + Fire bar on useCoarsePointer() and drops from two boards to one off a measured cell size rather than a device check (fullFrameOnTouch in src/lib/arcade/presentation.ts, src/lib/games/xayaships-adapter.tsx). And the worked empty-cfgSuffix example (the "Config" section of blob/MANIFEST.md). |
| https://github.com/xaya/arcade-xayatrails | public | A neon trail-battle game at 2..4 seats: a template fork with its own rules. Also two reference details worth stealing: a real multi-field cfgSuffix byte table at 2..4 seats (the "Config" section of blob/MANIFEST.md), and an arcade_share_weights that states its payout instead of leaving it to the host's fallback: a decided match is winner-take-all, and a draw splits equally between the non-ejected seats holding the most round wins (shareWeights in rules/arcade_core.hpp and rules/arcade_core.cpp). |
| https://github.com/xaya/arcade-dungeonchannel | public | The hidden-information channel game: the engine supports 2..4 seats; the hosted Arcade registers it at two. Secret per-seat knowledge that never enters the shared signed state, and the commitment/disclosure discipline that keeps it verifiable by a judge that sees only the packed bytes. Read it when your game has fog of war, a hidden hand, or anything one seat may not learn from the proof chain: this skill's HIDDEN-INFORMATION.md is built on it. Also: the minimal non-empty cfgSuffix (01, and it must never be empty), a verdict-aware share-weights split that cannot pay a convicted cheater, and a pure-JS SHA-256 path, so it plays over plain HTTP like HTTPS (src/lib/dungeon/secret.ts). |
| https://github.com/xaya/arcade-taurion-racer | public | Real-time racing; touch controls in src/lib/games/racer-adapter.ts, payout weights and an explicit zero-ejection mask in rules/arcade_abi.cpp. |
| https://github.com/xaya/arcade-fps-duel | public | Desktop FPS tech demo with deterministic rules. The hosted Arcade takes it free-only. |
| https://github.com/xaya/arcade-taurion-rts | public | RTS tech demo with deterministic rules and optional skill wagers. Profile saturated states and long matches when adapting it. |
Trap: xaya/xayaman - no arcade- prefix - is the frozen pre-split
monorepo, not the template. Never build on it. The template is xaya/arcade-xayaman. The same
trap exists for xaya/polyxayaships against xaya/arcade-xayaships.
The commit-reveal coin flip (arcade-xayaships). The judge ABI supplies no randomness, so a
fair "who starts?" has to be built out of the players' own secrets: seat 0 commits to a 32-byte
seed by hash, seat 1 sends its seed in the clear, then seat 0 reveals its own, and the starting
player is a single bit of a hash over the two seeds back to back:
SHA256(seed_preimage || seed_1)[0] & 1, with 1 meaning player 1 goes first (applySeedReveal
in rules/ships_core.cpp). Neither side can steer it without breaking the hash, and both sides
recompute it identically inside the blob. Reuse the shape whenever your rules need an
outcome no participant can predict or bias.
Ships and Dungeon Channel use commit-reveal for different jobs and you want both rows: once for
a coin and a fleet, every round for a choice. That is COMMIT-REVEAL.md.
The xayaman board JSON
This is the shape a board state converter turns into renderer types. The blob emits no JSON:
the arcade_* ABI has no JSON export and exchanges packed bytes only. This object is produced
entirely TS-side by the game's own ParsedBoardState.toJson(): in the template,
XayamanPackedBoardRules.toJson() calling decodePackedState() in
src/lib/xayaman/packed-codec.ts, a hand-maintained TypeScript mirror of the packed encoder in
rules/arcade_core.cpp that a fork must keep in step with its C++. It is then consumed by
src/lib/xayaman/board-state-converter.ts:
{ netTick, gameTick, seed, finished, side, turn?, winner?,
grid:int[169],
players:[{cell,x,y,alive,ejected,maxBombs,bombsActive,blastRange,moveCooldown}],
bombs:[{cell,x,y,owner,fuse,range}],
fires:[{cell,x,y,ttl}],
powerups:[{cell,x,y,type}] }
or, before the second participant joins: { phase: "waiting for opponent" }, which likewise comes
from the SDK-side placeholder state, not from the blob (the referee short-circuits the empty
on-chain state without ever calling the judge). Handle this pre-join shape explicitly; it is not
an error state. grid is a flat cell array whose length is the
game's own CELLS constant (src/game/types.ts defines CELLS = SIDE * SIDE, 169 for
xayaman's square board). Read the converter's own header comment before copying it.
General conversion pattern:
function boardStateToGameState(boardJson, ctx /* persisted: maps, track, playerIndex */) {
const gameTick = boardJson.gameTick ?? 0;
return {
tick: gameTick,
// map WASM arrays → your renderer's types here
// carry ctx fields forward: anything not IN the proof (loaded assets,
// static geometry) must be supplied from context, never invented
};
}
Any field that is derived state but not part of the signed proof (e.g. a "time since X" field
seeded from 0 and corrected on the next snap) must be documented at the call site: silently
defaulting such a field to zero has caused real bugs, such as an effect's expiry computed from the
wrong base tick and expiring instantly instead of on schedule.
Standalone channel games: you run the GSP and the relay
| Repo | Access | What it demonstrates |
|---|---|---|
xaya/xayaman | private; superseded - do not start here | The pre-split reference implementation cited throughout STANDALONE.md: one game running its OWN GSP + relay + frontend (channel manager, state proofs, session keys, relay client). Read it, never fork it. |
xaya/soccer2d | private | Continuous-motion sport on the channel protocol: a deterministic Q16.16 C++ engine held to native==WASM parity, with a web client renderer over the top. |
xaya/xayarts | private | A 2-player browser RTS: many units under one seat, showing the protocol does not assume one avatar per participant. |
xaya/xayafpsdemo | private | The twitch-latency end of the protocol - a browser 3D shooter. Its divergences from a turn-based game are the patterns below. |
xaya/taurion_racer | private | A 2-player real-time racer, and the whole standalone stack in one repo: deterministic C++ under racer-cpp/ - Q19.12 fixed-point (racer-cpp/math/fixed.hpp documents 12 fractional bits, 19 integer bits and a sign bit in 32), the channel BoardRules (racer-cpp/board/board.cpp) and its own GSP daemon (racer-cpp/gsp/): all compiled from one source tree, with relay + frontend + GSP standing up as three services (docker/docker-compose.yml defines relay, frontend and racerd). It also splits prediction from authority: a TypeScript local sim for smooth visuals snapping to the signed WASM state (README.md), the opposite of xayafpsdemo's single-engine choice below. |
| https://github.com/xaya/xayaships_frontend | public | Superseded: do not start here. The Xaya Core-era ships frontend; it name-collides with arcade-xayaships and predates everything in this skill. |
xaya/polyxayaships | private; superseded - do not start here | The frozen pre-split Polygon-era ships monorepo, kept for history. |
Simultaneous-input / FPS patterns (xayafpsdemo)
For a genuinely twitch-latency game sitting on this same channel protocol, these diverge from a turn-based game like xayaman, stated as patterns:
- WASM does both prediction and authority: no separate TypeScript local sim. The module
exposes two entry points: a deterministic
applyNetTick(inputs[], fixedDt)used for signed proofs, and a non-deterministicapplyPredictionTick(input, variableDt)used purely for smooth local rendering (variable dt from the render loop). Only the net-tick path is ever signed or sent. The net tick is itself a fixed run of physics steps:game-cpp/include/fps_types.hdefinesTICKS_PER_NET = 6.taurion_racertakes the other route, keeping a TypeScript sim for visuals; both are legitimate, and the choice is yours. - Q16.16 fixed-point: CORDIC sin/cos for angles, all arithmetic through
fxMul/fxDiv/fxSqrt, andgame-cpp/include/fps_fixed.hsetsFX_SHIFT = 16for the fractional half of the word. Not xayaman's board-cell integer math, and not the Q19.12taurion_raceruses (racer-cpp/math/fixed.hppsetsSHIFT = 12). No floating point anywhere in anything that feeds a signed proof. - Input-only protocol as anti-cheat by construction: players submit only
{forward, backward, left, right, jump, shoot, yaw, pitch}(thePlayerInputstruct atgame-cpp/include/fps_types.h), never positions or health. The engine deterministically derives everything else under hard physics constraints (speed cap + friction, AABB collision, hitscan ray computed from the derived eye position, fixed damage and cooldown), so speed hacks and teleporting are structurally impossible rather than merely detected. - BSP collision determinism: if collision geometry comes from an external map format parsed client-side, the authority's compiled-in collision data and the client's parsed data must be the exact same extracted AABBs, produced by one canonical extraction tool, or the two sides silently diverge on physics.
- Vanilla renderer, no framework requirement: the channel protocol itself has zero opinion about React/Next vs a plain render loop with a DOM HUD; the relay and channel-manager code are framework-agnostic. (The hosted Arcade path is the exception: its SDK is React/Next only today.)
Infrastructure and platform: read or run, never fork
| Repo | Access | What it demonstrates |
|---|---|---|
| https://github.com/xaya/xaya-relay | public | The universal WebSocket relay a standalone channel game runs one instance of per game: a dumb forwarder for signed off-chain traffic that stamps each frame with its sender's address, plus peer-join/leave events. Arcade games never deploy one. |
| https://github.com/xaya/arcade-platform | public | The host GSP, the SDK you build against, the bundle server and the submissions service. It is the authority you verify ABI and judge claims against (engine/judge/wasm_judge.cpp, docs/ARCADE-ABI.md). |
| https://github.com/xaya/xaya-arcade | public | The arcade website itself - lobby, /docs, the (closed) submission front, and the shell that frames your game in an iframe. Consumed, never forked. |
| https://github.com/xaya/arcade-wager | public | The deployed ArcadeWager.sol the arcade's stakes escrow into: WAGERING.md §1. |
For the persistent-world examples: the GSP library and its mover sample, the XayaX bridge, and
the on-chain MMO-class games: load the building-persistent-games skill and read its
EXAMPLES.md.
Every access mark above was read from gh repo view xaya/<slug> --json visibility; re-run it before trusting a row, because a repo can be opened up at any time. The file citations are arcade-xayaman/src/lib/xayaman/board-state-converter.ts, arcade-xayaman/src/game/types.ts, arcade-xayaships/rules/ships_core.cpp, xayafpsdemo/game-cpp/include/fps_types.h, xayafpsdemo/game-cpp/include/fps_fixed.h, taurion_racer/racer-cpp/math/fixed.hpp, taurion_racer/docker/docker-compose.yml and taurion_racer/README.md; the Discord invite above is the one the site itself publishes (xaya-arcade/src/lib/constraints.ts, DISCORD_INVITE).