What's new in Kriya 0.5.4: a game runner that isn't secretly the editor
Portable Windows and macOS exports used to clone the entire Kriya editor and hope nobody noticed. A dedicated, prebuilt game runner replaces that trick and cuts a portable export to a fraction of its old size.
0.5.3 made every export target signable. 0.5.4 fixes something that had been sitting underneath all of it, undisturbed since portable builds first shipped: the fast, default “Portable” path for Windows and macOS was never really exporting a game. It was exporting the editor, with a game folder taped to the side.
What “Portable” actually shipped
Distribution-signed builds go through a real compile — builder/build-service.mjs generates a small, per-project Tauri shell and builds it fresh. Portable builds, the ones you get by leaving Distribution signing off, took a shortcut for speed: build_portable_macos copied the currently running Kriya.app, and build_portable_windows copied current_exe() — the editor’s own executable — renamed it after your game, and dropped a game/ folder next to it. A small runtime check at boot (portable_game_directory) looks for that folder and, if it finds one, skips the editor UI and boots straight into the runtime instead.
Clever, and fast — no compiler, no wait. But it meant a portable export carried the entire editor along for the ride: the full React app, Monaco, every editor-only Tauri command, all of it, just not rendered. A portable macOS build of a nearly-empty test project came out to 33.8 MB. Android and iOS builds of the same project landed under 10 MB.
A runner with nothing in it but the game
game-runner/ is a second, minimal Tauri binary, compiled once and reused by every portable export instead of recompiled per project. Its frontend is the same lean runtime bundle every web and mobile export already uses — not the editor’s bundle — and its Rust side registers exactly one command, get_portable_game, the same IPC call the editor used internally to hand a portable project over to the runtime. Moving that one command into its own binary was enough: the runner boots, asks for the game sitting next to it, and renders it, with no editor UI it could ever fall back to and no editor-only commands compiled in to reach.
Its capabilities are scoped to fs:allow-appdata-read and fs:allow-appdata-write — nothing else. The old approach shipped whatever the editor’s own capability file allowed, because it was the editor’s binary.
The same test project that came out to 33.8 MB now builds at 7.7 MB — under a quarter of the size, verified by actually launching the runner with real exported project data and confirming it boots and renders before ever handing this to a real build.
Building it once, not per export
bun run build:game-runner compiles the runner ahead of time; bun run desktop and every package:desktop* script now run it automatically before packaging. A portable export just copies the already-compiled binary — the same instant path as before, minus the part where it was quietly the editor.
Two smaller fixes that came out of building this
- Distribution binaries got smaller too. Neither the editor’s own
Cargo.tomlnor the per-project templatebuild-service.mjsgenerates for signed builds had a[profile.release]— Cargo’s bare default, with full debug symbols and no LTO. Addingstrip,lto,panic = "abort", andcodegen-units = 1to both cut a compiled distribution binary roughly in half. - The app icon could go missing.
icon.icnswas only listed underbundle.icon— Tauri’s own app-icon slot — not underbundle.resources, so the portable path’s icon copy silently found nothing and a packaged export could show Finder’s generic blank icon instead of Kriya’s. It’s now registered as an explicit resource, and the regression test that should have caught this now actually exercises the icon-copy path instead of skipping it.
Windows and Linux needed one more adjustment: the runner’s bundled path has a platform-specific extension (kriya-game-runner.exe vs kriya-game-runner), so that resource entry now lives in tauri.windows.conf.json/tauri.linux.conf.json rather than the shared config, where a single un-suffixed path couldn’t resolve correctly everywhere.
Where this leaves exports
Nothing about the Build Project window changed — same platforms, same toggle for Distribution signing, same output layout. What changed is underneath it: a portable Windows or macOS build is now an actual minimal game shell, sized like one, with a Tauri command surface that matches what a shipped game should be able to do rather than what the editor can do.