tellur-live
tellur-live is a local preview host for editing tellur timelines. It loads a
timeline plugin from a Rust cdylib, keeps the render process alive across
frame requests, and reuses one CachingRenderContext for the session.
The dynamic-library boundary is a Rust-internal ABI. Build the host and plugin from the same workspace/toolchain; this is not intended as a stable C ABI.
Build a Plugin
use ;
export_timeline!;
The bundled demo plugin can be built with:
Cargo writes it to:
target/release/examples/libdemo_timeline_plugin.so
Run the Preview Host
Open http://127.0.0.1:4317/ for the minimal browser client.
On startup, tellur-live prints a short banner to stderr with the listen URL,
CPU, selected GPU adapter (when enabled), and the effective TELLUR_CACHE_RAM /
TELLUR_VRAM budgets.
Use --host 0.0.0.0 when the preview server should be reachable from other
devices on the network.
Pass --verbose to print per-frame timing and cache statistics to stdout.
Set TELLUR_CACHE_RAM to cap Tellur-managed RAM caches (render images, audio
decode/conform buffers, and server-side MP4 segment reuse). Set TELLUR_VRAM to
cap large GPU backend allocations, including cached uploads, render targets,
readback staging, and scratch buffers. Both accept byte counts with optional
k, m, or g suffixes, for example TELLUR_CACHE_RAM=1g TELLUR_VRAM=2g.
When unset, both default to 1 GiB. TELLUR_VRAM is the total Tellur-managed GPU
allocation budget; GPU raster/upload caches keep separate internal byte caps
inside that total. If render-critical GPU allocation fails, those cache caps are
shrunk and LRU cache entries are evicted for subsequent frames. When VRAM stays
spare across many successful allocations, the caps grow gradually again.
Passing -p <package> --example <example> makes tellur-live infer the release
cdylib path (target/release/examples/lib<example>.so) and run
cargo build --release -p <package> --example <example> when watched source
files change. --examples is accepted as an alias for --example.
By default, watch paths are inferred from the package: its Cargo.toml, src,
the selected example file, the workspace lockfile/manifest, and local path
dependencies. Use --plugin <path> or repeated --watch-path <path> arguments
to override those inferred values.
When a release build succeeds and the cdylib contents change, tellur-live
reloads the plugin, clears the server render cache, and publishes a new
cacheKey to the browser. The browser uses that key in image/video URLs,
stores media responses as blobs in IndexedDB, and records the green cache
ranges separately. Old IndexedDB media entries and green ranges are revoked
only after a successful cdylib update. Failed builds leave the previous plugin
and cache key in place. Video cache entries are variable-length ranges. Starting
playback inside a cached range seeks within that blob instead of creating a
duplicate cache entry. Missing video ranges fall back to direct streaming
immediately; playback does not wait for IndexedDB cache fill. During playback
the client scans the continuous cached range from the current position and
starts one background stream from the next cache gap. When that stream finishes,
its full range is saved to IndexedDB. When stopped, it fills only the next
three seconds from the current position.
The browser UI is intentionally a thin validation client. It requests
coalesced PNG frames for still previews and seeking, and fragmented MP4/H.264
for playback. The Size and FPS controls lower the request resolution and frame
rate when full-resolution playback is too expensive. The Size control sends an
explicit width and height selected from browser presets, including low,
HD, 4K, and vertical variants. While idle, the client
preloads the beginning of the MP4 stream for the current position so the play
button can reuse already-buffered video data.
HTTP Endpoints
GET /api/inforeturns resolution, fps, the current mediacacheKey, compile status (compiled,compiling, orfailed), hot-reload errors, and timeline metadata.GET /api/eventsstreams the same info payload as Server-Sent Events. The browser client uses this instead of polling/api/info.GET /api/frame?time=1.25&timeline=mainreturns one PNG frame.GET /api/frame?frame=42&timeline=mainreturns one PNG frame by frame index.GET /api/frame?time=1.25&timeline=main&format=rgbareturns raw RGBA8 bytes withX-Tellur-Width/X-Tellur-Heightheaders.GET /api/video.mp4?time=1.25&timeline=main&fps=60&gop=12&crf=23streams fragmented MP4/H.264 throughffmpeg. The browser client uses this path for playback so<video>handles decode and presentation timing.duration=<seconds>limits the generated stream length and is used for IndexedDB video cache segments. Frame and stream endpoints also acceptwidth=<pixels>&height=<pixels>orscale=<ratio>to override the default preview resolution.GET /api/stream?time=0&timeline=main&fps=30returns a simple multipart PNG stream. This endpoint is useful for experiments.