creative-effects

v2026.09.25

Expert knowledge for artistic and creative animation effects - morphing shapes, liquid animations, glitch effects, distortion, and experimental visual techniques that push creative boundaries.

GitHub
Install command
npx skhub add thelobbi/creative-effects
Markdown
SKILL.md

Creative Effects Skill

Expert knowledge for artistic and creative animation effects - morphing shapes, liquid animations, glitch effects, distortion, and experimental visual techniques that push creative boundaries.

When to Use

Activate this skill when:

  • User wants liquid/fluid animations
  • Creating morphing shape transitions
  • Building glitch or distortion effects
  • Need experimental/artistic visuals
  • Creating loading animations with personality
  • Building creative reveals and transitions

File Patterns

  • **/*.tsx with creative components
  • **/components/Creative*.tsx
  • **/components/Effect*.tsx
  • **/components/Liquid*.tsx

Creative Effect Types

1. Morphing Shapes

Liquid Button

import { motion, useAnimation } from 'framer-motion';

export function LiquidButton({ children }: { children: React.ReactNode }) {
  const controls = useAnimation();

  const liquidVariants = {
    rest: {
      d: "M0,20 Q25,0 50,20 T100,20 L100,80 Q75,100 50,80 T0,80 Z",
    },
    hover: {
      d: "M0,30 Q25,10 50,30 T100,30 L100,70 Q75,90 50,70 T0,70 Z",
    },
    tap: {
      d: "M0,25 Q25,15 50,25 T100,25 L100,75 Q75,85 50,75 T0,75 Z",
    },
  };

  return (
    <motion.button
      className="relative px-8 py-4 text-white font-medium"
      initial="rest"
      whileHover="hover"
      whileTap="tap"
    >
      <svg
        className="absolute inset-0 w-full h-full"
        viewBox="0 0 100 100"
        preserveAspectRatio="none"
      >
        <motion.path
          fill="url(#liquid-gradient)"
          variants={liquidVariants}
          transition={{ type: 'spring', stiffness: 300, damping: 20 }}
        />
        <defs>
          <linearGradient id="liquid-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" stopColor="#667eea" />
            <stop offset="100%" stopColor="#764ba2" />
          </linearGradient>
        </defs>
      </svg>
      <span className="relative z-10">{children}</span>
    </motion.button>
  );
}

Morphing Blob

export function MorphingBlob() {
  const paths = [
    "M45.3,-51.2C58.3,-40.8,68.4,-25.6,71.8,-8.4C75.2,8.8,71.9,28,61.6,41.8C51.3,55.6,34,64,15.6,68.9C-2.8,73.8,-22.3,75.2,-38.1,67.6C-53.9,60,-66,43.4,-71.4,24.9C-76.8,6.4,-75.5,-14,-67.4,-30.7C-59.3,-47.4,-44.4,-60.4,-28.6,-69.7C-12.8,-79,-0.1,-84.6,8.9,-78.5C17.9,-72.4,32.3,-54.6,45.3,-51.2Z",
    "M39.9,-47.1C53.3,-36.9,66.7,-26.3,72.2,-11.9C77.7,2.5,75.4,20.7,66.4,35.1C57.4,49.5,41.7,60.1,24.6,66.2C7.5,72.3,-11,73.9,-27.8,68.4C-44.6,62.9,-59.7,50.3,-67.8,34.3C-75.9,18.3,-77,-1.1,-72.1,-18.7C-67.2,-36.3,-56.3,-52.1,-42.4,-62.1C-28.5,-72.1,-11.6,-76.3,1.8,-78.5C15.2,-80.7,26.5,-57.3,39.9,-47.1Z",
    "M42.7,-49.7C55.5,-38.8,66.1,-25.3,69.7,-9.8C73.3,5.7,69.9,23.2,60.6,37.4C51.3,51.6,36.1,62.5,19.3,68.3C2.5,74.1,-15.9,74.8,-32.8,68.7C-49.7,62.6,-65.1,49.7,-72.6,33.4C-80.1,17.1,-79.7,-2.6,-73.3,-20C-66.9,-37.4,-54.5,-52.5,-40.1,-63C-25.7,-73.5,-9.3,-79.4,3.6,-83.7C16.5,-88,29.9,-60.6,42.7,-49.7Z",
  ];

  return (
    <motion.svg viewBox="-100 -100 200 200" className="w-64 h-64">
      <motion.path
        fill="url(#blob-gradient)"
        animate={{
          d: paths,
        }}
        transition={{
          duration: 10,
          repeat: Infinity,
          ease: 'easeInOut',
        }}
      />
      <defs>
        <linearGradient id="blob-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
          <stop offset="0%" stopColor="#667eea" />
          <stop offset="50%" stopColor="#764ba2" />
          <stop offset="100%" stopColor="#f093fb" />
        </linearGradient>
      </defs>
    </motion.svg>
  );
}

2. Glitch Effects

Glitch Text

export function GlitchText({ children }: { children: string }) {
  return (
    <div className="relative inline-block">
      {/* Main text */}
      <span className="relative z-10">{children}</span>

      {/* Glitch layer 1 - Red */}
      <motion.span
        className="absolute inset-0 text-red-500 opacity-80"
        style={{ clipPath: 'inset(0 0 0 0)' }}
        animate={{
          x: [-2, 2, -2],
          clipPath: [
            'inset(40% 0 61% 0)',
            'inset(92% 0 1% 0)',
            'inset(43% 0 1% 0)',
            'inset(25% 0 58% 0)',
          ],
        }}
        transition={{
          duration: 0.3,
          repeat: Infinity,
          repeatType: 'reverse',
        }}
      >
        {children}
      </motion.span>

      {/* Glitch layer 2 - Cyan */}
      <motion.span
        className="absolute inset-0 text-cyan-500 opacity-80"
        style={{ clipPath: 'inset(0 0 0 0)' }}
        animate={{
          x: [2, -2, 2],
          clipPath: [
            'inset(85% 0 7% 0)',
            'inset(15% 0 80% 0)',
            'inset(45% 0 50% 0)',
            'inset(70% 0 25% 0)',
          ],
        }}
        transition={{
          duration: 0.2,
          repeat: Infinity,
          repeatType: 'reverse',
        }}
      >
        {children}
      </motion.span>
    </div>
  );
}

Glitch Image

export function GlitchImage({ src, alt }: { src: string; alt: string }) {
  return (
    <div className="relative overflow-hidden">
      <img src={src} alt={alt} className="relative z-10" />

      <motion.img
        src={src}
        alt=""
        className="absolute inset-0 opacity-50"
        style={{ mixBlendMode: 'multiply' }}
        animate={{
          x: [-5, 5, -5],
          filter: ['hue-rotate(0deg)', 'hue-rotate(90deg)', 'hue-rotate(0deg)'],
        }}
        transition={{
          duration: 0.2,
          repeat: Infinity,
        }}
      />

      <motion.div
        className="absolute inset-0 bg-gradient-to-r from-red-500/20 to-cyan-500/20"
        animate={{
          opacity: [0, 0.3, 0],
          scaleY: [1, 1.02, 1],
        }}
        transition={{
          duration: 0.1,
          repeat: Infinity,
          repeatDelay: 2,
        }}
      />
    </div>
  );
}

3. Liquid/Fluid Effects

Liquid Fill

export function LiquidFill({ progress = 0.7 }: { progress?: number }) {
  const fillHeight = progress * 100;

  return (
    <div className="relative w-32 h-48 bg-slate-800 rounded-2xl overflow-hidden">
      {/* Liquid */}
      <motion.div
        className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-blue-600 to-blue-400"
        initial={{ height: 0 }}
        animate={{ height: `${fillHeight}%` }}
        transition={{ duration: 2, ease: 'easeOut' }}
      >
        {/* Wave effect */}
        <svg
          className="absolute top-0 left-0 w-full"
          viewBox="0 0 100 20"
          preserveAspectRatio="none"
          style={{ transform: 'translateY(-50%)' }}
        >
          <motion.path
            fill="currentColor"
            className="text-blue-400"
            d="M0,10 Q25,0 50,10 T100,10 L100,20 L0,20 Z"
            animate={{
              d: [
                "M0,10 Q25,0 50,10 T100,10 L100,20 L0,20 Z",
                "M0,10 Q25,20 50,10 T100,10 L100,20 L0,20 Z",
                "M0,10 Q25,0 50,10 T100,10 L100,20 L0,20 Z",
              ],
            }}
            transition={{
              duration: 2,
              repeat: Infinity,
              ease: 'easeInOut',
            }}
          />
        </svg>
      </motion.div>

      {/* Bubbles */}
      {Array.from({ length: 5 }).map((_, i) => (
        <motion.div
          key={i}
          className="absolute w-2 h-2 bg-white/30 rounded-full"
          style={{
            left: `${20 + i * 15}%`,
            bottom: 0,
          }}
          animate={{
            y: [0, -fillHeight * 2],
            opacity: [0, 1, 0],
            scale: [0.5, 1, 0.5],
          }}
          transition={{
            duration: 2 + Math.random(),
            delay: i * 0.3,
            repeat: Infinity,
          }}
        />
      ))}
    </div>
  );
}

4. Distortion Effects

Magnetic Button

export function MagneticButton({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLButtonElement>(null);
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    const centerX = rect.left + rect.width / 2;
    const centerY = rect.top + rect.height / 2;

    const distanceX = e.clientX - centerX;
    const distanceY = e.clientY - centerY;

    setPosition({
      x: distanceX * 0.3,
      y: distanceY * 0.3,
    });
  };

  const handleMouseLeave = () => {
    setPosition({ x: 0, y: 0 });
  };

  return (
    <motion.button
      ref={ref}
      className="px-8 py-4 bg-gradient-to-r from-purple-500 to-pink-500 rounded-xl text-white font-medium"
      animate={{ x: position.x, y: position.y }}
      transition={{ type: 'spring', stiffness: 150, damping: 15 }}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
    >
      {children}
    </motion.button>
  );
}

Elastic Container

export function ElasticContainer({ children }: { children: React.ReactNode }) {
  const [isPressed, setIsPressed] = useState(false);

  return (
    <motion.div
      className="cursor-pointer"
      animate={{
        scaleX: isPressed ? 1.1 : 1,
        scaleY: isPressed ? 0.9 : 1,
      }}
      transition={{
        type: 'spring',
        stiffness: 400,
        damping: 10,
      }}
      onMouseDown={() => setIsPressed(true)}
      onMouseUp={() => setIsPressed(false)}
      onMouseLeave={() => setIsPressed(false)}
    >
      {children}
    </motion.div>
  );
}

5. Creative Loaders

DNA Helix Loader

export function DNALoader() {
  const dots = Array.from({ length: 10 });

  return (
    <div className="flex items-center justify-center h-20">
      {dots.map((_, i) => (
        <div key={i} className="relative w-4 mx-0.5">
          <motion.div
            className="absolute w-3 h-3 bg-blue-500 rounded-full"
            animate={{
              y: [-15, 15, -15],
              scale: [1, 0.8, 1],
              opacity: [1, 0.5, 1],
            }}
            transition={{
              duration: 1,
              delay: i * 0.1,
              repeat: Infinity,
              ease: 'easeInOut',
            }}
          />
          <motion.div
            className="absolute w-3 h-3 bg-purple-500 rounded-full"
            animate={{
              y: [15, -15, 15],
              scale: [0.8, 1, 0.8],
              opacity: [0.5, 1, 0.5],
            }}
            transition={{
              duration: 1,
              delay: i * 0.1,
              repeat: Infinity,
              ease: 'easeInOut',
            }}
          />
        </div>
      ))}
    </div>
  );
}

Orbiting Loader

export function OrbitingLoader() {
  const orbits = [
    { radius: 20, duration: 1.5, color: '#667eea' },
    { radius: 35, duration: 2, color: '#764ba2' },
    { radius: 50, duration: 2.5, color: '#f093fb' },
  ];

  return (
    <div className="relative w-32 h-32">
      {/* Center dot */}
      <motion.div
        className="absolute top-1/2 left-1/2 w-4 h-4 -ml-2 -mt-2 bg-white rounded-full"
        animate={{ scale: [1, 1.2, 1] }}
        transition={{ duration: 1, repeat: Infinity }}
      />

      {/* Orbiting dots */}
      {orbits.map((orbit, i) => (
        <motion.div
          key={i}
          className="absolute top-1/2 left-1/2 w-3 h-3 -ml-1.5 -mt-1.5 rounded-full"
          style={{ backgroundColor: orbit.color }}
          animate={{
            x: [orbit.radius, 0, -orbit.radius, 0, orbit.radius],
            y: [0, orbit.radius, 0, -orbit.radius, 0],
          }}
          transition={{
            duration: orbit.duration,
            repeat: Infinity,
            ease: 'linear',
          }}
        />
      ))}
    </div>
  );
}

6. Reveal Effects

Mask Reveal

export function MaskReveal({
  children,
  delay = 0,
}: {
  children: React.ReactNode;
  delay?: number;
}) {
  return (
    <div className="relative overflow-hidden">
      <motion.div
        initial={{ y: '100%' }}
        animate={{ y: '0%' }}
        transition={{
          duration: 0.8,
          delay,
          ease: [0.25, 0.1, 0.25, 1],
        }}
      >
        {children}
      </motion.div>
      <motion.div
        className="absolute inset-0 bg-gradient-to-r from-purple-500 to-pink-500"
        initial={{ x: '0%' }}
        animate={{ x: '100%' }}
        transition={{
          duration: 0.6,
          delay: delay + 0.2,
          ease: [0.25, 0.1, 0.25, 1],
        }}
      />
    </div>
  );
}

Split Reveal

export function SplitReveal({ children }: { children: React.ReactNode }) {
  return (
    <div className="relative overflow-hidden">
      <div className="relative z-10">{children}</div>

      {/* Top curtain */}
      <motion.div
        className="absolute inset-x-0 top-0 h-1/2 bg-slate-900 origin-top"
        initial={{ scaleY: 1 }}
        animate={{ scaleY: 0 }}
        transition={{ duration: 0.8, ease: [0.25, 0.1, 0.25, 1] }}
      />

      {/* Bottom curtain */}
      <motion.div
        className="absolute inset-x-0 bottom-0 h-1/2 bg-slate-900 origin-bottom"
        initial={{ scaleY: 1 }}
        animate={{ scaleY: 0 }}
        transition={{ duration: 0.8, ease: [0.25, 0.1, 0.25, 1] }}
      />
    </div>
  );
}

Examples

<example> Context: User wants a liquid morphing button user: "Create a button that feels liquid when hovered" assistant: Using the LiquidButton component: ```tsx <LiquidButton>Get Started</LiquidButton> ``` The button's background morphs like liquid on hover and tap. </example> <example> Context: User wants glitch text effect user: "Add a glitch effect to my heading" assistant: Using GlitchText: ```tsx <h1 className="text-4xl font-bold"> <GlitchText>CYBERPUNK 2077</GlitchText> </h1> ``` </example>

Related Skills

  • background-animations - Full-page creative backgrounds
  • accent-animations - Decorative elements
  • svg-animations - Path morphing

Author

Created by Brookside BI as part of React Animation Studio

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.25

Published

Sep 25, 2026

Category

Uncategorized

License

MIT

Source path

plugins/react-animation-studio/skills/creative-effects

Default branch

main

Latest commit

2f1269c

Tree SHA

629e050