DocumentationLight Lines

Light Lines

An animated background with flowing light trails that move along vertical lines. Creates a mesmerizing, futuristic atmosphere perfect for hero sections and landing pages.

Welcome

Install using CLI

npx shadcn@latest add "https://vengeance-ui.vercel.app/r/light-lines.json"

Install Manually

1

Install dependencies

npm install clsx tailwind-merge
2

Add util file

lib/utils.ts

import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3

Copy the source code

Copy the code below and paste it into components/ui/light-lines.tsx

"use client";
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
interface LightLinesProps {
className?: string;
linesOpacity?: number;
lightsOpacity?: number;
speedMultiplier?: number;
gradientFrom?: string;
gradientTo?: string;
lightColor?: string;
lineColor?: string;
children?: React.ReactNode;
}
interface AnimatedLightRef {
element: SVGPathElement | null;
from: number;
to: number;
duration: number;
}
export function LightLines({
className,
linesOpacity = 0.05,
lightsOpacity = 0.9,
speedMultiplier = 1,
gradientFrom = "#2462F6",
gradientTo = "#5999F8",
lightColor = "#fff",
lineColor = "#fff",
children,
}: LightLinesProps) {
const containerRef = useRef<HTMLDivElement>(null);
const animationsRef = useRef<AnimatedLightRef[]>([]);
const frameRef = useRef<number | null>(null);
useEffect(() => {
const lightsDown = [
{ selector: ".light4", from: -1080, to: 1080 },
{ selector: ".light5", from: -1080, to: 1080 },
{ selector: ".light6", from: -1080, to: 1080 },
{ selector: ".light7", from: -1080, to: 1080 },
{ selector: ".light8", from: -1080, to: 1080 },
{ selector: ".light11", from: -1080, to: 1080 },
{ selector: ".light12", from: -1080, to: 1080 },
{ selector: ".light13", from: -1080, to: 1080 },
{ selector: ".light14", from: -1080, to: 1080 },
{ selector: ".light15", from: -1080, to: 1080 },
{ selector: ".light16", from: -1080, to: 1080 },
];
const lightsUp = [
{ selector: ".light1", from: 1080, to: -1080 },
{ selector: ".light2", from: 1080, to: -1080 },
{ selector: ".light3", from: 1080, to: -1080 },
{ selector: ".light9", from: 1080, to: -1080 },
{ selector: ".light10", from: 1080, to: -1080 },
{ selector: ".light17", from: 1080, to: -1080 },
];
const container = containerRef.current;
if (!container) return;
const allLights = [...lightsDown, ...lightsUp];
animationsRef.current = allLights.map((light) => {
const element = container.querySelector(light.selector) as SVGPathElement | null;
const duration = (Math.floor(Math.random() * 59) + 2) * 0.5 + 0.5;
return { element, from: light.from, to: light.to, duration: duration / speedMultiplier };
});
const animationState = animationsRef.current.map(() => ({
startTime: performance.now() - Math.random() * 5000, currentY: 0,
}));
const animate = (time: number) => {
animationsRef.current.forEach((ref, index) => {
if (!ref.element) return;
const state = animationState[index];
const elapsed = (time - state.startTime) / 1000;
const progress = (elapsed % ref.duration) / ref.duration;
const currentY = ref.from + (ref.to - ref.from) * progress;
ref.element.style.transform = "translateY(" + currentY + "px)";
});
frameRef.current = requestAnimationFrame(animate);
};
frameRef.current = requestAnimationFrame(animate);
return () => { if (frameRef.current) cancelAnimationFrame(frameRef.current); };
}, [speedMultiplier]);
return (
<div ref={containerRef} className={cn("absolute inset-0 h-full w-full flex justify-center overflow-hidden", className)}
style={{ background: "linear-gradient(180deg, " + gradientFrom + " 0%, " + gradientTo + " 100%)" }}>
<svg className="absolute h-full" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" preserveAspectRatio="none">
<g className="lines" style={{ opacity: linesOpacity }}>
<rect className="line" x="1253.6" width="4.5" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="873.3" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1100" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1547.1" width="4.5" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="615" width="4.5" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="684.6" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1369.4" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1310.2" width="0.9" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1233.4" width="0.9" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="124.2" width="0.9" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1818.4" width="4.5" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="70.3" width="4.5" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1618.6" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="455.9" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="328.7" width="1.8" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="300.8" width="4.6" height="1080" style={{ fill: lineColor }} />
<rect className="line" x="1666.4" width="0.9" height="1080" style={{ fill: lineColor }} />
</g>
<g className="lights" style={{ opacity: lightsOpacity }}>
<path className="light1 light" style={{ fill: lightColor }} d="M619.5,298.4H615v19.5h4.5V298.4z M619.5,674.8H615v9.8h4.5V674.8z M619.5,135.1H615v5.6h4.5V135.1z M619.5,55.5H615v68.7h4.5V55.5z" />
<path className="light2 light" style={{ fill: lightColor }} d="M1258.2,531.9h-4.5v8.1h4.5V531.9z M1258.2,497.9h-4.5v17.9h4.5V497.9z M1258.2,0h-4.5v25.3h4.5V0z M1258.2,252.2h-4.5v42.4h4.5V252.2z" />
<path className="light3 light" style={{ fill: lightColor }} d="M875.1,123.8h-1.8v4h1.8V123.8z M875.1,289.4h-1.8v24.1h1.8V289.4z M875.1,0h-1.8v31.4h1.8V0z M875.1,50.2h-1.8v11.5h1.8V50.2z" />
<path className="light4 light" style={{ fill: lightColor }} d="M1101.8,983.8h-1.8v8.2h1.8V983.8z M1101.8,1075.9h-1.8v4.1h1.8V1075.9z M1101.8,873.7h-1.8v4.2h1.8V873.7z M1101.8,851h-1.8v18.2h1.8V851z" />
<path className="light5 light" style={{ fill: lightColor }} d="M686.4,822.7h-1.8v3.8h1.8V822.7z M686.4,928.4h-1.8v23h1.8V928.4z M686.4,1043.8h-1.8v36.2h1.8V1043.8z" />
<path className="light6 light" style={{ fill: lightColor }} d="M1551.6,860.9h-4.4v-34.1h4.4V860.9z M1551.6,533.5h-4.4v-13.9h4.4V533.5z M1551.6,1080h-4.4v-89.1h4.4V1080z" />
<path className="light7 light" style={{ fill: lightColor }} d="M1311.1,707.7h-0.9V698h0.9V707.7z M1311.1,436.8h-0.9v-58.9h0.9V436.8z M1311.1,140.7h-0.9V48h0.9V140.7z" />
<path className="light8 light" style={{ fill: lightColor }} d="M125.1,514.5h-0.9v-9.7h0.9V514.5z M125.1,243.6h-0.9v-58.9h0.9V243.6z" />
<path className="light9 light" style={{ fill: lightColor }} d="M305.4,806.7h-4.6v-42.5h4.6V806.7z M305.4,398.5h-4.6v-17.3h4.6V398.5z M305.4,1080h-4.6V968.8h4.6V1080z" />
<path className="light10 light" style={{ fill: lightColor }} d="M1822.9,170.7h-4.5v13.7h4.5V170.7z M1822.9,435.1h-4.5v6.8h4.5V435.1z M1822.9,55.9h-4.5v4h4.5V55.9z M1822.9,0h-4.5v48.3h4.5V0z" />
<path className="light11 light" style={{ fill: lightColor }} d="M1666.4,331.5h0.9v9.7h-0.9V331.5z M1666.4,602.4h0.9v58.9h-0.9V602.4z M1666.4,898.5h0.9v92.7h-0.9V898.5z" />
<path className="light12 light" style={{ fill: lightColor }} d="M1620.4,200.7h-1.8v6.4h1.8V200.7z M1620.4,469.1h-1.8v39h1.8V469.1z M1620.4,0h-1.8v51h1.8V0z M1620.4,81.3h-1.8V100h1.8V81.3z" />
<path className="light13 light" style={{ fill: lightColor }} d="M74.8,201h-4.5v16.2h4.5V201z M74.8,512.3h-4.5v8.1h4.5V512.3z M74.8,65.8h-4.5v4.6h4.5V65.8z M74.8,0h-4.5v56.8h4.5V0z" />
<path className="light14 light" style={{ fill: lightColor }} d="M1371.2,655.3h-1.8v6.3h1.8V655.3z M1371.2,829.7h-1.8v37.9h1.8V829.7z M1371.2,1020.3h-1.8v59.7h1.8V1020.3z" />
<path className="light15 light" style={{ fill: lightColor }} d="M1234.3,898.1h-0.9v-4.9h0.9V898.1z M1234.3,762.5h-0.9v-29.5h0.9V762.5z M1234.3,614.4h-0.9v-46.4h0.9V614.4z" />
<path className="light16 light" style={{ fill: lightColor }} d="M457.7,1010.8h-1.8v-18.1h1.8V1010.8z M457.7,507.5h-1.8V398h1.8V507.5z" />
<path className="light17 light" style={{ fill: lightColor }} d="M330.5,170.7h-1.8v13.7h1.8V170.7z M330.5,435.1h-1.8v6.8h1.8V435.1z M330.5,55.9h-1.8v4h1.8V55.9z M330.5,0h-1.8v48.3h1.8V0z" />
</g>
</svg>
{children && <div className="relative z-10 w-full h-full">{children}</div>}
</div>
);
}
export default LightLines;

Usage

1import { LightLines } from "@/components/ui/light-lines"
2
3export function HeroSection() {
4return (
5 <section className="relative h-screen">
6 <LightLines>
7 <div className="flex items-center justify-center h-full">
8 <h1 className="text-6xl font-bold text-white">
9 Your Content Here
10 </h1>
11 </div>
12 </LightLines>
13 </section>
14);
15}

Examples

Purple Theme

Purple Theme

Cyber / Dark Theme

Cyber Theme

Fast Animation

Fast Mode

Props

Prop NameTypeDefaultDescription
classNamestring""Additional CSS classes for the container.
linesOpacitynumber0.05Opacity of the static background lines (0-1).
lightsOpacitynumber0.9Opacity of the animated light trails (0-1).
speedMultipliernumber1Multiplier for animation speed. Higher = faster.
gradientFromstring"#2462F6"Starting color of the background gradient.
gradientTostring"#5999F8"Ending color of the background gradient.
lightColorstring"#fff"Color of the animated light trails.
lineColorstring"#fff"Color of the static background lines.
childrenReact.ReactNodeundefinedContent to overlay on top of the animation.

Features

  • Smooth Animations: Uses requestAnimationFrame for buttery 60fps animations
  • Customizable Colors: Full control over gradient, lines, and lights colors
  • Speed Control: Adjustable animation speed with speedMultiplier prop
  • Content Overlay: Pass children to overlay content on top of the animation
  • No External Dependencies: Uses native JavaScript animations, no GSAP required
  • Performance Optimized: Efficient animation loop with cleanup on unmount
  • Tailwind Integration: Uses cn() utility for class merging
  • Responsive: SVG-based design scales to any container size
  • Reusable: Pass any content as children to use as hero, loading screen, or background