SAMPLER
SHADER
MODE
sampler
shader
live
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
L camera
SPC play/pause
R reverse
flip V
rot 90°
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
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, the source controls and the GEN and FX chains in one go, leaving the mode buttons and the param sliders. 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 in the lower body — 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; GEN SHADER and FX SHADER start open. 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. It is set apart on purpose — it replaces both chains wholesale, which is not something to hit by accident while reaching for the camera or for OVR
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
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. Nothing you did not touch ever moves, which is what makes it possible to lay out a chain deliberately rather than watching everything shuffle
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, a blank slot, then SRC and the camera toggle, then another blank slot and BANK, OVR and CLR — the gap is there because what the source controls do has nothing to do with what the bank controls do. The source controls used to have a row of their own for two blocks, which was a row's worth of height for them. Below it the strip reads top-down in the order the signal actually travels: source → gen → fx
preset rowDirectly under the top row, one block per saved preset with the loaded one lit. 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, decided by whether a preset is lit in the bank row. WITH ONE LIT it deletes that preset, on a single tap and with no arming step — the highlight is already the selection, so a second tap would only be confirming what the strip is showing. The button turns magenta to say so, matching the bank row rather than the red of the full wipe. Deleting re-lights nothing, so the next tap goes back to meaning the whole bank. WITH NOTHING LIT it deletes every saved preset, and it arms rather than firing: the first tap lights it red and names how many it is about to delete, the second does it. Escape, or a tap on any other control, cancels — and so does deleting a single preset, since a half-committed wipe should not survive a change to the bank it was aimed at. There is no undo either way, and the bank does not travel with the file, so EXPORT BANK in the SAVE dialog is the only backup — take one first if you are not certain. Presets you have 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
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
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 twelve; the rest 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
wavesSummed travelling sine bands, softer and more orderly than squarewaves. frequency sets how many bands cross the frame and speed how fast they travel. count is how many wave sets are summed — each comes in at its own angle, so raising it moves the field from plain stripes through moiré into woven interference. palette picks the colour ramp and zoom pulls the whole field in or out. At the bottom of count it is close to a single travelling gradient, which makes it a good quiet base layer under something busier
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 default is 8 sides. It used to sit exactly halfway between the stops for 7 and 8, which put the shader on the one input where GLSL leaves the rounding direction up to the driver — so the shipped default rendered as 7 on some GPUs and 8 on others. Both this and kaleido-warp now round the same way everywhere. 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
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
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
bitcrushPixelation and colour quantisation together. block-size sets the pixel grid, up to 64 px, measured from the frame CENTRE rather than a corner so animating it does not make the grid march sideways. color-depth reduces levels per channel and runs BACKWARDS, so the top of the slider is the coarsest. gap opens a dark grid line between blocks. mix cross-fades the whole thing against the untouched frame and defaults to 0, so a freshly added bitcrush shows nothing until you raise it. 1-bit discards all of the above and reduces to on/off on luma; threshold is the cutoff and hue the colour of the on pixels. That one is a selector rather than a slider, so it snaps
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
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)
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. Pitch has a FLOOR that depends on the render buffer, and on a large one it eats the bottom of the slider. The particle field is a fixed 512×512 texture, one dot per texel, so the screen has to fit inside 512 cells: below about a five-hundredth of the buffer's long edge, cell 0 and cell 512 are the same texel and the whole field repeats as a visible tile. The floor stops that, which means at 4K the lowest third of pitch all lands on the same spacing and the slider looks broken there — it is not, there is simply no finer lattice available at that size. Drop RENDER CAP to 1080p and the floor drops with it and the travel comes back. The I overlay reports the floor for the buffer you are actually on. FEATURE — sensitivity is the detector gain and it runs BACKWARDS — 2000 at the bottom of the slider, 2 at the top, each tenth of travel a factor of two, so pulling it DOWN is what brings more of the frame up to dot-worthy; 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
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. Put this ahead of flow-dots and the dots track the folded image rather than the source — the detector reads whatever the slot before it produced
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
feedbackFrame trails, and the only effect here that does not process the frame in front of it. It keeps a history buffer, transforms and decays it every frame, then blends the live image back in, so what you see is an accumulation rather than a filter. decay is how much history survives each frame — near 1 is an almost infinite hold, low values clear almost at once. spread blurs the history as it decays, over an eight-tap ring, which is what turns a hard trail into a smear. zoom and rotate are centred at 0.5 for no change and are deliberately tiny per frame, a few per cent of scale and a couple of degrees, because the effect compounds: a small zoom in becomes a tunnel, a small zoom out a receding well, and rotate turns either into a spiral. blend-mode picks how the echo composites back. It carries a whole extra full-size buffer, which makes it the most expensive thing in the FX list by memory; bypass it and that buffer is released after two seconds, and the trail re-seeds from the current frame when you bring it back. T toggles it from anywhere
mirrorRadial fold of the incoming frame. axes runs from 1 to 8 mirror lines, rotation turns the whole fold, and centre-x / centre-y move the origin anywhere in the frame — the fold is about a POINT, not an edge, so moving it off the middle is what makes this read as a lens rather than a symmetry filter. The default sits low on axes, close to a single fold. Related to kaleido-warp, which does the same thing with a snapped wedge count and its own spin
invertPer-channel inversion. R-invert, G-invert and B-invert each cross-fade one channel between itself and its negative, so they are continuous rather than switches — inverting only red on a blue-lit shot recolours rather than negates. amount then cross-fades the whole result against the untouched frame. All four default to fully on, which is a straight negative
grainVideo texture, four things at once. scanlines darkens alternate lines at buffer scale. noise adds per-pixel dither, re-rolled on a time step so it crawls like emulsion instead of sitting still — which is what keeps a frozen frame alive under sample-hold. speed sets how fast it re-rolls, from about ten changes a second to sixty. luma-crush pulls colour toward its own brightness, up to half way, desaturating without flattening. Scanlines are measured against buffer height, so they get finer as render resolution rises — drop RES or RENDER CAP to keep them coarse
wobbleSine displacement, each axis independent. X-amp and Y-amp are the distances, up to about a tenth of the frame; X-freq and Y-freq set how many waves cross it, from 2 to 30. The two axes run at slightly different rates on purpose, so the motion never collapses into a straight diagonal and never quite repeats. Low amplitude at high frequency reads as heat haze, high amplitude at low frequency as liquid. Edges clamp rather than wrap, so pushing hard smears the border pixels
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 used to measure that grid out from the bottom-left corner of the frame, because that is where the coordinate origin sits. It looked fine standing still, but animating the size — especially from an LFO — slid the whole pattern diagonally out of that corner 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 gained the most: its angle sliders rotate about the origin too, so they used to swing the entire screen around the bottom-left corner rather than spinning the dot screen in place. gamma-ray, grain, oscilloscope and scatter are deliberately unchanged — measured, they gain nothing, 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
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, and fall on flow-dots. Arrow keys step one position at a time rather than nudging by a fraction, so a selector cannot be left stranded between two stops. The row shows the position number rather than a decimal, and the help entry for that shader lists what each one is
GEN / FX layerTap the GEN or FX layer buttons to switch which shader's params are shown in the upper slot
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 / tabSelect the audio source — off disables, mic uses microphone, vid uses loaded video audio, tab shares another browser tab (enable "Share audio" in the permission prompt)
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 mode the loaded video is the base
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
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. The 1× button snaps straight back to normal. 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 only appears in LIVE, or whenever the camera is running — in SAMPLER the source is a file, so it would only be a mode switch you already have above. 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 — only shown on touch devices, since desktops generally ignore facing mode
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 don't hide your footage — SHADER bypasses nothing so it isn't needed there. For per-slot control, double-click blocks in the flow strip It starts off in two places: arriving in SHADER, and loading a clip. Landing on a shader half-mixed with whatever was already loaded reads as the shader being broken, and a clip you just opened is the thing you want to look at. A preset keeps whatever it saved — loading one does not go 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 sizeThe one that matters. A recording used to be whatever the canvas happened to be — your window, times device pixel ratio, times RES, capped by RENDER CAP — so a take from a half-height window at RES ½ came out a few hundred pixels wide and looked it. Pick a size and the render buffer is pinned to exactly that for the take. The list is grouped. SCREEN is the plain resolutions. SOCIAL is the four frames worth hitting natively, because all of those platforms re-encode whatever you give them and the aim is to give them their own shape so the only resampling is the codec's: 9:16 for reels, stories, shorts and tiktok; 4:5 for an instagram or facebook feed post, which is the most screen a post may occupy in a scroll; 1:1 for a square that survives every feed uncropped; and 16:9 for reddit, facebook and youtube. Reddit and facebook both cap at 1080p, so sending them a 4K take means it is re-encoded DOWN and you lose detail rather than gain it — keep the 4K for screens and projectors
export framingWhat happens when the size you picked is not the shape your preview is running at. This is the setting that decides whether the file looks like what was on screen. A shader is not resolution-independent, it is resolution-PARAMETRISED: nearly every one here fixes the vertical extent and lets the horizontal follow the aspect, and everything with a size in pixels — flow-dots pitch, grain, ascii cells, halftone — keeps its absolute size while the frame changes. So re-rendering a wide preview into a tall frame does not resize the image, it re-runs it on a narrower window with coarser features, which reads as a zoom. FIT is the default and loses nothing: the chain renders at the preview's shape and the result is scaled to fit, with black bars where the shapes differ. FILL renders at the preview's shape and scales to cover, cropping the overflow — usually what a feed post wants, and at most sizes it is a straight 1:1 centre crop with no resampling at all. REFRAME is the old behaviour, re-rendering natively at the take's shape. It is the right answer when the take IS the composition — a 9:16 set built and watched in a 9:16 window should render 9:16 natively and be sharper for it — and the wrong answer otherwise. Under fit and fill the render buffer is LARGER than the file and ignores RENDER CAP, because a crop needs more pixels than it keeps; the estimate line reports the buffer size and how much is cropped or barred
export qualityBitrate, as a multiplier on a resolution-and-framerate estimate rather than a fixed number, so the same setting means the same visual quality at every size. The estimate under the dialog is live and worth reading before a long take at 4K
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, which is worth knowing before rather than after. The completion dialog names the length actually recorded next to the filename, so a file whose timeline disagrees with its footage shows up straight away
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
Projection / dual screen (CAST)
CAST buttonOpens a second browser window showing only the canvas — no controls. Use on a projector or second screen
● CAST indicatorPulses cyan when an output window is connected. All param changes, shader switches, LFO and audio sync automatically via BroadcastChannel
fullscreenThe output window requests fullscreen automatically — if blocked by the browser, click anywhere in it or press F
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
SHARECopies a link that carries the whole patch — both chains, every parameter, blend modes, LFOs, MIDI and audio bindings — gzipped into the URL. No footage travels with it, so a patch built on a clip arrives on whatever the other end has loaded. A link from someone else is untrusted input and is treated as such: the payload is size-capped before and after decompression, every field is range-checked on the way in, and anything malformed is ignored rather than applied, so a broken or hostile link cannot do more than fail to load
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
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. SKIP silences that particular file 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
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
BKSPSwitch param layer: gen ↔ fx
?Show / hide this help screen
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.