CRT Loader
A cathode-ray simulation with live controls for the tube and text reveal.
Camera · 59.94 Hz
Implementation
Copy the current setup.
// Position-dependent CRT beam misconvergence
vec2 p = uv * 2.0 - 1.0;
float edge = pow(clamp(dot(p,p) * .62, 0., 1.), .78);
vec2 rField = vec2(1.08*p.x + .28*p.y, -.18*p.x + .52*p.y);
vec2 bField = vec2(-.82*p.x - .16*p.y, .24*p.x - .66*p.y);
vec3 excitation = vec3(
sampleSource(uv + rField * texel * convergence * edge),
sampleSource(uv),
sampleSource(uv + bField * texel * convergence * edge)
);
// Bright phosphors produce a wider beam profile
float sigma = mix(.20, .39, pow(max3(excitation), .55));
float beam = exp(-.5 * pow(distanceToRaster / sigma, 2.));
// Refresh is phosphor decay behind a moving raster—not opacity jitter
float age = fract(time * refreshHz - uv.y);
float decay = exp(-age * mix(4.8, 2.1, persistence));
excitation *= mix(1.0, mix(.94, 1.07, decay), flicker);
// Camera mode adds shutter/refresh beat after tube synthesis
color *= cameraMode ? shutterExposure(uv, time, syncOffset) : 1.0;
// Healthy startup: blank first, then reveal the full raster and settle.
float blankGate = smoothstep(.68, .84, elapsed);
float emission = pow(smoothstep(.66, 1.32, elapsed), 1.45);
float settle = smoothstep(.82, 1.68, elapsed);
color *= blankGate * emission;
// No center line: that belongs to shutdown or deflection failure.