A picture as a screen receives it, one scanline at a time.
A picture as a screen receives it. A frame in a black surround is ruled into rows and columns and cut into blocks, and each block carries one kind of signal: barcode bars, dark on black or light on black, a grey carrier, dashes of data, a stripe, a checker. None of it is drawn as a shape. It is laid down one scanline at a time, the way a raster draws a picture, so every bar is a stack of short segments, each a hair off the one above, and a sync burst is a few columns of bright dashes.
There are three channels. The first cuts the frame into small blocks and lets a slow field decide where the bars run light. The second cuts it into large ones: stripes over a ground of data, checkers, and grey fields cut by black bands that step across from row to row. The third is a timing chart. Its rows come in threes, and in each group the bars start a little earlier or stop a little sooner on every repeat, so the frame fills with ladders.
Play it and a beam runs down the frame, redrawing it a scanline at a time. Data changes on every pass. Every so often a block changes, arrives in signal for one pass, and then shows as itself. Now and then the horizontal hold slips, and a band of lines tears sideways, wraps around, and settles back.
The blocks
javascript·signal.js
// cut at grid lines, mostly across the longer side, until each piece is about `area` cells
const split = (x0, x1, y0, y1) => {
const W = x1 - x0, H = y1 - y0;
if (W * H < area * (0.5 + random() * 1.5)) return blocks.push({ x0, x1, y0, y1 });
if (random() < W ** 2 / (W ** 2 + H ** 2)) {
const c = x0 + minC + floor(random() * (W - minC * 2 + 1));
split(x0, c, y0, y1); split(c, x1, y0, y1);
} else {
const r = y0 + minR + floor(random() * (H - minR * 2 + 1));
split(x0, x1, y0, r); split(x0, x1, r, y1);
}
};
The scanline
javascript·signal.js
// every block is drawn one scanline at a time; a bar is its segments, stacked
for (const [x, w, level] of bars) {
const n = hash(seed, s, i);
if (n < 0.008) continue; // a segment the signal dropped
fill(level + (n - 0.5) * 0.03, x + (hash(s, i, seed) - 0.5) * unit * 0.2, y, w, h);
}
The beam
javascript·signal.js
// a few scanlines a frame; a block that changes arrives in signal for one pass
for (let i = 0; i < perFrame; i++) {
line(beam);
if (++beam === scanlines) { beam = 0; pass++; }
}
// the hold slips: a band of lines shears sideways and wraps round, then settles
dx = amp * sin(PI * sqrt(e)) * (1 - e * 0.4) * (0.35 + 0.65 * along);
References