All docs
Engine Docs Synced doc Engine source of truth

Building Splitframe

Python package setup and native runtime build commands for the engine.

Generated from slicecore/splitframe View source doc

Note: This page is generated from the slicecore/splitframe engine repository. Edit the source document there and let automation sync it into splitframe-io.

One path from a clean environment to a working Python + native install.

Prerequisites

  • Python 3.11+
  • CMake 3.20+ (for the native runtime)
  • Vulkan SDK / development headers (for the native runtime)
  • A C++17 compiler

Quick Start

# 1. Clone and enter the repo
git clone <repo-url> splitframe
cd splitframe

# 2. Create a virtual environment and install
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]

# 3. Verify the Python package
pytest -q

This gives you a working splitframe install with all engine Python packages (splitframe, splitframe_api, splitframe_native_renderer) plus dev tooling (pytest, ruff, mypy).

Adding the Native Runtime

The native runtime provides the Vulkan renderer, host frame loop, and shader pipeline. Build it from the same environment:

# 4. Build the native module (minimal — no windowing or Vulkan bootstrap)
cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release
cmake --build native/build --config Release

# 5. Verify the native extension
python -m scripts.native.native_backend_smoke --module-dir native/build --json

Native binaries embed the git SHA of the checkout they were built from. After switching branches or committing new engine changes, refresh the build through the provenance tool so backend selection can distinguish “not built for this checkout” from real renderer failures:

python -m scripts.native.native_build_provenance check --build-dir native/build
python -m scripts.native.native_build_provenance refresh --build-dir native/build

refresh reruns CMake configuration for the existing build directory and then builds _splitframe_native_renderer, preserving cached build options such as GLFW or Vulkan bootstrap.

For the full host-capable build (GLFW windowing + Vulkan bootstrap):

cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release \
  -DSPLITFRAME_NATIVE_USE_GLFW=ON \
  -DSPLITFRAME_NATIVE_USE_VULKAN_BOOTSTRAP=ON
cmake --build native/build --config Release

# Verify through the GameEngine host path
python -m scripts.native.native_build_provenance check --build-dir native/build
python -m scripts.native.native_game_engine_runtime_smoke --module-dir native/build --json
python -m scripts.native.native_simple_game_smoke --module-dir native/build --json

Generated Files

A handful of contract modules are generated from a source of truth and committed so the native build and Python runtime share identical constants without a build-time codegen step. If you change one of the sources below, rerun its generator and commit the regenerated output in the same change.

Committed output(s)Source of truthRegenerate with
splitframe/observability/_metric_registry_generated.pyscripts/maturity/render_metric_registry.jsonpython scripts/maturity/generate_render_metric_registry.py
splitframe/rendering/_frame_packet_schema_generated.py, native/include/splitframe_native/frame_packet_schema.generated.hscripts/maturity/frame_packet_schema.jsonpython scripts/maturity/generate_native_schema_contracts.py
splitframe/rendering/native_bridge/_schema_versions_generated.py, native/include/splitframe_native/native_schema_versions.generated.hscripts/maturity/native_schema_versions.jsonpython scripts/maturity/generate_native_schema_contracts.py
splitframe/rendering/native_bridge/_build_provenance_generated.py, native/include/splitframe_native/build_provenance.generated.hgenerator constants + native/shaders/toolchain.lock.jsonpython -m scripts.native.generate_native_build_provenance

You do not have to remember to do this: every generator above ships a --check mode (or an equivalent render-and-compare test), and CI runs it. A stale committed artifact fails test_native_schema_contract_generator_is_current, test_native_build_provenance_generator_is_current, or test_render_metric_registry_generated_file_is_current — so a forgotten regeneration is caught before merge rather than silently shipping a mismatched Python/C++ contract. The table is the fast path; the tests are the backstop.

The build_git_sha.generated.h files under native/build*/ are per-build artifacts, not source contracts. Their freshness is enforced separately by the native build provenance gate (see Adding the Native Runtime above and tests/_native_capture_support.py), not by a regeneration check.

What CI Runs

CI splits this flow across maturity-shaped job buckets:

lint-and-typecheck job — Python-only (steps 1–3 above), plus:

  • Lint (ruff check)
  • Boundary audit (scripts/audit_splitframe_boundaries.sh)
  • Source compilation (compileall)
  • Content validation (python -m splitframe.content.validation)
  • Import smoke for all public packages
  • Type checking and dependency vulnerability audit

core job — Tier 1 supported-engine tests.

native-tooling-contract job — Tier 2 native bridge/tooling tests plus extension-optional native facade smokes.

example-acceptance-headless job — Tier 3 example acceptance tests that do not require a host-capable native renderer.

renderer-contract-headless job — Tier 3 renderer contract Python tests.

renderer-validation-review job — builds a small Vulkan-bootstrap native module, captures the primitive_renderer and text_glyphs charts at 640x360, writes JSON plus Markdown review artifacts, and uploads them for PR inspection. This keeps real renderer review artifacts available without running the full Vulkan capture matrix on every PR.

quarantine-controls job — maturity, tier, module-audit, and scene/world dependency inventories.

full-suite-backstop job — cross-platform full Python suite with coverage.

native-smoke job — Python install + native build (steps 1–5 above), plus the full native smoke suite covering backend selection, feature tiers, renderer submission, bridge threading, and the GameEngine host path.

native-smoke-cross-platform job — Windows and macOS native build/provenance smoke so platform-specific build drift is visible separately from the Linux native smoke lane.

Build Variants

VariantCMake flagsUse case
Minimal(defaults)Contract validation, smoke coverage
Host-capableSPLITFRAME_NATIVE_USE_GLFW=ON, SPLITFRAME_NATIVE_USE_VULKAN_BOOTSTRAP=ONApplication/game development

Both variants produce the same _splitframe_native_renderer Python extension module. The host-capable variant additionally links GLFW for native windowing and enables Vulkan instance/device bootstrap during renderer initialization.

Downstream Application Path

For downstream game/application code, the supported entry path is:

  1. Build an EngineConfig
  2. Create GameEngine
  3. Let the engine own backend selection and native startup

The canonical example is examples/simple_game/. See docs/ENGINE.md for the full engine API and native/README.md for native-specific details.

Installed Layout

A pip install splitframe produces three Python packages:

PackageContents
splitframeEngine core, scenes, entities, content pipeline, and renderer integration
splitframe_apiPublic API module
splitframe_native_rendererPure-Python facade for the native renderer

Packaged data lands under splitframe/resources/ (currently themes/*.json). The native extension module (_splitframe_native_renderer) is built separately via CMake and is not included in the Python package; it must be on sys.path or in the working directory at runtime.

splitframe.__version__ reflects the version from pyproject.toml.

Compatibility

Splitframe follows these compatibility rules during 0.x:

  • The symbols in splitframe.public are the supported public surface for new engine code.
  • The root splitframe package exposes package metadata only; it is not a compatibility barrel for public symbols.
  • Symbols accessible only through their owning modules remain internal unless documented in splitframe.public.
  • The cooked content manifest format (splitframe.content.cooked.asset.v1) is stable within a minor version. Re-cooking is expected across minor version upgrades.
  • The native extension’s Python binding surface (splitframe_native_renderer) labels env/profile ingress and advanced mutation surface explicitly. Only RequestedFeatureTier and resolve_runtime_config() are supported for direct use; per-feature mutation is advanced/test-only.

Troubleshooting

Missing Vulkan headers — Install your platform’s Vulkan SDK. On Ubuntu: sudo apt install libvulkan-dev vulkan-tools.

Missing GLFW — Install libglfw3-dev or build with -DSPLITFRAME_NATIVE_USE_GLFW=OFF (default).

pygfx/wgpu import errors — The old pygfx window renderer has been retired. Core engine functionality, tests, and supported examples use the native renderer path. Supported runtime work should use the native Vulkan renderer and the splitframe.rendering.native_runtime_* Python surfaces.