Read this page as markdown — for coding agents, or for anyone who prefers the source.
Publishing guide
How to get a game onto Bananai. Read
SUBMISSION-RULES.md first — this document covers the
mechanics, that one covers the requirements.
Everything below is yours to do. Registering the game in the catalogue and deploying it are ours, and happen after review; you never edit a file outside your own folder.
The fastest start is not this page. It is the starter: a complete working game whose sizing, SDK lifecycle, storage guards and touch handling are already correct. Copy it, change the id, replace the game.
1. Create the folder
<id>/
├── bananai.json
├── index.html
├── assets/thumb.png
├── css/style.css
└── js/
├── main.js bootstrap: mounts the game, wires the SDK
└── <id>.js game logic
One top-level directory, named as the game id, with everything inside it. It is
published at /games/<id>/ unchanged — the folder you send is the folder that
ships.
The <id> is lowercase, hyphen-separated, and permanent — it appears in
URLs, cache keys and score records. It must match id in bananai.json and the
directory name exactly. A submission arrived once as pallanoids against a
manifest saying pallanoid, and it had to be corrected by hand.
2. Load the SDK
<script src="/sdk/v0/bananai-sdk.js"></script>
Root-relative, with no origin in front of it. Your game is served from the
portal's own origin, so this always resolves;
https://bananai.games/sdk/v0/bananai-sdk.js is a cross-origin request everywhere
except live production and is rejected by the checks. You may also vendor a copy
into your folder — ARCADE-SDK.md covers the trade-off.
await Bananai.init({ gameId: '<id>' });
Bananai.loadingFinished();
Bananai.gameplayStart(); // play begins, and after every resume
// ...
Bananai.gameplayStop(); // pause, settings, tab hidden
// ...
Bananai.gameOver({ score, level, durationMs }); // implies gameplayStop()
window.addEventListener('bananai:restart', () => resetGame());
gameplayStop() is not optional — it is in the MUST list of the submission
rules, and the pair is what measures the playtime you are paid on. A game that
starts play and never stops it reports one session that runs until the tab
closes, which is not a favour to anybody.
Full reference: ARCADE-SDK.md. A complete working game,
runnable as it stands: the starter.
3. Technical requirements
- Responsive. Fill the container, do not assume fixed dimensions.
In p5:
createCanvas(el.clientWidth, el.clientHeight)pluswindowResized(). - Touch.
touchStarted/touchMoved/touchEndedmust returnfalse, otherwise the page scrolls under the player's finger. - Self-contained. Libraries and assets live inside the game folder. No external requests.
- Audio silent until interaction. Browsers enforce this anyway.
4. Thumbnail
assets/thumb.png inside your folder (or .svg, or .webp), square, 400×400,
declared in bananai.json.
It lives inside the game folder, not in the portal's shared /assets/. The
submission is then one self-contained directory that can be added or removed as
a unit — no orphaned image left behind when a game is withdrawn.
It has to read clearly at roughly 180px, which is the actual card size in the grid. Check it at that size, not at full resolution.
Compose it; do not screenshot the starting screen. No HUD — no score, no
level, no press SPACE line: the card prints the title and category beside the
image already, and at 180px that text is a smear. One subject filling the frame,
built from few large shapes. Putting the game's name inside the image is allowed
and usually worth it. The full reasoning, and what went wrong when this said
only "400×400, legible at 180px", is in
SUBMISSION-RULES.md.
Strongly recommended: an animated hover thumbnail. Optional, but fourteen
of the fifteen games in the catalogue have one, and on desktop a card that does
not move under the cursor looks unfinished beside them. Put it at
assets/thumb-hover.webp and declare it as thumbHover in bananai.json,
alongside thumb. It must be an animated WebP, not a GIF, not an APNG and
not a video: 400×400, 2–3 seconds looping seamlessly, under 300 KB, and the
same composition rules as the still image. Details in
SUBMISSION-RULES.md.
5. Send it
Zip the folder — the whole thing, with your game id as the single top-level directory — and email it to hello@bananai.games. Under 25 MB compressed, which is the hard ceiling in the submission rules.
Tell us the game id, and what changed if this is not the first version.
An upload form will replace the email. The package it accepts is the same one described here, so nothing you build now is wasted.
What happens next
- Review. The game is loaded standalone and inside the shell at several viewport sizes, and played through the QA checklist — which is published precisely so you can run it first.
- Findings, if any, come back to you. They do not get fixed for you: your folder is yours, and nothing outside it may modify what is inside it. That is a rule, not a courtesy — a change we made to your game is a change you never agreed to and cannot maintain.
- We register it and deploy. The catalogue entry, the sitemap and the changelog are ours to write. The folder ships exactly as you sent it.
Before you send it
Everything here is something you can check yourself, on your own machine.
- Works standalone at
/games/<id>/index.html, served over HTTP — not opened as afile://URL, where the root-relative SDK path cannot resolve - Works on mobile: touch, both orientations, 320px width
- SDK lifecycle calls present and correctly sequenced,
gameplayStop()included -
bananai:restartrestarts without a page reload - Thumbnail composed rather than screenshotted, no HUD, legible at 180px — the size the grid actually renders
- Recommended: an animated hover thumbnail declared as
thumbHover— an animated WebP, 400×400, 2–3 seconds looping, under 300 KB -
bananai.jsonidmatches the folder name exactly -
sdkMinVersionis0.2.0or newer, and no higher than the SDK version currently published -
sdkVendoredandlanguagesare declared - No console errors
- No network requests to any origin other than the one it is served from
To serve it locally:
python -m http.server 8000 --directory <the folder containing your game>
Common failures lists the ways submissions are actually rejected, with the code that causes each one. It is a shorter read than this page and catches more.
Document history
- 2026-09-17 — The animated hover thumbnail is now mentioned here, as optional and strongly recommended, and added to the checklist.
- 2026-08-19 —
sdkVersionrenamed tosdkMinVersion;sdkVendoredandlanguagesadded to the checklist. - 2026-08-16 — Thumbnail rule spells out what the image must show, not just its size.
- 2026-08-11 — Internal-only publishing steps moved out; the runnable starter added.
- 2026-08-08 — Product renamed to Bananai; SDK envelope unified at 0.2.0.