JSFiddle - React, Tailwind, and code Playground

HTML

<div style="margin-bottom:1000px">top div, scroll down</div>

<div class="logo-message txt-anim">
  <p>
    <span class="letter">L</span>
    <span class="letter">i</span>
    <span class="letter">q</span>
    <span class="letter">u</span>
    <span class="letter">i</span>
    <span class="letter">d</span>
    <span class="letter empty"> </span>
    <span class="letter">i</span>
    <span class="letter">d</span>
    <span class="letter">e</span>
    <span class="letter">a</span>
    <span class="letter">s</span>
    <span class="letter empty"> </span>
    <span class="letter">t</span>
    <span class="letter">o</span>
    <span class="letter empty"> </span>
    <span class="letter">g</span>
    <span class="letter">e</span>
    <span class="letter">t</span>
    <span class="letter empty"> </span>
    <span class="letter">a</span>
    <span class="letter">n</span>
    <span class="letter">y</span>
    <span class="letter">w</span>
    <span class="letter">h</span>
    <span class="letter">e</span>
    <span class="letter">r</span>
    <span class="letter">e</span>
  </p>
</div>

JavaScript 1.7

let txtAnimStarted = false;
function txtAnim(speed){
		if (txtAnimStarted) return;
    txtAnimStarted = true;
		console.log('starting txtAnim');
    jQuery('.txt-anim').css("opacity", "1");

    var skills = jQuery('.txt-anim p').contents().filter(function() {
        return this.nodeType === 3; // only immediate text in div, not in span
    }).map(function() {
        var txt = "<span class='letter'>" + jQuery(this).text().split("").join("</span><span class='letter'>") + "</span>";
        // console.log(txt);
        jQuery(this).replaceWith(txt);
    });

    var i = 0;
    var span = jQuery('.txt-anim').find('span');

    jQuery(".txt-anim p").empty();

    typeWriter();
    function typeWriter() {
        if (i < span.length) {
            jQuery('.txt-anim p').append(span[i]) ;
            i++;
            setTimeout(typeWriter, speed);
        }else{
            console.log("text animation ended");
            jQuery('.home-page-cities-mobile').css("opacity", "1");
            jQuery('.flecha-home').css("opacity", "1");
        }
    }

}    
//Intersection Observer
const textAnim = document.querySelector('.txt-anim');
let options = {
  rootMargin: "0px",
  threshold: 1.0
};

let observer = new IntersectionObserver((entries) => {
	const entry = entries[0];
  if (entry.isIntersecting) txtAnim(20);
}, options);

observer.observe(textAnim);