@amplib/: visual-effects

GitHub ↗

One interface for generators and filters

AVVA's renderer synthesises images from uniforms. A CRT filter transforms an image it is given. They differ in whether a pass samples an incoming image, and in nothing else.

inputs: { source?: boolean; feedback?: boolean }

A pass that sets source is a filter and receives uSrc. A pass that does not is a generator. The chain feeds each pass's output to the next either way.

Active chain

Source

field runs the generator and passes nothing in. bars feeds a test-pattern canvas. Or drop in a video.

The three passes

field   generator + feedback + compile-time defines.
        N_HUES is a #define, so the hues slider recompiles.

bloom   filter + a private quarter-res ping-pong buffer
        + a four-step draw hook.

crt     filter, single draw.

Three decisions in the CRT pass

Scanline density is a line count. Keyed to device pixels it shifts on a retina display and on every resize.

Ghosting samples uPrev, this pass's own previous output. The previous input gives a one-frame echo that never accumulates.

Curvature runs −1 to 1, zoomed either way to fill the frame without reaching past the source edge. Which point sets that zoom changes with the sign: the corner one way, the middle of each side the other. Pin the corner alone and pincushion oversamples 30% at −1, smearing down each side.

Resolution

uRes is the buffer this pass renders into; uOutRes is the chain's final output. Grain, blur taps and bloom want the former, or a pass at scale: 0.5 quietly changes its own look.

Uniforms are typed by the program, not the caller

uniforms() returns a plain bag of names to values. A Float32Array is a float[] or a vec3[] depending on what the shader declared, so the chain reads the types back off the linked program. Names the compiler dropped are ignored.

No domain data anywhere

The params below are neutral: energy, motion, x, y, impulse. Here they come from a few LFOs; in AVVA, from an AudioFrame through an adapter at the call site. The chain cannot tell which.

Slot colors divide the wheel into equal sectors of perceptual hue — what @amplib/color is for. Equal steps of HSV hue do not look equal.