Tau
Distributed multi-projector rendering: state replication over UDP, OSC parameter sync, and per-projection warp/blend. For authoring multimedia work in the AlloSphere with no dependency on allolib.
In quantum physics, τ (tau) denotes the tangle, a measure of entanglement. For three or more parts it is what is left once every pairwise correlation has been accounted for: a property of the whole system, belonging to no pair within it.
The import package is tau; it is published to PyPI as tau-av.
Install
Tau is used from a clone — the examples, the tests, and the deploy scripts live in the repository tree.
git clone https://github.com/kr4g/Tau.git
cd Tau
python3 -m venv .venv
.venv/bin/python -m pip install -e .
It is also installable as a dependency in a tree of your own:
pip install tau-av
Machine self-check
.venv/bin/python -m tau.preflight
Verifies Python version, GL context, shader compilation, numba JIT, calibration presence, port availability, and UDP send/receive — run it after installing, and on any machine before it joins a cluster.
Run
The launcher lists the apps under examples/ and apps/, switches between the
two, and runs the selection as a subprocess; picking another app stops the
first:
.venv/bin/python -m tau.launcher # window; --tui for a terminal menu
Further directories are listed with --apps-dir. When node agents are running
(see "Running in the AlloSphere"), a launch or stop also fans out to them, so
the selection changes what the whole cluster shows.
A single app is targeted directly; every app has the same entry point:
# perspective window (default view)
.venv/bin/python -m examples.<name>.app
# start in a different view: pov, cross (cubemap box), or equirect panorama
.venv/bin/python -m examples.<name>.app --view equirect
Each app adds its own flags on top of the shared renderer flags below; run it
with --help, or read the module docstring in its app.py.
Controls: arrow keys look around (yaw/pitch), WASD moves in the view plane,
E/C move up and down, ` (backtick) stops all motion and returns the
camera to its home pose, v cycles the view (pov → cross → equirect), Esc
quits. The view is local to each machine and can be changed while the app
runs. A second instance started while the first is open auto-elects as a
replica and syncs over the network.
The camera home pose is the origin with identity orientation; an app may
capture a different one with self.nav().set_home().
Every start prints a role banner — host, role, primary/replica, broadcast target, renderer, calibration — so a process that resolved to the wrong role is visible at startup.
Renderer flags
| Flag | Purpose |
|---|---|
--view {pov,cross,equirect} |
starting desktop view (v cycles at runtime) |
--omni |
alias for --view cross |
--sim |
elect this machine as the simulator (any host) |
--broadcast ADDR |
state broadcast address override |
--windowed |
force a windowed AlloSphere renderer (disable auto-fullscreen) |
--fullscreen |
force a spanned undecorated window |
--capture-res N |
per-projector capture resolution |
--calibration-dir DIR |
calibration directory (<host>.txt + projN.bin) |
--no-gui |
suppress the control panel |
Environment
| Variable | Effect |
|---|---|
TAU_PRIMARY_HOST |
hostname that elects as primary (default ar01) |
TAU_NO_GUI=1 |
never open the control panel |
TAU_NO_NUMBA=1 |
force the numpy path even where Numba is installed |
TAU_PARALLEL_MIN |
population below which the parallel neighbor kernel runs serially (default 1500); thread spin-up costs more than it saves for small counts |
TAU_CACHE_DIR |
where precomputed data is cached; point it at a shared path so every node loads one copy (default: XDG user cache) |
Writing an app
Apps you write go in apps/. An app is a Python module that subclasses
DistributedApp and overrides a few methods: on_init, on_create,
on_animate(dt), on_draw(g), and optionally on_gui(panel) and
on_keys(keys). The same file runs as a window on one machine and across the
cluster in the AlloSphere, where the runtime elects a primary, replicates state
to the renderers, and warps and blends each projector from its calibration.
The apps under examples/ all follow one layout: a model module holding the
algorithm as vectorized numpy, a state.py declaring the replicated dtype, and
an app.py with a main() that calls tau.run.
on_animate(dt) runs once per frame; on_draw(g) runs once per projector per
eye. Build and upload geometry in on_animate, and issue only draw calls in
on_draw. An app that uploads inside on_draw renders correctly in a window
and differently on each projector.
Where your code goes
tau/ and examples/ change upstream. Two directories are yours:
| Directory | Contents |
|---|---|
apps/ |
apps you write; the launcher switches between these and the examples |
ext/ |
code your apps import: helpers, kernels, shaders |
Both ship empty and their contents are ignored by git, so a pull does not
affect them. An app in apps/<name>/ runs as python -m apps.<name>.app, the
same shape as an example; anything under ext/ is imported directly, as
from ext.<module> import .... Nothing under ext/ is a launch target — the
node agent runs modules from apps., examples., and tau. only.
Working with a coding agent
AGENTS.md carries the conventions and the reasons for them, in a
form meant to be read by an agent as much as by a person; agents working in a
clone pick it up from the repository root without being asked. The apps under
examples/ are the patterns to work from.
The checks below cover what can be checked automatically. Whether an app reads
from inside the AlloSphere is not one of those things — it can pass everything
and still be composed for a rectangle. Look at it in --view equirect and
--view pov.
Control panel
A second window with a view selector, a slider or field for every registered
parameter, and the cluster roster. Apps add custom UI by overriding
on_gui(panel).
It opens only on the simulator/primary; render nodes never open one. Disable it
with --no-gui or TAU_NO_GUI=1.
Shaders
The renderer supplies tau_ModelViewMatrix, tau_ProjectionMatrix, and
tau_ViewMatrix. Declare whichever the shader uses:
uniform mat4 tau_ModelViewMatrix;
uniform mat4 tau_ProjectionMatrix;
Shaders loaded through ShaderManager reload on file change while the app runs.
Checking an app
The suite is layered so that a pass on one machine predicts behavior on the
cluster. Every app is drawn twice for the same frame through the
multi-projector path and must produce identical output. Every shader must
compile at #version 410, the strictest version the renderers accept. The
warp composite is checked pixel-for-pixel against an independent
reimplementation, and a two-process rehearsal runs election and transport over
loopback.
.venv/bin/python -m pytest
bash scripts/test-py310.sh runs the same suite on the interpreter the
renderers use. Broadcast delivery on a subnet, driver differences, the spanned
X screen, and quad-buffer stereo are checked on site.
For cost rather than correctness, python -m tests.bench_sphere reports
simulation and render timings; --save before.json and --compare before.json bracket a change. Set TAU_CALIBRATION_DIR to profile against a
real calibration set.
Running in the AlloSphere
Stage the app on the shared /alloshare mount and build the venv there once,
from a renderer (Linux/x86_64): bash deploy/build_venv.sh. Then either start
the same app on every machine by hand:
# identical on the simulator and on every renderer
# (e.g. broadcast to all panes in an iTerm2 multishell)
.venv/bin/python -m examples.<name>.app
or start the node agents once and switch content from the simulator alone:
bash deploy/launch_sphere.sh start # an agent on every renderer
.venv/bin/python -m tau.launcher # pick an app; the cluster follows
Role and renderer are auto-resolved by hostname and calibration, so no flags
are needed. The rank-0 host is the primary and sends state; the renderers are
replicas that receive it. A renderer with a
/home/sphere/calibration-current/<host>.txt manifest applies warp and blend
and runs fullscreen automatically. To drive the cluster from a machine whose
hostname the cluster does not know, add --sim.
State ships as full snapshots fragmented over UDP, latest-wins, with 16 MB socket buffers on both ends.
Cluster status
Every node broadcasts a heartbeat once a second. The primary's control panel shows the roster (host, role, app, frame rate), and
.venv/bin/python -m tau.heartbeat
is the same table in a terminal. Two simultaneous primaries — for example
--sim on a laptop while the resident simulator is up — are reported on both.
Projector identification
Setting the /tau/pattern parameter (a slider in every app's control panel;
number keys 0–5 in examples.calibration) switches all renderers into a
diagnostic pattern without stopping content: per-projector labels, solid hash
colors, viewport outlines, checkerboards, or an orientation glyph that
distinguishes a physically rotated projector from bad warp data. 0 returns
to normal rendering. Degraded states — no calibration, state not arriving —
are drawn on the output itself.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tau_av-0.1.1.tar.gz.
File metadata
- Download URL: tau_av-0.1.1.tar.gz
- Upload date:
- Size: 274.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdc3ac5e3ba1d99c14e567998b92a40ef0901ff536ce359ca1334a4cc1821214
|
|
| MD5 |
3f3ee8f3b40820ed10439a03e0ceb36d
|
|
| BLAKE2b-256 |
8898ee2c1adc7ff9b492cc92658a52a73498b10e7268ccfb954c0be9308d0cc9
|
File details
Details for the file tau_av-0.1.1-py3-none-any.whl.
File metadata
- Download URL: tau_av-0.1.1-py3-none-any.whl
- Upload date:
- Size: 118.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f69db7dbcd721efab686fc51c6925ba4f317db31a4496a46bdbeb045f34b8eea
|
|
| MD5 |
b64abe2d2915d4650a4185f524dda8c4
|
|
| BLAKE2b-256 |
216733dc796a22420ac157ccbbab2538ef087be5d64ae0c2e239add390793749
|