Game package format
A game is delivered as one folder. This page lists every rule the platform's validator applies to that folder. A game that breaks a rule marked as an error is not published.
The folder at a glance
my-game/
index.html the page the game starts from
js/ img/ audio/ anything the game loads, referred to by relative path
game.json optional: title, description, controls and other metadata
thumbnail.png optional: 16:9 artwork for the game's card and page
Only index.html (or another entry page, see below) is required. A game can be that single file.
The entry HTML file
The entry file is the page a visitor's browser loads when they press Play. It is chosen in this order:
- The file named by
"entry"ingame.json, if that field is set. The file must exist in the folder. - Otherwise, a file named
index.htmlorindex.htmat the top level of the folder. - Otherwise, the only
.htmlor.htmfile at the top level, whatever it is called.
It is an error when:
- There are several HTML files at the top level and none is
index.html. Rename one, or set"entry". - There is no HTML file at the top level. If the game's files sit one folder down, move them up a level or set
"entry". - The entry file does not look like an HTML document. It must contain at least one of an
html,body,scriptorcanvastag, or an HTML doctype.
One limit applies to the entry file in particular: keep it under 6 MB. The platform reads the entry file in order to inspect it, and it does not read HTML or CSS files larger than that. An entry file over the limit is rejected with the message that it could not be read. This matters mostly for single-file games with large assets embedded in the page.
Size limits
| Limit | Value |
|---|---|
| Files in a game | 2,000 |
| Size of one file | 50 MB |
| Size of the whole game | 300 MB |
| Length of a file path | 240 characters |
| Entry HTML file, in practice | 6 MB |
An empty folder is an error. An empty file produces a warning.
File types
Only the file types on this list are accepted and served. A file with any other extension, or with none, is an error. Upper and lower case in the extension make no difference.
| Kind | Extensions |
|---|---|
| Pages and code | .html .htm .js .mjs .css .wasm |
| Data and text | .json .txt .xml .csv .map .webmanifest |
| Images | .png .jpg .jpeg .gif .webp .avif .svg .ico .bmp .ktx2 .basis |
| Audio | .mp3 .ogg .oga .opus .wav .m4a .aac .flac |
| Video | .mp4 .webm |
| Fonts | .woff .woff2 .ttf .otf |
| 3D models | .glb .gltf |
| Game and engine data | .bin .data .dat .pck .unityweb .atlas .fnt .tmx .tsx .glsl .vert .frag |
Each file is served with a fixed content type decided by its extension. .tsx is treated as a tileset file and served as XML, not as script source.
Files that are rejected
These are errors, with a message naming the file. They exist to stop private material being published by accident.
| Rejected | Examples |
|---|---|
| Version-control data | a .git folder |
| Dependency trees | a node_modules folder |
| Environment and secrets files | .env, .env.local, .dev.vars |
| Keys and certificates | .pem .key .p12 .pfx .crt .cer .keystore .jks |
| Credential files | id_rsa, id_ed25519, .npmrc, .htpasswd, credentials.json, secrets.json |
| Editor backups | names ending in ~, .bak, .swp, .orig or .tmp |
| Server-side or executable code | .php .asp .aspx .jsp .cgi .sh .bat .cmd .exe .dll .so .dylib .py .rb .pl |
| Any other hidden file or folder | any name beginning with a dot |
Files that are left out
Some files may sit in the folder without being published. They are skipped quietly.
- Files for the publisher, at the top level only:
game.json,thumbnail.png,thumbnail.jpg,thumbnail.jpeg,thumbnail.webp, and files namedREADME,LICENSEorCHANGELOGwith or without an extension. These are read where relevant but never served to players. - Operating-system clutter, anywhere in the folder:
.DS_Store,Thumbs.db,desktop.ini,__MACOSX,.gitkeep,.gitignoreand.gitattributes.
The publisher files are skipped only at the top level. A README.md inside a subfolder, for example, is treated as a game file, and since .md is not an accepted type it is an error.
File names and paths
Every file path, measured from the top of the folder, must be safe to use in a web address. A path is an error if it:
- Contains a backslash, a control character, or any of the characters
<,>,",|,?,*,#or%. - Has a folder or file name that ends with a space or a dot.
- Is longer than 240 characters.
Spaces and parentheses inside a name are accepted.
Two files whose paths differ only by upper and lower case, such as Logo.png and logo.png, are an error. They would collide on systems that ignore case.
Relative paths only
Refer to every file the game loads by a path relative to the file that refers to it: img/ship.png, not /img/ship.png and not a path on your own disk.
The validator reads the entry page, every other HTML file and every CSS file, and checks each reference it finds. HTML and CSS files larger than 6 MB are not read.
| Problem | Result |
|---|---|
| The referenced file is not in the folder | Error |
| The file exists but the reference uses different upper or lower case | Error. Addresses are case-sensitive once published. |
The reference climbs out of the game folder with ../ | Error |
The references it reads are:
- In HTML: the source of scripts, images, audio, video, media sources and tracks, frames, embeds and objects; the link target of stylesheets, icons and other linked resources; video posters; and SVG
imageandusereferences. - In CSS files and
styleblocks:url(...)values and@importrules.
References to data: and blob: addresses, page fragments beginning with #, and mailto: and tel: links are ignored. So are link tags whose relation is canonical, alternate, author, license, help, dns-prefetch or preconnect.
What the validator cannot see
Two things are worth testing yourself, because the automatic checks do not cover them.
- Files loaded by script. A file that your JavaScript requests at run time, for example with
fetchor by setting an image's source in code, is not checked. If it is missing, the game fails for players, not at validation. - Paths that begin with a slash. A game is not served from the root of its address but from a path that includes its build identifier. A reference such as
/img/ship.pngtherefore does not resolve once published. The validator checks that the file exists but does not flag the leading slash.
A good test for both: serve the folder from a sub-path of a local web server, open the game there with the network otherwise disconnected, and watch the browser console for failed requests.
No external resources
A reference in HTML or CSS to another website, whether it begins with http://, https:// or //, is an error:
Loads resources from https://cdn.example.com, which the game sandbox blocks. Bundle the files with the game, or add "https://cdn.example.com" to permissions.network in game.json.
The simplest fix is to copy the file into the game folder.
The alternative is to list the origin under permissions.network in game.json. Only https origins can be listed, and a network permission has to be agreed with the team; see Sandbox and permissions.
Warnings
Warnings do not stop a game from being published. They point at things that will not work, or may not work, once the game is in its sandbox.
| The game... | Warning |
|---|---|
| Has no viewport meta tag | It may render tiny on phones. |
| Registers a service worker | A sandboxed game cannot rely on one; it will be ignored or fail. |
Uses document.cookie | Cookies are unreliable inside the sandbox; prefer localStorage. |
| Tries to navigate the top-level page | The sandbox blocks this. |
Calls alert, confirm or prompt | Blocked unless permissions.modals is set. |
| Opens links in new windows or tabs | Blocked unless permissions.popups is set. |
Calls network APIs such as XMLHttpRequest, WebSocket or fetch with a full address | Requests to origins not listed in permissions.network are blocked. |
| Contains an empty file | The file is empty. |
These checks look for patterns in the source of the entry HTML file, and only there. They can miss code that is assembled at run time, they can flag code that is present but never runs, and they do not read separate script files at all.
The same is true of what the platform detects automatically about a game: the inputs it uses, its preferred orientation and the abilities it needs. If your game's code lives in separate .js files, state those things in game.json yourself. See the metadata reference and Sandbox and permissions.
The slug
Every game has a slug: its permanent identifier. It appears in the game's page address and in the name of the subdomain the game is served from, so it cannot be changed later without the game becoming a different game.
By default the slug is the folder name, lower-cased, with anything other than letters and digits turned into hyphens. game.json can set it explicitly. The rules, and the list of reserved words, are in the metadata reference.
Where validation happens
The same checks run more than once: when the game is prepared for import, and again on the platform's server, which reads the stored files itself and has the final say. A file's size and checksum are verified when it is stored.
A game that fails stays unpublished and nothing already live is changed. Publishing workflow describes what happens after a game passes.