KaoGames for developers · beta
Upload an HTML5 or Unity WebGL game. We host it for free, show it to players, and share a creator fund with everyone who publishes, every month.
index.html at the top (up to 30 MB), one HTML file, or a link to where it already runs.Using Claude, ChatGPT, Cursor or another coding assistant? Copy a prompt and paste it in with your project. Each one includes everything the AI needs to know, so it doesn't have to read this page. Open a guide to see what it will do first.
Your AI interviews you first: what the game is about, how you win, the controls, the look. It sums up the design for you to approve, then builds the game in HTML5.
Just an idea, and an assistant that can create files, such as Claude, ChatGPT or Cursor.
Start small: one idea that is fun for a minute. Play it, then ask for changes. Games grow best a step at a time.
# Make a new HTML5 game with me for KaoGames
You're my game developer. Help me design and build a small, polished browser game that I can publish on KaoGames (kaogames.com).
## Step 1: Ask me about the game first
Before writing any code, ask me these one or two at a time and wait for my answers:
- What is the game about, in one sentence? What does the player do?
- Which games is it like?
- How do you win, lose or score?
- Controls: keyboard, mouse, touch, or all three? (Recommend touch: games that play on phones get far more players.)
- Look and feel: art style, colors, mood, sound.
- How long is one round?
- Anything that must be in it?
Then sum up the design as a short list and ask me to confirm or change it.
## Step 2: Build it
- Plain HTML5, CSS and JavaScript (canvas or DOM), with no build step and no outside servers.
- Draw graphics in code and make sound effects with the Web Audio API, so there are no asset files to license.
- Get the core loop feeling good first: responsive controls, clear feedback, a score, a game-over screen and a quick restart.
- Fill the whole window and handle resizing: portrait on phones, landscape on desktop.
- Use pointer events so mouse and touch share one code path, plus keyboard controls on desktop.
## Step 3: Make it ready for KaoGames
- Load the Kao SDK before the game code: <script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>
- Start the game inside Kao.init().then(...), and call Kao.ready() once the first frame is drawn.
- Save progress (best score, unlocks, settings) with Kao.get('save', defaults) and Kao.set('save', data): one key, under 64 KB. Don't use localStorage directly.
- The game runs in a sandboxed frame, so don't use window.open, alert/confirm/prompt, forms or requestFullscreen.
## Step 4: Hand it over
- Give me every file, with index.html at the top level, and tell me how to play it on my computer.
- Help me zip it for upload: index.html at the top of the zip, at most 30 MB.
- Suggest a 16:9 thumbnail image (thumb.png, 1280x720) and what it should show.
- After I play it, ask me what to improve.Each one has its own card below, with the code.
Your gameplay. The prompt tells the AI not to touch it, and to show you every file it changes.
Run through "Check my game before I upload", then upload the zip in Your games.
# Get my HTML5 game ready for KaoGames I'm publishing my HTML5 game on KaoGames (kaogames.com). Make every change it needs, without changing gameplay. ## 1. Add the Kao SDK Put <script src="https://kaogames.com/sdk/kao-1.1.0.js"></script> in index.html before my game's own scripts. It creates a global `Kao`: - Kao.init(): a Promise that resolves when the player's save is ready. Start the game only after it resolves. - Kao.progress(n): loading progress from 0 to 1. - Kao.ready(): call once the first frame is on screen. - Kao.fail(message): show an error instead of an endless loading screen. - Kao.get(key, fallback) and Kao.set(key, value): synchronous saves of any JSON value, synced to the player's account. ## 2. Move saves to Kao Replace localStorage, sessionStorage, IndexedDB and cookies with Kao.get/Kao.set. Keep the whole save in ONE key (the newest copy wins as a whole) and under 64 KB. ## 3. Fix what the player blocks The game runs in a sandboxed iframe (allow-scripts allow-same-origin allow-pointer-lock). Remove window.open, target="_blank" links, forms, alert/confirm/prompt, requestFullscreen and anything that navigates the top page. ## 4. Fit any screen Fill whatever size the game is given and handle resizing, in landscape and portrait. Use relative paths for every asset. ## 5. Package it Make a production build and zip it with index.html at the top level. Limits: 30 MB zipped, 80 MB unpacked, 1,500 files. Optionally add a 16:9 thumb.png (1280x720) at the top level. ## When you're done Show me every file you changed and why.
Your AI uses the KaoGames MCP server to create the listing, zip your game, upload it and check the review status, all from your chat.
KaoGames reviews game builds before they go live. Your AI can’t approve games, buy boosts or move money.
# Publish my game to KaoGames Use the KaoGames MCP server (tools: get_publishing_guide, create_game, begin_upload, get_status, get_share_kit). 1. Call get_publishing_guide and check my game against it. Fix anything that would fail (the Kao SDK script, saves through Kao.get/Kao.set, blocked popups or fullscreen, sizing, relative paths). Show me what you changed. 2. Call list_my_games. If this game isn't listed yet, call create_game with a good title, a one-line tagline that sells it, up to 3 genres, the orientation, short controls, and phone_ready only if touch controls really work. 3. Make a production build and zip it with index.html at the top level (include a 16:9 thumb.png if there is one). 4. Call begin_upload and upload the zip with the command it returns. 5. Show me the automatic check results. If there are errors, fix them and upload again. 6. Call get_status and tell me where it stands. Once it's live, call get_share_kit and give me the link and post.
claude.ai artifact links only open on claude.ai: no other site can show them. So you publish the artifact’s code instead, as one HTML file.
Things that only work inside Claude, like its built-in storage or asking Claude questions, are swapped for the Kao SDK, so saves still work and sync to players’ accounts.
# Turn this artifact into a KaoGames game
I want to publish this artifact as a game on KaoGames (kaogames.com). Give me the whole game as ONE complete, self-contained HTML file that runs on its own in a browser.
## Rules
- One file: everything inline, starting with <!doctype html>. If it is a React artifact, include React from a CDN and compile it so it runs as plain HTML (no build step).
- Scripts from public CDNs (cdnjs, jsdelivr, unpkg) are fine; nothing that needs a server or an API key.
- Replace anything that only works inside Claude (window.claude, window.storage, artifact storage, asking Claude) with the Kao SDK: add <script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>, start the game after Kao.init() resolves, call Kao.ready() once the first frame is drawn, and keep the save in one key with Kao.get('save', defaults) / Kao.set('save', value).
- No popups (window.open), forms, alert/confirm/prompt or its own fullscreen button: the KaoGames player blocks them.
- Fill whatever size it is given and handle resize. If it works with touch, make it play well upright on a phone too.
## When you're done
Give me the complete file in one code block, then list what you changed, and suggest a title, a one-line tagline and up to 3 genres for the listing.Content-Security-Policy:
frame-ancestors 'self' https://kaogames.com Use the address from your game’s Embed option (it looks like itch.io/embed-upload/123456), not the game’s page.
claude.ai links can’t be shown on other sites. Use the Publish my Claude artifact prompt instead.
# Make my hosted game linkable on KaoGames My game is already online and I want to publish it on KaoGames (kaogames.com) by linking to it, so it shows inside their player in an iframe. 1. Find the address that is just the game (its own index.html), not a page with the game embedded in it. 2. Check my hosting config for X-Frame-Options or a Content-Security-Policy frame-ancestors rule. Remove X-Frame-Options, and if there is a CSP, change it to: frame-ancestors 'self' https://kaogames.com 3. Make sure the game fills whatever size it is given, handles resize, and doesn't use popups, forms or its own fullscreen button (the player blocks them). 4. Add the Kao SDK (<script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>, start after Kao.init(), Kao.ready() on the first frame, saves through Kao.get/Kao.set) so loading and cloud saves work. 5. Tell me the exact address to paste into Link it, and what you changed.
In index.html, before your game's own scripts:
<script src="https://kaogames.com/sdk/kao-1.1.0.js"></script> It resolves once the player's save is ready, or after 1.5 seconds if the page never answers (when you open the game on its own).
Kao.init().then(function () {
startGame(); // your code
}); While loading assets, call Kao.progress(loaded / total) with a number from 0 to 1. Once the first frame is drawn, call Kao.ready(): the site hides its loading screen straight away. Without it the screen waits up to 12 seconds.
If loading fails, call Kao.fail('message') so players see an error instead of a stuck loading bar. Uncaught errors are reported for you.
# Add the Kao SDK to my HTML5 game I'm publishing my HTML5 game on KaoGames (kaogames.com). ## The SDK One script: <script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>. It must load before my game's own code, and creates a global `Kao`: - Kao.init(): a Promise that resolves when the player's save is ready. Start the game only after it resolves. - Kao.progress(n): loading progress from 0 to 1, shown on the site's loading bar. - Kao.ready(): call once the first frame is on screen. It hides the site's loading screen. - Kao.fail(message): shows an error instead of an endless loading screen. - Kao.get(key, fallback) and Kao.set(key, value): synchronous saves of any JSON value. ## What to do 1. Add the script tag to index.html before my game's scripts. 2. Wrap my game's startup in Kao.init().then(...). 3. If my game loads assets, report real progress with Kao.progress, and call Kao.ready() right after the first frame is drawn. ## Rules Don't change gameplay. Show me every file you changed.
Kao.init().then(function () {
var save = Kao.get('save', { level: 1, best: 0 });
startGame(save);
}); Kao.set('save', save);It's synchronous and writes to the browser immediately. For signed-in players, a copy goes to their account a few seconds later and again when they leave.
# Switch my game's saves to Kao cloud saves
My HTML5 game is going on KaoGames, which gives free cloud saves through the Kao SDK (loaded on the page as the global `Kao`). Replace my game's save system with it.
## How Kao saves work
- Read with Kao.get(key, fallback) and write with Kao.set(key, value). Both are synchronous and take any JSON value.
- Only read saves after Kao.init() has resolved.
- Saves sync as a whole and the newest copy wins, so keep everything that belongs together (progress, unlocks, settings) in ONE key, for example Kao.set('save', {...}).
- Keep the save under 64 KB as JSON. Save progress, never caches or assets.
## What to do
- Remove every direct use of localStorage, sessionStorage, IndexedDB and cookies for saving.
- If players may already have an old save, read it once on startup, copy it into Kao.set('save', ...), then use Kao from then on.
## When you're done
List every place the game saves and confirm each one now calls Kao.set.Games run in an iframe with sandbox="allow-scripts allow-same-origin allow-pointer-lock". These fail silently there:
Desktop gives you a 16:9 area; phones give you the whole screen in portrait. Size to the window and follow it:
html, body { margin: 0; height: 100%; overflow: hidden; }function fit() {
var r = Math.min(devicePixelRatio, 2);
canvas.width = innerWidth * r;
canvas.height = innerHeight * r;
canvas.style.width = innerWidth + 'px';
canvas.style.height = innerHeight + 'px';
}
addEventListener('resize', fit);
fit(); Write ./assets/hero.png, not /assets/hero.png or a full URL. Every version of your game lives in its own folder, so absolute paths load the wrong files.
Pointer lock, WebGL, Web Audio (after the first tap or click), and WebAssembly all work.
# Fix what breaks in the KaoGames player My HTML5 game will run on KaoGames inside a sandboxed iframe (sandbox="allow-scripts allow-same-origin allow-pointer-lock"). Find and fix anything that won't work there. ## Blocked in the player - window.open, target="_blank" links, <form> submissions and anything that navigates top or parent. Remove them or replace them with in-game UI, and remove links to other sites. - requestFullscreen. Remove fullscreen buttons; the site has its own. - alert, confirm and prompt. Replace them with in-game UI. - Any check that refuses to run inside an iframe. Remove it. ## Sizing and paths - Fill whatever size the game is given and handle resizing. Desktop is usually a 16:9 area; phones are full-screen portrait. Use window.innerWidth/innerHeight, listen for resize, and avoid fixed page sizes and page scrollbars. - Every asset path must be relative (./assets/x.png, not /assets/x.png or a full URL). ## When you're done List each problem with its file and line, then fix them.
Use pointer events, and stop the page scrolling or zooming under the game:
canvas.addEventListener('pointerdown', onPress);
canvas.addEventListener('pointermove', onMove);
canvas.addEventListener('pointerup', onRelease);canvas { touch-action: none; } Show on-screen buttons the first time the screen is touched. That's more reliable than guessing the device:
addEventListener('touchstart', showTouchControls, { once: true }); Tick "Plays on phones" for your game in Your games. Phone players only see games marked as phone-ready.
# Make my HTML5 game playable on phones On KaoGames, games that work on phones get far more players. ## Controls - Add touch controls for everything that needs a keyboard or mouse (on-screen buttons, taps or swipes, whatever suits the game). Show them only on touch devices. - Use pointer events so mouse and touch share one code path. - Stop the page scrolling or zooming during play (touch-action: none on the game canvas). ## Layout - Work on a portrait phone screen as well as a landscape desktop one, and handle rotation and resizing. - Make tap targets at least 44px and keep text readable at phone size. ## Speed Cap the device pixel ratio at 2 and avoid huge textures. ## When you're done Tell me how to test it in a desktop browser with device emulation.
Download both from the Unity section of the technical reference below. Your PlayerPrefs calls then save to the cloud on KaoGames, and work as before everywhere else. Calls written as UnityEngine.PlayerPrefs in full skip it.
In your template's index.html (make a custom one under Assets/WebGLTemplates/ if you use a built-in template):
<script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>
<script src="Build/{{{ LOADER_FILENAME }}}"></script>
<script>
Kao.init()
.then(function () {
return createUnityInstance(canvas, config, function (p) { Kao.progress(p); });
})
.then(function () { Kao.ready(); })
.catch(function (e) { Kao.fail(String(e)); });
</script> Publishing Settings: Compression Format Brotli or Gzip, Decompression Fallback off. KaoGames serves compressed files with the right headers.
# Set up my Unity WebGL game for KaoGames Set up my Unity WebGL game for KaoGames (kaogames.com), with cloud saves and a real loading bar. ## 1. Add the save plugin Download these two files into my project: - https://kaogames.com/sdk/unity/KaoPlayerPrefs.cs into Assets/ (anywhere, but not inside a folder with its own .asmdef) - https://kaogames.com/sdk/unity/KaoPrefs.jslib into Assets/Plugins/WebGL/ KaoPlayerPrefs.cs defines a global PlayerPrefs class, so existing PlayerPrefs calls become cloud saves on KaoGames with no code changes, and behave as normal everywhere else. Check that no script writes UnityEngine.PlayerPrefs in full; if any do, change them to just PlayerPrefs. ## 2. Edit the WebGL template In my WebGL template's index.html (make a custom template under Assets/WebGLTemplates/ if I use a built-in one): - Add <script src="https://kaogames.com/sdk/kao-1.1.0.js"></script> before the Unity loader script. - Call createUnityInstance only after Kao.init() resolves. - In createUnityInstance's progress callback, call Kao.progress(progress). - When the instance is created, call Kao.ready(). If it fails, call Kao.fail(message). ## 3. Player Settings Publishing Settings: Compression Format Brotli (or Gzip), Decompression Fallback off. KaoGames serves compressed files with the right headers. ## 4. Fit the page Make the canvas fill the page and follow window resizes, instead of a fixed size. Remove Application.OpenURL and fullscreen toggles; the site has its own fullscreen button. ## 5. Build and zip Build, then zip the contents of the build folder so index.html is at the top of the zip (limits: 30 MB zipped, 80 MB unpacked).
my-game.zip
├─ index.html
├─ thumb.png optional, 16:9, becomes your picture in Discover
└─ assets/ ...One wrapping folder around everything is fine; it is removed on upload.
Run these next to your build folder (here called build). macOS or Linux:
cd build && zip -r ../my-game.zip .Windows (PowerShell):
Compress-Archive -Path build\* -DestinationPath my-game.zip Leave out source maps, tests and anything your game never loads.
# Package my HTML5 game for upload to KaoGames ## Requirements - A .zip with index.html at the top level, not inside a folder. - At most 30 MB zipped, 80 MB unpacked and 1,500 files. Under 15 MB unpacked loads much faster on phones. - Relative paths for every asset. - Optional: a 16:9 picture named thumb.png, thumb.jpg or thumb.webp at the top level (1280x720 is ideal). It becomes the game's picture in Discover. ## What to do - Make a production build: minified, no source maps, no test or dev files. - Remove unused assets, and compress images where it won't visibly hurt quality. - Give me the exact commands to create the zip on my computer. ## When you're done List the zip's top-level contents so I can check index.html is at the root.
We crop it three ways: 16:9 on game cards, 4:3 on homepage tiles and wide 21:8 for Today's pick. Put anything that matters (your hero, the title) in the middle 960 × 480, and let the edges be background.
1280 × 720
┌──────────────────────────────┐
│ ┌──────────────────┐ │
│ │ safe: 960 × 480 │ │
│ └──────────────────┘ │
└──────────────────────────────┘ Easiest: take a screenshot of your best moment at 1280 × 720 with the interface hidden. Better: compose one from your own sprites or models, with a background, your hero large and in front, and an effect or two, then add the title.
Show what the game really looks like, and only use art you made or have the rights to.
# Make a thumbnail for my game from its own assets My game is going on KaoGames (kaogames.com). Make it a striking thumbnail using the game's own art. ## Step 1: Look at what I have Go through my project's assets (sprites, textures, 3D models, backgrounds, logos, fonts, colour palette) and the game's code, and tell me what the game is about and what its most exciting moment is. Then pitch three thumbnail ideas in one line each, and ask me to pick one. ## Step 2: Build it Write something that composes the image from my actual asset files, so I can re-run it whenever the art changes: - For a 2D game: an HTML page with a canvas (or a small Node or Python script) that layers a background, my main character or object large, and an effect or two, then saves a PNG. - For a 3D game: a small three.js scene that loads my models, frames a dramatic camera angle and saves a PNG. ## Rules - 1280 × 720 (16:9), saved as thumb.png, under about 400 KB. - KaoGames crops thumbnails to 4:3 and to a wide 21:8, so keep the subject and any title inside the centre 960 × 480. - One big subject filling a third of the frame or more, strong contrast, and a moment of action rather than a menu. - If there's a title, two or three words, bold, with an outline, readable when the whole image is 150 px wide. - No small text or interface elements. Only use assets from my project. Don't invent features the game doesn't have. ## When you're done Show me the result, explain how to re-run it, and remind me to put thumb.png at the top level of my upload zip.
Upload the zip in Your games. The automatic checks run in seconds, and KaoGames reviews it before it goes live.
# Check my game before I upload it to KaoGames For each item answer pass, fail or not sure, with the file and line for every fail. ## Checklist 1. index.html is at the top of the build, and every asset path is relative. 2. The Kao SDK (https://kaogames.com/sdk/kao-1.1.0.js) loads before the game code, the game starts inside Kao.init().then(...), and Kao.ready() is called once something is on screen. 3. Saves use only Kao.get/Kao.set, in one key, under 64 KB. No localStorage, sessionStorage, IndexedDB or cookies. 4. No window.open, target="_blank", forms, alert/confirm/prompt, requestFullscreen, or top/parent navigation. 5. The game fills its container and handles resizing, in landscape and portrait. 6. Touch controls work, if the game is meant to be playable on phones. 7. The build is at most 30 MB zipped and 80 MB unpacked (ideally under 15 MB), with no source maps or dev files. 8. No errors in the console on startup. ## When you're done Finish with the three most important fixes.
KaoGames has an MCP server, so assistants like Claude Code and Cursor can publish for you: create listings, upload builds, check review status, read your analytics and get share links. KaoGames still reviews game builds before they go live, and an assistant can never approve games or spend money.
claude mcp add --transport http kaogames https://kaogames.com/api/mcp --header "Authorization: Bearer YOUR_TOKEN" Cursor (.cursor/mcp.json) and other clients with remote MCP: {
"mcpServers": {
"kaogames": {
"url": "https://kaogames.com/api/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
} Claude Desktop and clients that only run local servers: {
"mcpServers": {
"kaogames": {
"command": "npx",
"args": ["mcp-remote", "https://kaogames.com/api/mcp", "--header", "Authorization:Bearer YOUR_TOKEN"]
}
}
} Tools: whoami · get_publishing_guide · list_my_games · create_game · update_game · begin_upload · link_game · get_status · get_analytics · get_share_kit
The Kao SDK is one small script for games on KaoGames. It tells the site when your game is loading and when it is ready, and gives you a save API that works in every browser and follows signed-in players to every device. Our own games use the same file.
Load the SDK before your game's own code, wait for Kao.init(), then start:
<script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>
<script>
Kao.init().then(function () {
const save = Kao.get('save', { level: 1, coins: 0 });
startGame(save); // your code
});
// While loading: Kao.progress(0.5);
// First frame drawn: Kao.ready();
// Progress changed: Kao.set('save', { level: 2, coins: 140 });
</script> Players who aren't signed in still get saves, kept in their browser. Signed-in players get the same save on every device.
| Call | What it does |
|---|---|
Kao.init() | Returns a promise that resolves once the player's save is ready to read. Call it once at startup and read saves after it resolves. If the page never answers (for example when you open the game on its own), it resolves after 1.5 seconds. |
Kao.progress(n) | Loading progress from 0 to 1, shown on the site's loading bar. |
Kao.ready() | Your game has drawn its first frame, so the site hides its loading screen. Without it, the screen stays up for 12 seconds after your page loads. |
Kao.fail(message) | Shows an error instead of an endless loading screen. Uncaught errors are reported for you. |
Kao.get(key, fallback) | Reads a saved value, or fallback if there is none. Synchronous. |
Kao.set(key, value) | Saves any JSON value and returns true, or false if the browser refused (for example, storage is full). Synchronous. |
Kao.version | The SDK version, currently "1.1.0". |
Kao.set writes straight to the player's browser, so a save is never lost to a network problem.Kao.set, and again when the player leaves, the save is copied to their account.Games run in a sandboxed frame with allow-scripts allow-same-origin allow-pointer-lock. These fail silently there, even though they work when you test the game on its own:
window.open, forms, target="_blank" links, alert/confirm/prompt, or navigating the top page.requestFullscreen. KaoGames has its own fullscreen button.localStorage or sessionStorage directly. Use Kao.get and Kao.set, which keep each game's saves apart.For a good experience: call Kao.ready() as soon as something is on screen, fill whatever size you're given and handle resizing, support touch if you can, and use relative paths for assets.
| Zip size | Up to 30 MB |
| Unpacked size | Up to 80 MB. Over 15 MB, the first load is slow on phones. |
| Files | Up to 1,500 |
| Entry point | index.html at the top of the zip (one wrapping folder is fine; it's removed) |
| Thumbnail | Optional thumb.png, .jpg or .webp at the top, 16:9 |
| Compressed files | .br and .gz are served with the right encoding, so Unity's compressed builds work as they are |
Two files give a Unity WebGL game cloud saves with no code changes:
KaoPlayerPrefs.cs (anywhere in Assets/, outside any
folder with its own .asmdef) and KaoPrefs.jslib (in
Assets/Plugins/WebGL/). The first defines a global PlayerPrefs class, so
your existing PlayerPrefs calls save through the Kao SDK on KaoGames and behave
as normal everywhere else. Existing progress carries over the first time a key is read.
Then load the SDK in your WebGL template's index.html and start Unity once it's ready:
<script src="https://kaogames.com/sdk/kao-1.1.0.js"></script>
<script src="Build/{{{ LOADER_FILENAME }}}"></script>
<script>
Kao.init()
.then(function () {
return createUnityInstance(canvas, config, function (p) { Kao.progress(p); });
})
.then(function () { Kao.ready(); })
.catch(function (e) { Kao.fail(String(e)); });
</script> Each SDK version lives at its own address and never changes, so your game keeps working exactly as tested.
Questions? Ask in the KaoGames Discord or email developers@kaogames.com.