Animated Beam

An animated beam of light which travels along a path.

Installation

pnpm dlx shadcn@latest add "https://vritti.thesatyajit.com/r/animated-beam"

Dependencies

pnpm add motion

Examples

Bidirectional

"use client"

import React, { forwardRef, useRef } from "react"

import { cn } from "@/lib/utils"
import { AnimatedBeam } from "@/components/vritti/animated-beam"

const Circle = forwardRef<
  HTMLDivElement,
  { className?: string; children?: React.ReactNode }
>(({ className, children }, ref) => {
  return (
    <div
      ref={ref}
      className={cn(
        "z-10 flex size-12 items-center justify-center rounded-full border-2 bg-white p-3 shadow-[0_0_20px_-12px_rgba(0,0,0,0.8)]",
        className,
      )}
    >
      {children}
    </div>
  )
})
Circle.displayName = "Circle"

export function AnimatedBeamBidirectionalExample() {
  const containerRef = useRef<HTMLDivElement>(null)
  const div1Ref = useRef<HTMLDivElement>(null)
  const div2Ref = useRef<HTMLDivElement>(null)

  return (
    <div
      className="relative flex w-full max-w-[500px] items-center justify-center overflow-hidden rounded-lg border bg-background p-10 md:shadow-xl"
      ref={containerRef}
    >
      <div className="flex size-full flex-col items-stretch justify-between gap-10">
        <div className="flex flex-row justify-between">
          <Circle ref={div1Ref}>
            <span className="text-sm">A</span>
          </Circle>
          <Circle ref={div2Ref}>
            <span className="text-sm">B</span>
          </Circle>
        </div>
      </div>

      <AnimatedBeam
        containerRef={containerRef}
        fromRef={div1Ref}
        toRef={div2Ref}
      />
      <AnimatedBeam
        containerRef={containerRef}
        fromRef={div2Ref}
        toRef={div1Ref}
        reverse
      />
    </div>
  )
}

Multiple Inputs

"use client"

import React, { forwardRef, useRef } from "react"

import { cn } from "@/lib/utils"
import { AnimatedBeam } from "@/components/vritti/animated-beam"

const Circle = forwardRef<
  HTMLDivElement,
  { className?: string; children?: React.ReactNode }
>(({ className, children }, ref) => {
  return (
    <div
      ref={ref}
      className={cn(
        "z-10 flex size-12 items-center justify-center rounded-full border-2 bg-white p-3 shadow-[0_0_20px_-12px_rgba(0,0,0,0.8)]",
        className,
      )}
    >
      {children}
    </div>
  )
})
Circle.displayName = "Circle"

export function AnimatedBeamMultipleInputsExample() {
  const containerRef = useRef<HTMLDivElement>(null)
  const input1Ref = useRef<HTMLDivElement>(null)
  const input2Ref = useRef<HTMLDivElement>(null)
  const input3Ref = useRef<HTMLDivElement>(null)
  const outputRef = useRef<HTMLDivElement>(null)

  return (
    <div
      className="relative flex w-full max-w-[500px] items-center justify-center overflow-hidden rounded-lg border bg-background p-10 md:shadow-xl"
      ref={containerRef}
    >
      <div className="flex size-full flex-row items-stretch justify-between gap-10">
        <div className="flex flex-col justify-center gap-4">
          <Circle ref={input1Ref}>
            <span className="text-xs">1</span>
          </Circle>
          <Circle ref={input2Ref}>
            <span className="text-xs">2</span>
          </Circle>
          <Circle ref={input3Ref}>
            <span className="text-xs">3</span>
          </Circle>
        </div>
        <div className="flex flex-col justify-center">
          <Circle ref={outputRef} className="size-16">
            <span className="text-sm font-bold">Out</span>
          </Circle>
        </div>
      </div>

      <AnimatedBeam containerRef={containerRef} fromRef={input1Ref} toRef={outputRef} curvature={-40} />
      <AnimatedBeam containerRef={containerRef} fromRef={input2Ref} toRef={outputRef} />
      <AnimatedBeam containerRef={containerRef} fromRef={input3Ref} toRef={outputRef} curvature={40} />
    </div>
  )
}

Props

Animated Beam

PropTypeDefaultDescription
classNamestring-Additional CSS classes for the SVG element
containerRefRefObject<HTMLElement | null>-Ref to the container element for positioning
fromRefRefObject<HTMLElement | null>-Ref to the element where the beam starts
toRefRefObject<HTMLElement | null>-Ref to the element where the beam ends
curvaturenumber0Curvature of the beam path
reversebooleanfalseWhether to reverse the beam animation direction
durationnumberMath.random() * 3 + 4Duration of the beam animation in seconds
delaynumber0Delay before the animation starts in seconds
pathColorstring"gray"Color of the static beam path
pathWidthnumber2Width of the beam path stroke
pathOpacitynumber0.2Opacity of the static beam path
gradientStartColorstring"#ffaa40"Starting color of the animated gradient
gradientStopColorstring"#9c40ff"Ending color of the animated gradient
startXOffsetnumber0Horizontal offset for the beam start position
startYOffsetnumber0Vertical offset for the beam start position
endXOffsetnumber0Horizontal offset for the beam end position
endYOffsetnumber0Vertical offset for the beam end position