Releases: stoatworks-labs/receipt
Release list
Receipt v0.1.0
The picture printed by a thermal receipt printer, as an FFGL effect for Resolume Arena and Avenue, shown as SW Receipt. A thermal printer has no ink. A line of heaters, 576 across an 80 mm roll or 384 across 58 mm, eight to the millimetre, sits on heat-sensitive paper, and the paper darkens where it gets hot enough, one dot row at a time. Receipt runs that physics row by row, and the look falls out of the heat rather than being drawn.
Tone is a dither (Bayer 8 × 8, Floyd–Steinberg or Atkinson, in raster order). A heater that fired is still warm on the next row, so lines thicken, every mark trails a tail below itself and dark areas block up; History Control shortens a warm firing heater's strobe by the predicted heat, which stops the thickening but cannot cool a heater that is not firing. The supply can only fire so many dots at once, so the head is strobed in 1 to 8 blocks and a block over the budget sags: dense rows print paler and band at the block boundaries, and dark footage prints a banded grey. A slipping roller repeats or overprints rows. Static prints each frame as a receipt; Printing scrolls the receipt out of the slot in real time, each row printed from the frame on screen when the head reached it, and tears it off. Age, six paper tints, Letterbox / Rotate / Tile.
What is verified
By tools/verify.sh on an M4 Max, macOS 26.4, on 2026-09-25, at two rasters (320×180 and 1280×720), and again on Apple's software renderer (the one CI's runners fall back to):
- Dither: on ten flat greys Bayer fires exactly its count of 64 dots; Floyd–Steinberg is within 0.0013 of the tone (derived bound 0.0053) at 320×180 and 0.0009 (0.0029) at 1280×720; Atkinson within 0.068 (bound 0.13), and exactly blank below an eighth.
- Heat: at Heat Carry 0.81 with no History Control a 9-dot line is 11 dots wide from its fifth row, as predicted, and runs on 11 rows below its end; under full History Control it stays 9 and runs on 3; every density within 10⁻⁷ of the closed form.
- Budget: at 2, 3 and 4 strobe blocks every visible dot of four bands prints at the stated sag to 10⁻⁷, and every density step sits within a dot of a block boundary.
- Slip: forced repeats and stalls of 1 and 3 rows move exactly the stated rows. Grid: every pixel is ink, paper or off the paper exactly as the dot grid says. Printing: the same rows after 0.45 s at 60, 50 and 30 fps, exactly where elapsed time puts them, and the tear where stated. Resize: every dot kept across a resize mid-print. Alpha: paper opaque, off the paper transparent.
- Seven perturbed printers each fail their check; a one-character mutation of the shipped display shader is caught by
--alpha. - All 14 controls change the picture;
oxbowloads it asSW Receipt/RC01/ effect and renders 120 frames; the two macOS slices' output is byte-identical under Rosetta. - Windows, in Resolume Arena 7.27.1 (win-lab, Mesa llvmpipe, no GPU, 2026-09-25): the DLL of this source loads, registers as
SW Receipt/RC01/ effect, all 20 host controls match the declaration, it renders and Arena's log stays clean: 9 of the fleet gate's 9 checks, with all 14 controls and Arena's Opacity shown moving the picture (Print Speed and Tear Length in Printing mode). Software rendering says nothing about a GPU or about speed.
What it costs, and what is assumed
The dither and the print run on the CPU at the head's resolution, after a read-back of the GPU's sample pass: about 1.2 ms a frame for error diffusion and 0.4 ms for Bayer on an M4 Max, whatever the output's size (1.7 / 1.9 / 2.6 ms in all at 720p / 1080p / 4K; Printing 0.4 / 0.4 / 1.1 ms). The read-back's stall inside a real Resolume composition is unmeasured: glReadPixels waits for everything queued before it, the host's layers included.
The printer's constants are chosen, not measured from a real printer: the paper's threshold 0.35 and saturation 1, the lateral heat spread 0.22, the budget of 96 dots a block and the optical density 1.3, and the paper and dye colours. The shape of the response is the real one; the numbers are this plugin's.
What is not
- Never loaded into Resolume on macOS. Footage has been seen only through the harness's
--pipe(every bundled clip, and the project video). - Feed jitter is not modelled (slips are whole rows); a dense row sags rather than being re-strobed; Heat Carry is per row, not per second; Rotate turns one way only.
- No OpenFX port and no presets. There is a user guide at https://stoatworks-labs.com/software/receipt/guide/ and a browser demo at https://receipt-demo.stoatworks-labs.com/ (a port to a web page, not the plugin: the shaders are the plugin's, the print engine is a port to JavaScript).
The macOS builds are Developer ID-signed and notarised (the .dmg and the bundle inside the .zip, tickets stapled). The Windows build is unsigned, so SmartScreen warns once.