Introducing Eldora UI 2.0!
We are excited to announce the release of Eldora UI 2.0. With improved components, faster performance, and a more customizable design system, its never been easier to create stunning, responsive UIs. Start building with Eldora UI 2.0 today!
Installation
pnpm add clsx framer-motion
pnpm add clsx framer-motion
Copy and paste the following code into your project.
components/eldoraui/wrapcontainer.tsx
import React, { useCallback, useMemo } from "react";
import clsx from "clsx";
import { motion } from "framer-motion";
interface WarpAnimationContainerProps {
children: React.ReactNode;
perspective?: number;
className?: string;
beamsPerSide?: number;
beamSize?: number /* Percentage of the container's size */;
beamDelayMax?: number;
beamDelayMin?: number;
beamDuration?: number;
}
const Beam = ({
width,
x,
delay,
duration,
}: {
width: string | number;
x: string | number;
delay: number;
duration: number;
}) => {
const hue = Math.floor(Math.random() * 360);
const ar = Math.floor(Math.random() * 10) + 1;
return (
<motion.div
className={clsx(`absolute top-0`)}
style={{
left: x,
width,
aspectRatio: 1 / ar,
background: `linear-gradient(hsl(${hue} 80% 60%), transparent)`,
}}
initial={{ y: "100cqmax", x: "-50%" }}
animate={{ y: "-100%", x: "-50%" }}
transition={{
duration,
delay,
repeat: Infinity,
ease: "linear",
}}
/>
);
};
const WarpAnimationContainer: React.FC<WarpAnimationContainerProps> = ({
children,
perspective = 100,
className,
beamsPerSide = 3,
beamSize = 5,
beamDelayMax = 3,
beamDelayMin = 0,
beamDuration = 3,
}) => {
const sideStyle: React.CSSProperties = {
position: "absolute",
transformStyle: "preserve-3d",
containerType: "inline-size",
};
const generateBeams = useCallback(() => {
const beams = [];
const cellsPerSide = Math.floor(100 / beamSize);
const step = cellsPerSide / beamsPerSide;
for (let i = 0; i < beamsPerSide; i++) {
const x = Math.floor(i * step);
const delay =
Math.random() * (beamDelayMax - beamDelayMin) + beamDelayMin;
beams.push({ x, delay });
}
return beams;
}, [beamsPerSide, beamSize, beamDelayMax, beamDelayMin]);
const topBeams = useMemo(() => generateBeams(), [generateBeams]);
const rightBeams = useMemo(() => generateBeams(), [generateBeams]);
const bottomBeams = useMemo(() => generateBeams(), [generateBeams]);
const leftBeams = useMemo(() => generateBeams(), [generateBeams]);
return (
<div
className={clsx(
"relative grid place-items-center border rounded p-20",
className,
)}
style={{
transformStyle: "preserve-3d",
}}
>
<div
className="pointer-events-none absolute left-0 top-0 size-full overflow-hidden"
style={{
perspective: `${perspective}px`,
containerType: "size",
transformStyle: "preserve-3d",
clipPath: "inset(0 0 0 0)",
}}
>
{/* warp__side--top */}
<div
style={{
...sideStyle,
width: "100cqi", // 100% of the container's inline size
height: "100cqmax",
transformOrigin: "50% 0%",
transform: "rotateX(-90deg)",
}}
>
{topBeams.map((beam, index) => (
<Beam
key={`top-${index}`}
width={`${beamSize}%`}
x={`${beam.x * beamSize}%`}
delay={beam.delay}
duration={beamDuration}
/>
))}
</div>
{/* warp__side--right */}
<div
style={{
...sideStyle,
width: "100cqh", // 100% of the container's block size
height: "100cqmax",
top: 0,
right: 0,
transformOrigin: "100% 0%",
transform: "rotate(-90deg) rotateX(-90deg)",
}}
>
{rightBeams.map((beam, index) => (
<Beam
key={`right-${index}`}
width={`${beamSize}%`}
x={`${beam.x * beamSize}%`}
delay={beam.delay}
duration={beamDuration}
/>
))}
</div>
{/* warp__side--bottom */}
<div
style={{
...sideStyle,
width: "100cqi", // 100% of the container's inline size
height: "100cqmax",
top: "100%",
transformOrigin: "50% 0%",
transform: "rotateX(-90deg)",
}}
>
{bottomBeams.map((beam, index) => (
<Beam
key={`bottom-${index}`}
width={`${beamSize}%`}
x={beam.x}
delay={beam.delay}
duration={beamDuration}
/>
))}
</div>
{/* warp__side--left */}
<div
className={clsx("warp__side", "warp__side--left")}
style={{
...sideStyle,
width: "100cqh", // 100% of the container's block size
height: "100cqmax",
top: 0,
left: 0,
transformOrigin: "0% 0%",
transform: "rotate(90deg) rotateX(-90deg)",
}}
>
{leftBeams.map((beam, index) => (
<Beam
key={`left-${index}`}
width={`${beamSize}%`}
x={`${beam.x * beamSize}%`}
delay={beam.delay}
duration={beamDuration}
/>
))}
</div>
</div>
<div className="relative">{children}</div>
</div>
);
};
export WarpAnimationContainer;
Update the import paths to match your project setup.
Props
Prop | Type | Description | Default |
---|---|---|---|
children | React.ReactNode | The content to be put inside the warp animation | - |
perspective | number | The perspective of the warp animation | 100 |
beamsPerSide | number | The number of beams per side | 3 |
beamSize | number | The size of the beams | 5 |
beamDelayMax | number | The maximum delay of the beams | 5 |
beamDelayMin | number | The minimum delay of the beams | 0 |
beamDuration | number | The duration of the beams | 3 |