pyvista-blender
Render PyVista plotter scenes through
Blender (bpy) — photoreal output, full
animation export, no file round-trip.
Build the scene once in PyVista. Pick VTK's preview or Blender's
Cycles / Eevee Next for the final render. Export entire deforming,
colour-evolving, lit animations to a single .blend that plays
natively in Blender with no Python script inside.
Showcase
These structural mechanics examples start as PyVista scenes and use Blender for the final render. The transparent animated WebP previews link to the transparent VP9 WebM files.
|
|
|
| I-beam bending Fedoo stress animation with support and load geometry. |
Gyroid compression Metallic gyroid material revealed through a stress-alpha overlay. |
Status
Initial public release (0.1.0). The offline render path, the desktop
and browser interactive viewports, the Jupyter inline backend, and the
full animation export to .blend are implemented and tested. The full
ruff (select = ["ALL"]) + ty + format gate is clean.
See the features list in the docs for the
full surface and the architecture page for
the translation pipeline.
Install
pip install pyvista-blender
# or
uv add pyvista-blender
For the Jupyter inline backend and the Trame-served browser viewport
(pl.blender.show(backend="web")), install pyvista[jupyter]
alongside; the bridge reuses pyvista's Trame stack rather than
shipping its own extras.
pip install pyvista-blender 'pyvista[jupyter]'
Requires Python 3.11 (Blender 4.5 LTS via bpy>=4.5,<5) or
3.13 (Blender 5.x via bpy>=5.0,<6). Python 3.10, 3.12, and 3.14
have no matching bpy wheel on PyPI; requires-python blocks them.
Quick start
import pyvista as pv
pl = pv.Plotter(off_screen=True, window_size=(1920, 1080))
pl.add_mesh(pv.read("data.vtu"), scalars="von_mises", cmap="viridis", pbr=True)
pl.add_light(pv.Light(position=(5, -5, 5), light_type="scene light"))
pl.camera_position = "iso"
# Offline render via Cycles + OptiX denoise. No `import pyvista_blender`
# needed — the namespace registers itself on install through PyVista
# 0.48's plotter-component entry point.
pl.blender.render("frame.png", samples=128)
# Interactive hybrid viewport: VTK 60 fps during drag, Cycles render
# on mouse release. One window, mouse-driven, no auto-exec prompts.
pl.blender.show()
API surface
| Entry point | What it does |
|---|---|
pl.blender.render(path, ...) |
Render a single frame to PNG via Cycles or Eevee Next. |
pl.blender.animate(path, updater, frames, fps=...) |
Render an animation as gif / mp4 / webm / mov / mkv via imageio + imageio-ffmpeg. |
pl.blender.show() |
Hybrid VTK / Cycles interactive viewport — VTK during drag, settled Cycles on release. |
pl.blender.add_glyph(source, geom, *, orient, scale, factor) |
Geometry-Nodes-instanced glyphs; memory cost scales N + V instead of N · V. |
pl.blender.export_blend(path) |
Save the live PyVista scene as a .blend for finishing in Blender. |
pl.blender.export_animation_blend(path, updater, frames, fps, **bake) |
Bake a full animation into a .blend that plays natively on file open. |
pl.blender.orbit_camera(n_frames=...) |
Build an updater for animate / export_animation_blend. |
Three-tier config resolution everywhere: per-call kwarg → component
attribute (pl.blender.engine = ...) → module default
(pyvista_blender.config.*).
Animation export to .blend
export_animation_blend bakes each animation channel through its own
opt-in kwarg. Every backend plays back natively when the file is
opened in Blender — no Python in the .blend, no auto-execution
prompt, no need to "Run Scripts" on load.
| Kwarg | Mechanism | File layout |
|---|---|---|
bake_camera=True (default) |
Keyframes on scene.camera.location + rotation_quaternion per frame |
inside .blend |
bake_deformation="shape_keys" |
One Shape Key per frame, value-keyframed with linear interpolation | inside .blend |
bake_deformation="mdd" (= True) |
Lightwave MDD sidecar + MESH_CACHE modifier |
.blend + __<mesh>.mdd |
bake_scalars=True |
Packed PNG (rows = frames, columns = vertices / cells) + Geometry Nodes graph; works for point-data and cell-data scalars | inside .blend |
bake_lights=True |
Per-light keyframes on location, rotation, energy, color |
inside .blend |
Example: full multi-channel animation in one self-contained file.
import numpy as np
import pyvista as pv
pl = pv.Plotter(off_screen=True, window_size=(1280, 720))
plane = pv.Plane(i_resolution=60, j_resolution=60)
plane.cell_data["heat"] = np.zeros(plane.n_cells, dtype=np.float32)
pl.add_mesh(plane, scalars="heat", cmap="inferno", clim=[-1.0, 1.0])
light = pv.Light(position=(5, 0, 4), light_type="scene light", intensity=1.0)
pl.add_light(light)
n_frames = 60
orbit = pl.blender.orbit_camera(n_frames=n_frames)
centers_xy = plane.cell_centers().points[:, :2]
def update(frame: int) -> None:
orbit(frame)
angle = -frame * (2.0 * np.pi / n_frames)
light.position = (5.0 * np.cos(angle), 5.0 * np.sin(angle), 5.0)
light.intensity = 0.4 + 0.6 * (0.5 + 0.5 * np.sin(frame * 0.3))
r = np.linalg.norm(centers_xy, axis=1)
plane.cell_data["heat"] = np.sin(2.0 * r - frame * 0.2).astype(np.float32)
pl.blender.export_animation_blend(
"scene.blend",
update,
frames=range(n_frames),
fps=30,
bake_camera=True,
bake_lights=True,
bake_scalars=True,
)
pl.close()
Open scene.blend in Blender 4.5+ / 5.x and press Space:
camera orbits, the explicit light orbits in the opposite direction
while pulsing, the heat field travels as a radial wave with flat per-
cell shading. One file, ~500 KB, nothing to ship alongside.
Development
uv sync --group dev --no-install-package bpy # fast local sync (no 200 MB bpy wheel)
uvx prek install # install pre-commit hooks
uv run pytest # ~10 s with bpy installed
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run ty check
Real bpy is only needed for the @pytest.mark.bpy tests. CI runs
the full suite against the live wheel.
License
GPL-3.0-or-later. Forced by bpy's license; every source file
carries an SPDX header. See LICENSE.
Metadata
Release files for pyvista-blender 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyvista_blender-0.1.0.tar.gz | 136.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyvista_blender-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 292.2 kB
Release files / pyvista_blender-0.1.0.tar.gz
| Download URL | pyvista_blender-0.1.0.tar.gz |
|---|---|
| Size | 136.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00cb7e52aee3485ff9670bd1ebe4a3724489644d6675852ccba39cafcaad7ca0
|
|
BLAKE2b-256 checksum How to use checksums |
cbc2acf1f432f2936ce142ab4784b9d3f555c8221130e3e56649804e3b1fe0f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 6, 2026.
Transparency logRelease files / pyvista_blender-0.1.0-py3-none-any.whl
| Download URL | pyvista_blender-0.1.0-py3-none-any.whl |
|---|---|
| Size | 156.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6d0bf07dfdda51af183c6d3166bc86dfbc0e8a2a5bd5b66ee72e1d247924b727
|
|
BLAKE2b-256 checksum How to use checksums |
94f5d08defd5bfdcc4933da36edc0c8beb143e8cd583450bc503fb899d4caec4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 6, 2026.
Transparency log