Text Glitch

A different apporach to a basic typewriter effect

Implementation

Component for the Text Glitch.

text-glitch.tsx - typescript
import { textGlitch } from "@core/lib/animations";
import { useCallback, useEffect, useRef } from "react";

export const TextGlitch = () => {
    const ref = useRef<HTMLParagraphElement | null>(null);

    const handleMouseEnter = useCallback((text: string) => {
        textGlitch({
            text: text,
            duration: 50,
            glitch: 2,
            callbackFn: (newText) => {
                if (ref.current) {
                    ref.current.innerText = newText;
                }
            },
        });
    }, []);


    useEffect(()=>{
        if(ref.current){
            textGlitch({
                text: text,
                duration: 50,
                glitch: 2,
                hidden: true,
                callbackFn: (newText) => {
                    if (ref.current) {
                        ref.current.innerText = newText;
                    }
                },
            });
        }
    },[ref])

    const text = 'Hover Me';
    return (
        <div>
            <p
                className="uppercase text-5xl"
                ref={(el) => {
                    ref.current = el;
                }}
                onMouseEnter={() => handleMouseEnter(text)}
            >
            </p>
        </div>
    );
};

Implementation

Animation for the Text Glitch.

animations.ts - typescript
const alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
export async function textGlitch({
    text,
    duration = 25,
    glitch = 3,
    hidden = false,
    callbackFn
}: {
    text: string;
    duration?: number;
    glitch: number;
    hidden?: boolean;
    callbackFn: (text: string) => any;
}) {
    const size = text.length;
    const initial = text
    let memoizedText: string[] = []
    if(!hidden){
        memoizedText = [...initial];
    }
    const initialPassDuration = duration / 2;

    let y = 1;
    const initialPass = setInterval(() => {
        if(!hidden){
            if (y >= size) {
                clearInterval(initialPass);
                return
            }
            const randomCharacter = alphabets[Math.floor(Math.random() * alphabets.length)];
            memoizedText[y] = randomCharacter;
            callbackFn(memoizedText.join(''));
        }
        y++;
    }, initialPassDuration);
    
    let i = hidden ? 0 : 1;
    let j = 0;

    const secondPass = setInterval(() => {
        if (i >= size) {
            clearInterval(secondPass);
            return;
        }

        if (y > i) {
            const randomCharacter = alphabets[Math.floor(Math.random() * alphabets.length)];
            memoizedText[i] = (j === glitch - 1) ? initial[i] : randomCharacter;
            callbackFn(memoizedText.join(''));

            j++;
            if (j >= glitch) {
                j = 0;
                i++;
            }
        }
    }, duration);
}