I have React code with a CSS animation in a codesandbox and on my staging site.
You will notice that over time, the animation timing drifts. After a certain number of loops it presents the text too early and is not in sync with the animation.
I have tried changing the timing making the array switch happen faster and slower.
Any ideas would be greatly appreciated.
import "./styles.css";
import styled, { keyframes } from "styled-components";
import React, { useEffect, useState } from "react";
const animation = keyframes`
  0% { opacity: 0; transform: translateY(-100px) skewX(10deg) skewY(10deg) rotateZ(30deg); filter: blur(10px); }
  25% { opacity: 1; transform: translateY(0px) skewX(0deg) skewY(0deg) rotateZ(0deg); filter: blur(0px); }
  75% { opacity: 1; transform: translateY(0px) skewX(0deg) skewY(0deg) rotateZ(0deg); filter: blur(1px); }
  100% { opacity: 0; transform: translateY(-100px) skewX(10deg) skewY(10deg) rotateZ(30deg); filter: blur(10px); }
`;
const StaticText = styled.div`
  position: absolute;
  top: 100px;
  h1 {
    color: #bcbcbc;
  }
  span {
    color: red;
  }
  h1,
  span {
    font-size: 5rem;
    @media (max-width: 720px) {
      font-size: 3rem;
    }
  }
  width: 50%;
  text-align: center;
  left: 50%;
  margin-left: -25%;
`;
const Animate = styled.span`
  display: inline-block;
  span {
    opacity: 0;
    display: inline-block;
    animation-name: ${animation};
    animation-duration: 3s;
    animation-timing-function: cubic-bezier(0.075, 0.82, 0.165, 1);
    animation-fill-mode: forwards;
    animation-iteration-count: infinite;
    font-weight: bold;
  }
  span:nth-child(1) {
    animation-delay: 0.1s;
  }
  span:nth-child(2) {
    animation-delay: 0.2s;
  }
  span:nth-child(3) {
    animation-delay: 0.3s;
  }
  span:nth-child(4) {
    animation-delay: 0.4s;
  }
  span:nth-child(5) {
    animation-delay: 0.5s;
  }
`;
export default function App() {
  const array = ["wood", "cork", "leather", "vinyl", "carpet"];
  const [text, setText] = useState(array[0].split(""));
  const [countUp, setCountUp] = useState(0);
  useEffect(() => {
    const id = setTimeout(() => {
      if (countUp === array.length -1) {
        setCountUp(0);
      } else {
        setCountUp((prev) => prev + 1);
      }
    }, 3000);
    return () => {
      clearTimeout(id);
    };
  }, [countUp]);
  useEffect(() => {
    setText(array[countUp].split(""));
  }, [countUp]);
  return (
    <div className="App">
      <StaticText>
        <h1>More than just</h1>
        <Animate>
          {text.map((item, index) => (
            <span key={index}>{item}</span>
          ))}
        </Animate>
      </StaticText>
    </div>
  );
}
 
    