VHS Tape Text

· 4 min · Article · Joost van der Laan

Nobody who grew up with a VCR remembers VHS as blurry. They remember it as a specific set of failures: colour that runs past the edge of a letter, a picture that breathes sideways, a white tear that walks down the frame, and the moment you nudged TRACKING and the whole thing snapped into focus.

This plate rebuilds those failures from the signal up. Type your own words into it — the effect is applied live, to real text, not to a picture of text.

Style
Tape warble and dropout severity
How far colour smears past the luma edge
Chroma noise in the shadows

The four styles are the four ways a tape goes wrong. 01 is a clean deck on a blue broadcast field. 02 is a tape that has been watched too many times. 03 is the one where you get up and hit the machine. 04 is a camera pointed straight at the tube, close enough to resolve the shadow mask.

Teardown

The whole effect is a fake of one thing: composite video does not carry colour and brightness at the same resolution. Luma gets the bandwidth, chroma gets what is left. Every artefact below falls out of that one fact, so the chain models it directly instead of stacking Photoshop filters.

The signal, not the picture. Text is rendered into an offscreen buffer 400px wide — roughly what VHS actually resolves horizontally — and everything downstream operates on that buffer before it is scaled up to the canvas. This is why the glyphs go blocky. It is not a pixelate filter; it is the same loss of horizontal resolution that made real tape titles look like that, so it lands correctly on any text at any size without tuning.

Chroma bleed. Each scanline is decomposed into YIQ — the encoding composite video genuinely uses. Luma is sampled sharp; the I and Q channels are box-averaged over a window that ends at the sample point, so colour smears rightward off every edge and never leftward. The window is a prefix sum, so the smear costs the same whether it is 3 pixels or 30. That directional smear is the tell that separates VHS from a generic glow.

Misregistration. Luma is sampled three times per pixel at slightly different delays — one each for R, G and B. Edges pick up a warm fringe on one side and a cold one on the other, which is the fringing in the reference, and it emerges from the sampling rather than being painted on as a coloured drop shadow.

Tape transport. Row displacement is the sum of three sines at different frequencies (slow warble, medium flutter, per-line jitter), all pure functions of (row, time). On top of that: seeded dropouts that drift down the frame and briefly tear and brighten a band, and a head-switching skew in the bottom 4.5% of the picture, where a real deck swaps video heads mid-scan.

The tube. Grille, scanlines and vignette are drawn at output resolution, not signal resolution, because they are artefacts of the screen rather than the tape — a real camera resolves the shadow mask independently of how bad the tape is. Bloom is a blurred, tinted copy composited additively on top, so glow spills across the grille gaps the way phosphor does.

Determinism. Grain and dropouts come from the harness’s seeded PRNG, so ?seed=N reproduces a specific tape exactly, and Save PNG exports the frame you are looking at. Nothing calls Math.random() or Date.now().

Reduced motion. Under prefers-reduced-motion: reduce the harness runs a single step and draw and never schedules a frame. All of the static degradation survives — resolution loss, bleed, fringing, grille, bloom, grain — and only the transport motion stops, so the plate still reads as VHS instead of collapsing to plain text. Control changes force an explicit redraw, since there is no animation loop to pick them up.