Docs
Animated Beam
Animated beam background section where the meteor beam of lights move through the line.
Installation
Update tailwind.config.js
Add the following to your tailwind.config.js file.
module.exports = {
theme: {
extend: {
keyframes: {
meteor: {
"0%": { transform: "translateY(-20%) translateX(-50%)" },
"100%": { transform: "translateY(300%) translateX(-50%)" },
},
},
animation: {
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.tsx
Paste 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 animate-meteor", {
"[--duration:7s]": flag,
"[--duration:11s]": !flag,
})}
style={{
width: "6px",
transform: "translateY(-20%)",
"--delay": `${index * 0.5}s`,
}}
>
<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-gradient-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-1 absolute inset-0 flex h-full w-full flex-row justify-between bg-gradient-to-t from-indigo-900 to-indigo-950"
>
<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 bg-opacity-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("storybook-fix relative w-full overflow-hidden", className)}>
<Background />
<div className="relative h-full w-full">{children}</div>
</div>
);
}
Credits
Built by hari