Skip to content

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.html must not set GODOT_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:

json
{
  "engine": {
    "kind": "godot",
    "entry": "index",
    "files": ["index.js", "index.wasm", "index.pck"],
    "threads": false
  }
}
FieldWhat it is
kind"godot" or "unity"
entryThe export's name without an extension, relative to engine/: Godot index, Unity Build/<name>
filesThe export's files, relative to engine/ (1 to 512). Each one must be in the package's engine/ folder
threadsMust be false

A Unity example:

json
{
  "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:

TierDownloadWho gets it
Sup to 16 MBEvery reviewed engine app
Mup to 64 MBOn 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:connect with 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 save and load actions 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-lock permission, and the engine's own pointer lock works (Godot Input.mouse_mode = Input.MOUSE_MODE_CAPTURED, Unity Cursor.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.