Build for desktop and Android
Run the same src/game.ts on Windows, macOS, Linux and Android, then package and verify a release players can install.
On this page
Platform support
@threenative/runtime-native is a native host for your game entry. It draws the Three.js scene
with its own renderer, not inside a WebView. ThreeNative is alpha and all packages are 0.x. Keep
the @threenative package versions in step with each other.
| Platform | Renderer | Status |
|---|---|---|
| Web | WebGPU, WebGL2 fallback | Supported |
| Windows, macOS, Linux | Native host | Supported |
| Android | Native host | Supported |
| iOS | None | Not supported |
Build for desktop
The minimal template sets nativeEntry: "src/game.ts" in threenative.config.ts and ships a
desktop build script. Native builds bundle that entry as the game's single native module.
pnpm create threenative my-game --template minimal
cd my-game
pnpm install
pnpm exec threenative doctor --text --target desktop
pnpm build:desktopDoctor reports the missing tools for the target you name. You can keep developing in the browser and add native tools later. Build and test on each desktop OS you ship.
Build for Android
pnpm exec threenative doctor --text --target android
pnpm build:androidThe build downloads prebuilt runtime files for your installed package version. It reads them from
the release's prebuilt-lock.json and checks each SHA-256. You need the Android SDK and a JDK. You
do not need an NDK or CMake.
If you work offline or keep the files locally, set THREENATIVE_PREBUILT_MANIFEST to a local
prebuilt-lock.json. The checksum checks still run.
build:android makes a debug APK. A release build needs your signing key and refuses to fall back
to a debug key:
pnpm exec threenative build --target android --mode release --format apk
pnpm exec threenative build --target android --mode release --format aabSupply the key through ORG_GRADLE_PROJECT_threenativeKeystore,
ORG_GRADLE_PROJECT_threenativeKeystoreAlias, ORG_GRADLE_PROJECT_threenativeKeystorePassword and
ORG_GRADLE_PROJECT_threenativeKeyPassword.
Check textures and sound on the device. Android has no Basis transcoder or Meshopt decoder. See Assets and Audio for the formats it loads.
Choose the UI renderer
ui.renderer in threenative.config.ts picks how menus and HUD draw on native targets.
| Setting | Template | How the UI draws |
|---|---|---|
ui: { renderer: "native" } |
minimal |
In the 3D scene. No src/ui/. |
ui: { renderer: "web" } |
starter |
src/ui/ in a WebUI overlay above the native renderer. |
The WebUI overlay talks to the game through state updates and action messages. Test keyboard focus, touch, pause and resume in the UI mode you ship.
Package a desktop release
pnpm exec threenative build --target desktop --mode releaseRelease mode wraps the executable, the ui/ bundle and the non-system libraries it loads into one
relocatable container:
| OS | Output |
|---|---|
| Linux | tar.gz with lib/ and a .desktop entry |
| macOS | <Name>.app inside a ZIP |
| Windows | Portable ZIP and a *-setup.exe installer |
Each container carries threenative-container.json, which lists every file with its SHA-256.
Packaging on Windows needs zip, NSIS 3, rcedit and dumpbin. A missing tool stops the build
with TN_DESKTOP_ARCHIVE_TOOL_MISSING or TN_DESKTOP_RESOURCE_TOOL_MISSING.
The container does not ship the web view or windowing stack. The player's machine provides them:
| OS | Player prerequisite |
|---|---|
| Linux | WebKitGTK 4.1 and GTK 3 |
| Windows | WebView2 Evergreen Runtime, when WebUI is selected. The installer adds it if missing. |
| macOS | System WebKit, included with macOS |
Extract the container, then verify it:
node node_modules/@threenative/runtime-native/scripts/verify-starter-desktop.mjs \
--container <unpacked-directory> \
--config .threenative/build/config.jsonThe verifier checks file integrity. On Linux it also checks that the player prerequisites resolve.
With --config it compares the app name, icon and loading sequence against your project. It
refuses a container that still carries the engine's default icon.
Desktop containers are unsigned unless you configure signing, for example with
THREENATIVE_DESKTOP_SIGN=1 and the matching identity variables. See
RELEASE-SIGNING.md. Run your playtests against the
extracted build before you ship.
Build the runtime from source
If you change the native runtime itself, set THREENATIVE_RUNTIME_SOURCE to
packages/runtime-native in a full engine checkout. The packager needs CMakeLists.txt and the dependencies that
node scripts/download-deps.mjs stages in that checkout. An installed npm package has neither.
This variable does not fix a failing download. For that, check the installed version, the manifest
and the network error.