Engine apps: Godot and Unity games
An engine app is a game made in Godot 4.3+ or Unity 2021.3+, exported for the web and run on a token page. You upload the export folder as it is. The platform's boot component starts it, so you write no viewer code.
What runs
Single-threaded exports only. A threaded build needs cross-origin isolation, which a token page doesn't have, and Safari can't run one in an app's frame at all. So a manifest with threads: true is refused.
- Godot: export for Web with Thread Support off (Godot 4.3 or later). The export's
index.htmlmust not setGODOT_THREADS_ENABLED = true. - Unity: the default WebGL build, which is single-threaded (Unity 2021.3 or later). Uncompressed, Brotli and Gzip builds all work.
The engine block
Add an engine block to your manifest:
{
"engine": {
"kind": "godot",
"entry": "index",
"files": ["index.js", "index.wasm", "index.pck"],
"threads": false
}
}| Field | What it is |
|---|---|
kind | "godot" or "unity" |
entry | The export's name without an extension, relative to engine/: Godot index, Unity Build/<name> |
files | The export's files, relative to engine/ (1 to 512). Each one must be in the package's engine/ folder |
threads | Must be false |
A Unity example:
{
"engine": {
"kind": "unity",
"entry": "Build/WebGL",
"files": ["Build/WebGL.loader.js", "Build/WebGL.framework.js.br", "Build/WebGL.data.br", "Build/WebGL.wasm.br"],
"threads": false
}
}File names may use letters, digits, spaces, ., _, - and / for folders. Folders are kept as they are, so a Unity StreamingAssets/ folder works.
The engine/ folder
Your export folder goes in engine/, beside your manifest. The package needs no bundle.js: the platform's boot component runs the export. Every file in engine/ is covered by the package's HASHES.json, like the rest of your app, and is served from your app's own version:
https://apps.chaindaddy.io/{appId}/{version}/engine/<file>Files are stored compressed with brotli when you submit, and served with the headers the engines need (application/wasm for .wasm, so it compiles while it downloads). A Unity .br or .gz file is kept as it is and served with its own encoding. Each version's files never change, so a returning player downloads nothing.
Test locally
Run chaindaddy app dev with your export in engine/. It prints a report (threads off, the files your entry needs, and the size against the tiers). No viewer code is needed.
Once you've submitted a build, you can also play it on your own token page before it's reviewed: see Preview a build on your own token page. The preview runs the export you uploaded, for you alone, with an unreviewed build's limits.
Size tiers
Sizes are what a player downloads (brotli), for the whole engine/ folder:
| Tier | Download | Who gets it |
|---|---|---|
| S | up to 16 MB | Every reviewed engine app |
| M | up to 64 MB | On request |
Whatever the tier, the export may be at most 256 MB uncompressed, and 64 MB for any one file. A phone has to hold the game in memory.
Godot's engine alone is about 8 MB to download, so a small Godot game fits in S. A small Unity release build is about 6 MB.
What the frame allows
Your game runs in its own isolated frame, like every third-party app. In that frame:
- It can load its own version's files and nothing else, unless you declare
net:connectwith your server's origins (see App Manifest). - Saves go through the platform. Browser storage (IndexedDB) isn't available in the frame, so a save written there is gone on reload. Keep progress with the
saveandloadactions instead: one save of up to 256 KB per player, kept for that player on your token page. A player has to be signed in to save; a visitor who isn't loads nothing and starts fresh. - Fullscreen comes from the platform's own button, not the engine's. Hide your engine's fullscreen button.
- Pointer lock (for mouse-look games): declare the
ui:pointer-lockpermission, and the engine's own pointer lock works (GodotInput.mouse_mode = Input.MOUSE_MODE_CAPTURED, UnityCursor.lockState = CursorLockMode.Locked). The browser locks the pointer only after the player clicks the game, and Esc releases it. Without the permission, the lock is refused. - Audio starts after the player's first tap on Safari, as on any web page.
Engine apps haven't been tested on phones yet, so don't promise players a mobile version.
Review
Submitting reads every file in engine/, not just your bundle, and refuses a threaded build (its .wasm has shared memory, or its index.html sets GODOT_THREADS_ENABLED = true) or one made before Godot 4.3 or Unity 2021.3, the version read from your .pck, or your .data and .wasm. Anything it can't read, such as a .unityweb file, a reviewer checks by hand.