Stoatworks Labs

User guide

Genlock user guide

v0.1.0Updated 12 October 2026

Genlock is an Amiga genlock, flaws and all, as an FFGL mixer for Resolume Arena and Avenue. It keys the computer’s colour 0 over incoming video the way the hardware did, and cuts that key on the computer’s own pixel clock, which isn’t locked to the video.

So the key lands a pixel or so away from the fill it belongs to. Every edge of the overlay gets a coloured fringe, the fringe crawls as the two clocks drift apart, and when the sync goes the overlay rolls. None of it is drawn on; it’s what you get when a key is timed by the wrong clock.

The computer’s picture keyed over video, with a coloured fringe down one side of every edge

The repo’s two test cards through the plugin at a three-pixel key delay, rendered by the offline harness rather than captured from Resolume. The band down each graphic’s edges is where the key and the fill disagree, and Edge Tint has coloured it.

Before you rely on this: it’s released at v0.1.0, and still early days. The timing is measured rather than taken on trust. An offline harness drives the real plugin with two inputs at two different sizes. A whole-pixel key delay moves the key exactly (0 of 164 bytes differ). The crawl follows the rate its clock error predicts to 0.0176 texels over 30 frames. The roll lands within 0.0000 rows at two rasters. All 21 controls the harness can sweep change the picture. It has never been loaded into Resolume on macOS. On Windows it loads in Resolume Arena 7.27.1, appears as a layer Blend Mode, is driven every frame with both inputs, and takes its Opacity from the layer’s opacity fader. That was measured on software rendering, and nobody has looked at its picture inside Resolume yet. Arena doesn’t show the Key Source control, so there the key is always Colour 0. Try it on a spare layer first, and please tell me about anything that misbehaves.

This codebase was created with AI assistance, directed and reviewed by a human author.


Installing

Download the build for your platform: for macOS there’s a universal .dmg or .zip, and for Windows an x64 installer or .zip. Put the plugin in Resolume’s FFGL folder, then restart Resolume:

macOS    ~/Documents/Resolume Arena/Extra Effects/
Windows  %USERPROFILE%\Documents\Resolume Arena\Extra Effects\

Avenue uses the same layout in its own folder. Yes, it’s Extra Effects, even though this is a mixer: Resolume Arena 7 has one FFGL plugin folder, and sources, effects and mixers all load from it. There’s no Extra Mixers.

In Resolume a mixer turns up in a layer’s Blend Mode list (the same list Resolume uses for transitions), so you choose SW Genlock as the blend mode of the upper layer.

The macOS builds are Developer ID-signed and notarised, so the bundle loads without any extra steps. The Windows builds aren’t code-signed. Plugin files aren’t gated the way .exe files are, so Resolume loads them as normal; only the installer trips SmartScreen, and only once: More info → Run anyway.


It is a mixer, not an effect

An effect gets one picture. A mixer gets two, and Genlock needs both:

Input In the code What it is here
Dest the layer below The incoming video: what the genlock locks to. It never moves.
Src this layer The computer’s picture: the fill, and the colour 0 the key is cut from.

To patch it, put your video on a layer and the computer’s picture on the layer above it, meaning graphics on a flat background colour. Then set the upper layer’s Blend Mode to SW Genlock. If it’s only handed one picture, the plugin won’t draw, and the log records it the first time (see Diagnostics).

The two layers don’t have to be the same size. Each input is read at its own resolution, and every distance below is measured across the output picture.


Start here

The defaults are a working genlock. Put a graphic on a flat Workbench blue background (#0055AA) on the upper layer and video below it. The blue turns into video, and the graphic sits over it with a thin cyan fringe down its edges. The fringe walks about one Amiga pixel a second and snaps back. If your graphic is on black, set Key Source to Luma (you can’t in Resolume, where Key Source is hidden: put the graphic on a flat colour and use Colour 0 instead).

Next, try Key Delay. Push it further from zero and the fringe gets wider, and flipping the sign swaps which edge gets which kind of fringe. After that, take Clock Error up to watch the crawl turn into a blur, and pull Sync Quality below halfway to watch the overlay lose lock.


Key

Key Source: what counts as “show the video here”. The default is Colour 0.

In Resolume this control is missing. Resolume Arena 7.27.1 doesn’t show Key Source in the mixer’s panel (the other 25 controls are all there), so in Resolume the key is always Colour 0, and Luma and Alpha can’t be chosen. Measured on Windows on 2026-09-23; I don’t know why Arena hides it. Put your graphic on a flat background colour and set Key Colour to it.

Key Source Video shows through where this layer is…
Colour 0 close to Key Colour. This is the palette’s background colour, and it is what a real genlock keyed on.
Luma darker than Tolerance, using Rec. 709 luma. Use this for graphics on black.
Alpha more transparent than Tolerance.

The key is measured on straight (un-premultiplied) colour, so an antialiased edge isn’t mistaken for a darker colour.

Key Colour: the colour that becomes video. The host sees it as three parameters, Key Colour Red, Key Colour Green and Key Colour Blue, and can show them as one swatch. The default is Workbench blue, #0055AA. It’s only used when Key Source is Colour 0.

Tolerance: how far a pixel can be from the key colour and still be keyed, from 0 to 1. It’s a fraction of the longest distance in the RGB cube. Under Luma and Alpha it’s the threshold instead. The default is 0.12.

Softness: the width of the key’s soft edge, from 0 to 0.5 in the same units as Tolerance. At zero the key is a hard step.

Invert: swaps the two sides of the key. The graphic becomes the hole and the background becomes the fill.


Timing

Amiga Mode: Lores, Hires or Superhires. It sets how wide one “Amiga pixel” is: 1/320, 1/640 or 1/1280 of the picture width. That width is the same at every output resolution, so a one-pixel fringe is the same share of the frame at 720p and at 4K. It sits first in the group because it sets the unit Key Delay and Crawl Wrap are counted in. Those two count the computer’s own pixel clocks, so each is half the distance in Hires and a quarter in Superhires. The speed of the crawl across the picture, and how far a tear throws a line, are timing errors in the video, so they stay the same in every mode. The default is Lores.

Key Delay: how far the key lands from its fill, from −8 to +8 Amiga pixels of the current mode. The default is −1.

Negative lays the palette’s colour 0 over the video along the left edge of each graphic and cuts video into the graphic along the right; positive swaps them. Both happened on the real hardware. At zero the key and fill line up, until the crawl moves it.

Clock Error: how far the Amiga’s clock is from the video’s, from 0.01 to 50 parts per million. The slider’s scale is geometric because everything interesting is at the low end. At 0.01 ppm the fringe takes about fourteen seconds to walk one lores pixel. Above about 1 ppm it moves more than seven pixels a second and stops looking like a crawl. At 50 ppm, which is an ordinary crystal’s tolerance, it’s a blur. The default is about 0.13 ppm, or roughly one pixel a second.

Crawl Rate: multiplies the crawl without changing Clock Error, from 0 to 4. The default of 0.25 on the slider is ×1. At zero the fringe freezes wherever it is. That doesn’t mean the clocks are locked; it just stops the crawl.

Crawl Wrap: how far the fringe walks before line sync pulls it back, from 1 to 16 Amiga pixels of the current mode. The slider is linear. A real genlock re-locks on every line, so the fringe doesn’t drift away: it walks, snaps back and walks again. 1, the default, is a genlock that re-locks cleanly. 16 is the length of the PAL colour burst the genlock locks to. Past that, the device has lost lock, which is what Sync Quality is for.

Sync Quality: how well the genlock holds vertical lock, from 0 to 1. The default is 1, which is locked. At 0.5 and above there’s no roll at all, and this is a hard switch rather than a gradual fade. Below 0.5 the overlay rolls vertically at Roll Rate. Lines within about 6% of the picture height around the roll’s seam get thrown sideways. The further the quality drops, the further they go, up to 24 lores pixels at zero. The video underneath doesn’t move, because the overlay is the part that has lost lock.

Roll Rate: how fast the overlay rolls once lock is lost, from 0 to 4 rolls a second. One roll is the whole picture height. The default is half a roll a second. The roll speed doesn’t change with Sync Quality, but how hard the lines tear does.


Fader

Fader: a three-position switch, like the hardware had. The default is Overlay.

Fader Output
Video The layer below, untouched.
Overlay The keyed picture: the computer over the video.
Dissolve A mix between the two, set by Dissolve.

Dissolve: the dissolve knob, from 0 (all video) to 1 (all overlay). The default is 0.5. It only does anything at the Dissolve position.


Look

Fringe: how strongly Edge Tint colours the band where the key and the fill disagree, from 0 to 1. The default is 0.35. The fringe is there even at zero, because the disagreement itself is the artefact. Real hardware added chroma crosstalk on top of it, and this control sets how much of that you get. At a Key Delay of zero there’s nothing to tint.

Edge Tint: the colour of that crosstalk. Like Key Colour, the host sees it as three parameters: Edge Tint Red, Edge Tint Green and Edge Tint Blue. The default is a cyan I picked by eye. It’s styling, not a measured colour.

Opacity: the master blend against the layer below, from 0 to 1. At 0 the output is the video underneath. It’s called Opacity rather than Mix because the FFGL SDK’s own mixer example says Resolume looks for a parameter with that name to use as the mix. And it does: in Resolume this is driven by the layer’s Opacity fader, and the Opacity slider in the mixer’s panel is overridden, so moving it does nothing. Use the layer’s fader. (Measured in Arena 7.27.1 on Windows, 2026-09-23. Whether the layer’s transition or autopilot moves it too hasn’t been tried.)


How it works: the wrong clock

A genlock keys the computer’s background colour over incoming video, and the video sets the timing. The Amiga doesn’t follow it. The key is cut on the Amiga’s own pixel clock (PAL lores, 7.09379 MHz), which runs freely a few parts per million away from the video’s clock. So the key is fetched a small distance from the fill it belongs to, and that distance keeps growing. The rate is the pixel clock times the fractional error, and the line sync pulls it back every time it reaches Crawl Wrap. That gives you all three looks: the fringe from the fixed offset, the crawl from the error building up, and the roll when vertical sync is lost.

The shader never sees a clock. The host’s time is reduced on the CPU, in double precision, so a long session doesn’t lose precision. If the host never sends a time, the crawl and roll run on the wall clock (right speed, arbitrary start).


Diagnostics

The plugin writes a small log:

macOS    ~/Library/Logs/genlock/genlock.YYYY-MM-DD.log
Windows  %LOCALAPPDATA%\genlock\logs\genlock.YYYY-MM-DD.log

The first line is written as soon as Resolume loads the file, before anything is created, and it names the path it was loaded from. A log that holds that line and nothing after it means Resolume found the plugin but never used it. No log at all means Resolume never looked in that folder.

After that it records the host’s name and version; the GL vendor and viewport when it was put on a layer; the sizes both inputs arrived at on the first frame; the first time it was called with one input, none, or a null or empty one (each logged once); whether the host drives the clock and in which unit (at frame 1, frame 300 and shutdown); beat and sample-rate calls; and the first 16 changes to Opacity.

The Opacity lines follow the layer’s Opacity fader rather than the mixer’s own slider, which Resolume overrides. A shader that fails to compile shows up as a plugin that does nothing, and the reason is in this log.


Performance

It’s one pass with three texture reads. The worst of five runs on an Apple M4 Max was:

ms/frame Share of a 60 fps frame
1280×720 0.020 0.1%
1920×1080 0.036 0.2%
2560×1440 0.054 0.3%
3840×2160 0.118 0.7%

Repeated runs vary by as much as a factor of two, because at this size the measurement itself costs about as much as the work. Take the ceiling, not the average. I haven’t timed it inside Resolume.


Known limits

  • Key Source is missing in Resolume. Arena 7.27.1 doesn’t show it, so the key is always Colour 0 there; Luma and Alpha keying can’t be reached.
  • Never loaded into Resolume on macOS. On Windows, Arena 7.27.1 drives it every frame (measured on software rendering, 2026-09-23), but no picture from inside Resolume has been checked. Whether Resolume ever hands it only one input, and whether a layer transition moves Opacity, are still open.
  • PAL only, with no NTSC switch.
  • Hires and Superhires are arithmetic, not observation, and the 16-pixel Crawl Wrap ceiling is derived from the colour burst rather than measured on a genlock.
  • The tear at the roll seam is a look, not a model, and premultiplied alpha is assumed for both inputs.
  • No presets and no OpenFX port.
  • There’s a browser demo at genlock-demo.stoatworks-labs.com. It’s a port to a web page rather than the plugin: the shaders run in WebGL2 and any CPU half is rewritten in JavaScript. The page lists what it doesn’t reproduce.

About

The About group at the bottom has a credit line (name, version, licence, Stoatworks Labs) and buttons for this user guide, the project page, the source on GitHub, and the support page.

Report anything at github.com/stoatworks-labs/genlock/issues with a screenshot, your Resolume version and the day’s log. As this is the fleet’s first mixer, the log’s first dozen lines are the most useful part.

This guide lives in the project's own repository and is rebuilt from it, so corrections are welcome as a pull request against docs/USER-GUIDE.md. Last updated 12 October 2026.