SAMPLER
SHADER
MODE
sampler
shader
live
SOURCE
open
play
reverse
restart
loop
bounce
cam
front
rear
rot 0°
flip
mirror
blend
SPEED 1.00×
IN / OUT
BLEND normal 50%
SHADERS AND FX CHAINS
PARAMS
GEN SHADER
FX SHADER
fx off
VIDEO
O open file
capture screen
F9 snap png
L camera
SPC play/pause
R reverse
flip V
rot 90°
0 in→out→clr
record
LFO
120.0 BPM
LFO 1
AMP
0.50
OFS
0.00
SKW
0.50
CRV
0.50
4.0s
LFO 2
AMP
0.30
OFS
0.00
SKW
0.50
CRV
0.50
8.0s
LFO 3
AMP
0.30
OFS
0.00
SKW
0.50
CRV
0.50
16.0s
AUDIO INPUT
off
mic
vid
tab
file
BASS
MID
TRE
VOL
MOD DEPTH
50%
HOLD
0%
MIDI
MISC
F fullscreen
RST reset params
? help
P perf meter
I system info
DEF default
ZOOM 1.00× RES
RENDER CAP
DROP VIDEO

recur-recur

live visual instrument
Feed it video, camera, or screen capture and route it through stacked real-time GLSL shaders — generative patterns, kaleidoscopes, feedback, colour, distortion — with every parameter tweakable live. Audio, LFOs, and a tap-tempo BPM clock can modulate any parameter. Record output as video. Cast to a second screen for projection.
Panel
◀ tabTap the tab at the bottom centre of the screen to open / close the control panel
grip stripTap the grip at the top of the panel to close it. Drag it up/down to resize the panel height
SHADERS AND FX CHAINSFolds away the preset bank and the GEN and FX chains in one go, leaving the mode buttons, the source controls and the param sliders. The source controls have their own SOURCE header above them and fold separately. Handy on a phone when you only want to ride the sliders. Whichever way you leave it is remembered between sessions
PARAMS headerThe slider area has its own header above it, which folds the sliders away the same as any other section and names the shader they belong to — so you can still see what is selected with the sliders hidden
section headersEvery heading except MODE — SOURCE, SHADERS AND FX CHAINS, GEN SHADER, FX SHADER, VIDEO, LFO, AUDIO INPUT, MIDI, MISC — is a show/hide toggle. Tap one to fold that section away; the arrow on the right points down when open and right when closed. Useful on a phone where the panel would otherwise be a long scroll. VIDEO, LFO, AUDIO INPUT, MIDI and MISC start closed since they are mostly set-and-forget; SOURCE, GEN SHADER and FX SHADER start open. SOURCE is the open/pause row, the transform row and the speed and in/out sliders — fold it once a clip is running the way you want and the panel gets most of a screen shorter. MISC also holds ZOOM, RES and RENDER CAP, so open it if you are hunting for those. What you collapse from then on is remembered between sessions
MODE buttonssampler / shader / live sit at the top of the panel, directly under SAVE / LOAD / SHARE / CAST, so they stay visible instead of scrolling away with the rest of the body
RNDRandomise, hard left on the top row with a blank slot between it and SRC. Fills the GEN chain with 4 different shaders and the FX chain with 4 different effects, rolls every param, picks blend modes and amounts, re-rolls the per-slot seeds, re-rolls all three LFOs and assigns two to four of them. GEN slot 1 is always left on normal at full amount — it composites onto black, where a subtractive mode is an immediate blackout whatever follows it. It also switches to SHADER. Not because the chain would be bypassed — the slots it builds arrive live — but because slot 1 lands on normal at full amount and covers the source completely, so SHADER is simply where the result is. When clips are loaded it also fills all eight sequencer steps from them, never the same clip twice running and never the camera, so a random patch arrives with a sequence under it; with no clips loaded the steps are left alone, and the toast says which happened. The STEPS row is a SAMPLER row, so a randomise done from anywhere else fills it out of sight — it is waiting there when you switch back. It is set apart from the other controls because it replaces both chains wholesale
ZOOMGlobal zoom slider, in the MISC section near the bottom of the panel — it scales the canvas output and is useful when the device resolution is larger than the display area. Tap 1:1 to reset. It lives down there rather than with the chains because it is a set-once control, not something you ride mid-set
RESRender scale — ½ / ¾ / 1×, on the zoom row in the MISC section. A fraction of the display resolution, so it always tracks the screen you are on. Lower means fewer pixels through the shader chain, which is the first thing to reach for when a deep chain drops frames
RENDER CAPAn absolute ceiling on the internal buffer, on its own row in the MISC section — off / 1080 / 4K, defaulting to 4K. Where RES is a fraction of whatever display you plug into, this is a hard pixel budget that does not care how big the screen is. It bounds GPU memory on large displays and does nothing at all below the ceiling. Saved per device, and deliberately not part of presets or share links
resolution readoutThe figure at the end of the RENDER CAP row is the buffer size actually in use, after RES and RENDER CAP have both been applied. A ▼ after it means the cap is currently biting — without that you could not tell a capped picture from a small window
param slidersThe upper slot shows the active shader's parameters — scroll it independently. The lower body scrolls separately
Signal flow strip
GEN rowShows the generative shader chain as four fixed boxes on the same column ruler as every other row in the section. A block sits in the box you put it in and stays there — a single shader can live in box 4 with boxes 1 to 3 empty, so you can lay out a chain before you have filled it. Boxes run left to right in signal order, and empty ones cost nothing: a chain of one renders identically wherever it sits. A filled block carries a short abbreviation — hover for the full name — and clicking it selects its params.

Adding or selecting a GEN does not change mode. The chain composites over the base layer in every mode — the clip in SAMPLER, the camera in LIVE, black in SHADER — so a gen dropped in while a clip is playing lands over that clip and stays there. It arrives un-bypassed even though entering SAMPLER bypasses the chain, and the param sliders, LFO, audio and MIDI bindings all follow it wherever you are. This used to jump to SHADER, which threw away the clip in order to show the thing that was meant to sit on top of it
FX rowShows the FX chain on the same four boxes as GEN directly above it. Same rules: blocks hold their box, empties are free positions, and the order the boxes run in is the order the effects apply. GEN blocks composite onto each other; FX blocks run in series
drag to reorderDrag a block onto another box to move it there. If that box is occupied the two swap — the block you dragged takes the target and the one that was there takes the box you came from. No untouched block moves, so a chain can be laid out position by position
drag from gridDrag a GEN or FX button from the grid below onto a box in the strip. An empty box takes it; an occupied box is replaced, because with fixed boxes there is no gap to squeeze into and replacing is the only thing that puts the block exactly where you dropped it. Dragging the same GEN shader more than once gives you duplicate instances, each with its own random seed so the procedural patterns differ
double-clickDouble-click a block to bypass (disable) it — shown dimmed with strikethrough. Double-click again to re-enable. The shader stays in the chain but is skipped during rendering
top rowEverything that is not a chain, on one line: RND hard left in the label column, then SEQ, then SRC and the camera toggle, then a blank slot and BANK, OVR and CLR. SEQ is only there in SAMPLER, since nothing else plays clips; in the other modes that position is left blank rather than closed up, so SRC and CAM do not move sideways with the mode. The gap before BANK separates the source controls from the bank controls. Below it the strip reads top-down in the order the signal actually travels: clip → gen → fx, with the saved presets last. The bank is storage rather than signal, so it sits under the chains rather than between the controls and them
preset rowAt the foot of the section, under the GEN and FX chains, one block per saved preset with the loaded one lit. It sits there rather than up with the controls because the bank is storage rather than signal — the rows above it read clip → gen → fx in the order the picture is built. It starts hard left, running under the label column as well — it is the one row here that is not on the section's shared ruler, because a preset is not a chain position and there is nothing above or below for it to line up with. That buys most of another block per line. Click any block to jump straight to it: no dialog, no confirmation. [ and ] step backwards and forwards through the bank, which is the fastest way to work through a set. The row wraps to two lines and holds eight; past that it pages
BANKReads just BANK while everything fits. Once you have more than eight presets it reads BANK1, BANK2 and so on, and clicking it steps to the next page and wraps. Saving a preset, jumping to one, or stepping with [ and ] all pull the page to wherever the lit block is, so the loaded preset is never on a page you cannot see
OVROverwrite a saved preset with the patch you have now, keeping its name. Three taps, all on the strip — no dialog. Tap OVR and it lights; tap the preset you mean to replace and it lights, with its name in the toast; tap that same block again to write. Tapping a different preset re-aims instead of writing, so a slip moves the target rather than destroying the wrong one. Escape, a second tap on OVR, or turning the page cancels. While OVR is armed a click on a preset never jumps, so it will not throw away the patch you were about to save
CLRTwo jobs, and the button says which one the next tap does.

With a preset lit in the bank row, CLR is magenta and deletes just that one, on a single tap. No arming: the highlight already is the selection, so a second tap would only confirm something the strip is showing you. Deleting one entry re-lights nothing, so the very next CLR arms the full wipe instead.

With nothing lit, CLR is red and deletes every saved preset. It arms rather than firing: the first tap names how many it is about to delete, the second does it. Escape, or a tap on any other control, cancels.

Neither has an undo, and the bank does not travel with the file, so EXPORT BANK in the SAVE dialog is the only backup. Presets already loaded stay on screen; it is the saved bank that goes
what a jump restoresEverything the preset captured, exactly as saved — including the mode. A preset saved in LIVE will start the camera when you jump to it, and one saved in SAMPLER will drop you back to the loaded clip. Worth knowing before jumping mid-set
drag off stripDrag a block out of the strip and release to remove it. The box it was in is left empty and nothing else shifts, so you can pull an effect out, watch without it, and drop it straight back into the same box. The last GEN shader is the exception and cannot be dragged away
empty boxClick an empty box to arm it — it lights up — then click any shader or effect in the grid below and it drops into that box. This is the no-dragging route to building a chain in whatever order you like, and it is the easy one on a phone. Clicking the armed box again, or clicking any filled block, cancels it. Without a box armed, the grid buttons behave as they always did: tap to add, tap again to remove
Modes
SAMPLERPlays a loaded video file as the source texture — open file, drag onto canvas, or use a previously recorded export. Arriving here bypasses the whole GEN chain so the video shows straight through: both this and LIVE are about the source, and landing in one with the shader stack painted over the top hides the thing you just switched to look at. The chain is kept intact — the blend button in the source row puts it back in one tap, and a GEN you add while already in SAMPLER arrives live rather than bypassed, since you added it to see it
SHADERGenerates visuals from GLSL shaders — no video source needed. Optionally blend a video layer over the output. Arriving here undoes an all-bypassed chain, since SAMPLER and LIVE both leave one behind and you would otherwise land in the mode built for shaders and see none. If you have muted only SOME slots from the flow strip that selection is kept — only the everything-off state is cleared
LIVEUses the device camera as the source texture in real time. Like SAMPLER, arriving here bypasses the GEN chain so the camera shows straight through
ENTERCycle SAMPLER → SHADER → LIVE (keyboard). Each mode arrives set up for what that mode is about — see the three entries above
Video source (SAMPLER)
open fileBrowse for a video file — mp4, webm, mov and most common formats supported
drag & dropDrop any video file directly onto the canvas
capture screenShare your screen or a window as a live source — browser will prompt for permission. It takes over the clip position that is playing and hands it back when the capture ends, however it ends: from the browser's own stop-sharing bar, by selecting another clip, or by loading a file. The clip's name, in/out points and playhead come back with it. Not to be confused with snap png beside it, which writes a still of the output rather than taking a screen in as a source
SPACE / RPlay/pause forwards · Play/pause backwards
in/out pointsTap the in→out→clr button (or 0 key): first tap sets in-point, second sets out-point, third clears both. Video loops between the two points
flip V / rot 90°Flip video vertically or rotate 90° clockwise (cycles 0/90/180/270)
GEN shaders — generative layers
tap GEN buttonAdd that shader to the chain — multiple shaders stack and blend together (up to 4; adding a 5th drops the oldest)
tap againRemove from the chain
drag to stripDrag a GEN button onto the flow strip to insert it at a specific position in the chain
multi-layer blendWhen 2+ GEN shaders are active, a BLEND row appears in params — drag to set mix, tap the mode label to cycle blend modes
4 – 9Keyboard shortcuts to toggle gen shader slots 1–6 — the first six of the fifteen, in table order: plasma, kaleidoscope, tunnel, flowing-colours, hypnotic-rings, squarewaves. The other nine are panel-only
style slidersplasma, flowing-colours and zoom-clouds each carry a style selector with eight variants, plus extra shaping params. In every case style 0 with the new params at zero is exactly how that shader behaved before they were added, so old presets are unchanged — the variants are opt-in
plasmaInterference-field generator. speed/scale/warp/palette work as before. style picks the family, snapping through eight types: 0 classic (the original four-sine field), 1 fractal (the same field stacked over octaves), 2 warped (domain-warped fractal — the field displaces its own coordinates, giving slow organic cloud motion), 3 ridged (creased at every zero crossing, veined and marbled), 4 marble (a sine banded by turbulence — wood-grain and stone), 5 ripples (concentric rings modulated by the fractal field), 6 julia (an actual escape-time fractal, animated by walking c around a circle and coloured by banding the orbit-trap distance; scale is the zoom here rather than frequency — the heaviest style, drop render scale if it chugs), 7 flow (the field advects along itself into streaming filaments). detail sets fractal depth, 1 to 4 octaves, and opens up the falloff between them — it does nothing on style 0. contrast squeezes the field toward its extremes, turning smooth gradients into hard bands. fold applies up to three kaleidoscopic mirror-and-rotate passes for self-similar symmetry. drift walks the whole field along a slow bounded orbit so the pattern travels instead of standing still. All five sit at 0 on presets saved before they existed, and style 0 with detail 0 is exactly the old plasma
flowing-coloursBreathing colour-flow field. speed/detail/warp/hue/zoom work as before. style snaps through eight types: 0 classic (the original field), 1 layered (the same field stacked over octaves), 2 warped (the field displaces its own coordinates — slow organic churn), 3 veins (folded at every zero crossing), 4 contour (topographic banding), 5 vortex (rotated by radius so the field winds into a spiral), 6 moire (two counter-rotated copies multiplied, giving beat patterns a single field cannot make), 7 liquid (soft-thresholded into rounded masses that merge and split). layers sets octave depth 1 to 3 — each octave is six sines so it costs more than it looks, and it does nothing on style 0. contrast pushes toward the extremes, widening the flat saturated regions. fold adds up to three kaleidoscopic mirror passes. steady is the useful one live: the original multiplies the whole field by sin(t/10) so it periodically washes out to flat — at 0 that behaviour is kept, at 1 the amplitude holds constant. vivid boosts saturation. All six sit at 0 on presets saved before they existed, and style 0 with steady 0 is exactly the old flowing-colours
zoom-cloudsDomain-warped cloud field. speed/detail/warp/hue/zoom work as before. style snaps through eight types: 0 classic, 1 billow (folded noise — cumulus rather than haze), 2 wispy (finer scale, thin cirrus), 3 marble (the field banded through a sine), 4 ridged (inverted turbulence, sharp veins filling the frame), 5 storm (extra warp on folded noise, dark and violent), 6 contour (topographic bands), 7 streaks (stretched horizontally into wind-blown layers). contrast is the one worth reaching for: the original ramp blows about half of a typical frame out to flat cream, so this pulls the ramp gain back as you raise it while steepening the curve — you recover the washed-out highlights and get more definition at the same time, rather than trading one for the other. rough raises the octave falloff from the original 0.5 up to 0.78, making the clouds progressively grainier — the fine detail gains weight relative to the broad shapes, and the field is renormalised so raising it adds texture rather than just brightening everything. relief fakes lighting from the field's gradient, giving the clouds volume instead of a flat wash — it is normalised against render resolution, so it looks the same at every RES setting rather than changing strength when you drop the render scale. drift runs the outer warp layer faster than the inner one so they shear past each other rather than boiling in place. palette blends the fixed blue-to-cream ramp toward a full colour palette. All six sit at 0 on presets saved before they existed, and style 0 with rough 0 is exactly the old zoom-clouds
voronoiCellular / particle field. density now scales up to ~44 cells across; speed sets motion; edge softens cell boundaries; palette picks colour. mode selects the look: cells (distance-shaded), borders (cracked-cell network), mosaic (flat colour per cell), or particles (dark field of dots). size sets the dot radius and glow adds an additive halo, so cell centres render as points on top of any mode. swarm blends independent jitter into coherent flow-field motion where neighbouring points stream together like a flock. warp bends the lattice for organic, non-grid cells
squarewavesInterference-wave field, now layered and audio-reactive. amplitude/wavetype/frequency/hue/zoom/softness/rotation work as before. detail stacks octaves for depth (and adds a motion-smear trail); warp bends space with the wave itself for a liquid look; fold applies kaleidoscopic domain folding for fractal structure; relief fakes 3D lighting from the wave gradient to kill the flatness. audio brightens the field per-column with the live spectrum (needs audio enabled; fades out in silence). Heavier at high detail — drop detail or render scale if it chugs on mobile
oscilloscopeDedicated audio-waveform visualiser (needs audio enabled — mic/tab/video). style picks the display: line, filled, mirrored, bars, or radial (circular scope). thickness sets stroke width, scale/gain set the vertical size and sensitivity, hue the colour. persistence leaves a slowly-fading trail of past waveforms (up to ~1s), outline draws a bright edge on the filled styles, glow adds a halo, brightness lifts the background. When audio stops the trail ages out and fades on its own. Use an 'add' blend mode to overlay it on video/other layers
kaleidoscopeRadial mirror pattern generated from its own wave field — unrelated to the mirror and kaleido-warp effects, which fold incoming video instead. sides snaps from 3 to 12 segments, spin rotates the fold (centre is still, either side turns opposite ways), zoom scales the pattern inside each wedge, palette picks the colour ramp. The fold angle is eased so the seam where segments meet stays invisible while the mirror lines themselves stay sharp
tunnelPerspective tunnel — rings rushing toward you with segments running down the walls. speed drives the travel, segs sets how many segments go round (rounded to a whole number so the seam at the back closes cleanly), twist shears them into a helix that tightens with radius, zoom and palette as usual. The centre fades out rather than collapsing to a point
hypnotic-ringsThree sets of concentric rings, one per colour channel, thrown from sources that orbit each other — the interference between them is the effect. speed drives the orbit, freq sets ring spacing, orbit sets how far the two main sources swing from centre, hue rotates the result. softness takes the ring edges from hard bands to a smooth gradient. wavetype morphs the ring profile sine → triangle → sawtooth. drift adds a slower independent wander to all three sources so the pattern stops repeating on a fixed cycle
starfieldTwo independent star emitters, ported from the Pi recur project. Stars run along fixed radial lanes — stars sets how many, up to 500. e1-speed and e2-speed control each emitter: centre is still, above centre throws stars outward, below centre pulls them inward. e1-trail/e2-trail stretch each star into a streak, e1-size/e2-size set the dot (stars grow as they travel). e2-x and e2-y place the second emitter anywhere on screen while the first stays centred, so you can run an outward and an inward field at once. palette and zoom apply to both
gamma-raySingle-frame particle noise — every pixel is re-randomised each frame, so it flickers rather than drifting. density sets how many particles land, on a curve that keeps the low end sparse; brightness scales them; size sets the dot from 1 up to 6 pixels. colour at 0 is white, and raising it sweeps through the phosphor and scintillator colours — green, blue, red. Works well over video on an add or screen blend
wavesThe plainest generator in the table and the cheapest to run. Stacked sine bands rippling across the frame: frequency sets how tightly they pack, speed how fast they travel, count how many layers stack, palette picks the colour ramp and zoom scales the whole field. Five params, no selector, no octave stack — it is the one to reach for as a base layer under something expensive, or when a deep FX chain has already spent the frame budget
FX shaders — effects pipeline
tap FX buttonToggle the effect in/out of the pipeline (up to 4 active; adding a 5th drops the oldest). Badge shows position
drag to stripDrag an FX button onto the FX row of the flow strip to insert it at a specific position
fx blend + mixEvery FX slot has its own BLEND row at the top of its params, same as a GEN layer. Tap the mode label to cycle the compositing mode and drag the mix row to set how much of the processed image comes through. mix is wet/dry: 1.00 is the full effect, 0.00 is the untouched input. With a non-normal mode the effect output is composited back over its own dry input — e.g. difference on an edgy effect leaves only what the effect changed, add keeps the original and layers the effect's brightness on top, and multiply darkens where the effect is dark. The slot still feeds the next one in the chain, so modes stack down the pipeline. FEEDBACK is the exception: it accumulates across frames rather than processing an input, so it sits outside the chain and its BLEND row does nothing. The trail is always composited with screen at a fixed quarter strength, which is what makes it build up frame on frame. Use its own decay and spread params to shape it, and note that its blend-mode param is a different control again — that one reshapes the decayed trail itself
fx off btnClears every FX shader, its params, and mod bindings from the chain instantly — not reversible from the button itself. For a temporary, reversible bypass, double-click a block in the flow strip instead
bitcrush 1-bitEnable the 1-bit toggle in bitcrush params to reduce to pure on/off based on luma. Hue slider sets the "on" colour, threshold sets the cutoff
asciiConverts the image to coloured ASCII characters. Char-size sets character size, invert flips the brightness mapping, mix blends with the original, variation adds per-cell randomness so uniform areas show different characters — it jitters the brightness each cell reads before choosing its glyph, so the character mix loosens while the image still reads. charset picks which alphabet the glyphs come from: 0 all (every block together — what presets saved before this param get), 1 ascii (the full 95-character printable set, the default for new instances), 2 ascii+katakana, 3 katakana only, 4 CJK only. Each set is ranked by ink coverage on its own, so every charset gives a correct dark-to-light ramp rather than a slice of someone else's. rate sets how much the characters churn: it raises both the tick speed — from about one change every 2.5 seconds up to 14 a second — and how far each re-roll is allowed to move along the character ramp. Because the colour of each cell is sampled from the video every frame regardless, a low rate gives you a character that holds still for a beat while its colour keeps shifting with the footage, and a high rate gives a busy flickering lattice. It works on its own and stacks on top of variation
halftoneClassic RGB halftone screen — each colour channel is rendered as a grid of dots at its own angle (R-angle, G-angle, B-angle) and cell size (R-size, G-size, B-size). Default angles approximate traditional printing screens (R=15°, G=75°, B=0°). Mix blends with the original image
levelsTone-curve adjustment (Photoshop/GIMP Levels) — shows a live curve canvas with 5 control points (blacks, shadows, midtones, highlights, whites). Drag a point up/down to reshape the tone curve. Bezier tangent arms show curve slope. All 5 points support audio, LFO, and MIDI modulation via the param sliders below the canvas
sample-holdFreezes the screen at random intervals driven by a noise generator — rate slider controls how often a new sample is taken (slow = long freezes, fast = rapid flicker)
glitchDigital corruption stack. intensity = horizontal slice displacement; rate = how fast the glitch state jumps; channel = RGB split; slices = number of horizontal bands, scaling all the way up to one-per-scanline (per-pixel) at max; variation = pulls neighbouring slices together and occasionally stretches a band to a single repeated line. blocks = macroblock corruption, modelled on how a codec actually fails: a run of consecutive blocks along the scan share one wrong motion vector, so damage arrives as coherent horizontal drags of varying length rather than evenly scattered squares, and it runs at two block sizes at once so the chunks are not all the same size. Displacement snaps to the block lattice, which is what makes it tile like block damage instead of smearing. noise = digital dropout, cycling the failure modes a broken MPEG/JPEG frame really shows — DC-only blocks (detail gone, flat average colour), scrambled-AC blocks (a DCT basis wave showing through as a striped ripple), chroma desync (luma survives, colour comes from the wrong place) and channel roll. Dropouts share the run structure and cluster on blocks that are already displaced, so the two read as one fault. crush = colour bit-crush/quantise (down to ~2 levels), wave = analog sine warp / horizontal wobble. New features sit at 0 (off) on presets saved before they existed
feature-dots (retired)Not in the effects grid and cannot be added to a chain. flow-dots replaced it: it answers the same brief with particles that actually travel and carries the link net as well, so nothing was left that only feature-dots could do.

The entry still exists, and holds its place in the table on purpose. A shader is stored as a number, so removing one renumbers every effect after it — scatter and flow-dots would shift down and every preset and share URL naming either would silently open as the wrong effect. Keeping the slot costs one passthrough draw and keeps every other patch honest. An old patch that used it still loads; that slot passes its input through unchanged rather than drawing dots
scatterCuts the frame into a square grid and rearranges it. grid sets how many cells across, from a handful of big slabs up to 48 fine tiles. shuffle is how far a cell may travel, up to ten cells away, and amount is how many of them move at all — the rest pass through untouched. pixelate quantises inside each cell, from full detail down to one flat colour per tile. rate re-rolls the arrangement on a timer; at 0 it holds still, so you get a fixed scramble rather than a churn. seam darkens a border inside each cell so the grid reads as laid tiles. mode picks how cells move: 0 scatter (each jumps somewhere random), 1 swap (cells trade in pairs — a true permutation, so nothing is duplicated or lost), 2 rows (whole rows slide sideways), 3 columns (whole columns slide vertically), 4 spin (cells stay put but their contents rotate in 90 degree steps)
feedbackTrails. It keeps a history buffer and composites each new frame into it, so the picture builds on itself instead of being processed once and passed on. That also means it sits outside the FX chain. Its BLEND row drives the injection: how each new frame is mixed into the decayed history. That is a different job from the row on any other slot, where it mixes wet back over dry — here it is inside the loop, so whatever it does compounds frame on frame. screen, add and lighten accumulate, so the trail builds and holds; normal crossfades, so the trail decays toward the live frame; difference inverts against the history and gives edge trails; multiply and darken subtract, eating into the picture. The amount row is labelled inject rather than mix for the same reason — it is strength, not wet/dry. At 1.00 with normal the history is fully replaced every frame and there is no trail at all, which is why a new feedback slot starts at screen/0.25 rather than the normal/1.00 every other slot gets. Patches saved before the row was live carry normal/1.00 on their feedback slot and are restored to screen/0.25 on load, which is exactly what they rendered as at the time. decay is how much of the trail survives each frame and is the main length control: 0.92 is a second or so, past about 0.98 it holds almost indefinitely. spread blurs the trail as it ages. Keep it low: the blur compounds every frame, so 0.15 smears the trail to a 36-pixel radius within ten frames and the whole thing reads as a blur filter rather than as echoes. It ships at 0.03. zoom is what actually makes echoes visible — it moves the history a little each frame so each copy lands somewhere new instead of on top of the last one, and at 0 you get no steps at all, just an average. The slider is squared before it is applied, so the middle third is fine control and the ends still reach six per cent a frame, which is nearly seven times over a full trail. It ships slightly zoomed in rather than neutral. rotate works the same way and spirals the trail; it ships at 0.5, meaning none. centre-x and centre-y move the point zoom and rotate work about. At the middle you get concentric rings; move it and the vanishing point goes with it, so the echoes travel across frame. Anything the transform pulls in from outside the frame comes back BLACK rather than as a stretched edge pixel, which is what gives the tunnel a defined border instead of dragging the edge inward for ever. TRAIL is a five-position selector for how the trail is treated as it ages. Every position can only remove light, never add it, so none of them can strobe or blow out to white however the other params are set, and every one of them changes the picture whether your source is colourful or nearly grey. plain is decay alone. cycle tints the trail through a rotating colour, so the whole trail cycles the spectrum over a few seconds — it makes colour rather than shifting what is already there, so it works on monochrome footage too. edge keeps only where the trail differs from its own blur, so the history reduces to outlines and the picture etches itself instead of smearing; spread widens the outline. crisp drops the trail once it dims past a knee, which keeps successive echoes separate instead of smearing them together. ember decays through warm — blue goes first, then green, leaving a red glow that fades last
flow-dotsDots that spawn on visual features, are carried by the motion of the image, and respawn. It replaced feature-dots, which laid a grid out in a field that followed the image and was pulled back toward its rest state every frame, so dots stretched away and settled rather than going anywhere. Here each dot is its own thing, with its own position and its own age, and nothing pulls it home. The controls are grouped: the lattice first, then what counts as a feature, then how a dot lives, then travel, then colour, then the net. LATTICE — pitch is the cell spacing, dot-size the radius, jitter how far a dot strays from its cell. Dot radius has a floor of about a pixel: below that a dot used to fade rather than shrink, because the anti-aliasing band is a fixed width and once the dot is smaller than its own edge it never reaches full brightness — and the composite squares whatever it does reach. On a weak feature at a fine pitch that took the peak to roughly half by the time dot-size reached 0.14. Small dots now stop shrinking instead of dimming. Everything at a normal dot-size renders exactly as before. Pitch has a floor that depends on your buffer: particle state lives in a fixed 512-square texture and the cell index wraps into it, so past 500 cells across the screen, cell 0 and cell 512 are the same particle and the whole field repeats mid-frame. The slider clamps rather than tiling. At 1080p the floor is under the slider minimum and costs nothing; at 4K it is 7.7px, so the lowest third of the travel is flat. The I overlay's dot pitch line gives the number for your machine. FEATURE — sensitivity is the detector gain, exponential from 2 at the bottom to 2000 at the top, so each tenth of travel is a factor of two; it runs on the square root of cornerness, which is linear in contrast where cornerness itself is quadratic. gamma sets how much the dot field distinguishes a strong feature from a weak one, and it is the most powerful control here: measured on a face against a busy room, taking it from the top of its travel to the bottom moves the face from nine per cent of the background's ink to seventy. detect sweeps what registers — 0 corners only, 0.5 every contour, and past 0.5 into the inverse, so at 1 the dots land on everything that is NOT a feature and the features are left bare; around 0.75 the two cancel into a near-uniform field. Flat regions are where optical flow has nothing to solve for, so inverted dots barely respond to the footage and will mostly sit still or fall. LIFE — flow scales how closely a dot follows the motion: 0.25 is exactly the measured speed, the default 0.5 runs at twice it, and the top of the slider at four times, because Lucas-Kanade over a 3x3 window systematically under-reads real motion. life is how long a dot lasts, staggered per dot so the field never blinks all at once; the soft ends are automatic, fifteen per cent of the life at each end with a four-frame minimum for very short lives. TRAVEL — fall is a nine-position selector, off then eight compass directions starting at down and stepping clockwise, and fall-speed sets the rate, from a crawl to about a screen height in under a second. Changing direction changes the velocity and not the position, so a hard turn does not jump the field. Travel is unlimited because every dot shares it: a common velocity is a translation of the whole lattice rather than a journey each dot has to be searched for. The same fact is why it cannot accelerate, so this is a steady fall rather than a ballistic one. COLOUR — tint runs from the colour of whatever the dot is sitting on, taken at square-root brightness so a dark frame still reads, to a per-dot palette hue that drifts slowly. NET — link joins each dot to its neighbours to the right and below, and is the line thickness; 0 turns the net off entirely and is the default, so nothing saved before it existed changes. A link lasts exactly as long as both its dots do and nothing else ends it: the pairing is fixed when the dots spawn, it is never re-tied, and the line stretches to whatever length the two dots drift apart to. It thins out only as one end dies, so a respawn does not pop. This came over from feature-dots, which had it as three sliders; there was one param byte left, so the mesh style is fixed and only the thickness is exposed, and feature-dots' coherence test — which cut a link whenever its two dots disagreed about where they were going — was dropped rather than kept, since that is the opposite of a net that stretches. Length is capped only by how far a dot may wander before it is recycled, which is about three cells. Lines take the colour of the dot they start from, and they draw underneath the dots — at a fine pitch with large dots there may be nothing left to see between them, so open the pitch or drop dot-size to read the net. SELFIE MODE, since it is the case that catches everyone out: skin is smooth, and a corner detector measures contrast, so a face carries about one twentieth of a busy background's cornerness even when it is lit identically — and if the camera exposes for the window behind you, the quadratic law takes another factor of three. The lever is gamma down, or detect up: at 0.9 the face carries more ink than the room does. Sensitivity will not fix it, because it raises both halves of the frame together. The dots composite onto black, so use a screen or add blend to put the footage back. Needs float render targets, which the I overlay reports
maze-flightEndless flight through an infinite fractal maze — a solid universe with corridors carved at three nested scales, so every wall is itself a smaller maze. Ported from a CC0 shader by ksin on glslop. speed sets how fast you travel (0 freezes the frame), fov widens or narrows the lens, turns is how hard the path wanders — at 0 it runs dead straight. width sets corridor size and density how many walls open, so the two together take you from tight warren to open hall. detail switches in the second and third nested scales at a third and three-quarters of its travel, and also buys the extra march steps needed to resolve them — it is the performance control, so drop it first if the frame rate suffers. It ships at 0.6, which leaves the third scale off: those corridors are under a tenth of a unit wide and sweep past the camera faster than a frame, which is most of what reads as sparkle. Push it past 0.75 for the full fractal and expect the near field to get busy. glow lights convex edges, circuits runs light along the wall grooves, windows lights sparse wall panels. hue sets the neon colour and drifts slowly on its own, saturation and fog finish the image. It ignores video entirely, so in LIVE mode set the slot blend to screen or add — the corridors are near black and the footage shows through them while the neon stays lit. Two slots running it land in different parts of the maze
quaternionA 4D Julia set raymarched as a solid object you orbit around — the fractal equivalent of a sculpture on a turntable. Ported from a CC0 shader by ufffd on glslop. FORM: form slides through five seed quaternions, and every position on it is a well-formed creature rather than a set of presets with dead space between them. slice is the interesting one — the object is genuinely four-dimensional and this cuts a different 3D cross-section through it, so the shape reorganises rather than deforming; it stops short of the values where the set becomes empty. morph drifts the seed on a small circle so the creature breathes, and at 0 it holds still. detail sets iteration count and march steps together: it barely touches the silhouette but triples the cost, so it is the surface-detail and performance control. CAMERA: spin orbits the camera, centred at half travel so left of centre reverses; tilt raises or lowers the eye; zoom pulls the camera in — turn it up to come closer, and the top of the travel puts the eye inside the object, so you fly through the structure rather than orbiting it. Which forms enclose you there varies: at the very top, form around a quarter and around one wrap right around you, form near three quarters opens back out into a gap. speed drives the morph and tumble only, so at speed 0 with spin up you get a frozen form you can rotate around. COLOUR: hue rotates the palette. palette picks which orbit trap drives the colour — each of the four is scaled so it sweeps a full turn of the wheel rather than parking the object on one hue. glow is the electric rim light, and shade balances flat-and-electric against modelled-and-solid. The background is black, so on a screen or add blend the object floats over video
mandelboxFolded architecture rather than a creature — infinite slabs, corridors and rounded corners cut out of one solid, raymarched on the same turntable as quaternion. SHAPE: scale is the main form control and runs from stocky and rounded to lacy and spindly; the slider is warped so equal moves give equal change rather than doing most of its work at one end. fold sets the size of the box the space keeps folding back into, which is the strongest shape knob here — but the camera is normalised against it, so the object stays the same size on screen and fold changes only what it looks like. morph drifts scale and fold on a small circle so the structure breathes, and at 0 it holds still. detail sets iterations and march steps together. CAMERA: spin orbits, centred at half travel so left of centre reverses; tilt raises or lowers the eye; zoom pulls the camera in, and at the top of its travel you are inside the folds looking out through them. speed drives the morph and tumble only. COLOUR: hue rotates the palette, palette picks which orbit trap drives it, glow is the rim light, shade balances flat against modelled. The background is black, so on a screen or add blend it floats over video
mirrorReflects the frame about one or both axes. axes picks the arrangement, rotation turns the mirror line before the fold so the seam can run diagonally rather than square, and centre-x / centre-y move the fold origin off the middle of frame. Distinct from kaleido-warp, which folds into radial wedges — this one is straight reflection
invertPer-channel inversion. R-invert, G-invert and B-invert each flip one channel, so inverting one or two gives a colour shift rather than a negative — all three together is the full negative. amount blends the result against the original, so it works as a strength control. Defaults are all four at 1, which is a straight negative
bitcrushTwo reductions in one effect. block-size pixelates, colour-depth quantises each channel to a small number of steps, and gap draws a grid line between blocks for a hard LED-panel look. mix blends against the original. See bitcrush 1-bit below for the threshold mode.

block-size runs on an exponential scale: 1 px at the bottom, 512 px at the top, doubling every ninth of the travel. At the top that is under four blocks across a 1080p frame. The slider is coarse at the far end by design — a linear or squared map spends nearly all of its travel in the range where the picture is still legible and never reaches a size that reads as a handful of big cells. It costs the same whatever the setting; there is no loop, just one texture read per block.

Each block takes the colour of the single pixel at its centre rather than the average of what it covers. On stills that is invisible. On moving footage at large sizes it flickers, because one pixel is standing in for a quarter of a million, and whatever crosses that exact point sets the colour of the whole cell
grainFilm and tape texture as one effect. scanlines darkens alternate rows, noise adds per-pixel grain, luma-crush quantises brightness so the noise sits in visible steps rather than dissolving smoothly, and speed sets how fast the noise pattern is re-rolled — low values leave a fixed dirt pattern sitting over the image, high values give live static
wobbleSine displacement on both axes independently. X-amp and X-freq set how far and how tightly the image ripples horizontally, Y-amp and Y-freq the same vertically. Setting one axis to zero amplitude gives a clean single-axis wave; running both at different frequencies gives the drifting interference pattern
vhsAnalog tape emulation. chroma pulls red and blue apart horizontally, scanlines darkens alternate lines, noise adds per-pixel grain, and tracking jitters whole scanlines sideways at random — the tape-alignment wobble. A slight desaturation and warm tint are applied on top
posterizeReduces the image to a small number of colour steps — levels sets how many, 2 to 16 per channel. contrast is applied after the quantisation, so it hardens the edges between bands rather than creating more of them. tint-hue rotates the hue of the posterised result, centre being no shift. mix blends back against the original
colorizerReplaces the image colour with a hue derived from its brightness, then scrolls that mapping over time. bands sets how many times the hue wraps across the brightness range, speed scrolls it, spread is the saturation. Unlike hue-cycle the mapping stays continuous, so gradients come out smooth
hue-cycleThe banded counterpart to colorizer: brightness is quantised into steps first and each step gets its own hue, giving flat blocks of colour instead of a sweep. bands sets how many, speed scrolls the hues through them, saturation and amount as usual
hsv-shiftDirect HSV adjustment. hue rotates the whole image (centre is no change), saturation multiplies from a fifth up to double, value from a third up to 1.7x. amount blends against the original, so it doubles as a strength control
kaleido-warpFolds the incoming video into mirrored wedges — the video-processing counterpart to the kaleidoscope generator. sectors snaps from 2 to 16, spin rotates the fold over time with centre being still, and centre-x / centre-y move the fold origin anywhere in the frame
rotate-zoomPlain geometric transform. spin covers a full turn across the slider with centre at no rotation, zoom scales from a tenth up to 4x, and centre-x / centre-y set the pivot. Edges clamp rather than wrapping, so pushing past the frame smears the border pixels
zoom-fxZoom with a heartbeat. zoom scales from a quarter up to 3x about the chosen centre, and pulse adds a continuous sine breathing on top. At pulse 0 it is a static zoom
Parameters
param sliderDrag horizontally to change value. Tap a row to select it (highlighted). Some params are toggles (☐/☑) — tap to flip
pattern centringEffects built on a repeating grid measure that grid from the centre of the frame, not from the coordinate origin at the bottom-left. Measured from the corner, animating the cell size — from an LFO, say — slides the whole pattern diagonally instead of scaling in place. bitcrush, ascii, halftone and flow-dots now count their grids out from the CENTRE of the frame, so a size sweep grows and shrinks around the middle and whatever is in the centre of shot stays put. halftone applies the same to its angle sliders, which rotate the dot screen in place rather than swinging the whole frame about a corner. gamma-ray, grain, oscilloscope and scatter are unchanged: they gain nothing from it, and scatter's grid has to stay an exact tiling for its swap mode to remain reversible. Existing presets shift by under half a cell standing still; the difference is only obvious in motion
clip slotsSAMPLER holds four clips at once. The CLIP row in the flow strip shows all four positions, filled or not, on the same column ruler as every other row — so the clip you loaded second is always the second block, and reachable by number without looking.

A fifth block, LIVE, is not a clip: it puts the camera in the source position instead of the selected clip, on shift+5 or a tap. It is the same feed LIVE mode uses and follows the same camera controls — front/rear appears in the SOURCE row while it is lit — but it is reached from the other side and changes nothing about the mode. LIVE mode remains its own thing. Tapping any of the four clips takes the camera straight back out, so the row is a five-way switch between four clips and the camera. Switching to or from it is always a cut, never a crossfade: a fade is a composite of two clip elements and the camera is not one of them. The transport, speed and in/out controls go on applying to whichever clip is selected, so it is waiting where you left it when you come back.

Load them with OPEN and a multi-select (they fill consecutive slots from the current one), or shift-drop a file to land it in the next empty slot instead of replacing what is playing. shift+1 to shift+4 jump to a slot; ; and ' step to the previous and next loaded slot, skipping empties — the same gesture as [ and ] on the preset bank. Shifted digits because the bare ones are all live param and gen controls, and a clip jump reloads the source.

Each slot keeps its own in/out points, rate, loop, ping-pong and reverse setting, and its own playhead, so a jump away and back resumes where it was — including the direction it was running in. The clip bank itself is session-local: presets and share links do not carry four files, because four missing-clip prompts before anything plays is worse than one.

Each slot owns its own video element, so a jump is a switch rather than a load — the incoming clip is already decoded and holding a frame. Only the active element plays; the other three sit paused. That is deliberate: concurrent hardware decode is a per-device limit and some phones set it at one.

On iOS, play() only works from a user gesture, and an LFO- or MIDI-driven jump is not one. So every element is touched once — play then immediately pause — inside the gesture that loads the clips, which is what makes later automated switching work at all. If a slot ever refuses, the toast says to tap.

The two blocks at the right-hand end of the row set what a clip change does, whether you make it or the sequencer does. The first is the fade length — CUT, or 0.25 up to 4 seconds, tapping to cycle. The second appears once a length is set and picks how the two clips are mixed on the way across: normal is a straight crossfade, and the other nine blend modes are there because the composite reuses the same shader the gen chain does, so they cost nothing. difference and multiply between two clips are worth a try. A fade never outlasts the clips it is between: if either the outgoing or the incoming clip is shorter than the length set — a 3-second clip under a 4-second fade — that fade runs for the shorter clip's length instead. Left at 4 seconds it would still be crossing when the clip reached its out point, so the switch would land somewhere other than where the in and out points put it. Duration here means the in/out span at the clip's own speed, so a tighter in/out or a faster rate shortens the fade with it, and the block's tooltip names what a fade from the clip on screen would actually last. Both settings are part of the patch and travel in presets and share links, unlike the clips themselves.

During a fade both slots light in the row, because both are on screen. Both elements keep playing, which is what makes it a crossfade rather than a dissolve into a frozen frame — a clip that was reversing or ping-ponging runs forward for the length of the fade, because the stepper that drives those directions follows the active clip and the outgoing one would otherwise hold a single frame — and it is the only time two clips decode at once. Starting a fade while one is running finishes the first immediately rather than layering; a third element in flight is more than some phones will do.

Fade position is advanced from real elapsed time, not a frame count, so a 2-second fade takes two seconds whatever the frame rate is doing. The delta is capped at 100ms so a tab that was backgrounded resumes its fade instead of jumping to the end.
sequencerSAMPLER: the STEPS row under the CLIP row is an eight-step sequence of clip slots. Drag a clip block onto a step to fill it; drag a step onto another to swap them, or off the row to clear it. The same slot can fill any number of steps, so 1 1 2 1 3 is five steps using three clips.

The LIVE block can be dragged in too. A live step shows the camera, and since the camera has no in/out to end on it runs for a set length, shown on the step: L15s to start with. Tapping a live step cycles its length through 2, 4, 8, 15, 30 and 60 seconds; changing the one that is playing re-times it from that moment. A live step is always a cut in and out. The camera is asked for as the step is dropped, not at the first live step — a permission prompt belongs on the gesture that asked for it, not in the middle of a set — and is then held open while any live step is in the row, so it is not asked for again each time round. Clearing the last live step releases it. If permission is refused the step stays, and runs its length showing whatever is underneath. SEQ, on the RND row, starts it from the first filled step and stops it; tapping a clip step starts it there, or jumps a running sequence to it.

Each step plays its clip once across that slot's own in/out span, at its own speed and in its own direction, then hands over to the next filled step, wrapping after the eighth. Forward runs in to out, reverse out to in, and ping-pong one full round trip, in to out and back. The slot's loop setting is the one thing a step ignores — inside a sequence the sequence decides how long a clip holds the screen.

RND fills all eight steps from the loaded clips, never the same clip twice running and never the camera, so a random patch arrives with a sequence under it. It leaves the steps alone when no clip is loaded.

With a fade length set, a step hands over early by the length of the fade, so the fade runs across the tail of its span and the step still ends where its out point is. The lead is capped at 40% of the span so a short step is not all fade, and the fade itself is shortened to fit the shorter of the two clips. The same slot twice in a row is always a cut, because a fade needs two clips. A reversing or ping-ponging clip runs forward while it fades out, for the reason given under clip slots.

Steps name slots, not files: loading a new clip into slot 2 changes what every step naming 2 plays. A step whose slot is emptied is kept, drawn struck through, and skipped until the slot is filled again. The step lit in the row, and SEQn on the HUD status line, is the one playing.

Picking a clip by hand — a tap, shift+1 to 4, ; or ' — stops the sequence, as does tapping the LIVE block, opening or dropping a file over the playing clip, or leaving SAMPLER; the clip on screen carries on under its own loop setting. Editing the steps does not: a change lands at the next step end. PAUSE holds the sequence where it is. Like the clip bank it serves, the sequence is session-local and is not saved in presets or share links.
snapping slidersSome params are selectors rather than continuous values and snap to fixed positions as you drag: style on plasma, flowing-colours and zoom-clouds, sides on kaleidoscope, sectors on kaleido-warp, charset and invert on ascii, 1-bit on bitcrush, mode on scatter, fall on flow-dots, and trail on feedback. The row shows the position number rather than a decimal, and the help entry for that shader lists what each one is
audio badgeEach param row has an audio badge (—/B/M/T/V). Tap to cycle: none → bass → mid → treble → volume. The selected band drives that param with audio level
LFO badgeEach param row has an LFO badge (—/L1/L2/L3). Tap to assign an LFO to that param — cycles through LFOs then back to none. Audio and LFO modulation add together
MIDI badgeEach param row also has a MIDI badge (—). Tap it to bind a CC — see the MIDI control section. MIDI sets the base value, then audio and LFO add on top of it
1 / 2 / 3Keyboard: next param · decrease · increase
BKSPSwitch layer: gen ↔ fx (keyboard)
LFO — low frequency oscillators
3 LFOsThree independent LFOs each with shape, amplitude, and period controls. Output is always positive (0 to amp) so it adds to the base parameter value
shapesFive icon buttons: sine, triangle, ramp, square, and sample-and-hold (stepped random). The icons are drawn as vectors rather than text characters, so they render the same on every platform
SKWSkew — warps the waveform's timing without changing shape. At 0.50 the wave is symmetrical. Slide it up and a triangle's peak moves toward the end (becoming a ramp up), a square's duty cycle widens, and a sine gains a slow rise with a fast fall; slide it down for the mirror image. Works on every shape
CRVCurve — bends the path between low and high. At 0.50 it moves linearly. Below that the value accelerates toward the peak, giving a spiky fast-attack shape good for stabs; above it the value eases in and lingers at the top, giving a plateau. Applies to sample-and-hold too, reshaping the distribution of held values
previewThe mini waveform at the right of each LFO row shows the actual output including amp, offset, skew and curve — the faint horizontal line is the offset floor
AMPHow much the LFO adds to the parameter — 0 = no effect, 1 = full range
OFSOffset shifts the LFO floor — the parameter oscillates between OFS and OFS+AMP instead of 0 to AMP. Raise it to prevent the parameter hitting zero
SEC modePeriod set in seconds (0.1s – 30s). Drag the period slider to adjust
BPM modeTap SEC to switch to BPM — period snaps to musical divisions of the global tempo: 1/8 · 1/4 · 1/2 · 1 · 2 · 4 · 8 · 16 beats
TAPTap repeatedly to set the global BPM — averages up to 8 taps, resets if gap exceeds 3 seconds
SYNCCopies LFO 1's period and mode (SEC or BPM) to LFOs 2 and 3, then resets all three phases to zero simultaneously — locks them to the same tempo and beat
assign to paramTap the LFO badge on any parameter row to cycle through L1 / L2 / L3 / none. Audio and LFO signals are summed
MIDI control
enable MIDIMIDI is opt-in — tap "enable MIDI" in the MIDI section to request device access. Nothing connects automatically on load
device pickerOnce enabled, select your MIDI controller from the dropdown — the dot turns green when connected. Works with any class-compliant USB or Bluetooth MIDI device
channelSet the MIDI channel to listen on (1–16) or All to receive from every channel. Useful when a device sends on a specific channel or when multiple devices share the same port
MIDI badgeEach parameter row has a MIDI badge (—). Tap it to enter learn mode (badge pulses yellow ●) — a popup appears where you can type a CC number (0–127) and press Enter, or just move a knob/fader on your controller to bind automatically
bound badgeShows the CC number (e.g. C7) when bound — the controller directly sets the parameter value. Tap again to clear and re-enter a new binding. Press Escape or click outside the popup to cancel
stackingMIDI, audio modulation, and LFO all stack — MIDI sets the base value, then audio and LFO add on top
persistenceCC bindings are saved with presets and the share URL
Audio modulation
off / mic / vid / tab / fileSelect the audio source. mic is the microphone. vid taps the loaded clip's own soundtrack, so the visuals react to the footage rather than the room — it is an analysis tap only, the clip is never played to the speakers. It follows whichever clip is on screen, through jumps, loads and the sequencer, and during a crossfade it hears both clips at once. A clip with no soundtrack reads as silence. tab shares another browser tab and uses its audio.

file plays an audio file you supply — mp3, wav, ogg, m4a, flac, opus. Tap it to pick one, or drop the file anywhere on the window. Unlike vid this one is audible: it plays through its own element and the analyser taps the captured stream, so it is heard once, not twice. It loops, because a mod source that stops is a patch that stops moving. Tapping file while it is already running opens the picker again to swap the track. The HUD audio line and the export dialog both name the file rather than just saying “file”.

It records. Export audio set to source clones whatever the analyser is listening to, so the track that drove the visuals is the track on the finished video, in sync and with no second pass
tab audio, by browserOnly Chrome, Edge and Opera can do this. The picker has a Share tab audio checkbox that is not ticked by default, and without it you get a video track and no audio. Firefox and Safari implement the screen-share API but ignore the audio option entirely — no error, no checkbox, no audio track — so tab cannot work there at all and the toast says so. Use mic or vid instead on those browsers
if a source will not startThe toast names the reason and the console carries the full error, the sample rate the context settled on and the track's own settings. Two causes account for most of it. A browser remembers a permission answer, so a second attempt shows no prompt at all — a mic that was blocked or dismissed once fails instantly and silently, and has to be re-allowed from the padlock in the address bar. And Firefox will not resample between a capture stream and an AudioContext: where the two run at different rates it refuses outright rather than converting, while Chrome and Safari convert without comment. The audio engine negotiates the rate against the track and retries, so this should no longer bite, but it is what a sample-rate mismatch toast means
audio suspendedBrowsers start an AudioContext suspended unless it is created during a click, and a permission prompt can sit open long enough that the click stops counting. A suspended context runs nothing, so the meters sit flat with no error anywhere. The AUDIO line in the panel turns amber and reads suspended when this happens, and the next tap or keypress anywhere starts it
vid, by browser and by transportNeeds captureStream on the video element, which Safari and iOS do not have. It also only produces audio while the element is actually playing: reverse and ping-pong drive the playhead by hand with the element paused, so the meters flatline on any reverse pass. It follows the clip on screen by itself — through jumps, shift+N, loads and the sequencer — and during a crossfade it hears both clips, so the sound crosses with the picture; there is no need to reselect vid after changing clip. A clip with no audio track reads as silence rather than as a fault. Screen capture cannot feed it, since that path binds a stream rather than a file
nothing is movingThe status line above the meters names the source, and adds (suspended) when the browser has an audio context open but not running — tap anywhere and it will start. If a source fails, the toast names the reason rather than a bare error code: denied permission, no device, device busy, or a sample-rate mismatch. The console carries the sample rate and context state for every successful start
BASS / MID / TRE / VOLReal-time level meters for each frequency band
MOD DEPTHHow strongly the selected band drives the selected parameter — 0% = none, 100% = full sweep
HOLDPeak-hold decay — 0% = instant follow, higher values let transients sustain before falling back
Blend modes — per-shader compositing
stack orderIn SAMPLER and LIVE modes, the video/camera sits as the base layer. Each GEN shader composites on top of it in chain order
blend rowWhen a GEN shader is selected, a BLEND row appears at the top of its params. Drag it to set how much that shader mixes onto the layer below it
mode labelTap the mode label in the blend row to cycle through compositing modes: normal · add · screen · multiply · difference · lighten · darken · overlay · dodge · burn
FX blend rowFX slots have the same two rows, but they mix the effect against its own input rather than against the layer below. The full list of modes is identical
normal vs the restnormal at mix 1.00 is a plain serial effect — nothing is composited, so it costs nothing extra. Any other mode always runs a compositing pass, even at mix 1.00
◉ CAMTap the camera block on the top row, just right of SRC, to turn the live camera on/off directly. In LIVE mode the camera is the base layer; in SAMPLER the base is the selected clip, or the camera when the fifth CLIP block is lit.

Four things can claim the camera: LIVE mode, the fifth CLIP block, a SHADER blend running against the live source, and a live step sitting in the sequencer's STEPS row — that last one from the moment the step is dropped, whether the sequence is running or not, which is why the light comes on as you build the sequence rather than when it first reaches the step. Dropping the last of them does not stop the stream immediately — it is held for about eight seconds, and anything that asks in that window reuses it. That is not a cosmetic delay: reacquiring means a second permission request, which Chrome answers from the stored grant but Safari and any file:// copy cannot, so you would be asked again for a camera you had just allowed. Once nothing claims it the tracks stop on the timer and the light goes out. The timer re-checks on the way out, so taking a fresh claim inside that window keeps the camera rather than losing it when the eight seconds are up
Source section
appears automaticallyA permanent row of source controls appears just below the SAVE/LOAD/SHARE/CAST buttons whenever the camera is on, or LIVE or SAMPLER mode is selected — no need to open anything
SAMPLER transportA row of icon buttons matching the SRC row: play/pause (the icon shows what tapping will do, and the caption follows it), reverse — which works the same way, playing backwards and then pausing, with the play button being how you return to forwards — restart to the in-point, open a file, loop, and ping-pong. Each lights when active, and only one direction can be lit at a time. Speed sits on its own row as text pills, and the in/out slider gets a full row to itself since it needs the width.

Every button in the section is one cell of a fixed 46px grid, so the transform row lines up block-for-block under the transport row above it and the leftover space stays at the right — which is where anything added later goes. Captions are clipped to their cell. They used to be 7px text in a 30px box free to overflow it, and 7px is below the size any browser guarantees to honour: a minimum-font-size setting or mobile text autosizing rendered them at 11 or 12px while the box stayed 30px wide, and neighbouring captions ran into each other.

SPEED and IN / OUT are the same control drawn twice: label on the left, a 3px track across the rest of the row, and the value in a shared right-hand column. Speed has no 1× button any more — double-click the slider. On the in/out track the two markers are the in and out points and the cyan tick is the playhead, standing above and below the track rather than inside it. The number is the length of the range; the in and out clock times are on its tooltip. Each marker carries an invisible touch box about four times its width, so what you drag is finger-sized while what you look at is not a slab of green
play from a dead spotIf the playhead is outside the in/out range — which is where dragging the out handle leaves it — play snaps back to the in-point instead of resuming into a dead spot and stopping again. Pausing and playing anywhere inside the range resumes where you left off; restart always jumps to the in-point
SAMPLER: restartJumps back to the in-point (or the start) and plays forward from there
SAMPLER: open file…Same as the O key / open file button elsewhere — opens the file picker dialog to load a video
SAMPLER: SPEEDA continuous slider from ¼× to 4×, log-mapped so 1× sits dead centre and every doubling covers the same distance. It has soft detents — land within a hair of ¼ ⅓ ½ ¾ 1 1¼ 1½ 2 3 4 and it grabs the round number, otherwise you keep whatever you dragged to, shown to two decimals beside it. Double-click the slider to snap straight back to 1× — the button that used to do it has gone, and the row is the better for the width. Applies to forward playback and to reverse/ping-pong stepping, and carries over when a new file is loaded
SAMPLER: LOOPOn (default): restart at the in-point (or the start) once the out-point (or the end) is reached. Off: playback stops there instead of restarting
SAMPLER: PING-PONGBounce direction at each boundary instead of restarting — plays forward to the out-point, then reverses to the in-point, and repeats. Overrides LOOP while enabled
IN / OUT previewDragging a handle parks the playhead on it — the in handle shows the frame you are starting from, the out handle the frame you are ending on — so you can set points by eye. Playback holds still while you drag and picks up again when you let go
SAMPLER: IN / OUTA slider spanning the whole clip. Drag the left handle to set the in-point and the right handle to set the out-point — playback loops (or ping-pongs) between them, and the cyan bar shows the live playhead. Drag a handle fully to the start/end to unset it; clr resets both. Stays in sync with the 0-key in/out method
SRC iconsTwo tight groups with a gap between them: camera on/off plus front / rear facing (a face in a frame for the selfie camera, a landscape for the rear), then rotate, flip and mirror. The camera group appears in LIVE, whenever the camera is running, and in SAMPLER while the fifth CLIP block is lit — wherever the camera is the picture, front/rear has to be reachable. In SAMPLER with that block lit the camera icon turns it back off rather than jumping to LIVE mode. Each icon lights when active and rotate shows its angle. In LIVE the camera icon stays lit and does nothing when tapped; the L key still toggles LIVE from the keyboard
FACINGSwitch between front and rear camera. On a device with no coarse pointer the two buttons are dimmed and inert rather than hidden — the row keeps its layout, so nothing shifts when you move between a phone and a desktop. facingMode is a preference and not a guarantee: the app records which camera it actually got, not which one it asked for
rotate / flip / mirrorThe last three icons in the SRC row: rotate the source 90° at a time (the icon shows the current angle), flip it vertically, mirror it horizontally. Each lights when active
BLEND rowOnly appears in SHADER mode, since that is the only mode that composites generated output against footage. The two overlapping circles mark the row; the two icons pick what it blends against — a play symbol for the loaded video, a camera for the live camera. The on/off button toggles the blend, and the text beside it shows the current mode and amount, which are set from the BLEND row in the params above
blend toggleThe rightmost icon in the SRC row, marked blend. One switch: either the source plays straight through, or the whole generative stack is composited over it. It only appears in SAMPLER and LIVE, the two modes that bypass the gen chain by default so the shaders do not cover the footage; SHADER bypasses nothing, so it is not needed there. For per-slot control, double-click blocks in the flow strip instead. It starts off in two places — arriving in SHADER, and loading a clip — so neither lands half-mixed with whatever was there before. A preset keeps whatever it saved: loading one does not route through the mode switch, and locating a preset's missing clip restores the saved setting after the load.
Export video
recordSits with flip V and rot 90° in the VIDEO section. Everything a take needs is asked for when you press it, so there is nothing to set up first. While a take runs the button becomes the progress bar — it fills left to right and reads elapsed, total and percentage, so you can see how far in you are without leaving the output. Tap it again to stop early; the file keeps whatever was recorded
export sizePins the render buffer to an exact size for the take, ignoring window size, device pixel ratio, RES and RENDER CAP.

The preview changes when a take starts, and both changes are the point rather than faults. The frame takes the export's shape, letterboxed inside the window, so what is on screen is framed the way the file is. And the picture goes to the export's resolution, because captureStream reads the canvas backing store and that store has to be the file. On a display bigger than the export — a 4K panel recording 1080p, say — the preview is upscaled for the duration and looks softer than it did a second earlier. That is the file's real resolution on screen, not something the take did to it. Exporting at a larger size is the only thing that changes it: the canvas is pinned to the export size under all three framing modes, so the preview looks the same in each and reframe does not help here. 720p, 1080p, 4K, 1080×1920 vertical and 1080×1080 square, or as displayed for the old behaviour. While a sized take runs the preview letterboxes to that shape, so you are composing against the framing that will be in the file rather than your window’s
framingWhat happens when the size you picked is not the shape the preview is running at. fit is the default and the only one that loses nothing: the whole frame goes in, with bars where the shapes differ, and the file is a resample of exactly what was on screen. fill fills the frame and crops the overflow — usually what a feed post wants. reframe re-renders the chain at the target shape instead, which is right when the take is the composition: a 9:16 set built and watched in a 9:16 window renders 9:16 natively and comes out sharper for it.

Worth being exact about what each one renders at. All three render big and scale down. The buffer is sized to two floors at once: large enough to cover the export on both axes, and holding at least as many pixels as the preview was composing with. The second floor is the one that matters on a large display, where the file is usually smaller than the window — without it a take drops to the file's pixel count and every grid-based effect lands proportionally larger, which looks like a zoom. fit and fill draw at the preview's shape; reframe draws at the export's shape, at the same pixel count. From a 16:9 preview running a 2560×1440 buffer, a 1080×1920 export renders 3413×1920 under fit or fill and 1440×2560 under reframe — both larger than the file, both downsampled into it. Reframe changes the framing; the other two do not.

Why fit and fill do not simply re-render: every effect built on a grid or a fixed pixel size — bitcrush, ascii, halftone, flow-dots, grain — keeps its cell size in absolute pixels while the frame changes shape, so those cells grow or shrink relative to the frame when the aspect changes. That reads as a zoom rather than a crop. Under fit and fill the chain draws at the preview's shape and that image is mapped into the file, so nothing in the chain has to know the export is happening. Reframe does change the shape, deliberately, but holds the pixel count — cells per frame is an area relationship, so equal area is the same cell size relative to the frame whatever the aspect does.

The estimate line says what each choice will cost before you commit — how much of the frame goes to bars, or how much gets cropped off which edge. It also names the render buffer when it is larger than the file, which under fill it usually is: a 4K fill from a 9:16 preview wants 3840×6827, about 26 megapixels a buffer. RENDER CAP is deliberately ignored here, because it exists to protect interactive frame rate and a take is not interactive — inheriting it would force the upscale this whole path exists to avoid
will it keep upThe estimate line predicts the frame rate a take will hold, and warns when it will not. The number comes from ordinary use rather than from a benchmark: the app divides the frame time it is already measuring by the work it already knows about — buffer size times the number of passes the live chain runs — which gives milliseconds per megapixel-pass on this device, at its current temperature, with this chain loaded. It re-learns continuously, so a phone that has warmed up predicts lower than the same phone did cold.

This matters because captureStream never drops frames, it repeats the last one. A take the device cannot keep up with does not come out short; it comes out exactly the right length with stuttered motion, and nothing about the file says so afterwards. The warning before you record is the only notice you get.

The prediction extrapolates linearly from the size currently being rendered, which holds while the GPU is fragment-bound and breaks once a large buffer crosses a memory-bandwidth limit — so it is optimistic exactly where a phone falls over. That is why the memory ceiling beside it is plain arithmetic and not measured: whether a take allocates is a multiply, and it stays answerable on a device whose capability strings cannot be trusted. Both numbers are on the I overlay.
export qualitydraft 5, good 10, high 25 or max 50 Mbps. A single rate cannot serve every size — 8 Mbps is generous at 720p and starved at 4K — so it is picked per take. The line under the fields gives the buffer size, the frame rate and the estimated file size, and warns when the bitrate is thin for the size selected
export lengthSeconds, 1 to 120, typed rather than dragged. The estimate updates as you type; two minutes of 4K at max is about 750 MB. The completion dialog names the length actually recorded next to the filename, so a file whose timeline disagrees with its footage is visible without opening it
export audioThree settings, defaulting to off: no take opens a microphone unasked. source records the audio input already running — mic, tab or the loaded video’s own track — which is the same signal the visuals are reacting to, so picture and sound line up in the file. It is selectable only while an input is running; with AUDIO off the option is greyed and names why. mic opens a microphone for the take alone, with echo cancellation, noise suppression and auto gain all turned off, since those three defaults suit speech rather than music. Use it to record the room over a set running on tab audio or on nothing
audio and the filePicking a source switches the container to a codec pair that carries audio: avc1+aac for mp4, vp9+opus for webm. Audio rides at 256 kbps and is left out of the size estimate, being about 32 kB a second — under 3% of the video track.

Every capture asks for unprocessed stereo at 48k, with echo cancellation, noise suppression and auto gain all off. Those three are on by default in a browser audio capture and all three are wrong for music: echo cancellation subtracts a delayed estimate of the signal from itself, which on anything but speech is a sweeping comb filter — the phasing, underwater sound. Noise suppression eats sustained tones and cymbals, and auto gain rides the level. Constraints are requests the browser may narrow, so the recording toast names what the track actually settled on: a capture that came back mono at 16k is worth knowing about before the take rather than after listening to it. If the mic is refused or the source has stopped, the take still runs — silent, with a toast naming the reason
record btnOpens filename dialog — enter a name and tap record. Button counts down; tap again to stop early
save dialogTap SAVE to trigger the platform save/share sheet (iOS: Files or AirDrop; desktop: choose location). Tap DISCARD to delete
formatSaves as mp4 where supported, webm otherwise — both can be reloaded as SAMPLER sources
iOS tipIf the save sheet doesn't appear, use iOS Screen Recording (swipe to Control Centre, tap record) to capture the full screen
snap pngA single frame, written as a PNG. Sits next to capture screen in the VIDEO section; that one brings a screen in as a source, this writes the output out. F9 is the keyboard equivalent. It uses the same EXPORT SIZE as a recording, so a snap at 4K is 4K regardless of window size: the buffer is resized, held three frames while the render targets settle, read, then handed back. Two limits — resizing clears the feedback history, so a snap of a long trail catches it three frames old, and a snap is refused while a take is recording, since resizing under a running capture would corrupt the rest of the file
Projection / dual screen (CAST)
CAST buttonOpens a second browser window showing only the canvas — no controls, no locate bar, black background, and no text of any kind: the toast messages, the perf meter, the system info panel and the help overlay are all suppressed there, so a shader change or a numpad press from the controls never writes green text across the projection. Use on a projector or second screen; in Chrome it opens on the other screen by itself. Click it once to fill that screen — see fullscreen below
● CAST indicatorPulses cyan when an output window is connected. All param changes, shader switches, LFO and audio sync automatically via BroadcastChannel
fullscreenFullscreen always takes the screen the window itself is on, so the output window has to be ON the second screen before it fills it. There are two ways to fill it, and on macOS they are not the same thing.

Click the output window to size it to the screen it is on. It stays an ordinary window, so everything on your other display stays exactly where it is. The browser's title bar stays too — about 28px across the top. M does the same from the keyboard.

F is true fullscreen, which is the only way to be rid of that bar. On macOS it also hands the window a Space of its own, and unless Displays have separate Spaces is turned on in System Settings → Desktop & Dock → Mission Control, every other display goes black for the duration — the controls vanish until you leave fullscreen. That setting needs a log out and back in to take effect, and it is the fix if you want a borderless output. It is a system setting; no page can opt out of it, which is why a click fills the screen rather than going fullscreen. F again leaves.

In Chrome and Edge, CAST asks for permission to see your screen layout the first time, then opens the output window on the screen the controls are not on, sized to it. On Windows and Linux it opens fullscreen there as well; on macOS it is sized rather than fullscreen, for the reason above. With three or more screens, pressing CAST again walks the output on to the next one. In Safari and Firefox no page can know a second screen exists, so the window opens where the browser puts it and the line at the bottom says to drag it across first. The pointer hides itself after two still seconds
SAMPLER / LIVEThe output window cannot share the control window's video or camera — load the same file (O key or drag) or start the camera (L) separately in the output window
same machine onlyBroadcastChannel works within the same browser on the same device only
Diagnostics
P — perf meterTop-left overlay, also on the MISC row. Frame rate and mean frame time over a rolling second, the worst single frame in that second (peak), how many frames missed their deadline (late), the internal buffer size, the source texture size, an estimate of resident GPU memory, and how many non-bypassed GEN and FX slots are running. The figure turns amber past 16.8 ms and red past 33.3 ms — absolute thresholds, because the question is always whether it is holding 60
mean vs peakBoth are shown because either alone lies. A 90 ms hitch once a second still averages out near 60 fps, and a mean that looks fine next to a peak that does not is exactly what a visible stutter is
I — system infoTop-right overlay. GPU renderer and vendor, the translation backend (native, or which ANGLE flavour), shader precision, texture limits, float render-target support, device pixel ratio, screen and buffer size, cap and scale settings, and the loaded source. COPY puts the lot on the clipboard — the fastest way to answer “it runs slower on my machine”
mediump lineThe one worth understanding. 10 bits means the GPU runs mediump as true fp16, which is roughly twice the arithmetic throughput; 23 bits means it is promoted to fp32. Apple Silicon gives the former, Windows through ANGLE the latter — the same shaders, a real speed difference, and not something either machine reports on its own
source lineResolution, duration, estimated frame rate and file size of the loaded clip, also reported to the console on load. RENDER CAP does not bound this: the source texture is whatever the file is, and it is re-uploaded every frame. A clip wider than the GPU's texture limit cannot upload at all and now says so instead of showing black
Save / Load / Share
SAVEStore the full current state as a named preset in the browser — shader chain, FX chain, all params, LFO config, blend settings. The name is filled in for you as time, then date, then the word preset — 1432-12aug-preset. A block on the strip is only about ten characters wide, so leading with the time is what makes one save tell itself apart from the next at a glance; the trailing word is cut off there but still reads in this list. Type over it with anything you like
LOADRestore a saved preset — lists all stored presets with timestamps
SHAREGenerate a compact URL with all settings encoded — all per-slot parameters, FX blend modes and mix amounts, chain order, LFO/audio/MIDI modulation are preserved. Bookmark or share to reload exact state on any device (video file not included). A real link is a few hundred bytes; anything claiming to be far larger is refused rather than opened, so a malformed or hostile link fails with a message instead of locking up the tab.

Links written by older releases still open: version 4 and 5 are read as well as the current format, which is the only one written. Older than that will not open, and that is deliberate rather than an oversight — those links index a shader table that has since changed size, so decoding one would quietly name the wrong shaders instead of failing. A link that opens as somebody else's patch is worse than a link that says it cannot be read
unplayable filesA file the browser cannot decode now says why — format unsupported, decode failed, network error or aborted — instead of leaving loading… up forever. Codec support is checked before the load starts, not after it fails
RSTReset all shader and FX parameters to defaults, keeping the current chain
EXPORT BANKIn the SAVE dialog, in its own block under the preset name — writing the bank out is a save, the same as writing one preset. Name the file in the box beside the button; it is filled in with the date and you can type over it. Anything a filesystem would object to is replaced with a dash, and the toast names the file it actually wrote. Writes every saved preset to a single .json you can copy onto a flash drive next to index.html, mail to someone, or keep in version control. The video files themselves are not included
IMPORT BANKIn the LOAD dialog — or just drag the .json onto the window. Loads a bank file back. It merges: presets already here are kept, and re-importing the same file adds nothing. Nothing a bank file can contain will overwrite what you already have
presets and footageA preset saved in SAMPLER records which clip it was built on — filename, size and length — and its in / out points, but not the file itself. Load one whose clip is not open and a bar appears naming the file, with LOCATE to point at it. The shaders load instantly either way; the bar never blocks a jump.

Tick remember clip names & sequence in the SAVE dialog and the preset carries all four clip slots instead of one — each slot's file name, in / out points, speed, loop and direction — along with the STEPS row and the length of each live step. Loading it asks for everything missing at once: LOCATE takes a multiple selection, and FOLDER takes the folder the clips are in and binds every match in it, so a four-clip set is one pick. Matching is by file name, then by size where two files share a name; a re-encode under the same name is accepted and a single hand-picked file is taken at face value for the clip being asked for. Whatever is found lands in its own slot, so the sequence plays as saved. The setting is remembered between saves, and the row is greyed out when no clip is loaded. Without it a preset behaves as it always has and carries no file names at all
locate onceA located file is remembered for the rest of the session, so a bank of presets built on the same clip only ever asks once, and a second preset naming the same footage binds without a prompt. SKIP silences every file the bar is asking for until you reload — stepping through presets for footage you did not bring stays quiet
in / out pointsSaved with the preset and restored once the clip is bound, clamped to its actual length. A preset with no clip attached leaves your loop points alone
why presets don't travelSaved presets live in browser storage, which belongs to the browser profile, not to index.html. Copying the file to a flash drive copies none of them, and opening it from the drive may find a different set entirely. The bank file is how they move
preset storagePresets live in browser storage, which is capped at a few megabytes. If it fills, saving says so rather than failing quietly — and no longer claims to have saved. Delete a few from the LOAD list to make room. Private-browsing windows may refuse to store anything at all
DEFRevert to initial state — clears the FX chain, resets the GEN chain to a single shader with default params, and clears all blend and mod settings
Keyboard shortcuts
ENTERCycle mode: SAMPLER → SHADER → LIVE. SAMPLER and LIVE arrive with the GEN chain bypassed so the source shows through; SHADER arrives with it restored
FToggle fullscreen
LToggle camera
OOpen video file
SPACEPlay / pause (SAMPLER)
RPlay backwards, or pause if already reversing (SAMPLER). Press SPACE to go forwards again
0SAMPLER/LIVE: in → out → clear. SHADER: cycle selected gen. Has a button in the VIDEO section whose caption changes with the mode, so the current job is named on it
4 – 9SHADER: toggle gen shaders 1–6
− / +Toggle previous / next FX slot
/Clear the entire FX chain (same as the fx off button) — works the same in every mode
*Toggle next FX slot — same binding as +
.Toggle feedback trail
1 / 2 / 3Next param · decrease · increase
[  ]Previous / next preset in the bank
;  'SAMPLER: previous / next LOADED clip. The pair next to [ and ], which step the preset bank — same gesture, adjacent keys, different bank. Empty slots are skipped, and stepping off the live camera lands on a clip
shift 1–4SAMPLER: jump straight to clip slot 1–4. Shifted because the bare digits are param and gen-slot controls, and a clip jump reloads the source
shift 5SAMPLER: toggle the live camera in and out of the source position — the fifth CLIP block. Carries on the row where the four clips leave off
BKSPSwitch param layer: gen ↔ fx
F9Snap a PNG of the output at the export size. A function key rather than a letter: the letter keys are all live controls
ESCCancels an armed OVR or CLR. Does nothing otherwise — it is not a general escape, and it will not close this screen
?Show / hide this help screen
click to fill this screen  ·  F for true fullscreen
CC
WebGL2 not supported in this browser.

RECORDING COMPLETE

Camera Access

On most browsers: click the camera icon in the address bar, set to Allow, then reload.

Save Preset

⚠ Video files are not saved — only shader settings and parameters.
Bank — every saved preset in one file

Load Preset

Share Link

All current settings are embedded in this URL. Video files are not included.