Skip to main content

Bazalt

Bazalt is a modern Python library for rapid prototyping and building graphical applications using the Vulkan API. It provides a clean, intuitive interface over a high-performance C++ core, allowing developers to create rendering applications quickly without the typical boilerplate.

Installation

You can install bazalt easily via pip:

pip install bazalt

Prebuilt wheels are provided for Windows and Linux. Building from source requires a C++23 compiler — GCC 14+ or MSVC 19.36+ (Visual Studio 17.6) — and the Vulkan SDK.

Key Features

  • Modern Graphics API: Built on top of Vulkan for optimal hardware utilization.
  • Easy to Use Interface: Write clear and concise code with an intuitive API.
  • Automatic Shader Compilation: Compile GLSL shaders (Vertex/Fragment/Compute) directly from your code.
  • Compute Pipelines: ctx.compute_pipeline() + cmd.dispatch() — run GPU compute with results straight back into NumPy, no images required.
  • Storage Images: compute shaders write images too — .storage_image(binding) + set_storage_image() bind a read/write image for imageStore/imageLoad (post-processing, procedural textures). The barriers and layout transitions between the dispatch and a later sample are recorded for you.
  • Cubemaps & Texture Arrays: pass a list of layers (ctx.create_image([...], cube=True) or ctx.load_image([...6 paths...], cube=True)) for a cubemap, or without cube= for a texture array — one mechanism, sampled as samplerCube / sampler2DArray. Empty layered images can be filled in compute (procedural skyboxes). See examples/14_skybox.
  • Mipmaps: load_image() mips files by default (mipmaps=False to opt out); create_image(array, mipmaps=True) mips a numpy texture; create_image(w, h, mip_levels=N) allocates an empty chain and cmd.generate_mipmaps(image) fills it from mip 0 (for compute- or render-generated textures) — across every array layer / cube face.
  • Automatic Barriers: Hazards between resources (dispatch → dispatch, compute-written buffer → vertex fetch, compute-written image → sample) get their barriers computed at record time. Context(auto_barriers=False) hands you full manual control via cmd.barrier().
  • Pipeline & Buffer Management: Easy builder pattern for graphics pipelines and unified buffer creation.
  • Command Buffers: Explicit, yet simple command recording — calls chain (cmd.bind_pipeline(p).draw(3)), and with cmd.rendering(target): closes the pass for you.
  • Asynchronous Texture Streaming: ctx.load_image() returns immediately while the decode and GPU copy run in the background; anything that samples the image waits for it automatically. ctx.upload_progress gives you a loading bar for free.
  • Hot Reload: Context(hot_reload=True) watches the shaders (and their #includes) and images you loaded and applies edits live — shaders recompile and rebuild their pipelines in place, images re-upload into the same handle. A typo or a bad file is logged and the last good version keeps rendering, so a mistake never takes the app down. See examples/12_hot_reload.
  • Frame Timing & Debug Names: Context(gpu_timing=True) makes renderer.gpu_time_ms report the GPU time of a recent frame (opt-in — off by default it costs nothing); t = cmd.timer() … t.stop() … t.ms times any slice of a recording (handle-based, no with required) and reads back headless; name= / .name() label buffers, images and pipelines so validation messages name the culprit.
  • Headless Rendering: Draw into an offscreen RenderTarget and read the pixels back as a NumPy array — no window, no display required.
  • Render-to-Texture, MRT & Shadow Maps: Target attachments are ordinary Image objects in any supported Format — sample target.color[0] or a depth-only target's target.depth like any texture.
  • Multi-Window: one Context drives any number of windows. ctx.begin_frame() opens the frame; each window does renderer.acquire() / renderer.present(cmd) and owns its own swapchain, so resizing or closing one leaves the others rendering. See examples/19_multi_window.
  • Pick Your GPU: bz.list_devices() lists every card (name, type, VRAM, API version, per-feature support) before a Context exists; Context(device=...) runs on the one you chose. Omit it and bazalt picks for you, as before.
  • Runs Widely: Vulkan 1.2 baseline with 1.3 used where available, so bazalt runs on older integrated GPUs too. Capabilities are requested by name, never by version or extension.
  • Decoupled Architecture: Clean separation of concerns between Windowing (GLFW), Vulkan Context (GPU initialization), and render targets — a window is one target among others.

Quick Start: Rendering Without a Window

Everything below works with no display attached, which makes it usable from CI and tests:

import bazalt as bz

ctx = bz.Context()
target = bz.RenderTarget(ctx, 800, 600, depth=bz.Format.D32F)

pipeline = (ctx.graphics_pipeline()
    .vertex_shader(ctx.compile_shader("triangle.vert", bz.ShaderStage.VERTEX))
    .fragment_shader(ctx.compile_shader("triangle.frag", bz.ShaderStage.FRAGMENT))
    .vertex_format([bz.VertexFormat.FLOAT3, bz.VertexFormat.FLOAT3])
    .build(target))

# Interleaved position (x,y,z) and color (r,g,b)
vbuf = ctx.create_buffer([
     0.0, -0.5, 0.0,   1.0, 0.0, 0.0,
    -0.5,  0.5, 0.0,   0.0, 1.0, 0.0,
     0.5,  0.5, 0.0,   0.0, 0.0, 1.0,
], bz.BufferType.VERTEX, bz.MemoryUsage.STATIC, bz.DataType.FLOAT)

cmd = ctx.create_command_buffer()
cmd.begin()
with cmd.rendering(target, clear_color=[0.1, 0.2, 0.3, 1.0]) as c:
    c.bind_pipeline(pipeline).bind_vertex_buffer(vbuf).draw(3)

ctx.submit(cmd)

pixels = target.read_pixels()   # numpy (600, 800, 4) uint8

Quick Start: GPU Compute

Compute needs no window and no images — dispatch, then read the storage buffer back as a NumPy array:

import numpy as np
import bazalt as bz

ctx = bz.Context()

# double.comp: values[i] *= 2.0 over a std430 float array, local_size_x = 64
sim = (ctx.compute_pipeline()
    .shader(ctx.compile_shader("double.comp", bz.ShaderStage.COMPUTE))
    .storage_buffer(0)      # no stage argument — compute has exactly one stage
    .build())               # no target — compute has no attachments

data = np.arange(128, dtype=np.float32)
sbuf = ctx.create_buffer(data, bz.BufferType.STORAGE, bz.MemoryUsage.STATIC)

pool = ctx.create_descriptor_pool(max_sets=4, storage_buffers=4)
dset = pool.allocate_set(sim, set=0)
dset.set_buffer(0, sbuf)

cmd = ctx.create_command_buffer()
cmd.begin()
cmd.bind_pipeline(sim).bind_descriptor_set(dset, sim, set=0).dispatch(128 // 64)
ctx.submit(cmd)

assert np.allclose(sbuf.read(np.float32), data * 2)

Compute mixes freely with rendering in one command buffer — a dispatch that writes vertices and a draw that consumes them need no ceremony; the barrier between them is recorded automatically (see examples/11_particles).

Quick Start: Hot Reload

Add one keyword and bazalt watches the files it loaded — shaders (and their #includes) and images — recompiling and re-uploading on save:

ctx = bz.Context(logger, hot_reload=True)

vert = ctx.compile_shader("shader.vert", bz.ShaderStage.VERTEX)
frag = ctx.compile_shader("shader.frag", bz.ShaderStage.FRAGMENT)
tex  = ctx.load_image("wall.png")
pipeline = ctx.graphics_pipeline().vertex_shader(vert).fragment_shader(frag)...build(renderer)

while window.is_open():
    bz.poll_events()
    ctx.begin_frame()                  # edits are applied here (and at ctx.submit)
    if renderer.acquire():
        renderer.present(cmd)          # renderer.gpu_time_ms (with gpu_timing=True) gives GPU frame timing

Editing shader.frag rebuilds the pipeline in place; re-saving wall.png (same size and format) re-uploads into the same handle, so descriptor sets need no rewrite. A shader typo logs a ShaderError and the last good pipeline keeps rendering — a mistake never crashes the app. Full demo: examples/12_hot_reload.

Quick Start: Drawing a Triangle

Here is a minimal example demonstrating how to initialize the window, Vulkan Context, and SwapchainRenderer, compile shaders, create a pipeline, and draw a colorful triangle.

import bazalt as bz

# 1. Initialize Logger and register a callback.
#    Each message carries its severity and source as data, so you can filter
#    without parsing strings. This is optional: a Context created without one
#    reports warnings on stderr by default.
logger = bz.Logger(min_severity=bz.Severity.WARNING)
@logger.on_message
def on_message(msg):
    print(f"[{msg.severity}] {msg.text}")

# 2. Create the window, Vulkan Context, and SwapchainRenderer
window = bz.Window(1024, 720, "Bazalt Demo - Triangle", logger=logger)
ctx = bz.Context(logger)
renderer = bz.SwapchainRenderer(window, ctx)

if __name__ == "__main__":
    # Load and compile shaders. The vertex shader processes our geometry,
    # and the fragment shader determines the final color of the pixels.
    # Shaders are compiled through the Context.
    vert_spv = ctx.compile_shader("triangle.vert", bz.ShaderStage.VERTEX)
    frag_spv = ctx.compile_shader("triangle.frag", bz.ShaderStage.FRAGMENT)

    # The pipeline is a baked state object that tells the GPU how to interpret our data.
    # It is built against a render target, which supplies the color/depth formats.
    # A SwapchainRenderer is one, so is an offscreen RenderTarget — same call.
    pipeline = (ctx.graphics_pipeline()
        .vertex_shader(vert_spv)
        .fragment_shader(frag_spv)
        .vertex_format([bz.VertexFormat.FLOAT3, bz.VertexFormat.FLOAT3]) # Position + Color
        .build(renderer))

    # We interleave Position (x,y,z) and Color (r,g,b) in a single flat array.
    # Vulkan's Normalized Device Coordinates (NDC) range from -1 to 1,
    # where Y points downwards and X points to the right.
    vertices = [
         0.0, -0.5, 0.0,   1.0, 0.0, 0.0, # Top / Red
        -0.5,  0.5, 0.0,   0.0, 1.0, 0.0, # Bottom-Left / Green
         0.5,  0.5, 0.0,   0.0, 0.0, 1.0, # Bottom-Right / Blue
    ]
    
    # Create Vertex Buffer through the Context
    vbuf = ctx.create_buffer(vertices, bz.BufferType.VERTEX, bz.MemoryUsage.STATIC, bz.DataType.FLOAT)
    
    # Create Index Buffer through the Context
    ibuf = ctx.create_buffer([0, 1, 2], bz.BufferType.INDEX, bz.MemoryUsage.STATIC, bz.DataType.UINT32)

    # Command buffers store a sequence of commands for the GPU.
    # For a static triangle, we can record this buffer once during initialization 
    # and submit the same pre-recorded buffer every frame to save CPU time.
    cmd = ctx.create_command_buffer()

    cmd.begin()

    # begin_rendering names the target you are drawing into, clears it, and sets
    # a viewport and scissor covering it. Naming the target is what lets the same
    # code render to a window or to an offscreen image.
    cmd.begin_rendering(renderer, clear_color=[0.1, 0.2, 0.3, 1.0])

    # Bind the baked pipeline and the geometry buffers
    cmd.bind_pipeline(pipeline)
    cmd.bind_vertex_buffer(vbuf)
    cmd.bind_index_buffer(ibuf)

    # Draw 3 indices (1 triangle)
    cmd.draw_indexed(3)
    cmd.end_rendering(renderer)

    # Main game/rendering loop
    while window.is_open():
        bz.poll_events()
        
        # begin_frame opens one logical frame for every window on this
        # Context; acquire() takes this window's swapchain image and returns
        # False when it should sit the frame out (minimized, mid-resize)
        ctx.begin_frame()
        if renderer.acquire():
            renderer.present(cmd)

Metadata

Release files for bazalt 0.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for bazalt 0.14.0
File
bazalt-0.14.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
bazalt-0.14.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
bazalt-0.14.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
bazalt-0.14.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
bazalt-0.14.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
bazalt-0.14.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
bazalt-0.14.0-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
bazalt-0.14.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details

Total release size: 28.8 MB

Release files / bazalt-0.14.0-cp313-cp313-win_amd64.whl

Download URL bazalt-0.14.0-cp313-cp313-win_amd64.whl
Size 2.6 MB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
a515d385a627da3a5b657c1e2c9e4fa531f0c9cab65ae21d620e6f17684449d6
BLAKE2b-256 checksum
How to use checksums
8be5988bdfc62d476d796d93aed95385db8c8f50f87e33601d422bf5b09ab1ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL bazalt-0.14.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.6 MB
Tags CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
6dc1433f1d91e9071d121f6960b905ec9023b30a6e381ae54554fda837fff91d
BLAKE2b-256 checksum
How to use checksums
9306658023106b6adca7227a37416f3e09ab37f52009958756eea3753fff9a3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp312-cp312-win_amd64.whl

Download URL bazalt-0.14.0-cp312-cp312-win_amd64.whl
Size 2.6 MB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
1763aba4350b0391e1299300f98f17e9518b24fcde431f2d72bf2c85e0c8337f
BLAKE2b-256 checksum
How to use checksums
a519476fbc9208069bd08f530f40536b5c970091d91494a585d330d256b96e79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL bazalt-0.14.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.6 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
adf297099131c9fe1f91708e7ecc3eacb4d402f43675e990a9d0bdd50c6b6039
BLAKE2b-256 checksum
How to use checksums
52f011adc60fdac9bcabd9d9b51174d174fb0e1b0c206a82bc5ffd475a4d1816
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp311-cp311-win_amd64.whl

Download URL bazalt-0.14.0-cp311-cp311-win_amd64.whl
Size 2.6 MB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
d41ab1fd0034642349d26aeff2f0b210f1f1912a25286ec72c9aeaef456d0dbd
BLAKE2b-256 checksum
How to use checksums
604112cffd59a9c6546ae5fbe50ed76c80f0117c01baf31cc55c9d7fe126f902
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL bazalt-0.14.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.6 MB
Tags CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
23aab67a96c7585f4fbf9195ea0a2f5007f14cbe84735268bd7839d679976552
BLAKE2b-256 checksum
How to use checksums
cca1f0c5e6b5c77895a9d8061dff47355b0463e9faeaa262db9cad414db1aae3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp310-cp310-win_amd64.whl

Download URL bazalt-0.14.0-cp310-cp310-win_amd64.whl
Size 2.6 MB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
5906d0ad3a1e01cb498d86f452a210481f34c2cca7c8f3f2ea5ad2db765771c8
BLAKE2b-256 checksum
How to use checksums
ac788dbf6cc11230fb4c9a1413c5295bd5fc3d0783f3c6cafe525f76e58aeff9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / bazalt-0.14.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL bazalt-0.14.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.6 MB
Tags CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
e4b3e099fd10a7d14e3f72436e842de2bff95e5e7a3679ca5e276542115121af
BLAKE2b-256 checksum
How to use checksums
3bd4ec49ab129d61ca1a4e3fb8c90dbf5a7dfdfd2acbc1a00fec9a61c8e5d3e5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Security for bazalt 0.14.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 8 files in this release have been uploaded with provenance metadata.

Select from 8 files

Attestation for bazalt-0.14.0-cp313-cp313-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.14.0 This release

8 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page