Building & Publishing Games
One game module compiles to desktop, the web and Android from the same
source. import "arcade" and import "tame" behave identically on all three.
Desktop
Section titled “Desktop”tulpar game.tpr # compile + runtulpar build game.tpr mygame # standalone native binaryWeb (WebAssembly)
Section titled “Web (WebAssembly)”tulpar build --target=web game.tpr out/game# → out/game.html + out/game.js + out/game.wasm- Serve the files over HTTP (not
file://). - The output directory must already exist.
- The output name is a base:
.html/.js/.wasmare appended (a trailing.htmlyou write yourself is stripped, so-o gameand-o game.htmlare equivalent). - Every web build gets a touch gamepad for free — it appears only on touch devices and drives the game through synthetic key events, so arcade games are mobile-playable in the browser with no extra work.
Android (APK / AAB)
Section titled “Android (APK / AAB)”tulpar build --target=android game.tpr out # APK staging (arm64-v8a + x86_64)tulpar build --apk game.tpr out # → signed APK in one steptulpar build --aab game.tpr out # → Play Store bundleFrom one compiled module the driver emits both device (arm64-v8a) and emulator
(x86_64) objects and links them into a NativeActivity app. import "arcade" runs
on-device unchanged, and its on-screen D-pad / joystick / action button make every
arcade game touch-playable.
The app’s identity (package name, label, icon, orientation, version) comes from
[android] in tulpar.toml — see below.
Assets
Section titled “Assets”Bundle images, fonts and audio into the web/Android build:
TULPAR_WEB_ASSETS=./assets tulpar build --apk game.tpr outFiles are embedded so load_texture("player.png"), load_font(...),
load_sound(...) resolve at runtime on every platform.
The tulpar.toml config build
Section titled “The tulpar.toml config build”Instead of remembering a long command, describe the target once in tulpar.toml
and run a bare tulpar build:
name = "my-arcade"version = "1.0.0"
[android]package = "dev.example.arcade"name = "My Arcade"icon = "icon.png"orientation = "landscape"version_code = "1"version_name = "1.0"
[build]target = "apk" # desktop | web | android | apk | aabentry = "game.tpr"output = "my-arcade"tulpar build # reads [build] → produces the signed my-arcade.apkCLI flags still win (tulpar build --target=web game.tpr overrides the manifest),
so the config is a default, not a lock.
Publishing
Section titled “Publishing”- Web: copy the
.html/.js/.wasm(and any.data) to any static host and serve over HTTP. - Android: the signed
.apkinstalls directly (adb install -r app.apk); the.aabis what you upload to the Google Play Console. Bumpversion_codein[android]for every release.
The shipped Tulpar Arcade app — 13 games in one launcher — is built exactly this way.