Mobile | Thu May 01 20250 views

Particles Animation

Hi there! 👋

I needed an animation for an app I'm working on, so I went to bolt.new and ask the AI to generate a reaction animation. And it was a success!

In case you need a similar animation, you can use the code below.

🧙‍♂️ Want to become a React Native master? Check out the React Native Course.

Also, dive into the React with TypeScript Course to master TypeScript, handle payments, and deploy scalable apps. Learn more

How to use

Here's an example of how to use the animation:

import { useState } from "react";
import { View, Button } from "react-native";
import ReactionParticles from "./ReactionParticles";
 
const reactionColors = ["#FF7E7E", "#7EB3FF", "#8FD28F", "#FFE07E", "#D7A0FF"];
 
export default function ReactionAnimation() {
  const [activeParticle, setActiveParticle] = useState<boolean>(false);
 
  function handleShowParticles() {
    setActiveParticle(true);
    setTimeout(() => {
      setActiveParticle(false);
    }, 1000);
 
    return (
      <View>
        {activeParticle && (
          <ReactionParticles
            color={
              reactionColors[Math.floor(Math.random() * reactionColors.length)]
            }
          />
        )}
        <Button onPress={handleShowParticles}>Show Particles</Button>
      </View>
    );
  }
}

Simple as that! Just pass the color you want to use and the animation will be shown. We use a timeout to hide the animation after 1 second.

ReactionParticles Component

You can copy paste the code below to use the animation in your project. Just make sure you have react-native-reanimated installed.

import { useEffect } from "react";
import { View, StyleSheet } from "react-native";
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
  withDelay,
  Easing,
} from "react-native-reanimated";
 
interface ParticleProps {
  color: string;
  delay: number;
  x: number;
  y: number;
  size: number;
}
 
function Particle({ color, delay, x, y, size }: ParticleProps) {
  const opacity = useSharedValue(0);
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);
  const scale = useSharedValue(0);
 
  useEffect(() => {
    // Start animation
    opacity.value = withDelay(delay, withTiming(1, { duration: 200 }));
    scale.value = withDelay(delay, withTiming(1, { duration: 300 }));
    translateX.value = withDelay(
      delay,
      withTiming(x, {
        duration: 500,
        easing: Easing.bezier(0.25, 0.1, 0.25, 1),
      }),
    );
    translateY.value = withDelay(
      delay,
      withTiming(y, {
        duration: 500,
        easing: Easing.bezier(0.25, 0.1, 0.25, 1),
      }),
    );
 
    // Fade out
    const timerId = setTimeout(() => {
      opacity.value = withTiming(0, { duration: 300 });
      scale.value = withTiming(0.5, { duration: 300 });
    }, delay + 300);
 
    return () => clearTimeout(timerId);
  }, []);
 
  const animatedStyle = useAnimatedStyle(() => {
    return {
      opacity: opacity.value,
      transform: [
        { translateX: translateX.value },
        { translateY: translateY.value },
        { scale: scale.value },
      ],
    };
  });
 
  return (
    <Animated.View
      style={[
        styles.particle,
        { backgroundColor: color, width: size, height: size },
        animatedStyle,
      ]}
    />
  );
}
 
interface ReactionParticlesProps {
  color: string;
}
 
export function ReactionParticles({ color }: ReactionParticlesProps) {
  // Create particles in different directions
  const particles = Array.from({ length: 8 }).map((_, i) => {
    const angle = (i / 8) * Math.PI * 2;
    const distance = 25 + Math.random() * 10;
    return {
      id: i,
      color,
      delay: Math.random() * 100,
      x: Math.cos(angle) * distance,
      y: Math.sin(angle) * distance,
      size: 5 + Math.random() * 4,
    };
  });
 
  return (
    <View style={styles.container}>
      {particles.map((particle) => (
        <Particle
          key={particle.id}
          color={particle.color}
          delay={particle.delay}
          x={particle.x}
          y={particle.y}
          size={particle.size}
        />
      ))}
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: {
    position: "absolute",
    width: 40,
    height: 40,
    justifyContent: "center",
    alignItems: "center",
    zIndex: 10,
  },
  particle: {
    position: "absolute",
    borderRadius: 100,
  },
});

Stay tuned! 🔌

Create an account to get our newsletter with updates, tips, and exclusive content — delivered straight to your inbox. Just hit the Sign Up button in the top right to get started.