library / retro & cyberpunk / 1-crimson-glitch-stream
live - 60fps 1920 x 1080
1-crimson-glitch-stream.html - self-contained
<!DOCTYPE html>
<html>

<head>
    <title>1. Crimson Glitch Stream</title>
    <style>
        body {
            margin: 0;
            background-color: var(--matrix-bg);
            overflow: hidden;
        }

        canvas {
            display: block;
        }

        :root {
            --matrix-bg: #050000;
            --matrix-text: #b81c1c;
            --matrix-trail: rgba(10, 0, 0, 0.05);
            --matrix-flash: #ffeaea;
            --matrix-shadow: #ff4d4d;
            /* Default to monospace if no global font is set */
            font-family: var(--htmlhub-font, monospace);
        }
    </style>
</head>

<body>
    <canvas id="matrixCanvas"></canvas>
    <script>
        const canvas = document.getElementById('matrixCanvas');
        const ctx = canvas.getContext('2d');

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        // Characters used in the stream, focusing on hex and symbols
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()[]{};:?<>~';
        const hexChars = '0123456789ABCDEF';
        const characterSet = (hexChars + chars).split('');

        const fontSize = 16;
        const columns = Math.floor(canvas.width / fontSize);

        // Array to store the Y position of each stream column
        const drops = Array(columns).fill(1);

        function draw() {
            // Create the fading trail effect by drawing a semi-transparent background
            // Fetch color from CSS variable for live customization
            const style = getComputedStyle(document.documentElement);

            ctx.fillStyle = style.getPropertyValue('--matrix-trail').trim() || 'rgba(10, 0, 0, 0.05)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // Main text color
            ctx.fillStyle = style.getPropertyValue('--matrix-text').trim() || '#b81c1c';

            // Use global font variable
            const fontStack = style.getPropertyValue('--htmlhub-font').trim() || 'monospace';
            ctx.font = `${fontSize}px ${fontStack}`;

            for (let i = 0; i < drops.length; i++) {
                const text = characterSet[Math.floor(Math.random() * characterSet.length)];
                const x = i * fontSize;
                // Snap Y to grid to prevent jitter at slow speeds
                const y = Math.floor(drops[i]) * fontSize;

                // Main draw call for the character
                ctx.fillText(text, x, y);

                // Add the "glitch" effect randomly
                if (Math.random() > 0.985) {
                    // Flash effect: Draw a brighter, slightly offset character
                    ctx.fillStyle = style.getPropertyValue('--matrix-flash').trim() || '#ffeaea';
                    ctx.shadowColor = style.getPropertyValue('--matrix-shadow').trim() || '#ff4d4d';
                    ctx.shadowBlur = 10;
                    ctx.fillText(text, x + (Math.random() * 4 - 2), y);

                    // Reset styles
                    ctx.fillStyle = style.getPropertyValue('--matrix-text').trim() || '#b81c1c';
                    ctx.shadowBlur = 0;
                }

                // Reset a stream when it reaches the bottom of the screen
                // Add randomness to make the streams less uniform
                if (y > canvas.height && Math.random() > 0.975) {
                    drops[i] = 0;
                }

                // Increment by speed factor
                const speed = parseFloat(style.getPropertyValue('--htmlhub-speed')) || 1.0;
                drops[i] += speed;
            }
        }

        // Set animation to loop. The internal logic handles the seamlessness.
        setInterval(draw, 33);

        // Resize canvas if window size changes
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            // Re-initialize columns and drops array on resize
            const newColumns = Math.floor(canvas.width / fontSize);
            drops.length = 0; // Clear the array
            for (let i = 0; i < newColumns; i++) {
                drops.push(1);
            }
        });
    </script>
</body>

</html>

About this animation

A crimson-colored data stream with glitch effects.

Under the hood

CSS Hardware-Accelerated Glitching

This effect uses structural CSS layering and mix-blend-mode to simulate digital tearing. By utilizing clip-path and high-speed @keyframes, the browser offloads the text-shifting rendering directly to the GPU for a 60fps chromatic aberration without any JavaScript overhead.

Source Code
Source copied
Partner hosting options for the copied effect:
Vercel Netlify Hostinger