Installation¶
The full builds are served from the project’s own index. Either spelling works:
pip install --pre simvx --extra-index-url https://pypi.simvx.com/
uv pip install --pre simvx --extra-index-url https://pypi.simvx.com/
# ...and with the example library beside it
pip install --pre "simvx[examples]" --extra-index-url https://pypi.simvx.com/
The simvx name on public PyPI is a placeholder that reserves the name; it installs no code,
and its simvx-preflight script checks the environment and points here. Installing from
source (below) remains fully supported.
Requirements¶
System Requirements
Python 3.14+
Vulkan 1.2+ capable GPU and drivers
glslc shader compiler, optional (from the Vulkan SDK): only needed to recompile shaders; the compiler otherwise ships via
uv syncOne windowing library: GLFW3, SDL3, or PySide6 (any one works: see Windowing Backends)
uv: workspace packages resolve only throughuv run
Install uv if you don’t have it:
curl -LsSf https://astral.sh/uv/install.sh | sh
Per-Platform Setup¶
Arch / Manjaro¶
sudo pacman -S vulkan-devel glfw shaderc
Ubuntu / Debian¶
sudo apt install libvulkan-dev libglfw3-dev glslc
macOS¶
Install the Vulkan SDK (includes MoltenVK and glslc), then:
brew install glfw
Clone & Install¶
git clone https://git.simvx.com/simvx/simvx.git
cd simvx
# Install all workspace packages (editable) into the project venv
uv sync
# Optional: pull in dev tools (pytest, ruff, mypy, black) and/or doc build deps
uv sync --group dev --group docs
To install only a subset of packages editable (e.g. when working on a single package), use the explicit form instead:
uv pip install -e packages/core -e packages/graphics
The two dependency groups defined in the workspace pyproject.toml:
Group |
Adds |
When you need it |
|---|---|---|
|
|
running the test suite or pre-commit checks |
|
|
building the documentation locally |
Both are optional: you can use SimVX without either.
The example library¶
The examples are a distribution of their own, simvx-examples, and they install as an
extra of the engine:
pip install --pre "simvx[examples]" --extra-index-url https://pypi.simvx.com/
The index is not optional here either: the simvx name on public PyPI declares no extras,
so a bare pip install simvx[examples] warns that the extra does not exist and installs
nothing. pip install simvx-examples on its own is not an equivalent spelling either. That
distribution deliberately declares no dependencies, so alone it gives you neither the engine
the examples import nor the simvx command, which belongs to simvx-core.
With it installed, simvx examples browses, runs and copies the library:
simvx examples list # every installed example, grouped by tier
simvx examples list --tier tutorials
simvx examples list physics # search id, title, description and tags
simvx examples path features_2d_light # print the file, for your own tooling
simvx examples run tutorials_pong
simvx examples run tutorials_pong -- --test
simvx examples fork tutorials_pong --to ~/games/my-pong
fork is the one that matters. It copies the example, and everything beside it, into a
directory you own, with the LICENSE alongside. Editing the library inside site-packages
is not the way: it is version-managed, replaced on upgrade, and invisible to your own
version control.
SIMVX_EXAMPLES_ROOT overrides where the library is read from. That is how a Linux
distribution packages the tree somewhere its own policy prefers, and it is also how you
point the commands at a checkout:
SIMVX_EXAMPLES_ROOT=~/src/simvx/examples simvx examples list
From a checkout none of this is needed: the tree is already there, and each example’s docstring carries the direct command.
uv run python examples/tutorials/pong/main.py
Inside the repository, uv sync --extra examples is what puts the distribution itself into
the project venv the first time. There is no editable install of it, and a plain re-sync will
not notice that you edited it: after changing anything under examples/_package/, rebuild and
reinstall it explicitly.
uv sync --extra examples --reinstall-package simvx-examples
The fourth tier in the repository, examples/ports/, is not part of the distribution and
cannot be: each port re-implements a third-party game and is licensed individually against
the original. Read those in a checkout, or on the
gallery.
Native audio extension¶
Audio playback uses a small C extension (ma_engine) compiled at install
time by a PEP 517 build hook (packages/core/build_audio_ext_hook.py).
Three install modes control how the build is treated:
Env var |
Behaviour at install |
Behaviour at runtime |
|---|---|---|
(default) |
Tries to compile. On failure (no C compiler, etc.) the install succeeds and prints a stderr WARNING. |
If the |
|
Skips the compile step entirely. Quiet. |
Same legacy fallback with WARNING. |
|
Fails the install if the compile fails. For CI / production pipelines. |
Native required: runtime can’t fall back if the file was never built. |
# Default (best-effort native build)
uv pip install -e packages/core
# Skip the build, accept the legacy mixer
SIMVX_SKIP_AUDIO_BUILD=1 uv pip install -e packages/core
# Hard require: fail loud on missing compiler
SIMVX_REQUIRE_AUDIO_NATIVE=1 uv pip install -e packages/core
Two runtime env vars control the fallback policy:
Env var |
Effect |
|---|---|
(default) |
Native → legacy (with WARNING) → null (with WARNING). |
|
Native or |
What the legacy mixer costs¶
The fallback is not simply a slower version of the same thing:
Native ( |
Legacy mixer |
|
|---|---|---|
Latency |
20 ms |
100 ms |
Mixing runs in |
C, on miniaudio’s own thread |
Python and NumPy, on the audio thread under the GIL |
3D positional audio |
listener position, direction and Doppler applied |
no spatializer: the calls are accepted and discarded |
Bus routing, gain, effects |
yes |
yes |
The latency follows from where the mixing happens. The legacy path drives
miniaudio.PlaybackDevice from the miniaudio distribution, which wraps the
same C library as the native path but exposes only its device and decoder
layer, never its engine. Mixing therefore lands back in Python on the audio
thread, where a heavy frame on the main thread can stall it, so the buffer has
to be large enough to survive that.
The spatializer is the part worth noticing: a game built on 3D positional audio does not sound late on this path, it sounds wrong.
Getting the native extension¶
From a source checkout, build it in place:
uv run --with setuptools simvx build-audio
Installed from an index, reinstall from the sdist with a C compiler present. The wheels carry the CFFI glue but not the vendored miniaudio source, so an in-place rebuild has nothing to compile:
pip install --force-reinstall --no-binary simvx-core simvx-core
Verify Installation¶
Check the Vulkan driver:
vulkaninfo --summary
Import-check the packages:
from simvx.core import Node, SceneTree, Vec3, Property
from simvx.graphics import App
Run the core test suite:
uv run --package simvx-core pytest
Next¶
Quickstart: open a window in 20 lines
Your First 2D Game: build a Pong game end-to-end
Your First 3D Game: build your first 3D game (Gem Collector)