Skip to content

Releases: stoatworks-labs/fax

Release list

Fax v0.1.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 15:15

The picture sent as a Group 3 fax over a noisy telephone line, as an FFGL effect for Resolume Arena and Avenue, shown as SW Fax. A fax does not send pixels. It thresholds each scan line to black and white, 1728 pels across, and sends run lengths as variable-length codes, each line ended by an EOL; in MR most lines are sent as the differences from the line above, with a plain line every K. Fax sends the clip through a real ITU-T T.4 coder (MH or MR, fill, EOLs, RTC), a line that flips bits, and a real decoder, and the look falls out of the code rather than being drawn.

A bit error throws the decoder off the code, so it streaks from the error to the right edge and stops at the line's EOL. In MR the damage runs down to the next one-dimensional line, at most K = 2, 4 or 8 lines (standard, fine, superfine; T.4 07/2003 §4.2.1.1). A receiver that can tell a line is bad prints the line above instead. Standard resolution is 3.85 lines a millimetre against 8 pels, so a standard fax is squashed. In Page mode the frame is captured and sent at 2400 to 14400 bit/s and arrives line by line, fast over blank paper and slow through detail; in Live mode every frame is a new page. Frame, A4 Crop or A4 Letterbox; an 8 × 8 halftone; bursts; thermal or plain paper; a header line printed by the sending machine.

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):

  • All 204 code-table entries agree bit for bit with two independent transcriptions of T.4 (golang.org/x/image/ccitt and pdfminer.six); 5,820 runs of both colours round-trip at exactly the standard's bits.
  • Go's CCITT decoder, which shares no code with the plugin, decodes its MH and T.6 streams back to the page with 0 of 100,656 bytes different, and rejects a stream with a deliberately wrong vertical mode.
  • A clean line returns the sent page bit for bit in MH and MR, on 28 corpus pages and 8 plugin pages up to 4.4 million bits.
  • Each of 47 single bit errors in an MH line damaged its own line from the error on and nothing else; in MR, errors at K = 2, 4 and 8 never ran past the next one-dimensional line, and with concealment off the tallest was exactly K.
  • Every Repeat Line concealment is the line above, bit for bit; in Page mode all 466 lines arrive within 2 ms of their bit count over the baud, and no line is under the 10 ms floor.
  • The scan and the print agree with a recomputation in double (0 wrong pels; 0 pixels off by more than one 8-bit step; alpha 255 over a transparent source); the page survives a resize mid-page.
  • Nine perturbed models each fail their check; a one-character mutation of the shipped print shader is caught.
  • All 13 controls change the picture; oxbow loads it as SW Fax / FX01 / effect and renders 120 frames.
  • 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 Fax / FX01 / effect, all 19 host controls match the declaration, it renders and Arena's log stays clean: 9 of the fleet gate's 9 checks. Eight controls were shown moving the picture; Resolution, Coding, Bursts, Baud, Concealment and Header were inconclusive, because Live mode codes a new page with new bit errors every frame and the picture never stands still. Software rendering says nothing about a GPU or about speed.

What it costs

The coder, the line and the decoder run on the CPU, on the render thread. At the defaults (Live, a halftone page of ~2.2 million bits every frame) that is about 9–10 ms a frame at 720p–4K on an M4 Max, more than half of a 60 fps frame; with Halftone off, under 1 ms at 1080p. Superfine halftone in Live mode is not real-time (~32 ms a frame, about 31 fps). Page mode pays the coding cost once a page. Nothing was timed inside Resolume or on Windows.

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).
  • No Error Correction Mode: this is the fax of the 1980s. The error model and the paper colours are stated, not measured. MR's wedge is two or three lines of a 1080-line frame at any resolution (K doubles as the lines halve), so on screen it reads as a thick streak.
  • No OpenFX port and no presets. There is a user guide at https://stoatworks-labs.com/software/fax/guide/ and a browser demo at https://fax-demo.stoatworks-labs.com/ (a port to a web page, not the plugin: its coder, line and decoder are a hand port to JavaScript that nothing checks on the page; the repo's demo/tools/check_port.sh compares it bit for bit with the plugin's C++ on twelve test pages).

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.