Recreating the Glitch: Designing a Failing CRT Terminal in py5
2026/9/6
In the realm of generative media art, "kinetic_retro_crt_typography_glitch_2d" is an exploration of digital decay—a cyberpunk-inspired typographical animation that mimics the visual artifacts of a failing cathode-ray tube (CRT) monitor displaying a corrupted terminal stream. As you watch the animation, a dense grid of alphanumeric characters pulses and mutates violently, interrupted by chaotic horizontal scanline desyncs and slow-moving, intensely glowing phosphor bands. Python and py5 provide the perfect environment for this type of experiment; their seamless integration with Processing’s underlying rendering engine allows for rapid iteration of pixel-level noise operations while maintaining real-time mathematical precision for the glitch mechanics.
The Anatomy of Digital Decay
To achieve a cinematic and deeply realistic aesthetic, the visual rendering relies heavily on additive blending over a dark green-black background, referencing the classic phosphor glow of vintage mainframes. The entire piece avoids standard stylized treatments, opting instead for a raw, signal-distorted look driven by multi-layered mathematical noise. The core algorithms dictating the visuals depend on thresholded Perlin noise and overlapping sine waves rather than random number generators alone. By passing spatial coordinates and a looping time variable into noise functions, we create localized "pockets" of instability where the typography mutates rapidly, mirroring the organic failure of hardware components. Severe red and blue chromatic aberration is dynamically applied only during the most intense horizontal tearing events, simulating the moment when the electron beam completely loses sync.Technical Breakdown: Forcing the Glitch
The heart of the simulation lies in how the grid of characters is rendered and displaced each frame. Rather than applying a global post-processing shader, the CRT distortion is calculated per-character based on its spatial position, ensuring the text itself drives the visual breakdown.1. Noise-Driven Character MutationTo simulate corrupted memory banks or localized signal noise, characters do not change entirely at random. Instead, a 3D Perlin noise field determines "clusters" of mutation.
# Fast changing chars in noise clusters
if py5.noise(i * 0.05, j * 0.05, t * 8) > 0.65:
char = CHARS[(int(py5.noise(i, j, t * 30) * 100)) % len(CHARS)]By scaling the spatial coordinates (i * 0.05, j * 0.05) and evolving it over time (t * 8), the noise function generates organic blobs of instability. When the noise value crosses a strict threshold (0.65), the character is swapped out. The new character is also chosen deterministically using a higher-frequency noise field (t * 30), ensuring the flickering feels chaotic yet mathematically grounded.
2. Horizontal Sync Tearing and ScanningThe hallmark of a broken CRT is horizontal desynchronization—where lines of the display warp and slide out of phase.
glitch_noise = py5.noise(j * 0.02, t * 15)
x_offset = 0
# Horizontal sync tearing glitch
if glitch_noise > 0.7:
x_offset = py5.remap(glitch_noise, 0.7, 1.0, 0, CELL_SIZE * 15)
x_offset *= math.sin(y * 0.05 + loop_t * 5)Here, 1D Perlin noise across the vertical axis (`j * 0.02`) creates horizontal bands of distortion. When this noise exceeds `0.7`, we trigger a tearing event. The `py5.remap` function dictates the severity of the tear, translating the narrow 0.7–1.0 noise range into a massive horizontal offset (up to `CELL_SIZE * 15`). Crucially, multiplying this offset by a sine wave based on the y-coordinate gives the tear that characteristic wavy, "rolling" CRT distortion rather than a rigid block shift.
3. Dynamic Chromatic AberrationWhen the signal tears violently, the individual color channels of the monitor fail to converge. We simulate this by drawing harsh red and blue ghosts of the character when the horizontal offset is severe or the brightness peaks.
if abs(x_offset) > 5 or brightness > 200:
py5.fill(255, 0, 0, 180)
py5.text(char, (x_pos - max(x_offset * 0.1, 5)) % SIZE[0], y)
py5.fill(0, 0, 255, 180)
py5.text(char, (x_pos + max(x_offset * 0.1, 5)) % SIZE[0], y)The offset for the red and blue channels scales proportionally with the underlying `x_offset`, meaning the chromatic split worsens exactly as the horizontal tear becomes more aggressive. The modulo operator (`% SIZE[0]`) ensures that any text wrapping off the screen neatly re-enters on the opposite side, maintaining the illusion of a continuous, infinite data stream.

Conclusion
"kinetic_retro_crt_typography_glitch_2d" demonstrates that compelling glitch aesthetics do not require complex GLSL shaders; they can be built from the ground up using fundamental noise fields and coordinate displacement. By carefully controlling thresholds and combining overlapping wave functions, we can breathe unpredictable, hardware-like life into an otherwise rigid grid of text. The resulting animation is an homage to the beautiful imperfections of legacy technology.GitHub: https://github.com/asamiile/py5-media-art/tree/main/sketch/algorithmic_resonance_chambersPurchase assets: Adobe Stock