Skip to content

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.

Terminal window
tulpar game.tpr # compile + run
tulpar build game.tpr mygame # standalone native binary
Terminal window
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 / .wasm are appended (a trailing .html you write yourself is stripped, so -o game and -o game.html are 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.
Terminal window
tulpar build --target=android game.tpr out # APK staging (arm64-v8a + x86_64)
tulpar build --apk game.tpr out # → signed APK in one step
tulpar build --aab game.tpr out # → Play Store bundle

From 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.

Bundle images, fonts and audio into the web/Android build:

Terminal window
TULPAR_WEB_ASSETS=./assets tulpar build --apk game.tpr out

Files are embedded so load_texture("player.png"), load_font(...), load_sound(...) resolve at runtime on every platform.

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 | aab
entry = "game.tpr"
output = "my-arcade"
Terminal window
tulpar build # reads [build] → produces the signed my-arcade.apk

CLI flags still win (tulpar build --target=web game.tpr overrides the manifest), so the config is a default, not a lock.

  • Web: copy the .html / .js / .wasm (and any .data) to any static host and serve over HTTP.
  • Android: the signed .apk installs directly (adb install -r app.apk); the .aab is what you upload to the Google Play Console. Bump version_code in [android] for every release.

The shipped Tulpar Arcade app — 13 games in one launcher — is built exactly this way.