grains of vision

grainsOfVision · effects

GRAINS OF VISION — a granular VIDEO synthesizer. It shatters the incoming picture into a swarm of tiny windowed patches (grains) sampled from source A at jittered positions AND jittered moments in time (from a short frame-history ring, so grains have a real TEMPORAL axis — the novel part of granular VIDEO), re-scatters them into a new frame, then runs that through a FEEDBACK block and a video REVERB block on ONE fixed linear chain (video -> granular engine -> feedback -> reverb -> out) — NOT a node graph. The grain engine is a single fullscreen pass that is O(1) per pixel regardless of density: the frame is a jittered grid of cells (DENSITY = cells across), each cell hosts one hashed grain, and every pixel gathers its 3x3 cell neighbourhood, window-weights each grain and normalises — so density changes grain SIZE, not the cost. Knobs map the audio-granular vocabulary onto the image: SIZE (window radius), WINDOW (hard chip -> soft gaussian), SPRAY (position scatter of the grain + source-read; 0 reconstructs the picture faithfully, rising clouds it into abstraction), RATE (how far back in the frame history grains read — the pitch/rate analog), T-SPRAY (temporal scatter for a shimmering time-smear), ORIENT (per-grain rotation). The FEEDBACK block mixes the transformed previous OUTPUT back in (FB amount / decay / per-pass zoom + rotate that compound into tunnels and spirals); FB amount 0 (or FB Dry) is a transparent dry passthrough. The REVERB block is a true VIDEO reverb — the image analogue of an FDN/Schroeder tail: a decaying, spatially-diffused temporal accumulator (rev = blur(feedbackImg + decay*prevRev)), so each bright grain blooms outward (Rev Size = room size, Rev Diffuse = tap scatter) and lingers, fading over frames (Rev Decay = tail length), mixed dry/wet by Rev Mix; Rev Mix 0 (or Rev Dry) is a transparent dry passthrough (its blur passes skipped). Patch a second source into B and pick a COMPOSITE mode to have B modulate A grains region-by-region: density-map (B brightness thins/thickens grains), displace (B chroma warps where grains read from), size-map (B scales grain size), rate-map (B scrubs the per-region history time); with only A patched it runs mono-source (composite off). TWO video outputs: OUT (the full chain) and GRAINS (the raw granular scatter tap, pre-feedback/pre-reverb, resolved via read outputTexture:grains — a clean grains-only output to key/mix elsewhere, optional). Rendered at half engine resolution (SwiftShader/CI budget). Like every video processor an unpatched input renders black; the defaults are tuned so any patched source is immediately alive. All ports live on the yellow drill-down PATCH PANEL (no raw side jacks). The grain window / hash / temporal-blend / feedback-UV / reverb-accumulate / composite-mode math is a 1:1 CPU mirror unit-tested in $lib/video/modules/grainsOfVision.

grains of vision is a granular VIDEO synthesizer: it shatters the incoming picture into a swarm of tiny windowed patches (grains) and re-scatters them into a new frame, then runs that through a feedback block and a video-reverb block on ONE fixed linear chain (video -> granular engine -> feedback -> reverb -> out) — not a node graph. A grain is a small windowed patch of source A sampled at a jittered position AND a jittered moment in time (from a short history of recent frames), so grains have a real temporal axis — the novel part of GRANULAR video. Density sets how many grains pack the frame; Size sets each grain's radius (>=1 cell = overlapping, blended); Window morphs the grain edge from a hard chip to a soft gaussian bloom; Spray scatters where each grain sits and where in the source it grabs from (at 0 it reconstructs the picture faithfully, rising it clouds into abstraction); Rate sets how far back in the frame-history grains reach and T-Spray scatters them across time for a shimmering time-smear; Orient tumbles each patch. The FEEDBACK block mixes the previous OUTPUT back in, zoomed/rotated a touch each pass so it compounds into tunnels and trails (FB amount 0 = a transparent dry passthrough). The REVERB block is a true video reverb — a decaying, spatially-diffused accumulator (the image analogue of a reverb tail): each bright grain blooms outward (Rev Size = room size, Rev Diffuse = how it scatters) and lingers, fading over frames (Rev Decay = tail length), mixed dry/wet by Rev Mix (0 = a transparent dry passthrough). Patch a second source into B and pick a COMPOSITE mode to have B modulate A's grains region-by-region: density-map (B brightness thins/thickens grains), displace (B warps where grains grab from), size-map (B scales grain size), rate-map (B scrubs the per-region time). With only A patched it runs mono-source (composite off). Like every video processor an unpatched input renders black; the defaults are tuned so any patched source is immediately alive — a mid-density overlapping grain field with a little temporal smear, gentle feedback trails and a soft reverb bloom.

the faceplate

grains of visionin_avideoin_bvideodensitycvgrain_sizecvspraycvtime_spraycvratecvorientcvwindowcvfeedbackcvfb_decaycvfb_zoomcvfb_rotatecvrev_mixcvrev_sizecvrev_decaycvrev_diffusecvcompositecvcomp_amountcvoutvideograinsvideoaudiocvgatepitch
19 inputs · 2 outputs · 20 params

inputs

idcablewhat it does
in_avideoPRIMARY video source — the material that is shattered into grains. Unpatched, the output is black.
RGB video stream
in_bvideoMODULATOR video source (optional). When patched AND a COMPOSITE mode is selected, B modulates A's grain data region-by-region (Comp mode picks how). Unpatched, the module runs mono-source (composite off).
RGB video stream
densitycvCV that modulates Density (grid cells across → grain count), swept linearly over its 2..48 range.
control voltage (CV); modulates density (additive offset — ±1 CV sweeps the full range, centered on the knob)
grain_sizecvCV that modulates Size (grain window radius in cell units), swept linearly over 0.2..2.5.
control voltage (CV); modulates grain_size (additive offset — ±1 CV sweeps the full range, centered on the knob)
spraycvCV that modulates Spray (position scatter of the grain centre + source-read), swept linearly over 0..1.
control voltage (CV); modulates spray (additive offset — ±1 CV sweeps the full range, centered on the knob)
time_spraycvCV that modulates T-Spray (temporal scatter of the grains across the frame history), swept linearly over 0..1.
control voltage (CV); modulates time_spray (additive offset — ±1 CV sweeps the full range, centered on the knob)
ratecvCV that modulates Rate (how far back in the frame history grains read — the pitch/rate analog), swept linearly over 0..1.
control voltage (CV); modulates rate (additive offset — ±1 CV sweeps the full range, centered on the knob)
orientcvCV that modulates Orient (per-grain patch rotation), swept linearly over 0..1.
control voltage (CV); modulates orient (additive offset — ±1 CV sweeps the full range, centered on the knob)
windowcvCV that modulates Window (grain edge falloff, hard chip → soft gaussian), swept linearly over 0..1.
control voltage (CV); modulates window (additive offset — ±1 CV sweeps the full range, centered on the knob)
feedbackcvCV that modulates FB (feedback amount, 0 = dry passthrough), swept linearly over 0..0.98.
control voltage (CV); modulates feedback (additive offset — ±1 CV sweeps the full range, centered on the knob)
fb_decaycvCV that modulates FB Dec (feedback colour persistence per pass), swept linearly over 0..1.
control voltage (CV); modulates fb_decay (additive offset — ±1 CV sweeps the full range, centered on the knob)
fb_zoomcvCV that modulates FB Zoom (per-pass zoom of the feedback tap — the tunnel maker), swept linearly over 0.8..1.2.
control voltage (CV); modulates fb_zoom (additive offset — ±1 CV sweeps the full range, centered on the knob)
fb_rotatecvCV that modulates FB Rot (per-pass rotation of the feedback tap — the spiral maker), swept linearly over -20..20 degrees.
control voltage (CV); modulates fb_rotate (additive offset — ±1 CV sweeps the full range, centered on the knob)
rev_mixcvCV that modulates Rev Mix (reverb dry/wet, 0 = dry passthrough), swept linearly over 0..1.
control voltage (CV); modulates rev_mix (additive offset — ±1 CV sweeps the full range, centered on the knob)
rev_sizecvCV that modulates Rev Sz (reverb spatial spread / room size), swept linearly over 0..1.
control voltage (CV); modulates rev_size (additive offset — ±1 CV sweeps the full range, centered on the knob)
rev_decaycvCV that modulates Rev Dec (reverb tail length / temporal persistence), swept linearly over 0..0.99.
control voltage (CV); modulates rev_decay (additive offset — ±1 CV sweeps the full range, centered on the knob)
rev_diffusecvCV that modulates Rev Dif (reverb tap scatter — how isotropic the smear is), swept linearly over 0..1.
control voltage (CV); modulates rev_diffuse (additive offset — ±1 CV sweeps the full range, centered on the knob)
compositecvCV that SELECTS Comp (the composite mode) using a discrete cvScale, snapping to the 5 modes (off / density / displace / size / rate). Inert while B is unpatched. NOTE the discrete cvScale REPLACES the control rather than offsetting it: while a cable is patched here the Comp buttons on the card and the faceplate are inert, and a cable resting at 0 V selects mode 2 (displace), not the dial's setting.
control voltage (CV); modulates composite (integer buckets — CV selects a discrete step)
comp_amountcvCV that modulates Cmp Amt (composite modulation depth), swept linearly over 0..1.
control voltage (CV); modulates comp_amount (additive offset — ±1 CV sweeps the full range, centered on the knob)

outputs

idcablewhat it does
outvideoThe full chain output: the granular scatter after the feedback block and the reverb block.
RGB video stream
grainsvideoThe RAW granular scatter tap — the grain field BEFORE feedback and reverb (a clean grains-only output to key, mix, or feed elsewhere). Optional; leave it unpatched to ignore.
RGB video stream

params

idlabelrangedefaultcurve
densityDensity2..48linear
grain_sizeSize0.2..2.5linear
spraySpray0..1linear
time_sprayT-Spray0..1linear
rateRate0..1linear
orientOrient0..1linear
windowWindow0..1linear
feedbackFB0..0.98linear
fb_decayFB Dec0..1linear
fb_zoomFB Zoom?..?linear
fb_rotateFB Rot?..?linear
fb_dryFB Dry0..1discrete
rev_mixRev Mix0..1linear
rev_sizeRev Sz0..1linear
rev_decayRev Dec0..0.99linear
rev_diffuseRev Dif0..1linear
rev_dryRev Dry0..1discrete
compositeComp0..?discrete
comp_amountCmp Amt0..1linear
freezeFreeze0..1linear

controls

controlwhat it does
Cmp AmtCmp Amt (0..1, default 0.7): the depth of the COMPOSITE modulation. 0 leaves B inert even when a mode is selected; higher pushes B's influence toward extreme.
CompComp (discrete 0..4, default 1 = density): how a patched B modulates A's grains — off, density (B brightness thins/thickens grains), displace (B warps where grains read from), size (B scales grain size), rate (B scrubs the per-region history time). Inert while B is unpatched.
DensityDensity (2..48, default 14): grains across the frame. Higher packs more, smaller grains; lower gives fewer, larger chunks. (Per-pixel cost is constant — density changes grain SIZE, not the work.)
FB DecFB Dec (0..1, default 0.9): the per-pass colour persistence of the fed-back frame. Lower fades trails faster; near 1 they linger.
FB DryFB Dry (0/1, default 0): hard bypass of the feedback block. At 1 the block is a transparent passthrough regardless of the FB amount.
FB RotFB Rot (-20..20 deg, default 0): per-pass rotation of the feedback tap about centre. Combined with FB Zoom off 1.0 the echoes twist into a spiral.
FB ZoomFB Zoom (0.8..1.2, default 1.0 = identity): per-pass zoom of the feedback tap about centre. Off 1.0 the echo re-zooms every pass, compounding into a tunnel (>1 zoom-in, <1 expanding).
FBFB (0..0.98, default 0.4): feedback amount — how much of the transformed previous OUTPUT is mixed back over the grains. 0 = a transparent dry passthrough (feedback block off); higher builds trails/tunnels (clamped each frame so it never blows out).
FreezeFreeze (0/1, default 0): hidden determinism toggle. At >=0.5 draw() is a no-op so the ring + output hold their last frame for deterministic VRT capture. No card control.
SizeSize (0.2..2.5, default 1.1): each grain's window radius in cell units. >=1 makes grains overlap and blend smoothly; small values leave gaps of the dim fallback.
OrientOrient (0..1, default 0.25): per-grain rotation of the sampled patch. 0 = every grain upright; higher tumbles each grain to a random angle.
RateRate (0..1, default 0.15): the pitch/rate analog — how many frames back the grains' history tap reaches. 0 = live (no temporal effect); higher pulls the smear deeper into the past.
Rev DecRev Dec (0..0.99, default 0.85): reverb tail length — how long the diffuse smear persists and accumulates frame to frame before fading.
Rev DifRev Dif (0..1, default 0.5): reverb tap scatter — jitters and rotates the blur taps so the smear is a soft isotropic cloud rather than a boxy axis-aligned blur.
Rev DryRev Dry (0/1, default 0): hard bypass of the reverb block. At 1 the block is a transparent passthrough regardless of Rev Mix.
Rev MixRev Mix (0..1, default 0.25): reverb dry/wet. 0 = a transparent dry passthrough (reverb block off, its blur passes skipped); higher blends in the diffuse glowing tail.
Rev SzRev Sz (0..1, default 0.5): reverb room size — the spatial extent of the blur, i.e. how far each grain blooms outward.
SpraySpray (0..1, default 0.35): position scatter. At 0 grains sit on a tidy grid and read the source at their own location, faithfully reconstructing the picture; rising it jitters both the grain positions and where in the source they grab from, dissolving the image into a granular cloud.
T-SprayT-Spray (0..1, default 0.2): temporal scatter. Spreads the grains across the frame-history from live toward the Rate depth, so different grains show slightly different moments — a shimmering time-smear. 0 = all grains live.
WindowWindow (0..1, default 0.6): the grain window falloff. 0 = a near-hard chip (crisp mosaic); 1 = a soft gaussian shoulder (grains bloom and cross-fade).

source

grainsOfVision.ts on GitHub.

Generated from packages/web/src/lib/{audio,video}/module-registry.ts · repo