Shipping a Game¶
A SimVX game reaches players by three routes. None of them is a fallback for the others: pick the one that matches your audience.
Route |
What the player gets |
Install burden |
|---|---|---|
Source and wheel |
|
Needs Python |
Standalone executable |
A folder (or one file) they double-click |
None |
Web export |
A URL |
None; also the mobile answer |
Web export is covered in its own page, Web Export. This page covers the other two.
Source and wheel¶
The natural path for a Python engine. Build a wheel for your game, publish it, and a player with Python installs it like any other package:
uv build --wheel
pip install dist/your_game-1.0.0-py3-none-any.whl
your-game
This is the path with the least that can go wrong, because nothing repackages your dependencies: numpy, the Vulkan loader and the engine’s native extensions are installed by pip exactly as their authors built them.
Standalone executable¶
For players who will not install Python. The editor’s Export dialog offers a Standalone
Executable target, and simvx uses PyInstaller underneath.
The engine has four native pieces that a bundler has to carry: numpy, the Vulkan loader, the
CFFI audio extension, and (if you use it) the Jolt physics .so. It also loads shaders, fonts and
default assets through importlib.resources, which a bundler cannot see by reading import
statements. That second point is the one that bites: a bundler invoked with no options produces a
binary that dies on its first frame with ModuleNotFoundError: No module named 'simvx.graphics.shaders'.
So the collection flags are not optional:
pyinstaller --collect-all simvx --collect-all vulkan --collect-all glfw --collect-all freetype \
--hidden-import miniaudio --hidden-import _cffi_backend \
game.py
Expect roughly 155 MB for a one-directory build of a small game, most of it numpy, Pillow and the engine’s own assets. It starts in about the same time as running the game from a virtualenv: the engine’s Vulkan setup dominates, and the bundling costs nothing measurable.
--onefile compresses those 155 MB to about 62 MB, at the cost of unpacking into a temporary
directory on every launch: measured on Linux, that adds roughly 0.6 s to each start. Ship
one-directory unless the single file genuinely matters to you.
One-directory writes a folder named after your game, with the executable inside it next to an
_internal/ directory. dist/mygame/mygame is the thing you run; dist/mygame/ is the thing you
ship, and it must be shipped whole.
A bundle is host-only. PyInstaller does not cross-compile, so a Windows .exe is built on Windows
and a macOS app on macOS.
A bundle does not keep your code secret¶
Godot ships a .pck with optional encryption and Unity ships compiled assemblies; SimVX does
neither, and will not. Two different things happen to the two halves of a bundle, and it is worth
being precise about both:
The engine ships as plain readable source. A one-directory bundle contains around 440
.pyfiles under_internal/simvx/, plus shaders and default assets as ordinary files. Anyone can open them in an editor. That is the collection step doing its job.Your own modules are byte-compiled into the executable, in one-file and one-directory alike. You will not find
game.pyin the bundle, and searching it for a string from your source finds nothing.
The second point is not protection, and treating it as protection would be a mistake. The bundled code objects come back out with a few lines of standard library:
from PyInstaller.archive.readers import CArchiveReader
import marshal, dis
code = marshal.loads(CArchiveReader("dist/mygame/mygame").extract("game")) # "game" = your entry module
dis.dis(code) # docstrings, every string constant, the whole disassembly
That recovers your strings, your API keys if you put any there, and the full logic in disassembled form. A decompiler is only needed to turn it back into readable Python. Byte-compiling raises the effort of reading your code from “open the file” to “spend an afternoon”; it does not raise it to “cannot”.
That is a position, not an omission. An engine that promotes open source and treats source distribution as a first-class shipping path is not in the business of hiding the game’s source from the person running it.
Choose knowingly:
If your game’s value is in its content, its feel, or its multiplayer service, this costs you nothing.
If your business model depends on the client being opaque, use a different engine. Do not ship a SimVX bundle and assume the code inside it is private.
Packing assets into a single archive may still arrive, for load time and tidiness. Obfuscation is not a goal and is not on the roadmap.
Mobile¶
Play the web export in a mobile browser. That is the supported mobile path today, and it works: touch input is captured and the WebGPU renderer runs on current mobile browsers.
A native Android target is best-effort future work, not a scheduled feature. If you need a store listing rather than a URL, that gap is real and current.