Skip to main content

Quiltwright

Python License: BSD-3-Clause PyPI Version Tests Docs DOI

Quiltwright -- holographic output for scientific visualization.

Eric G. Suchanek, PhD -- Flux-Frontiers

Quiltwright is the last stage of a scientific rendering pipeline -- any pipeline that ends in a scene. It takes what you already have -- a PyVista or VTK scene built in memory, a Blender file or an exported mesh, or a .pov file written thirty years ago by someone who is no longer around to explain it -- and puts it on holographic hardware in glasses-free depth. Nothing is rewritten to get there: your scene file is never modified, the off-axis camera is supplied per view, and each scene is rendered by the renderer it already belongs to. Where that renderer is Blender's Cycles, the views are path-traced on the GPU's ray-tracing cores if the hardware has them.

It is used that way by WaveRider for geometric ML manifolds and by pypdb2pov for molecular structures, but neither is a prerequisite. If you can render it, you can hang it in the air.

Eric's Science Museum, the canonical POV-Ray render

A career in structural biophysics, arranged as exhibits: B-DNA and Z-DNA under bell jars, Ras and my original DNA Under Glass on the walls. The molecular models were generated by pdb2pov in 1997; the room dates to 1995. Quiltwright ray-traces it into a 48-view light-field quilt for Looking Glass light-field panels, or into 2-D video for Hololuminescent displays. A third output -- a 23-view sweep for LitiHolo's desktop hologram printer -- is in development. About the image


Latest news

v0.15.1 (2026-09-22). A fix for PyMOL cartoons, which came out as their own mirror image on both backends: correctly folded, with left-handed helices. cmd.get_povray() writes the model's right-handed coordinates, and cartoon_inc() and cartoon_obj() both treated them as already left-handed, so the POV-Ray include skipped the z flip pypdb2pov gives atoms and the Cycles OBJ added one it did not need. New tests measure each export against the structure's own CA atoms: 0.27 A to the ribbon, against 2.80 A for the mirror image. A camera placed for the old geometry now sees the molecule from its other face.

v0.15.0 (2026-09-19). LitiHolo's own capture tool orbits a camera around a pinned aim point and screenshots 23 stops, with no frustum shear anywhere in it, so render_pov_views() now takes geometry="toe-in" to match it. That is the projection this project's docstrings tell you not to use, and it is here because a hogel slicer is not a lens sheet: if it has only ever been fed toe-in sweeps, an off-axis set is an unlabelled change of input rather than a fix. LITIHOLO_TOOL_SWEEP records what the tool actually emits -- a 55-degree cone at 400x400, not the specification sheet's 45 degrees and 1600x2000 -- and pack_litiholo_sweep() re-encodes a rendered sweep under the vendor's own filenames. Off-axis remains the default everywhere.

v0.14.1 (2026-09-17). A fix for PyVista framing that put the focal plane in the wrong place. frame_and_focus() framed at whatever window shape the caller had set, while render_quilt() captures views at the display aspect -- and on 16-landscape the obvious choice, the quilt tile, is 4:3 against a 16:9 view. It now takes spec= and sizes the window itself. depth_report() gains view_cone=, so a capped cone is reported as rendered rather than at the preset's native 50 degrees.

v0.14.0 (2026-09-16). Two more subjects for the Looking Glass Go, and a real playlist to hold them together. quiltwright playlist builds a full Bridge playlist before it starts playing, which is what makes it actually advance instead of showing only the first entry -- and it takes a folder or a list of quilt files, in any mix of tilings. The two new subjects are an F1-ATPase cartoon rendered straight from PyMOL with a camera direction measured by PCA on the assembly's own coordinates, and the porin trimer recomposed 9:16 from its existing scene with no geometry duplicated. Getting the porin camera centered took two tries: a vertex bounding-box centroid overshot on the real panel, and the fix was to measure the rendered pixel centroid directly instead of trusting the mesh's own reported extents.

v0.13.0 (2026-09-13). A fourth backend: quiltwright paraview sweeps a saved ParaView session into a quilt by handing the .pvsm back to ParaView's own pvpython and moving the render view's camera in place, off-axis, the same recipe every other backend uses. Nothing is exported, so the session's filter pipeline, color maps, opacity transfer functions and camera all come across intact -- the thing a .vtm round-trip through PyVista loses. probe_paraview_state() reads the framed camera and depth range before the sweep is paid for. Verified against ParaView 6.1.1 in builtin-server mode and over a genuine client-server connection; IceT compositing across multiple MPI ranks is untested and documented as such.

Full history: CHANGELOG.md and releases.


What it's for

     scene sources                  quiltwright                  outputs

  PyVista / VTK  -----+        +------------------+        +-->  LFD  light-field panels
   (WaveRider, TVB)   |        |  off-axis views  |        |          multi-view quilts
                      +------->|  depth budget    |------->+-->  HLD  hololuminescent
  POV-Ray  -----------+        |  quilt assembly  |        |          2-D video
   (pypdb2pov, PyMOL) |        |  view sweeps     |        +-->  LitiHolo  hogel sweeps
                      |        +------------------+                       (in development)
  ParaView  ----------+
   (.pvsm states)     |
  Blender / meshes ---+
   (.blend, glTF, USD, OBJ)

Four backends share one assembler:

Backend Call Input
PyVista / VTK render_quilt() In-memory plotter
POV-Ray render_pov_quilt() .pov on disk; original never modified
Cycles render_cycles_quilt() .blend and mesh files; GPU ray tracing where available
ParaView render_paraview_quilt() .pvsm state file; the session's own pipeline, swept inside pvpython

render_cycles_quilt_from_plotter() takes the same PyVista plotter render_quilt() does and path-traces it instead. WaveRider, The Virtual Brain, PyVista example datasets, quiltwright.povgen, and a plain .pov file on disk all feed the same path.

Two display technologies. Light-field displays (LFD -- Portrait, Go, 16"/27"/32"/65") consume quilts: N views tiled into one image. quiltwright.lfd targets those. Hololuminescent displays (HLD -- 16"/27"/86") play ordinary 2-D video behind a fixed holographic optic and need dark-field styling rather than parallax; that is quiltwright.hld.

A third output is in development: render_pov_views() plus LITIHOLO_SWEEP write a 23-view single-row sweep for LitiHolo's desktop hologram printer. LITIHOLO_TOOL_SWEEP with geometry="toe-in" matches what LitiHolo's own capture tool emits instead of what its specification sheet says -- a 55-degree toe-in arc, not a 45-degree off-axis one -- and pack_litiholo_sweep() writes the JPEG sequence under the vendor's own filenames. Nothing has yet passed through a printer's software; docs/lfd.md records what remains open.

Off-axis, not toe-in

Each view must use an off-axis (asymmetric-frustum) projection: the camera slides sideways while continuing to face the same direction, with the image plane sheared back onto the original view axis.

The intuitive alternative is to swivel each camera to keep the subject centered. This "toe-in" approach introduces vertical parallax and keystone distortion, so the display cannot fuse the views: you get ghosting instead of depth. It is the single most common way light-field renders go wrong, and it produces output that looks perfectly plausible in any individual frame.


Install

pip install quiltwright                 # core: quilt geometry + Bridge control
pip install "quiltwright[viz]"          # + PyVista/VTK rendering backend
pip install "quiltwright[video]"        # + a bundled ffmpeg for video encoding
pip install "quiltwright[molecules]"    # + PDB and mmCIF, via pypdb2pov

Requires Python 3.12 or 3.13. Core depends only on numpy, pillow, and click.

POV-Ray, Blender, PyMOL, ffmpeg, and Looking Glass Bridge are external binaries, not pip dependencies. Poetry groups, from-source install, and the rest of the stack are in the installation guide.


Quick start

import pyvista as pv
from quiltwright import QUILT_PRESETS, render_quilt, save_quilt

p = pv.Plotter(off_screen=True)
p.add_mesh(pv.ParametricTorus())
spec = QUILT_PRESETS["portrait"]
save_quilt(render_quilt(p, spec), "torus", spec)   # -> torus_qs8x6a0.75.png

POV-Ray, Cycles, casting to Bridge, and hologram-printer sweeps: docs/usage.md. Shell targets and the CLI: docs/shell.md.


Driving it from the shell

The Makefile covers the bundled 1993-99 scenes. The quiltwright CLI covers hardware (cast, weave, wallpaper, dynamic, bridge) and arbitrary input (mesh, cartoon, probe). Worked exhibits stay in scripts/. Full tour: docs/shell.md.

make gallery                    # every reference still -> gallery/
make quilts                     # every bundled quilt, measured budgets dialled in
make preview-museum             # quarter-size, for iterating on composition

quiltwright cast renders/quilts/bell-jar-holo_qs8x6a1.77778.png
quiltwright bridge status       # is Bridge actually able to draw?
quiltwright weave ... && quiltwright wallpaper ...   # the no-Bridge path
quiltwright cartoon 2omf.cif.gz ompf_cartoon.inc     # molecular ribbon, via PyMOL
quiltwright mesh model.glb                           # any mesh file, camera auto-framed
quiltwright probe scene.pov --eye 0 35 -95 --aim 0 18 0   # measure its depth range

python scripts/make_exhibit.py 7AHL --quilt          # fetch -> convert -> render

RENDER_THREADS defaults to ncpu - 2. When the glass stays black, run quiltwright bridge status first -- Bridge keeps answering HTTP after crashing internally.


The depth budget

Whether a hologram fuses comes down to adjacent-view disparity: how far a feature moves between neighboring views. Roughly 4-5 px is the practical ceiling; past ~8 px, hard edges ghost. The arithmetic API is in docs/usage.md; the results worth knowing before you frame a shot -- each derived in docs/povray.md:

  • Content at the focal plane has zero disparity -- it is welded to the glass.
  • The focal plane belongs at the harmonic mean of the measured depth range, not the midpoint; near content is the expensive side.
  • A narrower field of view increases disparity. The widely repeated "~14 degree FOV" advice is specific to object-centric scenes; applied to an interior it makes ghosting worse.
  • Interiors have a fourth trap no arithmetic warns about: the camera sweep can run through a wall. Measure sweep clearance.
  • The depths themselves are measured, not guessed -- quiltwright probe sweeps an opaque plane along the view axis and reports where content actually begins and ends.

Supported devices

QUILT_PRESETS carries the official quilt settings for Portrait, Go, and the 16"/27"/32"/65" panels in both orientations. The 16" Gen3 Landscape entry is verified against what Bridge reports for real hardware -- see docs/usage.md.


Documentation

Document Contents
docs/install.md Installing the full stack: package extras, POV-Ray, ffmpeg, Bridge, pypdb2pov
docs/usage.md Library recipes: PyVista, POV-Ray, Cycles, casting to Bridge, printer sweeps, depth budget
docs/shell.md Driving it from the shell: every make target, the parallelism model, run reports, and what each CLI command is for
docs/cli.md Flag-by-flag reference for every quiltwright command
docs/architecture.md The module map, the off-axis invariant shared by all three backends, and why the geometry core stays free of VTK
docs/lfd.md Light-field output, Bridge/Studio setup, device presets, the PyVista path, view sweeps for hologram printers
docs/pyvista-datasets.md PyVista dataset ideas for holograms: topography, the Allen mouse brain atlas, other strong-depth candidates
docs/tvb-data.md Brain geometry from The Virtual Brain: cortical surfaces, connectomes, parcellations, downloaded on demand
docs/povray.md The POV-Ray backend: off-axis camera derivation, depth budget, sweep clearance, a worked case study
docs/cycles.md The Blender Cycles backend: hardware ray tracing (Metal/OptiX/HIP), mesh and .blend scenes, one process per sweep
docs/paraview.md The ParaView backend: a saved .pvsm session swept inside pvpython, pipeline and color maps intact
docs/mesh-import.md Any 3D object file (glTF/GLB, OBJ, FBX, USD, …) to a quilt in one command, with the camera auto-framed from the mesh's bounds
docs/povgen.md Writing POV-Ray scenes from analytic primitives, so a scene composed in Python can be ray-traced rather than rasterized
docs/pov-workflow.md The procedure: taking an archive scene from "won't parse" to a quilt that fuses, step by step
docs/pdb2pov.md Rendering molecular structures as holograms with pypdb2pov, from the shell or in-process
docs/hld.md Hololuminescent Displays, which play ordinary 2-D video rather than quilts
docs/about-the-image.md The museum scene: what is on display, and the thirty-year pipeline behind it
docs/gallery.md Every image in gallery/, which scene made it, and the aspect each must be rendered at

Testing

poetry install --with viz,dev    # or: pip install -e ".[viz]" && pip install pytest
pytest

Tests skip when their backend is absent. Headless CI: xvfb-run -a pytest. Layered install and skip conditions are in the installation guide.


The pipelines this serves

  • WaveRider -- manifold-aware geometric ML. Its voxel and manifold visualizer builds the PyVista scenes that render_quilt() sweeps.
  • pypdb2pov -- PDB and mmCIF to POV-Ray. Reads mmCIF and compressed input, ships the atom textures inside the package, and imports, so a conversion and a quilt render fit in one script. Scenes are byte-identical to pdb2pov, the 1993 C original.
  • proteusPy -- protein disulfide bond analysis and rendering.

Citation

If you use Quiltwright in your work, please cite it. Citation metadata is in CITATION.cff; GitHub's "Cite this repository" button generates BibTeX/APA from it, and the DOI badge above resolves to the archived release on Zenodo.

@software{suchanek_quiltwright,
  author  = {Suchanek, Eric G.},
  title   = {Quiltwright: Holographic Output for Looking Glass Displays},
  url     = {https://github.com/Flux-Frontiers/quiltwright},
  doi     = {10.5281/zenodo.21798503},
  version = {0.15.1},
  year    = {2026}
}

License

BSD 3-Clause. See LICENSE.

Metadata

Release files for quiltwright 0.15.1

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

Source distribution (sdist)

Source distribution for quiltwright 0.15.1
File Size Uploaded
quiltwright-0.15.1.tar.gz 171.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for quiltwright 0.15.1
File Interpreter ABI Platform
quiltwright-0.15.1-py3-none-any.whl Python 3 none any Details

Total release size: 358.0 kB

Release files / quiltwright-0.15.1.tar.gz

Download URL quiltwright-0.15.1.tar.gz
Size 171.5 kB
Tags Source
SHA-256 checksum
How to use checksums
8afeb9f162e1a40bb0eb3d49ed8052a7205bee0fb6dbfff5f881463a74e729a9
BLAKE2b-256 checksum
How to use checksums
b4cc95cf7cd0233ea6c74da97e894c67bacf5757274370ad44c194590a0e6306
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 23, 2026.

Transparency log

Release files / quiltwright-0.15.1-py3-none-any.whl

Download URL quiltwright-0.15.1-py3-none-any.whl
Size 186.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6645ef34d55bbd132525ced954172d25c4b4db8b4b2b047b479e23d12f8dc437
BLAKE2b-256 checksum
How to use checksums
c904ab4ca65b24405e8200a64bb082fa46fe858dc9e73ddad9e4a6ca6b6f3eb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

0.16.0

2 release files

This release

0.15.1 This release

2 release files

0.15.0

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

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