edgefader
edgefader · utilitiesEDGEFADER — a two-source video CROSSFADER that fades THROUGH THE EDGES. Both IN A and IN B get the EDGES operator every frame (Rec. 601 luma, 3×3 Sobel, THRESH gate, THICK dilation) at half engine resolution, packed into one atlas with where the two masks COINCIDE and a coarse edge-density similarity (the regions of A and B whose edges sit in the same place — the fade's anchors). The A/B fader (0 = only A, 1 = only B, exact at both ends) drives a CASCADE down the frame: five 20% bands, each fading over its own window of the fader's travel, the next band starting when the one above is half done (so the top band finishes exactly as the second reaches where the first was when the second began), interpolated between band centres so there is no seam. Within a band edged pixels fade first, coincident / similar edges first of all, a pixel just INSIDE an edge (centre-ward of it) leads one just outside, and flat regions follow — the fade ripples down the edges. The operator is a progressive BLUR that peaks mid-fade (edged regions go soft, then the incoming picture's edges sharpen in) or, with MELT engaged (a latching toggle OR'd with a gate jack), a liquid SCREEN MELT: each band slides down column by column (per-column start delay and drip length from an integer-hash value noise, the classic 1993 screen melt made stateless), with rounded droplet heads at the drip fronts, a sinusoidal horizontal wobble, and drips that carry the melting band down into the band below before dissolving. STATELESS — a pure function of (A, B, fader, thresh, thick, melt) with no clock, RNG or history — so a pinned engine renders the same frame every step; at the resting fader (0.5) the top two bands show B, the middle band is mid-fade and the bottom two show A. CV inputs for fader / thresh / thick (port id == param id) and a MELT gate. The cascade, lead and melt laws are a 1:1 CPU mirror unit-tested in $lib/video/modules/edgefader-core.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
in_a | video | The A video source — what shows when the A/B fader is at 0, and the picture whose edges are detected as A's edge mask. Left unpatched it reads as opaque black with no edges, so an unpatched A with the fader toward A gives a black frame. RGB video stream |
in_b | video | The B video source — what shows when the A/B fader is at 1, and the picture whose edges are detected as B's edge mask. Left unpatched it reads as opaque black with no edges. RGB video stream |
fader | cv | CV modulation of the A/B fade, centred on the manual A/B slider. Effective position = slider + CV x 0.5, clamped to 0..1. With the slider at 0.5 a bipolar -1..+1 signal sweeps fully from A to B. Unplugging restores the manual slider position. control voltage (CV); modulates fader (additive offset — ±1 CV sweeps the full range, centered on the knob) |
threshold | cv | CV input that modulates Thresh — raising it via CV keeps only the strongest gradients as edges (fewer anchor regions), lowering it lets faint edges lead the fade. Linear-scaled into the 0..1 control range. control voltage (CV); modulates threshold (additive offset — ±1 CV sweeps the full range, centered on the knob) |
thickness | cv | CV input that modulates Thick — drives the dilation of both edge masks in pixels, i.e. how wide a region around each contour leads the fade. Linear-scaled into the 1..8 px control range and clamped so it cannot blow up the dilation loop. control voltage (CV); modulates thickness (additive offset — ±1 CV sweeps the full range, centered on the knob) |
melt_gate | gate | MELT gate. WHILE the gate is HELD HIGH (level >= 0.5) the blur fade is replaced by the liquid melt — a momentary hold that drops back to the blur the instant the gate goes low. OR-combined with the MELT toggle, so either can engage the melt independently. gate / trigger; modulates meltGate (summed directly (the destination DSP scales it)); gate — acts while the level is high (reacts to both edges) |
outputs
| id | cable | what it does |
|---|---|---|
out | video | The crossfaded picture: exactly IN A with the fader at 0, exactly IN B at 1, and between them the edge-led cascade (blur, or melt when MELT is engaged). With nothing patched into either input this is black. RGB video stream |
params
| id | label | range | default | curve |
|---|---|---|---|---|
fader | A/B | 0..1 | — | linear |
threshold | Thresh | 0..1 | — | linear |
thickness | Thick | 1..?px | — | linear |
melt | Melt | 0..1 | — | discrete |
meltGate | Melt Gate | 0..1 | — | linear |
controls
| control | what it does |
|---|---|
| A/B | The A<->B crossfade position: 0 shows only IN A, 1 shows only IN B. In between, the fader's travel is split into five overlapping windows, one per 20% band of the picture from the top down (each band starts when the band above is half done), and within each band the edged regions fade first. At the 0.5 default the top two bands show B, the middle band's edges are fading first, and the bottom two show A. Clamped to 0..1. |
| Melt | MELT (0/1, default 0): a toggle you switch on and leave on — it swaps the blur fade for the liquid screen melt, where bands slide down in dripping columns with droplet tongues that fall into the band below. The melt gate additionally forces it while that gate is high. The fader's endpoints stay exact in either mode. |
| Melt Gate | Melt Gate (0..1, default 0): hidden synthetic param the melt-gate CV bridge writes each frame with the gate LEVEL; while it is HIGH (>= 0.5) the melt is forced (OR-combined with the MELT toggle, so the per-frame level never stomps the toggle's latched state). Exposed only as the melt gate jack, not as a knob. |
| Thick | Thick is the width in pixels (1..8 px, default 2) of the region around each detected contour that counts as edged and leads the fade — both masks are dilated by it (the same radius law as EDGES), so it is also the tolerance within which an edge of A and an edge of B count as coinciding. |
| Thresh | Thresh sets the normalised gradient magnitude (in luma-step units) at or above which a pixel counts as an edge in BOTH pictures. 0 = every pixel is an edge, so the whole frame fades as one edged region; 1 = almost nothing is, so the fade degrades to a plain delayed crossfade; default 0.2 catches salient contours without low-contrast texture noise. |
source
edgefader.ts on GitHub.