--- title: Scroll Paragraph description: A professional scroll-triggered typography component that reveals text paragraphs line-by-line while pinning the parent section, providing smooth GSAP-based scroll engagement like tracking websites. --- ## Installation CLI Manual ```bash npx lightswind@latest add scroll-paragraph ``` Copy and paste the following code into your project. ```tsx "use client"; import { useGSAP } from "@gsap/react"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { useRef } from "react"; import { cn } from "@/components/lib/utils"; export interface ScrollPara3DProps { /** * The text lines to reveal in 3D space. */ lines: string[]; className?: string; containerClassName?: string; textClassName?: string; /** * The perspective depth distance in pixels. * Less = more extreme 3D depth/stretch. * @default 600 */ perspective?: number; /** * The tilt angle of the text floor plane (rotateX degrees). * @default 50 */ angle?: number; /** * How much extra scrolling space to pin for the animation. * Multiplier based on content height. * @default 1.2 */ scrubSpeed?: number; /** * Font size in rem for each text line. * @default 3.5 */ fontSize?: number; } export function ScrollPara3D({ lines, className, containerClassName, textClassName, perspective = 600, angle = 50, scrubSpeed = 1.2, fontSize = 3.5, }: ScrollPara3DProps) { const sectionRef = useRef(null); const contentRef = useRef(null); useGSAP( () => { gsap.registerPlugin(ScrollTrigger); if (!contentRef.current || !sectionRef.current) return; const contentHeight = contentRef.current.offsetHeight; const windowHeight = window.innerHeight; const tl = gsap.timeline({ scrollTrigger: { trigger: sectionRef.current, start: "top top", end: `+=${contentHeight * scrubSpeed}`, pin: true, scrub: 1, anticipatePin: 1, }, }); // Start just below so text is immediately visible on scroll tl.fromTo( contentRef.current, { y: windowHeight * 0.3 }, { y: -contentHeight, ease: "none" } ); return () => { tl.kill(); }; }, { dependencies: [lines.length, perspective, angle, scrubSpeed, fontSize] } ); return (
{/* Top/bottom fade overlay */}
{/* Tilted floor plane. We use transformOrigin "center bottom" so the rotation pivots at the bottom center of the plane → text crawls toward viewer naturally. Width is 100% of the section. */}
{/* Scrolling content strip */}
{lines.map((line, i) => (

{line}

))}
); } ``` ## Usage ```tsx import { ScrollPara } from "@/components/lightswind/scroll-para" ``` ```tsx import { ScrollPara } from "@/components/lightswind/scroll-para"; const textLines = [ "In an era of digital noise", "Creating experiences that matter", "Requires more than just beauty" ]; export function Demo() { return (
); } ```