Driving it from the shell¶
Companion to: the README's shell section, which carries the summary this page expands.
Everything in the library docs is where a scene arrives from whichever pipeline built it. Three things sit around that:
| What it is | What it is not | |
|---|---|---|
| Library | render_quilt / render_pov_quilt / render_cycles_quilt from Python |
a CLI |
quiltwright CLI |
Hardware and tooling on a finished quilt (cast, weave, wallpaper, bridge), plus three commands that take arbitrary input (mesh, cartoon, probe) |
a generic quiltwright render museum.pov |
scripts/ |
Composed exhibits for the scenes this repo ships -- museum, vitrine, still-life, DNA helix, cartoon comparison, make_exhibit.py |
unfinished CLI |
The museum is a composed exhibit. It does not become a subcommand. A WaveRider
manifold or a freshly converted structure comes through the library, or
through quiltwright mesh if it is a file Blender can import.
make -- the bundled archive¶
The repository ships the 1993-99 POV-Ray scenes, and a Makefile that renders
them with their measured depth budgets already dialled in, so a hologram from a
clean clone is one command rather than a script you have to write. This covers
the bundled scenes only. A WaveRider manifold or a freshly converted
structure does not come through here -- it comes through the library, or through
scripts/render_pyvista_hologram.py for
the PyVista subjects -- and it lands in the same renders/quilts/, where the
CLI below picks it up regardless of origin.
make # the default goal is help; rendering is always explicit
make help # every target, and the still names
The gallery¶
One full-quality frame per scene, into gallery/, cataloged in
gallery.md. These are committed: they are the diffable record of
what each scene looks like, and the presented work rather than a build artifact
-- which is why they sit at the top level and not under renders/, where
everything is output and only reports/ is kept.
make gallery # all of them
make still-bell_jar_bj_holo # just one
Each renders at its own declared aspect -- POV-Ray maps right to image
width whatever pixel dimensions you ask for, so a mismatched frame stretches
silently. The Makefile carries the correct size per scene; the table is in
pov-workflow.md.
Quilts¶
Into renders/quilts/, through the render scripts, which inject a device
camera and place the focal plane from measured near/far depths rather than
from the scene's own aim point:
make quilts # bell jar, porin, lambda, museum
make quilt-bell-jar-holo # one, 16:9
make quilt-bell-jar-holo-2026 # the crystal cut
make quilt-bell-jar-portrait # the 9:16 companion, for tall panels
make preview-museum # quarter-size, for iterating on composition
Preview first when you are changing a composition -- a preview is seconds per view where a full quilt is minutes, and the depth budget it prints is the same one the full render will use.
Two knobs worth knowing:
make quilt-porin EXTRA_ARGS="--cast" # send it to the panel when done
make quilt-museum EXTRA_ARGS="--antialias 0.1"
make quilts RENDER_THREADS=$(sysctl -n hw.ncpu) # use the whole box
Parallelism, and why it works the way it does¶
RENDER_THREADS defaults to ncpu - 2, leaving two cores for the rest of
the machine so a multi-minute render does not make the desktop unusable. It
reaches POV-Ray through a generated POVINI, because the render scripts invoke
povray themselves and a command-line +WT would override them. JOBS stays
at 1 on purpose: POV-Ray already threads one render across every core, so extra
processes only split it.
The same two cores are held back when you call a render script directly, where
there is no POVINI to carry the Makefile's value -- --threads N sets it
explicitly, and --threads 0 lets POV-Ray take everything, which is its own
default. A Work_Threads line in POVINI always wins over the courtesy cap,
so make quilts RENDER_THREADS=... keeps working.
Run reports¶
Every full quilt writes a Markdown provenance record to renders/reports/.
A quilt is a 25-40 MB gitignored release asset; the report is the committed
record of how it was made -- scene file and its SHA-256, repository commit and
whether the tree was dirty, camera and measured depths, the depth budget
verbatim, the parallelism actually used, timings, and the output's own digest.
Pass --report to either render script to get one outside make.
quiltwright -- the CLI¶
Flag-by-flag reference: cli.md. This section is the why, not the full option list.
Installed as quiltwright, core-only (numpy, pillow, click). Most commands
operate on a quilt, which is where the backends have already met: a
manifold swept out of PyVista and a molecular scene ray-traced from POV-Ray
produce the same artifact, and cast / weave / wallpaper / dynamic
treat them identically. Three commands are a whole pipeline rather than a step after
one: mesh, cartoon, probe. None of them is a generic renderer for the
bundled scenes -- those stay in scripts/.
quiltwright bridge status # is Bridge actually able to draw?
quiltwright bridge reset # kill and relaunch a wedged daemon
quiltwright cast renders/quilts/bell-jar-holo_qs8x6a1.77778.png
quiltwright cast --check # which displays can Bridge see?
quiltwright weave renders/quilts/bell-jar-holo_qs8x6a1.77778.png --cal visual.json
quiltwright wallpaper bell-jar-holo_native_LKG-J00332.png
# two lighting variants, packed as a Dynamic Desktop (macOS)
# lighting= is real sun altitude/azimuth -- not POV-Ray's clock
quiltwright dynamic --appearance day_native_LKG-J00332.png night_native_LKG-J00332.png \
-o scene.heic
quiltwright wallpaper scene.heic
quiltwright cartoon 2omf.cif.gz ompf_cartoon.inc # a molecular ribbon, via PyMOL
quiltwright cartoon --check # is PyMOL reachable, and by which route?
quiltwright mesh model.glb # any mesh file -> a quilt, camera measured from it
quiltwright mesh scan.fbx --lighting sky --still
quiltwright probe pov-scenes/bell_jar/bj.pov --eye 0 35 -95 --aim 0 18 0
For a structure you have not downloaded yet, one command covers the whole pipeline -- fetch, convert, compose, render -- narrating each step:
python scripts/make_exhibit.py 7AHL --label "ALPHA-HEMOLYSIN" --quilt
Structures land in $PDB (default ~/pdb), and nothing already there is
fetched twice.
What each command is for¶
probe is the measurement every POV-Ray depth budget starts from: it slides
an opaque plane along the view axis and reports where content actually begins
and ends, which is what focal_distance_for_range() wants. Two cautions come
with it -- probe through the camera you will render with, and at +Q8 or
above, since below that POV-Ray disables transparency and a room reports no
windows at all. On a scene whose backdrop runs to the horizon the sweep never
closes and the printed far is the end of it; the command says so, and
--rows prints the curve to fit the knee from.
mesh is the exception to "downstream": it is a whole render, not a step
after one. Hand it any file Blender can import and it measures the object's
bounds, frames a camera on them and path-traces the sweep -- the only command
here that needs no scene of ours at all. It wants a blender binary; see
docs/mesh-import.md.
cartoon is the one command that reaches outside the pipeline: it drives
PyMOL to draw the representations pypdb2pov cannot -- ribbons and surfaces --
and writes them on the same object-only contract, so a cartoon mounts in a
scene exactly where an atom model would. PyMOL is optional and never a
dependency; --check says whether it is reachable before anything is loaded.
cast recovers the tiling from the _qs<cols>x<rows>a<aspect> filename suffix
that save_quilt() writes, so it usually needs no flags whatever produced the
views. weave then wallpaper is the no-Bridge path:
a woven frame is already interleaved for one panel, so setting it as that
panel's desktop picture makes the desktop a hologram with nothing running.
wallpaper matches the frame to the right display by the panel serial both
carry. dynamic packs several of those stills -- or ordinary 2D renders --
into one HEIC whose apple_desktop metadata lets macOS swap frames with
Light/Dark, the sun, or the wall clock. POV-Ray produces the variants with
render_pov_quilt(..., lighting="light"|"dark", sun=(altitude, azimuth));
that sun is a parallel light, not the animation clock.
When the glass stays black, bridge status is the first thing to run. Bridge
keeps its HTTP port open and keeps issuing session tokens after crashing
internally, so a cast can report success at every step against a daemon that
will never draw -- status checks the port, the session, the device list and
whether any device is actually a Looking Glass, then gives a verdict.