Web Animation: Create endless twitching ear motion with a certain interval
Tags: css, react, animation, beginners
Published: 2023-12-29 08:20:48

This post is a continuous of the previous one;
[CSS: Position separate elements properly within a character's body - DEV Community](https://dev.to/mich0w0h/css-position-separate-elements-properly-within-a-characters-body-23lk)

## What I want to achieve
- twitch a character's ears in a web app made by React + Typescript
- the twitch motion starts just after the page is loaded
- the motion continues endlessly in a certain interval.

## Screen visual of prev state
![prev screen visual](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ympzw60lkz7dasjabl45.png)


## Codes and Explanation
Set up a state of boolean variable `twitching`

```js
const [twitching, setTwitching] = useState(false);
```

When the `twitching` variable turns true, it applies a CSS class(`twitch-left` or `twitch-right`) to the respective ear, causing it to rotate slightly.

```jsx
<img
    src="/src/assets/character-left-ear.png"
    alt="Left ear"
    className={`ear left ${twitching ? 'twitch-left' : ''}`}
/>
```

Here's CSS.

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

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

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


All that's left is to toggle the state variable.
Use the `useEffect` hook to trigger the toggle shortly after the component mounts.


```js
useEffect(() => {
  // toggle variable
}, []);
```

Inside the effect, use `setInterval` to trigger the twitching motion at regular intervals.
```js
useEffect(() => {
    const twitchInterval = setInterval(() => {
        setTwitching(true);
    }, 3000);    // Interval between twitches
}, []);
```

By returning a cleanup function inside the `useEffect`, it can be ensured that the interval is stopped and cleaned up when the component unmounts.
```js
useEffect(() => {
    const twitchInterval = setInterval(() => {
        setTwitching(true);
        setTimeout(() => {
            setTwitching(false);
        }, twitchDuration);    // Duration of each twitch motion
    }, 3000);    // Interval between twitches

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

```

## Now it's done!
![twitching](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4d1uedzzvlho20m4122.gif)


## Complete form of codes

```tsx
import { useState, useEffect } from 'react';
import './CharacterDisplay.css'; // Import your CSS for character styling

const CharacterDisplay: React.FC = () => {
    const [twitching, setTwitching] = useState(false);
    const twitchDuration: number = 200;

    useEffect(() => {
        const twitchInterval = setInterval(() => {
            setTwitching(true);
            setTimeout(() => {
                setTwitching(false);
            }, twitchDuration);    // Duration of each twitch motion
        }, 3000);    // Interval between twitches

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

    const twitchEars = () => {
        setTwitching(true);
        setTimeout(() => {
            setTwitching(false);
        }, twitchDuration);
    };
    
    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);
}
```

## What's next
Twitch ears twice in a row