Docs
Animated Beam
Animated beam background section where the meteor beam of lights move through the line.
Loading...
Installation
CLI
pnpm dlx shadcn@latest add https://animata.design/r/background/animated-beam.json
Manual
Add to your CSS
@keyframes meteor {
0% { transform: translateY(-20%) translateX(-50%); }
100% { transform: translateY(300%) translateX(-50%); }
}
@theme {
--animate-meteor: meteor var(--duration) var(--delay) ease-in-out infinite;
}Run the following command
It will create a new file animated-beam.tsx inside the components/animata/background directory.
mkdir -p components/animata/background && touch components/animata/background/animated-beam.tsxPaste the code
Open the newly created file and paste the following code:
"use client";
import { useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
function Beam({ index }: { index: number }) {
const flag = index % 8 === 0;
return (
<div
className={cn("h-full", {
"[--duration:7s]": flag,
"[--duration:11s]": !flag,
})}
style={{
width: "6px",
transform: "translateY(-20%)",
"--delay": `${index * 0.5}s`,
animation: "meteor var(--duration) var(--delay) ease-in-out infinite",
}}
>
<div
style={{
clipPath: "polygon(54% 0, 54% 0, 60% 100%, 40% 100%)",
}}
className={cn("w-full", {
"h-8": flag,
"h-12": !flag,
})}
>
<div className="h-full w-full bg-linear-to-b from-neutral-50/50 via-neutral-100 via-75% to-neutral-50" />
</div>
</div>
);
}
function useGridCount() {
const containerRef = useRef<HTMLDivElement>(null);
const [count, setCount] = useState(0);
useEffect(() => {
const updateCount = () => {
const rect = containerRef.current?.getBoundingClientRect();
if (!rect) {
return;
}
const width = rect.width;
const cellSize = 40;
setCount(Math.ceil(width / cellSize));
};
updateCount();
// Can be debounced if needed
window.addEventListener("resize", updateCount);
return () => window.removeEventListener("resize", updateCount);
}, []);
return {
count,
containerRef,
};
}
function Background() {
const { count, containerRef } = useGridCount();
return (
<div
ref={containerRef}
className="z-0 absolute inset-0 flex h-full w-full flex-row justify-between bg-linear-to-t from-indigo-900 to-indigo-950"
>
<style>{`
@keyframes meteor {
0% { transform: translateY(-20%) translateX(-50%); }
100% { transform: translateY(300%) translateX(-50%); }
}
`}</style>
<div
style={{
background:
"radial-gradient(50% 50% at 50% 50%,#072a39 0%,rgb(7,42,57) 50%,rgba(7,42,57,0) 100%)",
}}
className="absolute inset-0 top-1/2 h-full w-full rounded-full opacity-40"
/>
{Array.from({ length: count }, (_, i) => (
<div key={i} className="relative h-full w-px rotate-12 bg-gray-100/10">
{(1 + i) % 4 === 0 && <Beam index={i + 1} />}
</div>
))}
</div>
);
}
export default function AnimatedBeam({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div className={cn("full-content relative w-full overflow-hidden", className)}>
<Background />
<div className="relative h-full w-full">{children}</div>
</div>
);
}Credits
Built by hari