Web Animation: Twitch ears twice in a row
Tags: react, javascript, beginners
Published: 2024-01-04 00:45:01

This post is a continuation of [Web Animation: Create endless twitching ear motion with a certain interval](https://dev.to/mich0w0h/css-create-endless-twitching-ear-motion-with-a-certain-interval-467j)

## What I want to achieve
- twitch a character's ears twice in a row in a web app project made of React + Typescript
- twitching motion itself has already been done in the previous article

## How to implement
Create a `Promise` to implement a delay.

```tsx
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
```
Then, update the `twitchEars` function into async one and insert delays between twitches in that function.

```tsx
const twitchEars = async () => {
    setTwitching(true);

    await delay(twitchDuration);
    setTwitching(false);

    await delay(200); // Delay between the twitches

    setTwitching(true);
    await delay(twitchDuration);

    setTwitching(false);
};
```

For a bit of a twist, I used `async` and `await` instead of just implementing it by the sequence of several `setTimeout`s.

## Now I did it!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msevuo9xajvsjzn6guma.gif)



## Overall view of the component
The overall view of the component so far is here.

CharacterDisplay.tsx
```tsx
import { useState, useEffect } from 'react';
import './CharacterDisplay.css';

const CharacterDisplay: React.FC = () => {
    const [twitching, setTwitching] = useState(false);
    const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
    const twitchDuration: number = 150;

    useEffect(() => {
        const twitchInterval = setInterval(() => {
            twitchEars();
        }, 2000);    // Interval between twitches

        return () => clearInterval(twitchInterval);
    }, []);

    
    const twitchEars = async () => {
        setTwitching(true);

        await delay(twitchDuration);
        setTwitching(false);

        await delay(200); // Delay between the twitches

        setTwitching(true);
        await delay(twitchDuration);

        setTwitching(false);
    };
    
    return (
        <div className="character">
             <img src="/src/assets/character-body.png" alt="Character body" className="character-body" />
            <img
                src="/src/assets/character-left-ear.png"
                alt="Left ear"
                className={`ear left ${twitching ? 'twitch-left' : ''}`}
                onClick={twitchEars}
            />
            <img
                src="/src/assets/character-right-ear.png"
                alt="Right ear"
                className={`ear right ${twitching ? 'twitch-right' : ''}`}
                onClick={twitchEars}
            />
        </div>
    );
};

export default CharacterDisplay;
```
CharacterDisplay.css
```css
.character {
    position: relative;
    width: 224px; 
    height: 246px; 
}

.character-body {
    position: absolute;
    width: 100%;
    height: 100%;
}

.ear {
    position: absolute;
    top: 2px;
    width: 40px;
    height: 40px;
    transition: transform 0.2s ease;
}

.left {    
    left: 40px;
}

.right {
    right: 43px;
}

.twitch-left {
    transform: rotate(-10deg);
}

.twitch-right {
    transform: rotate(10deg);
}
```