huff opens two windows. The controls window is your workspace. The canvas window is the fullscreen output that receives processed frames over the embedded WebSocket relay.
Controls are organised into collapsible groups. Click a group label to collapse or expand it. Collapsing a group does not disable its effects — use the ON toggle inside each group for that.
Top Bar
| Control | Description |
| File | Load a video file. Drag-and-drop also works. MP4, MOV, WebM, and any format your system decoder handles. |
| ▶ Play / ⏸ Pause | Toggle video playback. Resuming after pause restarts the frame pump automatically. |
| VOL | Output volume. Routed through a dedicated Web Audio AudioContext + GainNode so audio playback runs on its own thread and does not drop out under heavy canvas load. Drag to zero to mute. |
| RATE | Playback speed: 0.25×, 0.5×, 1×, 2×, 4×. Applies immediately without reloading. |
| LOOP | Loop the file continuously. Unchecking plays once and stops. |
| ↻ Refresh | Re-seed glitch randomisation. |
| ↺ Reset | Reset all parameters to defaults. |
| CLR BUF | Instantly wipes the frame ring and all internal buffers (gBuf, gWarp, gTemp) and resets cluster physics. Use this to clear accumulated trails/feedback/glitch history without resetting any parameter values or noise phases — the animation continues from where it was. |
| Camera | Select a webcam from the dropdown. Click ↻ Refresh to scan for newly connected devices. |
| Seek Bar | Scrub to any position in the loaded file. Uses fast keyframe seeking while dragging for low latency; playback resumes automatically on release. |
| Time Display | Shows current position and total duration as M:SS / M:SS. |
Source Group
| Control | Description |
| BASE VIDEO | Show the raw source frame underneath the glitch output. |
| BASE MIX | Opacity of the base video layer at final composite. 0 = fully glitched output, 1 = raw source on top. |
| BASE BG | Background fill colour when no tile covers a pixel: Black, Green (chroma key), Blue, or White. |
| SEED ON LOAD | Randomise the seed each time a new file is loaded, giving every clip a visually distinct glitch pattern. |
| SEED | Randomisation seed. Same seed + parameters = same output. |
| QUALITY | Scales the frame ring depth (0 → 4 frames, 1 → 60 frames). The single most impactful performance lever. |
Feedback Group
| Control | Range | Description |
| FEEDBACK | 0–3 | Contribution of the previous frame. Values > 1 over-expose. |
| PERSISTENCE | 0–10 | Decay rate between frames. Higher = trails linger longer. |
| FB X | -1–1 | Horizontal translation per frame. Creates lateral drift. |
| FB Y | -1–1 | Vertical translation per frame. |
| FB Z | 0.98–1.03 | Zoom per frame. < 1 = implode inward. > 1 = explode outward. |
| FB θ | -2–2 | Rotation in degrees per frame. Creates spinning feedback tunnels. |
| ↺ Reset Motion | button | Returns FB X/Y/Z/θ to neutral (0, 0, 1.0, 0). |
FEEDBACK above ~2.5 combined with non-neutral FB Z can saturate the buffer (full white or full black) within seconds. Recovery: lower FEEDBACK to 0, click ↺ Reset Motion, or use CLR BUF in the top bar to wipe the buffer instantly.
Glitch Group
The core datamosh engine. Reads tiles from past frames and blits them onto the current frame at noise-driven positions.
| Control | Range | Description |
| ON | toggle | Enable/disable the glitch pass entirely. |
| DEPTH | 0–0.5 | How far back in the ring tiles are sampled. |
| SCATTER | 0–1 | Per-tile randomisation of the lookback index. |
| CORRUPT % | 0–7 | Fraction of grid tiles displaced per frame. 0 = nothing moves. 7 = every tile replaced. |
| DRIFT | 0–1 | Noise-driven oscillation of corruption density. The percentage breathes slowly when > 0. |
| PIXEL SIZE | 150–2000 | Tile size in pixels. Larger = blockier datamosh. Smaller = fine grain displacement. |
| GLITCH SIZE | 1–60 | Spatial scaling of each tile relative to PIXEL SIZE. |
| OPACITY | 0–1 | Alpha of each blit tile. Also scaled by the A/B Mix layer-priority weight. |
| JITTER | 0–1 | Magnitude of per-tile position noise. |
| SMEAR | 0–200 | Duplicate stamps trailed behind each tile. |
| SMEAR ANGLE | 0–360 | Direction of the smear trail. 0 = noise-driven per frame. |
| SPEED | 0–5 | Phase velocity of the noise field driving tile selection. |
| FINE | 0–10 | Secondary fine speed multiplier. |
| MULT | 0–10 | Overall speed multiplier. |
| GLITCH X / Y | -1000–1000 | Base offset applied to all tile destination positions. |
Clusters Group
Locked directly beneath Glitch as part of the same conceptual unit. Biases glitch tile placement toward moving focal points (cluster centres) rather than scattering tiles randomly. Glitch must also be ON. Each centre has its own physics simulation with inertia, steering, and optional velocity bursts. Centres always use the physics simulation — even at SPEED 0, where the desired velocity is zero and centres glide to a stop and hold position (no per-frame re-randomisation).
| Control | Range | Description |
| ON | toggle | Enable cluster-biased tile placement. Glitch must also be ON. |
| CENTERS | 1–20 | Number of cluster centres. Each is an independent physics body that tiles gravitate toward. |
| SPREAD | 1–300 | Radius in pixels around each centre within which tiles are distributed. |
| MIN RAD | 0–150 | Minimum distance from centre — creates a hollow ring of tiles. |
| SPATIAL GAP | 0–200 | Minimum pixel distance between any two tiles. Prevents overlap. |
| BIAS | 0–1 | Fraction of tiles forced into clusters. Remainder placed randomly across the canvas. |
| DRIFT | 0–5 | Adds noise-driven wandering to centre positions. |
| SPEED | 0–10 | Speed of cluster centre physics simulation, step 0.01 for fine low-end control. 0 = centres glide to a stop and hold still. |
| SPD VAR | 0–2 | Per-centre speed variation. Each centre gets its own speed multiplier so they move at different rates. 0 = all same speed. |
| PULSE | 0–10 | Periodic velocity kick — centres suddenly burst in a random direction then settle. Higher = more frequent bursts. |
| INERTIA | 0.01–0.99 | Momentum of cluster centres. High = smooth gliding. Low = snappy response to steering. |
A / B Mix Group
Layer-priority mix between Glitch and Scanlines. Unlike a crossfade, neither effect is ever fully muted — both remain present at every position of the slider, with one becoming dominant and the other receding to a minimum contribution.
| Control | Range | Description |
| GLITCH ← → SCAN | 0–1 | 0 = Glitch at full priority, Scanlines recede to their floor. 1 = Scanlines at full priority, Glitch recedes to its floor. 0.5 = both at equal, slightly-reduced priority. The floor is 35% — the recessive effect never drops below that, so both are always visible. |
The slider scales each effect's own opacity setting (Glitch OPACITY, Scanlines OPACITY) rather than replacing it — both controls continue to work normally on top of the A/B weighting.
Luma Key Group
A pipeline gate that sits between Glitch and Scanlines, compositing the glitch output back against the clean source frame based on luminance — before scanlines run on top of the result. This is an A/B-style mix, not a threshold: both the clean source and the glitched buffer always contribute, with luminance determining the balance at each pixel.
| Control | Range | Description |
| ON | toggle | Enable the pipeline luma key. When off, glitch output passes straight through to Scanlines unchanged, regardless of the slider positions below. |
| CLEAN ← → GLITCH | 0–1 | 0 = clean source dominant — bright pixels still carry some glitch but clean is strong. 1 = glitch dominant — dark pixels still carry some clean but glitch is strong. Like A/B Mix, neither side drops below a 35% floor. |
| MIX | 0–1 | Overall strength of the key. 0 = no effect (buffer passes through unchanged even if ON is checked), 1 = full. |
| INVERT | toggle | Flips which luminance range favours clean vs. glitch. |
Buffer Trails Group
| Control | Range | Description |
| ON | toggle | Enable/disable. |
| TRAIL LAYERS | 0–4 | Number of ghost frames composited. |
| TRAIL DEPTH | 0–1 | How far back in the ring to pull trail frames from. |
| LUMA KEY | 0–1 | Drops dark pixels from trail frames. Only bright areas trail. |
Symmetry Group
| Control | Options | Description |
| ON | toggle | Enable/disable. |
| MODE | vertical / horizontal / both | Vertical mirror, horizontal mirror, or both axes. |
| SYM POS | 0–1 | Position of the mirror axis. 0.5 = centred. |
Scanlines Group
Displaces bands of the current video frame spatially — no temporal sampling from the ring. Bands shift the current content perpendicular to their axis; they do not pull from historical frames, so they stay smooth and follow live motion with no buffer-trail artifact. The whole band pattern can be rotated to any angle, including continuous spin.
| Control | Range | Description |
| ON | toggle | Enable/disable. |
| ANGLE | -180°–180°, step 0.5° | Rotates the entire band pattern. 0° = horizontal bands displaced left/right. 90°/-90° = vertical bands displaced up/down. Any other value = diagonal bands. The band span and displacement axis are recalculated for the full rotated canvas so bands always cover the whole frame and stay centred, at any angle. |
| 0° / -90° / 90° buttons | buttons | Snap ANGLE directly to 0°, -90°, or 90°. Because the slider spans 360° in a small space, landing exactly on these values by dragging is impractical — these buttons jump to them instantly and update the label. |
| SPIN L / SPIN R | toggles | Continuously rotate the band pattern left (counter-clockwise) or right (clockwise) instead of holding a static ANGLE. If both are somehow active, SPIN R takes priority. While neither is checked, the internal spin position stays in sync with the ANGLE slider so enabling spin starts from the slider's current angle with no jump. |
| SPIN SPD | 0.1–10 | Spin speed. At 1.0 the pattern completes a full rotation in roughly 12 seconds (60fps); higher values spin proportionally faster. |
| BANDS | 1–50 | Number of active displacement bands per frame. |
| SIZE | 1–120 | Base size of each band in pixels (along the band axis). |
| FOCUS | 0–1 | Biases where bands are distributed across the rotated span. 0.5 = even spread across the whole canvas. Toward 0 or 1 pulls bands toward one end of the span. Fixes the tendency of unbiased noise to cluster bands near the centre. |
| SHIFT | 0–0.5 | Maximum displacement perpendicular to the band axis, as a fraction of the canvas dimension along that axis. |
| SKEW | -1–1 | Position-based offset along the displacement axis, making bands angle diagonally relative to their own axis. |
| DRIFT | 0–3 | Dual-frequency noise driving band position along the rotated span: a slow base wander layered with faster, smaller jitter. Higher values increase both. |
| ROLL | -2–2 | Continuous scroll of all bands along the rotated span, independent of DRIFT. Positive and negative values scroll in opposite directions; 0 = no roll. |
| SPEED | 0–5 | Speed of the DRIFT/ROLL phase accumulation. Operates independently of glitch speed — works even with glitch off. |
| GAP | 0–200 | Snaps band positions to a regular grid spacing along the rotated span. |
| OPACITY | 0–1 | Alpha of displaced band content. Also scaled by the A/B Mix layer-priority weight. |
Global Mix Group
A blend-mode composite of the raw base video over the full effects chain, applied after Scanlines and before Feedback.
| Control | Range / Options | Description |
| ON | toggle | Enable/disable. When off, this pass is fully skipped. |
| BLEND | SCREEN / MULTIPLY / OVERLAY / DIFFERENCE / HARD LIGHT / ADD | CSS composite operation used to blend the base video onto the effects buffer. SCREEN brightens, MULTIPLY darkens, OVERLAY adds contrast, DIFFERENCE inverts where layers differ, HARD LIGHT is a stronger overlay, ADD (lighter) saturates quickly. GPU-accelerated, no pixel readback. |
| MIX | 0–1 | Opacity of the base video in the blend. 0 = no effect, 1 = full-strength blend. |
Solarize Group
| Control | Range | Description |
| ON | toggle | Enable/disable. |
| THRESH | 0–1 | Luminance threshold. Pixels above this are inverted. |
| AMOUNT | 0–1 | Inversion strength. |
| SOL R / G / B | 0–2 | Per-channel multiplier applied after inversion. > 1 over-exposes that channel. |
Flow Group
Noise-field UV displacement applied after Feedback. Each grid cell samples a Perlin noise field to determine where it pulls its source pixels from.
| Control | Range | Description |
| ON | toggle | Enable/disable. |
| STRENGTH | 0–20 | Maximum pixel displacement. |
| SCALE | 40–200 | Spatial scale of the noise field — grid cell size in pixels. |
| SPEED | 0–4 | Multiplies the time accumulator driving the noise field. 0 = frozen — the warp pattern stops evolving but stays applied. 1 = normal speed. |
| PULSE | 0–200 | Frames back in the ring to sample during warp. Adds temporal smear. 0 = sample the current buffer. |
| PULL | -1–1 | Radial bias added to the noise displacement. Positive values pull toward the canvas centre (implode). Negative values push away from centre (explode/centrifugal). 0 = pure noise field, no radial bias. |
| SWIRL | -2–2 | Rotates each cell's displacement vector by an angle proportional to its distance from centre, adding a vortex/spiral motion on top of the noise field and any PULL. Positive and negative values spin in opposite directions. |
| TURB | 0–1 | Blends in a second noise octave at higher frequency and lower amplitude, layered on top of the base field for more turbulent, less uniform displacement. 0 = single-octave field only. |
Presets
Presets are named snapshots of all current parameter values, stored in the browser's localStorage and listed in a dropdown for quick recall. JSON export/import provides portability across machines and sharing with collaborators.
| Control | Description |
| preset name field | Type a name, then click 💾 Save (or press Enter) to save the current parameter snapshot under that name. |
| 💾 Save | Saves the current snapshot to localStorage under the name in the field. Overwrites an existing preset of the same name. |
| — saved presets — dropdown | Lists all saved preset names alphabetically. Double-click an entry to load it. |
| ▶ Load | Loads the selected preset. Counts as one undo step. |
| ✕ Delete | Permanently removes the selected preset from localStorage. |
| ↑ Export JSON | Downloads all saved presets as a single timestamped .json file — a map of preset name → parameter snapshot. |
| ↓ Import JSON | Loads a previously exported file. A file containing a map of named presets merges all of them into your saved list (overwriting any name collisions). A file containing a single preset snapshot is imported under the name currently in the preset name field, or imported-<timestamp> if the field is empty. |
| Ctrl+Z / Cmd+Z | 10-step undo. Steps back through parameter changes one snapshot at a time. Loading a preset counts as one undo step. |
Presets are stored in the browser's localStorage — treat this as a cache, not a primary store. Use ↑ Export JSON to back up presets to a file you keep with your project. Cluster centre positions and velocities are runtime state and are not saved in presets; loading a preset restores all slider values but cluster centres will be wherever their physics simulation currently has them.
Keyboard Shortcuts
| Key | Action |
| P | Toggle the control panel. A pill indicator appears at the bottom of the screen reading "UI hidden · P to show" so you can always get back. |
| F | Toggle fullscreen. |
| Ctrl+Z / Cmd+Z | Undo the last parameter change. Up to 10 steps. |