Paragraph Scroll Effect One

ParaScrollEffectOne is a simple scroll animation component that adjusts a paragraph’s opacity based on scroll position. It creates a smooth fade effect and optionally supports a centered fixed layout for immersive sections.

framer-motionlenis

Live Demo

Installation

Install the required dependencies:

npm install framer-motion lenis
components/ui/paragraph-scroll-effect-one.tsx
"use client";
import Link from "next/link";
import React, { useState, useRef } from "react";

const buttonItems = [
  { index: 1, name: "Button 1", link: "#" },
  { index: 2, name: "Button 2", link: "#" },
  { index: 3, name: "Button 3", link: "#" },
  { index: 4, name: "Button 4", link: "#" },
  { index: 5, name: "Button 5", link: "#" },
];

export default function Navbar() {
  const [active, setActive] = useState(0);
  const [hover, setHover] = useState(-1);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const itemRefs = useRef<(HTMLAnchorElement | null)[]>([]);

  const getStyle = () => {
    if (hover < 0) {
      return { left: "4px", width: "98.5%" };
    }

    const item = itemRefs.current[hover];
    if (!item || !containerRef.current) return {};

    const itemRect = item.getBoundingClientRect();
    const parentRect = containerRef.current.getBoundingClientRect();

    return {
      left: `${itemRect.left - parentRect.left}px`,
      width: `${itemRect.width}px`,
    };
  };

  return (
    <nav className="w-full h-fit flex justify-center items-center">
      <div className="relative p-[3px] inset-[3px] rounded-full bg-gradient-to-b from-neutral-700 to-neutral-800">
        <div
          ref={containerRef}
          className="relative w-fit rounded-full bg-gradient-to-b from-neutral-800 to-neutral-900 h-14 flex items-center"
        >
          <div
            className="absolute top-[5px] h-[46px] bg-gradient-to-b from-white/10 to-white/5 rounded-full transition-all duration-300"
            style={getStyle()}
          />

          <div className="flex z-10 gap-1">
            {buttonItems.map((item) => (
              <Link
                href={item.link}
                key={item.index}
                ref={(el) => {
                  itemRefs.current[item.index] = el;
                }}
                onMouseEnter={() => setHover(item.index)}
                onMouseLeave={() => setHover(-1)}
                onClick={() => setActive(item.index)}
                className="relative cursor-pointer px-6 mx-1 py-3 z-10"
              >
                <p
                  className={`transition-colors duration-200 ${
                    active === item.index ? "text-black" : "text-white"
                  }`}
                >
                  {item.name}
                </p>
              </Link>
            ))}
          </div>
        </div>
      </div>
    </nav>
  );
}

Usecase

1. here prop - isParaFixedAtCenter=false (by default)

2. here prop - isParaFixedAtCenter=true

* ParaScrollEffectOne is a scroll-based text animation that fades content in and out using Framer Motion’s scroll progress.

Paragraph Scroll Effect Two

A cinematic scroll-driven text animation built with Framer Motion. The paragraph remains fixed at the center while words reveal progressively with fade, blur, and smooth motion effects based on scroll position.

framer-motionlenis

Live Demo

Installation

Install the required dependencies:

npm install framer-motion lenis
components/ui/paragraph-scroll-effect-two.tsx
"use client";
import Link from "next/link";
import React, { useState, useRef } from "react";

const buttonItems = [
  { index: 1, name: "Button 1", link: "#" },
  { index: 2, name: "Button 2", link: "#" },
  { index: 3, name: "Button 3", link: "#" },
  { index: 4, name: "Button 4", link: "#" },
  { index: 5, name: "Button 5", link: "#" },
];

export default function Navbar() {
  const [active, setActive] = useState(0);
  const [hover, setHover] = useState(-1);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const itemRefs = useRef<(HTMLAnchorElement | null)[]>([]);

  const getStyle = () => {
    if (hover < 0) {
      return { left: "4px", width: "98.5%" };
    }

    const item = itemRefs.current[hover];
    if (!item || !containerRef.current) return {};

    const itemRect = item.getBoundingClientRect();
    const parentRect = containerRef.current.getBoundingClientRect();

    return {
      left: `${itemRect.left - parentRect.left}px`,
      width: `${itemRect.width}px`,
    };
  };

  return (
    <nav className="w-full h-fit flex justify-center items-center">
      <div className="relative p-[3px] inset-[3px] rounded-full bg-gradient-to-b from-neutral-700 to-neutral-800">
        <div
          ref={containerRef}
          className="relative w-fit rounded-full bg-gradient-to-b from-neutral-800 to-neutral-900 h-14 flex items-center"
        >
          <div
            className="absolute top-[5px] h-[46px] bg-gradient-to-b from-white/10 to-white/5 rounded-full transition-all duration-300"
            style={getStyle()}
          />

          <div className="flex z-10 gap-1">
            {buttonItems.map((item) => (
              <Link
                href={item.link}
                key={item.index}
                ref={(el) => {
                  itemRefs.current[item.index] = el;
                }}
                onMouseEnter={() => setHover(item.index)}
                onMouseLeave={() => setHover(-1)}
                onClick={() => setActive(item.index)}
                className="relative cursor-pointer px-6 mx-1 py-3 z-10"
              >
                <p
                  className={`transition-colors duration-200 ${
                    active === item.index ? "text-black" : "text-white"
                  }`}
                >
                  {item.name}
                </p>
              </Link>
            ))}
          </div>
        </div>
      </div>
    </nav>
  );
}

Usecase

1. here prop - isParaFixedAtCenter=false (by default)

2. here prop - isParaFixedAtCenter=true

* A scroll-based text reveal animation where the paragraph stays centered and each word fades and animates in smoothly using Framer Motion.

Paragraph Scroll Effect Three

ParaScrollEffectThree is a scroll-driven text animation component where each character fades in progressively based on scroll position. It uses smooth scrolling and allows the paragraph to stay fixed at the center for a more immersive visual effect.

framer-motionlenis

Live Demo

Installation

Install the required dependencies:

npm install framer-motion lenis
components/ui/paragraph-scroll-effect-three.tsx
"use client";
import Link from "next/link";
import React, { useState, useRef } from "react";

const buttonItems = [
  { index: 1, name: "Button 1", link: "#" },
  { index: 2, name: "Button 2", link: "#" },
  { index: 3, name: "Button 3", link: "#" },
  { index: 4, name: "Button 4", link: "#" },
  { index: 5, name: "Button 5", link: "#" },
];

export default function Navbar() {
  const [active, setActive] = useState(0);
  const [hover, setHover] = useState(-1);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const itemRefs = useRef<(HTMLAnchorElement | null)[]>([]);

  const getStyle = () => {
    if (hover < 0) {
      return { left: "4px", width: "98.5%" };
    }

    const item = itemRefs.current[hover];
    if (!item || !containerRef.current) return {};

    const itemRect = item.getBoundingClientRect();
    const parentRect = containerRef.current.getBoundingClientRect();

    return {
      left: `${itemRect.left - parentRect.left}px`,
      width: `${itemRect.width}px`,
    };
  };

  return (
    <nav className="w-full h-fit flex justify-center items-center">
      <div className="relative p-[3px] inset-[3px] rounded-full bg-gradient-to-b from-neutral-700 to-neutral-800">
        <div
          ref={containerRef}
          className="relative w-fit rounded-full bg-gradient-to-b from-neutral-800 to-neutral-900 h-14 flex items-center"
        >
          <div
            className="absolute top-[5px] h-[46px] bg-gradient-to-b from-white/10 to-white/5 rounded-full transition-all duration-300"
            style={getStyle()}
          />

          <div className="flex z-10 gap-1">
            {buttonItems.map((item) => (
              <Link
                href={item.link}
                key={item.index}
                ref={(el) => {
                  itemRefs.current[item.index] = el;
                }}
                onMouseEnter={() => setHover(item.index)}
                onMouseLeave={() => setHover(-1)}
                onClick={() => setActive(item.index)}
                className="relative cursor-pointer px-6 mx-1 py-3 z-10"
              >
                <p
                  className={`transition-colors duration-200 ${
                    active === item.index ? "text-black" : "text-white"
                  }`}
                >
                  {item.name}
                </p>
              </Link>
            ))}
          </div>
        </div>
      </div>
    </nav>
  );
}

Usecase

1. here prop - isParaFixedAtCenter=false (by default)

2. here prop - isParaFixedAtCenter=true

* ParaScrollEffectThree reveals text character-by-character as you scroll, creating a smooth fade-in animation. It also supports an optional fixed-center layout.