Fancy Components Documentation

website·Indexed 34 days ago

https://www.fancycomponents.dev/docs/introduction

A collection of open-source, high-performance UI components featuring 3D transforms, physics-based animations with Matter.js, SVG filters, and advanced text effects. Includes a CLI for installation and a wide variety of interactive blocks such as 3D CSS Boxes, Box Carousels, and cursor-proximity text animations.

Tokens
64.5K
Snippets
286
Records
368
Agent score
70%

What's inside Fancy Components

  1. Overview of Letter Swap components

    The Letter Swap component creates a vertical sliding effect where letters are swapped on hover. It is available in two variants:

    1. Forward Animation: The animation timeline plays once forward when the user hovers over the text.
    2. Ping Pong Animation: The animation plays forward on hover and plays in the opposite direction when the user hovers away.
  2. Overview of TextRotate component

    The TextRotate component cycles through an array of strings provided in the texts prop. It supports automatic rotation (via the auto prop) or manual control using next() and previous() methods via a ref. It utilizes AnimatePresence from motion/react to handle the transition between the current and next text strings.
  3. Overview of Fancy Components

    Fancy Components is an open-source collection of playful and unique UI components and microinteractions. It is designed to provide copy-and-pasteable recreations of popular elements from award-winning websites, serving as either a direct implementation for projects or as inspiration for custom development. The library is free for both personal and commercial use.
  4. Animate text along an SVG path with AnimatedPathText

    The AnimatedPathText component allows you to animate text along a specified SVG path. It supports two animation modes: auto (time-based) and scroll (driven by a scroll container). Performance may decrease as path length and complexity increase, especially when using multiple instances.
  5. Animate font variations based on cursor proximity

    The VariableFontCursorProximity component animates the font variation settings of individual letters based on their distance from the cursor. It requires a variable font to function. The component calculates the distance between the cursor and each letter in real-time; as the cursor enters the specified radius, the letter's font variations interpolate from the fromFontVariationSettings state to the toFontVariationSettings state.
  6. TextCursorProximity component overview

    The TextCursorProximity component splits text into individual letters and animates their CSS properties based on the distance between the cursor and each letter. It uses the motion library to interpolate values between a 'from' state and a 'to' state as the cursor enters a defined radius. It supports any CSS value that the motion library can animate.
  7. TextRotate component overview

    The TextRotate component is a React component that cycles through an array of text strings with customizable animations. It supports automatic rotation, manual control via a ref, and various text-splitting strategies (characters, words, or lines) to create staggered animation effects.
  8. Implement Screensaver component manually

    To implement the Screensaver effect manually, you need two parts: a useDimensions hook to track the size of the container and the element, and the Screensaver component itself which uses motion/react (Framer Motion) to handle the animation and boundary collisions.
    import { RefObject, useEffect, useState } from "react"
    
    interface Dimensions {
      width: number
      height: number
    }
    
    export function useDimensions(
      ref: RefObject<HTMLElement | SVGElement | null>
    ): Dimensions {
      const [dimensions, setDimensions] = useState<Dimensions>({ width: 0, height: 0 })
    
      useEffect(() => {
        const updateDimensions = () => {
          if (ref.current) {
            const { width, height } = ref.current.getBoundingClientRect()
            setDimensions({ width, height })
          }
        }
        updateDimensions()
        window.addEventListener("resize", updateDimensions)
        return () => window.removeEventListener("resize", updateDimensions)
      }, [ref])
    
      return dimensions
    }
    
    // Screensaver Component
    "use client"
    import React, { useEffect, useRef } from "react"
    import { motion, useAnimationFrame, useMotionValue } from "motion/react"
    import { cn } from "@/lib/utils"
    import { useDimensions } from "@/hooks/use-dimensions"
    
    type ScreensaverProps = {
      children: React.ReactNode
      containerRef: React.RefObject<HTMLElement | null>
      speed?: number
      startPosition?: { x: number; y: number }
      startAngle?: number
      className?: string
    }
    
    const Screensaver: React.FC<ScreensaverProps> = ({
      children,
      speed = 3,
      startPosition = { x: 0, y: 0 },
      startAngle = 45,
      containerRef,
      className,
    }) => {
      const elementRef = useRef<HTMLDivElement>(null)
      const x = useMotionValue(0)
      const y = useMotionValue(0)
      const angle = useRef((startAngle * Math.PI) / 180)
    
      const containerDimensions = useDimensions(containerRef)
      const elementDimensions = useDimensions(elementRef)
    
      useEffect(() => {
        if (containerDimensions.width && containerDimensions.height) {
          const initialX = (startPosition.x / 100) * (containerDimensions.width - (elementDimensions.width || 0))
          const initialY = (startPosition.y / 100) * (containerDimensions.height - (elementDimensions.height || 0))
          x.set(initialX)
          y.set(initialY)
        }
      }, [containerDimensions, elementDimensions, startPosition])
    
      useAnimationFrame(() => {
        const velocity = speed
        const dx = Math.cos(angle.current) * velocity
        const dy = Math.sin(angle.current) * velocity
    
        let newX = x.get() + dx
        let newY = y.get() + dy
    
        if (newX <= 0 || newX + elementDimensions.width >= containerDimensions.width) {
          angle.current = Math.PI - angle.current
          newX = Math.max(0, Math.min(newX, containerDimensions.width - elementDimensions.width))
        }
        if (newY <= 0 || newY + elementDimensions.height >= containerDimensions.height) {
          angle.current = -angle.current
          newY = Math.max(0, Math.min(newY, containerDimensions.height - elementDimensions.height))
        }
    
        x.set(newX)
        y.set(newY)
      })
    
      return (
        <motion.div
          ref={elementRef}
          style={{ position: "absolute", top: 0, left: 0, x, y }}
          className={cn("transform will-change-transform", className)}
        >
          {children}
        </motion.div>
      )
    }
    
    export default Screensaver
  9. Manually implement Animated Gradient With SVG

    To manually implement the Animated Gradient component, you need a dimension-tracking hook, specific CSS keyframes in your global styles, and the component logic itself.
    // 1. Create useDimensions hook
    import { RefObject, useEffect, useState } from "react"
    
    interface Dimensions {
      width: number
      height: number
    }
    
    export function useDimensions(
      ref: RefObject<HTMLElement | SVGElement | null>
    ): Dimensions {
      const [dimensions, setDimensions] = useState<Dimensions>({ width: 0, height: 0 })
    
      useEffect(() => {
        const updateDimensions = () => {
          if (ref.current) {
            const { width, height } = ref.current.getBoundingClientRect()
            setDimensions({ width, height })
          }
        }
        updateDimensions()
        window.addEventListener("resize", updateDimensions)
        return () => window.removeEventListener("resize", updateDimensions)
      }, [ref])
    
      return dimensions
    }
    /* 2. Add to globals.css */
    @theme: {
      --animate-background-gradient: background-gradient;
      @keyframes: background-gradient {
        0%, 100% {
          transform: translate(0, 0);
          animationDelay: var(--background-gradient-delay, 0s);
        }
        20% { transform: translate(calc(100% * var(--tx-1, 1)), calc(100% * var(--ty-1, 1))); }
        40% { transform: translate(calc(100% * var(--tx-2, -1)), calc(100% * var(--ty-2, 1))); }
        60% { transform: translate(calc(100% * var(--tx-3, 1)), calc(100% * var(--ty-3, -1))); }
        80% { transform: translate(calc(100% * var(--tx-4, -1)), calc(100% * var(--ty-4, -1))); }
      }
    }
  10. Implement physics-based gravity animations with Gravity and MatterBody

    The Gravity component initializes a Matter.js physics world and manages the animation loop that syncs HTML element positions with physics bodies. To make an element react to physics, wrap it in a MatterBody component. You must provide initial x and y positions for each MatterBody, which can be specified as percentages (e.g., "50%") or absolute numbers. The component automatically calculates the width and height of the wrapped element.
    <Gravity>
      <MatterBody x="50%" y="50%">
        <div>Hello world!</div>
      </MatterBody>
      <MatterBody x="10%" y="10%">
        <div>fancy!</div>
      </MatterBody>
    </Gravity>