Display15
Form1
Playground3
Grid Beams
A component for displaying a grid of beams.
Default
Default grid beams
Modern Solutions
Innovative technology for tomorrow's challenges
grid-beams.tsx
1"use client";23import React, { useEffect, useRef } from "react";45interface Beam {6 color: string; // Color of the beam7 position: number; // Position of the beam8 progress: number; // Progress of the beam9 speed: number; // Speed of the beam10 width: number; // Width of the beam11 isHorizontal: boolean; // Whether the beam is horizontal12 opacity: number; // Opacity of the beam13 delay: number; // Time before beam starts moving14 pattern: number; // Pattern type (0: straight, 1: pulse, 2: accelerate-decelerate)15 length: number; // Length of the beam (0-1)16}1718// Pattern types as a type for better TypeScript support19type BeamPattern = "steady" | "pulse" | "accelerate-decelerate";2021interface GridBeamsProps {22 title?: string; // Title of the grid beams23 subtitle?: string; // Subtitle of the grid beams24 // Animation customization props25 baseSpeed?: number; // Base speed multiplier26 maxBeams?: number; // Maximum number of beams27 initialBeams?: number; // Initial number of beams28 beamDelay?: {29 // Delay configuration30 min: number; // Minimum delay frames31 max: number; // Maximum delay frames32 };33 defaultPattern?: BeamPattern; // Default pattern for random beams34 patternDistribution?: {35 // Distribution of patterns (must sum to 1)36 steady: number; // Proportion of steady beams37 pulse: number; // Proportion of pulsing beams38 "accelerate-decelerate": number; // Proportion of accelerate-decelerate beams39 };40 colors?: string[]; // Custom colors for beams41 gridSize?: number; // Size of grid cells in pixels42 randomStarts?: boolean; // Whether to randomize starting positions43 beamLength?: { min: number; max: number }; // Length of beams44}4546const GridBeams: React.FC<GridBeamsProps> = ({47 title,48 subtitle,49 baseSpeed = 1.0,50 maxBeams = 14,51 initialBeams = 10,52 beamDelay = { min: 0, max: 200 },53 defaultPattern,54 patternDistribution = {55 steady: 0.3,56 pulse: 0.4,57 "accelerate-decelerate": 0.3,58 },59 colors = ["#3B82F6", "#8B5CF6", "#EC4899", "#10B981"],60 gridSize = 40,61 randomStarts = true,62 beamLength = { min: 0.5, max: 0.9 },63}) => {64 const canvasRef = useRef<HTMLCanvasElement>(null);6566 // Convert pattern name to number67 const getPatternNumber = (pattern: BeamPattern): number => {68 switch (pattern) {69 case "steady":70 return 0;71 case "pulse":72 return 1;73 case "accelerate-decelerate":74 return 2;75 default:76 return 0;77 }78 };7980 // Get a random pattern based on distribution81 const getRandomPattern = (): number => {82 if (defaultPattern) {83 return getPatternNumber(defaultPattern);84 }8586 const rand = Math.random();87 let cumulativeProbability = 0;8889 if (rand < (cumulativeProbability += patternDistribution.steady)) {90 return 0; // Steady91 } else if (rand < (cumulativeProbability += patternDistribution.pulse)) {92 return 1; // Pulse93 } else {94 return 2; // Accelerate-decelerate95 }96 };9798 useEffect(() => {99 const canvas = canvasRef.current;100 if (!canvas) return;101102 const ctx = canvas.getContext("2d");103 if (!ctx) return;104105 let animationFrameId: number;106 let frame = 0;107108 // Set canvas dimensions to match parent container109 const resizeCanvas = () => {110 if (!canvas) return;111 canvas.width = canvas.offsetWidth;112 canvas.height = canvas.offsetHeight;113 };114115 resizeCanvas();116 window.addEventListener("resize", resizeCanvas);117118 const beams: Beam[] = [];119120 // Create initial beams with patterns121 const createBeam = (patternOverride?: number): Beam => {122 const isHorizontal = Math.random() > 0.5;123 const pattern =124 patternOverride !== undefined ? patternOverride : getRandomPattern();125126 // Calculate beam length based on the beamLength prop127 const length =128 beamLength.min + Math.random() * (beamLength.max - beamLength.min);129130 // Determine starting progress based on randomStarts131 const startProgress = randomStarts ? Math.random() * (1 - length) : 0;132133 return {134 color: colors[Math.floor(Math.random() * colors.length)],135 position:136 Math.floor(137 (Math.random() * (isHorizontal ? canvas.height : canvas.width)) /138 gridSize139 ) * gridSize,140 progress: startProgress,141 speed: (0.2 + Math.random() * 0.6) * baseSpeed, // Apply base speed multiplier142 width: 2 + Math.random() * 2,143 isHorizontal,144 opacity: 0.5 + Math.random() * 0.5,145 delay:146 beamDelay.min +147 Math.floor(Math.random() * (beamDelay.max - beamDelay.min)),148 pattern,149 length: length, // Store the beam length150 };151 };152153 // Create beams with specific patterns - one of each type for each direction154 const initializePatternedBeams = () => {155 // Horizontal beams with different patterns156 for (let i = 0; i < 3; i++) {157 const beam = createBeam(i);158 beam.isHorizontal = true;159 beam.position = gridSize * (1 + i * 2);160 beam.delay = i * 40; // Staggered delays161 beams.push(beam);162 }163164 // Vertical beams with different patterns165 for (let i = 0; i < 3; i++) {166 const beam = createBeam(i);167 beam.isHorizontal = false;168 beam.position = gridSize * (2 + i * 3);169 beam.delay = 30 + i * 40; // Different staggered delays170 beams.push(beam);171 }172173 // Add additional random beams up to initialBeams count174 const additionalBeams = Math.max(0, initialBeams - 6); // We already added 6 beams175 for (let i = 0; i < additionalBeams; i++) {176 beams.push(createBeam());177 }178 };179180 initializePatternedBeams();181182 // Update beam based on its pattern183 const updateBeamProgress = (beam: Beam) => {184 // Don't move if still in delay period185 if (beam.delay > 0) {186 beam.delay--;187 return;188 }189190 let speedFactor = 1;191192 switch (beam.pattern) {193 case 0: // Steady movement194 speedFactor = 1;195 break;196 case 1: // Pulsing - speed varies with sine wave197 speedFactor = 0.5 + Math.sin(frame / 50) * 0.5;198 break;199 case 2: // Accelerate-decelerate200 // Slower at beginning and end, faster in the middle201 speedFactor =202 beam.progress < 0.5 ? beam.progress * 2 : (1 - beam.progress) * 2;203 speedFactor = 0.3 + speedFactor * 0.7; // Keep minimum speed204 break;205 }206207 beam.progress += (beam.speed / 400) * speedFactor; // Base speed div by 400 (slower)208 };209210 // Animation loop211 const animate = () => {212 if (!canvas || !ctx) return;213 frame++;214215 ctx.clearRect(0, 0, canvas.width, canvas.height);216217 // Draw grid218 ctx.strokeStyle = "rgba(229, 231, 235, 0.1)"; // Light gray with transparency219 ctx.lineWidth = 1;220221 // Draw vertical grid lines222 for (let x = 0; x <= canvas.width; x += gridSize) {223 ctx.beginPath();224 ctx.moveTo(x, 0);225 ctx.lineTo(x, canvas.height);226 ctx.stroke();227 }228229 // Draw horizontal grid lines230 for (let y = 0; y <= canvas.height; y += gridSize) {231 ctx.beginPath();232 ctx.moveTo(0, y);233 ctx.lineTo(canvas.width, y);234 ctx.stroke();235 }236237 // Draw and update beams238 beams.forEach((beam, index) => {239 ctx.beginPath();240 ctx.globalAlpha = beam.opacity;241242 // For pulsing beams, also pulse opacity243 if (beam.pattern === 1 && beam.delay === 0) {244 ctx.globalAlpha = beam.opacity * (0.7 + Math.sin(frame / 50) * 0.3);245 }246247 ctx.strokeStyle = beam.color;248 ctx.lineWidth = beam.width;249250 if (beam.isHorizontal) {251 const startX = canvas.width * beam.progress;252 const endX = startX + canvas.width * beam.length;253 ctx.moveTo(startX, beam.position);254 ctx.lineTo(Math.min(endX, canvas.width), beam.position);255 } else {256 const startY = canvas.height * beam.progress;257 const endY = startY + canvas.height * beam.length;258 ctx.moveTo(beam.position, startY);259 ctx.lineTo(beam.position, Math.min(endY, canvas.height));260 }261262 ctx.stroke();263 ctx.globalAlpha = 1;264265 // Update beam progress based on pattern266 updateBeamProgress(beam);267268 // Reset beam when it reaches the end (fully off screen)269 if (beam.progress > 1) {270 // For patterned beams, maintain their pattern271 if (index < 6) {272 // The first 6 are our patterned beams273 beam.progress = randomStarts274 ? Math.random() * (1 - beam.length)275 : 0;276 beam.delay =277 beamDelay.min +278 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));279280 // Maybe change color281 if (Math.random() > 0.7) {282 beam.color = colors[Math.floor(Math.random() * colors.length)];283 }284 } else {285 // Random beams can change completely286 if (Math.random() > 0.3) {287 beam.progress = randomStarts288 ? Math.random() * (1 - beam.length)289 : 0;290 beam.delay =291 beamDelay.min +292 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));293 } else {294 beams[index] = createBeam();295 }296 }297 }298 });299300 // Add a new random beam occasionally but keep total reasonable301 if (beams.length < maxBeams && frame % 300 === 0) {302 beams.push(createBeam());303 }304305 animationFrameId = requestAnimationFrame(animate);306 };307308 animate();309310 // Clean up311 return () => {312 window.removeEventListener("resize", resizeCanvas);313 cancelAnimationFrame(animationFrameId);314 };315 }, [316 baseSpeed,317 maxBeams,318 initialBeams,319 beamDelay,320 defaultPattern,321 patternDistribution,322 colors,323 gridSize,324 randomStarts,325 beamLength,326 ]);327328 return (329 <div className="relative w-full h-[40vh] bg-gray-900 overflow-hidden">330 {/* Canvas for grid and beams */}331 <canvas ref={canvasRef} className="absolute inset-0 w-full h-[40vh]" />332333 {/* Overlay gradient for better text visibility */}334 <div className="absolute inset-0 bg-gradient-to-b from-gray-900/70 to-gray-900/90"></div>335336 {/* Content */}337 <div className="relative z-10 flex flex-col items-center justify-center h-full px-4 text-center">338 <h1 className="text-4xl md:text-6xl font-bold text-white mb-4">339 {title || "Building The Future"}340 </h1>341 <p className="text-xl md:text-2xl text-gray-300 max-w-2xl">342 {subtitle ||343 "Create something amazing with our next-generation technology platform"}344 </p>345 <div className="mt-8">346 <button className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg mr-4 transition-colors">347 Get Started348 </button>349 <button className="bg-transparent border border-white text-white font-bold py-3 px-6 rounded-lg hover:bg-white/10 transition-colors">350 Learn More351 </button>352 </div>353 </div>354 </div>355 );356};357358export default GridBeams;
E2E Beams
No random starting positions
Edge-to-Edge Beams
Classic grid beam effect starting from edges
grid-beams.tsx
1"use client";23import React, { useEffect, useRef } from "react";45interface Beam {6 color: string; // Color of the beam7 position: number; // Position of the beam8 progress: number; // Progress of the beam9 speed: number; // Speed of the beam10 width: number; // Width of the beam11 isHorizontal: boolean; // Whether the beam is horizontal12 opacity: number; // Opacity of the beam13 delay: number; // Time before beam starts moving14 pattern: number; // Pattern type (0: straight, 1: pulse, 2: accelerate-decelerate)15 length: number; // Length of the beam (0-1)16}1718// Pattern types as a type for better TypeScript support19type BeamPattern = "steady" | "pulse" | "accelerate-decelerate";2021interface GridBeamsProps {22 title?: string; // Title of the grid beams23 subtitle?: string; // Subtitle of the grid beams24 // Animation customization props25 baseSpeed?: number; // Base speed multiplier26 maxBeams?: number; // Maximum number of beams27 initialBeams?: number; // Initial number of beams28 beamDelay?: {29 // Delay configuration30 min: number; // Minimum delay frames31 max: number; // Maximum delay frames32 };33 defaultPattern?: BeamPattern; // Default pattern for random beams34 patternDistribution?: {35 // Distribution of patterns (must sum to 1)36 steady: number; // Proportion of steady beams37 pulse: number; // Proportion of pulsing beams38 "accelerate-decelerate": number; // Proportion of accelerate-decelerate beams39 };40 colors?: string[]; // Custom colors for beams41 gridSize?: number; // Size of grid cells in pixels42 randomStarts?: boolean; // Whether to randomize starting positions43 beamLength?: { min: number; max: number }; // Length of beams44}4546const GridBeams: React.FC<GridBeamsProps> = ({47 title,48 subtitle,49 baseSpeed = 1.0,50 maxBeams = 14,51 initialBeams = 10,52 beamDelay = { min: 0, max: 200 },53 defaultPattern,54 patternDistribution = {55 steady: 0.3,56 pulse: 0.4,57 "accelerate-decelerate": 0.3,58 },59 colors = ["#3B82F6", "#8B5CF6", "#EC4899", "#10B981"],60 gridSize = 40,61 randomStarts = true,62 beamLength = { min: 0.5, max: 0.9 },63}) => {64 const canvasRef = useRef<HTMLCanvasElement>(null);6566 // Convert pattern name to number67 const getPatternNumber = (pattern: BeamPattern): number => {68 switch (pattern) {69 case "steady":70 return 0;71 case "pulse":72 return 1;73 case "accelerate-decelerate":74 return 2;75 default:76 return 0;77 }78 };7980 // Get a random pattern based on distribution81 const getRandomPattern = (): number => {82 if (defaultPattern) {83 return getPatternNumber(defaultPattern);84 }8586 const rand = Math.random();87 let cumulativeProbability = 0;8889 if (rand < (cumulativeProbability += patternDistribution.steady)) {90 return 0; // Steady91 } else if (rand < (cumulativeProbability += patternDistribution.pulse)) {92 return 1; // Pulse93 } else {94 return 2; // Accelerate-decelerate95 }96 };9798 useEffect(() => {99 const canvas = canvasRef.current;100 if (!canvas) return;101102 const ctx = canvas.getContext("2d");103 if (!ctx) return;104105 let animationFrameId: number;106 let frame = 0;107108 // Set canvas dimensions to match parent container109 const resizeCanvas = () => {110 if (!canvas) return;111 canvas.width = canvas.offsetWidth;112 canvas.height = canvas.offsetHeight;113 };114115 resizeCanvas();116 window.addEventListener("resize", resizeCanvas);117118 const beams: Beam[] = [];119120 // Create initial beams with patterns121 const createBeam = (patternOverride?: number): Beam => {122 const isHorizontal = Math.random() > 0.5;123 const pattern =124 patternOverride !== undefined ? patternOverride : getRandomPattern();125126 // Calculate beam length based on the beamLength prop127 const length =128 beamLength.min + Math.random() * (beamLength.max - beamLength.min);129130 // Determine starting progress based on randomStarts131 const startProgress = randomStarts ? Math.random() * (1 - length) : 0;132133 return {134 color: colors[Math.floor(Math.random() * colors.length)],135 position:136 Math.floor(137 (Math.random() * (isHorizontal ? canvas.height : canvas.width)) /138 gridSize139 ) * gridSize,140 progress: startProgress,141 speed: (0.2 + Math.random() * 0.6) * baseSpeed, // Apply base speed multiplier142 width: 2 + Math.random() * 2,143 isHorizontal,144 opacity: 0.5 + Math.random() * 0.5,145 delay:146 beamDelay.min +147 Math.floor(Math.random() * (beamDelay.max - beamDelay.min)),148 pattern,149 length: length, // Store the beam length150 };151 };152153 // Create beams with specific patterns - one of each type for each direction154 const initializePatternedBeams = () => {155 // Horizontal beams with different patterns156 for (let i = 0; i < 3; i++) {157 const beam = createBeam(i);158 beam.isHorizontal = true;159 beam.position = gridSize * (1 + i * 2);160 beam.delay = i * 40; // Staggered delays161 beams.push(beam);162 }163164 // Vertical beams with different patterns165 for (let i = 0; i < 3; i++) {166 const beam = createBeam(i);167 beam.isHorizontal = false;168 beam.position = gridSize * (2 + i * 3);169 beam.delay = 30 + i * 40; // Different staggered delays170 beams.push(beam);171 }172173 // Add additional random beams up to initialBeams count174 const additionalBeams = Math.max(0, initialBeams - 6); // We already added 6 beams175 for (let i = 0; i < additionalBeams; i++) {176 beams.push(createBeam());177 }178 };179180 initializePatternedBeams();181182 // Update beam based on its pattern183 const updateBeamProgress = (beam: Beam) => {184 // Don't move if still in delay period185 if (beam.delay > 0) {186 beam.delay--;187 return;188 }189190 let speedFactor = 1;191192 switch (beam.pattern) {193 case 0: // Steady movement194 speedFactor = 1;195 break;196 case 1: // Pulsing - speed varies with sine wave197 speedFactor = 0.5 + Math.sin(frame / 50) * 0.5;198 break;199 case 2: // Accelerate-decelerate200 // Slower at beginning and end, faster in the middle201 speedFactor =202 beam.progress < 0.5 ? beam.progress * 2 : (1 - beam.progress) * 2;203 speedFactor = 0.3 + speedFactor * 0.7; // Keep minimum speed204 break;205 }206207 beam.progress += (beam.speed / 400) * speedFactor; // Base speed div by 400 (slower)208 };209210 // Animation loop211 const animate = () => {212 if (!canvas || !ctx) return;213 frame++;214215 ctx.clearRect(0, 0, canvas.width, canvas.height);216217 // Draw grid218 ctx.strokeStyle = "rgba(229, 231, 235, 0.1)"; // Light gray with transparency219 ctx.lineWidth = 1;220221 // Draw vertical grid lines222 for (let x = 0; x <= canvas.width; x += gridSize) {223 ctx.beginPath();224 ctx.moveTo(x, 0);225 ctx.lineTo(x, canvas.height);226 ctx.stroke();227 }228229 // Draw horizontal grid lines230 for (let y = 0; y <= canvas.height; y += gridSize) {231 ctx.beginPath();232 ctx.moveTo(0, y);233 ctx.lineTo(canvas.width, y);234 ctx.stroke();235 }236237 // Draw and update beams238 beams.forEach((beam, index) => {239 ctx.beginPath();240 ctx.globalAlpha = beam.opacity;241242 // For pulsing beams, also pulse opacity243 if (beam.pattern === 1 && beam.delay === 0) {244 ctx.globalAlpha = beam.opacity * (0.7 + Math.sin(frame / 50) * 0.3);245 }246247 ctx.strokeStyle = beam.color;248 ctx.lineWidth = beam.width;249250 if (beam.isHorizontal) {251 const startX = canvas.width * beam.progress;252 const endX = startX + canvas.width * beam.length;253 ctx.moveTo(startX, beam.position);254 ctx.lineTo(Math.min(endX, canvas.width), beam.position);255 } else {256 const startY = canvas.height * beam.progress;257 const endY = startY + canvas.height * beam.length;258 ctx.moveTo(beam.position, startY);259 ctx.lineTo(beam.position, Math.min(endY, canvas.height));260 }261262 ctx.stroke();263 ctx.globalAlpha = 1;264265 // Update beam progress based on pattern266 updateBeamProgress(beam);267268 // Reset beam when it reaches the end (fully off screen)269 if (beam.progress > 1) {270 // For patterned beams, maintain their pattern271 if (index < 6) {272 // The first 6 are our patterned beams273 beam.progress = randomStarts274 ? Math.random() * (1 - beam.length)275 : 0;276 beam.delay =277 beamDelay.min +278 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));279280 // Maybe change color281 if (Math.random() > 0.7) {282 beam.color = colors[Math.floor(Math.random() * colors.length)];283 }284 } else {285 // Random beams can change completely286 if (Math.random() > 0.3) {287 beam.progress = randomStarts288 ? Math.random() * (1 - beam.length)289 : 0;290 beam.delay =291 beamDelay.min +292 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));293 } else {294 beams[index] = createBeam();295 }296 }297 }298 });299300 // Add a new random beam occasionally but keep total reasonable301 if (beams.length < maxBeams && frame % 300 === 0) {302 beams.push(createBeam());303 }304305 animationFrameId = requestAnimationFrame(animate);306 };307308 animate();309310 // Clean up311 return () => {312 window.removeEventListener("resize", resizeCanvas);313 cancelAnimationFrame(animationFrameId);314 };315 }, [316 baseSpeed,317 maxBeams,318 initialBeams,319 beamDelay,320 defaultPattern,321 patternDistribution,322 colors,323 gridSize,324 randomStarts,325 beamLength,326 ]);327328 return (329 <div className="relative w-full h-[40vh] bg-gray-900 overflow-hidden">330 {/* Canvas for grid and beams */}331 <canvas ref={canvasRef} className="absolute inset-0 w-full h-[40vh]" />332333 {/* Overlay gradient for better text visibility */}334 <div className="absolute inset-0 bg-gradient-to-b from-gray-900/70 to-gray-900/90"></div>335336 {/* Content */}337 <div className="relative z-10 flex flex-col items-center justify-center h-full px-4 text-center">338 <h1 className="text-4xl md:text-6xl font-bold text-white mb-4">339 {title || "Building The Future"}340 </h1>341 <p className="text-xl md:text-2xl text-gray-300 max-w-2xl">342 {subtitle ||343 "Create something amazing with our next-generation technology platform"}344 </p>345 <div className="mt-8">346 <button className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg mr-4 transition-colors">347 Get Started348 </button>349 <button className="bg-transparent border border-white text-white font-bold py-3 px-6 rounded-lg hover:bg-white/10 transition-colors">350 Learn More351 </button>352 </div>353 </div>354 </div>355 );356};357358export default GridBeams;
Quick Pulses
Short, quick pulses across the grid
Quick Pulses
Short, quick pulses across the grid
grid-beams.tsx
1"use client";23import React, { useEffect, useRef } from "react";45interface Beam {6 color: string; // Color of the beam7 position: number; // Position of the beam8 progress: number; // Progress of the beam9 speed: number; // Speed of the beam10 width: number; // Width of the beam11 isHorizontal: boolean; // Whether the beam is horizontal12 opacity: number; // Opacity of the beam13 delay: number; // Time before beam starts moving14 pattern: number; // Pattern type (0: straight, 1: pulse, 2: accelerate-decelerate)15 length: number; // Length of the beam (0-1)16}1718// Pattern types as a type for better TypeScript support19type BeamPattern = "steady" | "pulse" | "accelerate-decelerate";2021interface GridBeamsProps {22 title?: string; // Title of the grid beams23 subtitle?: string; // Subtitle of the grid beams24 // Animation customization props25 baseSpeed?: number; // Base speed multiplier26 maxBeams?: number; // Maximum number of beams27 initialBeams?: number; // Initial number of beams28 beamDelay?: {29 // Delay configuration30 min: number; // Minimum delay frames31 max: number; // Maximum delay frames32 };33 defaultPattern?: BeamPattern; // Default pattern for random beams34 patternDistribution?: {35 // Distribution of patterns (must sum to 1)36 steady: number; // Proportion of steady beams37 pulse: number; // Proportion of pulsing beams38 "accelerate-decelerate": number; // Proportion of accelerate-decelerate beams39 };40 colors?: string[]; // Custom colors for beams41 gridSize?: number; // Size of grid cells in pixels42 randomStarts?: boolean; // Whether to randomize starting positions43 beamLength?: { min: number; max: number }; // Length of beams44}4546const GridBeams: React.FC<GridBeamsProps> = ({47 title,48 subtitle,49 baseSpeed = 1.0,50 maxBeams = 14,51 initialBeams = 10,52 beamDelay = { min: 0, max: 200 },53 defaultPattern,54 patternDistribution = {55 steady: 0.3,56 pulse: 0.4,57 "accelerate-decelerate": 0.3,58 },59 colors = ["#3B82F6", "#8B5CF6", "#EC4899", "#10B981"],60 gridSize = 40,61 randomStarts = true,62 beamLength = { min: 0.5, max: 0.9 },63}) => {64 const canvasRef = useRef<HTMLCanvasElement>(null);6566 // Convert pattern name to number67 const getPatternNumber = (pattern: BeamPattern): number => {68 switch (pattern) {69 case "steady":70 return 0;71 case "pulse":72 return 1;73 case "accelerate-decelerate":74 return 2;75 default:76 return 0;77 }78 };7980 // Get a random pattern based on distribution81 const getRandomPattern = (): number => {82 if (defaultPattern) {83 return getPatternNumber(defaultPattern);84 }8586 const rand = Math.random();87 let cumulativeProbability = 0;8889 if (rand < (cumulativeProbability += patternDistribution.steady)) {90 return 0; // Steady91 } else if (rand < (cumulativeProbability += patternDistribution.pulse)) {92 return 1; // Pulse93 } else {94 return 2; // Accelerate-decelerate95 }96 };9798 useEffect(() => {99 const canvas = canvasRef.current;100 if (!canvas) return;101102 const ctx = canvas.getContext("2d");103 if (!ctx) return;104105 let animationFrameId: number;106 let frame = 0;107108 // Set canvas dimensions to match parent container109 const resizeCanvas = () => {110 if (!canvas) return;111 canvas.width = canvas.offsetWidth;112 canvas.height = canvas.offsetHeight;113 };114115 resizeCanvas();116 window.addEventListener("resize", resizeCanvas);117118 const beams: Beam[] = [];119120 // Create initial beams with patterns121 const createBeam = (patternOverride?: number): Beam => {122 const isHorizontal = Math.random() > 0.5;123 const pattern =124 patternOverride !== undefined ? patternOverride : getRandomPattern();125126 // Calculate beam length based on the beamLength prop127 const length =128 beamLength.min + Math.random() * (beamLength.max - beamLength.min);129130 // Determine starting progress based on randomStarts131 const startProgress = randomStarts ? Math.random() * (1 - length) : 0;132133 return {134 color: colors[Math.floor(Math.random() * colors.length)],135 position:136 Math.floor(137 (Math.random() * (isHorizontal ? canvas.height : canvas.width)) /138 gridSize139 ) * gridSize,140 progress: startProgress,141 speed: (0.2 + Math.random() * 0.6) * baseSpeed, // Apply base speed multiplier142 width: 2 + Math.random() * 2,143 isHorizontal,144 opacity: 0.5 + Math.random() * 0.5,145 delay:146 beamDelay.min +147 Math.floor(Math.random() * (beamDelay.max - beamDelay.min)),148 pattern,149 length: length, // Store the beam length150 };151 };152153 // Create beams with specific patterns - one of each type for each direction154 const initializePatternedBeams = () => {155 // Horizontal beams with different patterns156 for (let i = 0; i < 3; i++) {157 const beam = createBeam(i);158 beam.isHorizontal = true;159 beam.position = gridSize * (1 + i * 2);160 beam.delay = i * 40; // Staggered delays161 beams.push(beam);162 }163164 // Vertical beams with different patterns165 for (let i = 0; i < 3; i++) {166 const beam = createBeam(i);167 beam.isHorizontal = false;168 beam.position = gridSize * (2 + i * 3);169 beam.delay = 30 + i * 40; // Different staggered delays170 beams.push(beam);171 }172173 // Add additional random beams up to initialBeams count174 const additionalBeams = Math.max(0, initialBeams - 6); // We already added 6 beams175 for (let i = 0; i < additionalBeams; i++) {176 beams.push(createBeam());177 }178 };179180 initializePatternedBeams();181182 // Update beam based on its pattern183 const updateBeamProgress = (beam: Beam) => {184 // Don't move if still in delay period185 if (beam.delay > 0) {186 beam.delay--;187 return;188 }189190 let speedFactor = 1;191192 switch (beam.pattern) {193 case 0: // Steady movement194 speedFactor = 1;195 break;196 case 1: // Pulsing - speed varies with sine wave197 speedFactor = 0.5 + Math.sin(frame / 50) * 0.5;198 break;199 case 2: // Accelerate-decelerate200 // Slower at beginning and end, faster in the middle201 speedFactor =202 beam.progress < 0.5 ? beam.progress * 2 : (1 - beam.progress) * 2;203 speedFactor = 0.3 + speedFactor * 0.7; // Keep minimum speed204 break;205 }206207 beam.progress += (beam.speed / 400) * speedFactor; // Base speed div by 400 (slower)208 };209210 // Animation loop211 const animate = () => {212 if (!canvas || !ctx) return;213 frame++;214215 ctx.clearRect(0, 0, canvas.width, canvas.height);216217 // Draw grid218 ctx.strokeStyle = "rgba(229, 231, 235, 0.1)"; // Light gray with transparency219 ctx.lineWidth = 1;220221 // Draw vertical grid lines222 for (let x = 0; x <= canvas.width; x += gridSize) {223 ctx.beginPath();224 ctx.moveTo(x, 0);225 ctx.lineTo(x, canvas.height);226 ctx.stroke();227 }228229 // Draw horizontal grid lines230 for (let y = 0; y <= canvas.height; y += gridSize) {231 ctx.beginPath();232 ctx.moveTo(0, y);233 ctx.lineTo(canvas.width, y);234 ctx.stroke();235 }236237 // Draw and update beams238 beams.forEach((beam, index) => {239 ctx.beginPath();240 ctx.globalAlpha = beam.opacity;241242 // For pulsing beams, also pulse opacity243 if (beam.pattern === 1 && beam.delay === 0) {244 ctx.globalAlpha = beam.opacity * (0.7 + Math.sin(frame / 50) * 0.3);245 }246247 ctx.strokeStyle = beam.color;248 ctx.lineWidth = beam.width;249250 if (beam.isHorizontal) {251 const startX = canvas.width * beam.progress;252 const endX = startX + canvas.width * beam.length;253 ctx.moveTo(startX, beam.position);254 ctx.lineTo(Math.min(endX, canvas.width), beam.position);255 } else {256 const startY = canvas.height * beam.progress;257 const endY = startY + canvas.height * beam.length;258 ctx.moveTo(beam.position, startY);259 ctx.lineTo(beam.position, Math.min(endY, canvas.height));260 }261262 ctx.stroke();263 ctx.globalAlpha = 1;264265 // Update beam progress based on pattern266 updateBeamProgress(beam);267268 // Reset beam when it reaches the end (fully off screen)269 if (beam.progress > 1) {270 // For patterned beams, maintain their pattern271 if (index < 6) {272 // The first 6 are our patterned beams273 beam.progress = randomStarts274 ? Math.random() * (1 - beam.length)275 : 0;276 beam.delay =277 beamDelay.min +278 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));279280 // Maybe change color281 if (Math.random() > 0.7) {282 beam.color = colors[Math.floor(Math.random() * colors.length)];283 }284 } else {285 // Random beams can change completely286 if (Math.random() > 0.3) {287 beam.progress = randomStarts288 ? Math.random() * (1 - beam.length)289 : 0;290 beam.delay =291 beamDelay.min +292 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));293 } else {294 beams[index] = createBeam();295 }296 }297 }298 });299300 // Add a new random beam occasionally but keep total reasonable301 if (beams.length < maxBeams && frame % 300 === 0) {302 beams.push(createBeam());303 }304305 animationFrameId = requestAnimationFrame(animate);306 };307308 animate();309310 // Clean up311 return () => {312 window.removeEventListener("resize", resizeCanvas);313 cancelAnimationFrame(animationFrameId);314 };315 }, [316 baseSpeed,317 maxBeams,318 initialBeams,319 beamDelay,320 defaultPattern,321 patternDistribution,322 colors,323 gridSize,324 randomStarts,325 beamLength,326 ]);327328 return (329 <div className="relative w-full h-[40vh] bg-gray-900 overflow-hidden">330 {/* Canvas for grid and beams */}331 <canvas ref={canvasRef} className="absolute inset-0 w-full h-[40vh]" />332333 {/* Overlay gradient for better text visibility */}334 <div className="absolute inset-0 bg-gradient-to-b from-gray-900/70 to-gray-900/90"></div>335336 {/* Content */}337 <div className="relative z-10 flex flex-col items-center justify-center h-full px-4 text-center">338 <h1 className="text-4xl md:text-6xl font-bold text-white mb-4">339 {title || "Building The Future"}340 </h1>341 <p className="text-xl md:text-2xl text-gray-300 max-w-2xl">342 {subtitle ||343 "Create something amazing with our next-generation technology platform"}344 </p>345 <div className="mt-8">346 <button className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg mr-4 transition-colors">347 Get Started348 </button>349 <button className="bg-transparent border border-white text-white font-bold py-3 px-6 rounded-lg hover:bg-white/10 transition-colors">350 Learn More351 </button>352 </div>353 </div>354 </div>355 );356};357358export default GridBeams;
Slow Motion Grid
Slow moving beams.
Slow Motion Grid
Custom animation with slow-moving beams
grid-beams.tsx
1"use client";23import React, { useEffect, useRef } from "react";45interface Beam {6 color: string; // Color of the beam7 position: number; // Position of the beam8 progress: number; // Progress of the beam9 speed: number; // Speed of the beam10 width: number; // Width of the beam11 isHorizontal: boolean; // Whether the beam is horizontal12 opacity: number; // Opacity of the beam13 delay: number; // Time before beam starts moving14 pattern: number; // Pattern type (0: straight, 1: pulse, 2: accelerate-decelerate)15 length: number; // Length of the beam (0-1)16}1718// Pattern types as a type for better TypeScript support19type BeamPattern = "steady" | "pulse" | "accelerate-decelerate";2021interface GridBeamsProps {22 title?: string; // Title of the grid beams23 subtitle?: string; // Subtitle of the grid beams24 // Animation customization props25 baseSpeed?: number; // Base speed multiplier26 maxBeams?: number; // Maximum number of beams27 initialBeams?: number; // Initial number of beams28 beamDelay?: {29 // Delay configuration30 min: number; // Minimum delay frames31 max: number; // Maximum delay frames32 };33 defaultPattern?: BeamPattern; // Default pattern for random beams34 patternDistribution?: {35 // Distribution of patterns (must sum to 1)36 steady: number; // Proportion of steady beams37 pulse: number; // Proportion of pulsing beams38 "accelerate-decelerate": number; // Proportion of accelerate-decelerate beams39 };40 colors?: string[]; // Custom colors for beams41 gridSize?: number; // Size of grid cells in pixels42 randomStarts?: boolean; // Whether to randomize starting positions43 beamLength?: { min: number; max: number }; // Length of beams44}4546const GridBeams: React.FC<GridBeamsProps> = ({47 title,48 subtitle,49 baseSpeed = 1.0,50 maxBeams = 14,51 initialBeams = 10,52 beamDelay = { min: 0, max: 200 },53 defaultPattern,54 patternDistribution = {55 steady: 0.3,56 pulse: 0.4,57 "accelerate-decelerate": 0.3,58 },59 colors = ["#3B82F6", "#8B5CF6", "#EC4899", "#10B981"],60 gridSize = 40,61 randomStarts = true,62 beamLength = { min: 0.5, max: 0.9 },63}) => {64 const canvasRef = useRef<HTMLCanvasElement>(null);6566 // Convert pattern name to number67 const getPatternNumber = (pattern: BeamPattern): number => {68 switch (pattern) {69 case "steady":70 return 0;71 case "pulse":72 return 1;73 case "accelerate-decelerate":74 return 2;75 default:76 return 0;77 }78 };7980 // Get a random pattern based on distribution81 const getRandomPattern = (): number => {82 if (defaultPattern) {83 return getPatternNumber(defaultPattern);84 }8586 const rand = Math.random();87 let cumulativeProbability = 0;8889 if (rand < (cumulativeProbability += patternDistribution.steady)) {90 return 0; // Steady91 } else if (rand < (cumulativeProbability += patternDistribution.pulse)) {92 return 1; // Pulse93 } else {94 return 2; // Accelerate-decelerate95 }96 };9798 useEffect(() => {99 const canvas = canvasRef.current;100 if (!canvas) return;101102 const ctx = canvas.getContext("2d");103 if (!ctx) return;104105 let animationFrameId: number;106 let frame = 0;107108 // Set canvas dimensions to match parent container109 const resizeCanvas = () => {110 if (!canvas) return;111 canvas.width = canvas.offsetWidth;112 canvas.height = canvas.offsetHeight;113 };114115 resizeCanvas();116 window.addEventListener("resize", resizeCanvas);117118 const beams: Beam[] = [];119120 // Create initial beams with patterns121 const createBeam = (patternOverride?: number): Beam => {122 const isHorizontal = Math.random() > 0.5;123 const pattern =124 patternOverride !== undefined ? patternOverride : getRandomPattern();125126 // Calculate beam length based on the beamLength prop127 const length =128 beamLength.min + Math.random() * (beamLength.max - beamLength.min);129130 // Determine starting progress based on randomStarts131 const startProgress = randomStarts ? Math.random() * (1 - length) : 0;132133 return {134 color: colors[Math.floor(Math.random() * colors.length)],135 position:136 Math.floor(137 (Math.random() * (isHorizontal ? canvas.height : canvas.width)) /138 gridSize139 ) * gridSize,140 progress: startProgress,141 speed: (0.2 + Math.random() * 0.6) * baseSpeed, // Apply base speed multiplier142 width: 2 + Math.random() * 2,143 isHorizontal,144 opacity: 0.5 + Math.random() * 0.5,145 delay:146 beamDelay.min +147 Math.floor(Math.random() * (beamDelay.max - beamDelay.min)),148 pattern,149 length: length, // Store the beam length150 };151 };152153 // Create beams with specific patterns - one of each type for each direction154 const initializePatternedBeams = () => {155 // Horizontal beams with different patterns156 for (let i = 0; i < 3; i++) {157 const beam = createBeam(i);158 beam.isHorizontal = true;159 beam.position = gridSize * (1 + i * 2);160 beam.delay = i * 40; // Staggered delays161 beams.push(beam);162 }163164 // Vertical beams with different patterns165 for (let i = 0; i < 3; i++) {166 const beam = createBeam(i);167 beam.isHorizontal = false;168 beam.position = gridSize * (2 + i * 3);169 beam.delay = 30 + i * 40; // Different staggered delays170 beams.push(beam);171 }172173 // Add additional random beams up to initialBeams count174 const additionalBeams = Math.max(0, initialBeams - 6); // We already added 6 beams175 for (let i = 0; i < additionalBeams; i++) {176 beams.push(createBeam());177 }178 };179180 initializePatternedBeams();181182 // Update beam based on its pattern183 const updateBeamProgress = (beam: Beam) => {184 // Don't move if still in delay period185 if (beam.delay > 0) {186 beam.delay--;187 return;188 }189190 let speedFactor = 1;191192 switch (beam.pattern) {193 case 0: // Steady movement194 speedFactor = 1;195 break;196 case 1: // Pulsing - speed varies with sine wave197 speedFactor = 0.5 + Math.sin(frame / 50) * 0.5;198 break;199 case 2: // Accelerate-decelerate200 // Slower at beginning and end, faster in the middle201 speedFactor =202 beam.progress < 0.5 ? beam.progress * 2 : (1 - beam.progress) * 2;203 speedFactor = 0.3 + speedFactor * 0.7; // Keep minimum speed204 break;205 }206207 beam.progress += (beam.speed / 400) * speedFactor; // Base speed div by 400 (slower)208 };209210 // Animation loop211 const animate = () => {212 if (!canvas || !ctx) return;213 frame++;214215 ctx.clearRect(0, 0, canvas.width, canvas.height);216217 // Draw grid218 ctx.strokeStyle = "rgba(229, 231, 235, 0.1)"; // Light gray with transparency219 ctx.lineWidth = 1;220221 // Draw vertical grid lines222 for (let x = 0; x <= canvas.width; x += gridSize) {223 ctx.beginPath();224 ctx.moveTo(x, 0);225 ctx.lineTo(x, canvas.height);226 ctx.stroke();227 }228229 // Draw horizontal grid lines230 for (let y = 0; y <= canvas.height; y += gridSize) {231 ctx.beginPath();232 ctx.moveTo(0, y);233 ctx.lineTo(canvas.width, y);234 ctx.stroke();235 }236237 // Draw and update beams238 beams.forEach((beam, index) => {239 ctx.beginPath();240 ctx.globalAlpha = beam.opacity;241242 // For pulsing beams, also pulse opacity243 if (beam.pattern === 1 && beam.delay === 0) {244 ctx.globalAlpha = beam.opacity * (0.7 + Math.sin(frame / 50) * 0.3);245 }246247 ctx.strokeStyle = beam.color;248 ctx.lineWidth = beam.width;249250 if (beam.isHorizontal) {251 const startX = canvas.width * beam.progress;252 const endX = startX + canvas.width * beam.length;253 ctx.moveTo(startX, beam.position);254 ctx.lineTo(Math.min(endX, canvas.width), beam.position);255 } else {256 const startY = canvas.height * beam.progress;257 const endY = startY + canvas.height * beam.length;258 ctx.moveTo(beam.position, startY);259 ctx.lineTo(beam.position, Math.min(endY, canvas.height));260 }261262 ctx.stroke();263 ctx.globalAlpha = 1;264265 // Update beam progress based on pattern266 updateBeamProgress(beam);267268 // Reset beam when it reaches the end (fully off screen)269 if (beam.progress > 1) {270 // For patterned beams, maintain their pattern271 if (index < 6) {272 // The first 6 are our patterned beams273 beam.progress = randomStarts274 ? Math.random() * (1 - beam.length)275 : 0;276 beam.delay =277 beamDelay.min +278 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));279280 // Maybe change color281 if (Math.random() > 0.7) {282 beam.color = colors[Math.floor(Math.random() * colors.length)];283 }284 } else {285 // Random beams can change completely286 if (Math.random() > 0.3) {287 beam.progress = randomStarts288 ? Math.random() * (1 - beam.length)289 : 0;290 beam.delay =291 beamDelay.min +292 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));293 } else {294 beams[index] = createBeam();295 }296 }297 }298 });299300 // Add a new random beam occasionally but keep total reasonable301 if (beams.length < maxBeams && frame % 300 === 0) {302 beams.push(createBeam());303 }304305 animationFrameId = requestAnimationFrame(animate);306 };307308 animate();309310 // Clean up311 return () => {312 window.removeEventListener("resize", resizeCanvas);313 cancelAnimationFrame(animationFrameId);314 };315 }, [316 baseSpeed,317 maxBeams,318 initialBeams,319 beamDelay,320 defaultPattern,321 patternDistribution,322 colors,323 gridSize,324 randomStarts,325 beamLength,326 ]);327328 return (329 <div className="relative w-full h-[40vh] bg-gray-900 overflow-hidden">330 {/* Canvas for grid and beams */}331 <canvas ref={canvasRef} className="absolute inset-0 w-full h-[40vh]" />332333 {/* Overlay gradient for better text visibility */}334 <div className="absolute inset-0 bg-gradient-to-b from-gray-900/70 to-gray-900/90"></div>335336 {/* Content */}337 <div className="relative z-10 flex flex-col items-center justify-center h-full px-4 text-center">338 <h1 className="text-4xl md:text-6xl font-bold text-white mb-4">339 {title || "Building The Future"}340 </h1>341 <p className="text-xl md:text-2xl text-gray-300 max-w-2xl">342 {subtitle ||343 "Create something amazing with our next-generation technology platform"}344 </p>345 <div className="mt-8">346 <button className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg mr-4 transition-colors">347 Get Started348 </button>349 <button className="bg-transparent border border-white text-white font-bold py-3 px-6 rounded-lg hover:bg-white/10 transition-colors">350 Learn More351 </button>352 </div>353 </div>354 </div>355 );356};357358export default GridBeams;
Mostly Accelerating Beams
Beams that accelerate and decelerate.
Mostly Accelerating Beams
More accelerate-decelerate pattern beams
grid-beams.tsx
1"use client";23import React, { useEffect, useRef } from "react";45interface Beam {6 color: string; // Color of the beam7 position: number; // Position of the beam8 progress: number; // Progress of the beam9 speed: number; // Speed of the beam10 width: number; // Width of the beam11 isHorizontal: boolean; // Whether the beam is horizontal12 opacity: number; // Opacity of the beam13 delay: number; // Time before beam starts moving14 pattern: number; // Pattern type (0: straight, 1: pulse, 2: accelerate-decelerate)15 length: number; // Length of the beam (0-1)16}1718// Pattern types as a type for better TypeScript support19type BeamPattern = "steady" | "pulse" | "accelerate-decelerate";2021interface GridBeamsProps {22 title?: string; // Title of the grid beams23 subtitle?: string; // Subtitle of the grid beams24 // Animation customization props25 baseSpeed?: number; // Base speed multiplier26 maxBeams?: number; // Maximum number of beams27 initialBeams?: number; // Initial number of beams28 beamDelay?: {29 // Delay configuration30 min: number; // Minimum delay frames31 max: number; // Maximum delay frames32 };33 defaultPattern?: BeamPattern; // Default pattern for random beams34 patternDistribution?: {35 // Distribution of patterns (must sum to 1)36 steady: number; // Proportion of steady beams37 pulse: number; // Proportion of pulsing beams38 "accelerate-decelerate": number; // Proportion of accelerate-decelerate beams39 };40 colors?: string[]; // Custom colors for beams41 gridSize?: number; // Size of grid cells in pixels42 randomStarts?: boolean; // Whether to randomize starting positions43 beamLength?: { min: number; max: number }; // Length of beams44}4546const GridBeams: React.FC<GridBeamsProps> = ({47 title,48 subtitle,49 baseSpeed = 1.0,50 maxBeams = 14,51 initialBeams = 10,52 beamDelay = { min: 0, max: 200 },53 defaultPattern,54 patternDistribution = {55 steady: 0.3,56 pulse: 0.4,57 "accelerate-decelerate": 0.3,58 },59 colors = ["#3B82F6", "#8B5CF6", "#EC4899", "#10B981"],60 gridSize = 40,61 randomStarts = true,62 beamLength = { min: 0.5, max: 0.9 },63}) => {64 const canvasRef = useRef<HTMLCanvasElement>(null);6566 // Convert pattern name to number67 const getPatternNumber = (pattern: BeamPattern): number => {68 switch (pattern) {69 case "steady":70 return 0;71 case "pulse":72 return 1;73 case "accelerate-decelerate":74 return 2;75 default:76 return 0;77 }78 };7980 // Get a random pattern based on distribution81 const getRandomPattern = (): number => {82 if (defaultPattern) {83 return getPatternNumber(defaultPattern);84 }8586 const rand = Math.random();87 let cumulativeProbability = 0;8889 if (rand < (cumulativeProbability += patternDistribution.steady)) {90 return 0; // Steady91 } else if (rand < (cumulativeProbability += patternDistribution.pulse)) {92 return 1; // Pulse93 } else {94 return 2; // Accelerate-decelerate95 }96 };9798 useEffect(() => {99 const canvas = canvasRef.current;100 if (!canvas) return;101102 const ctx = canvas.getContext("2d");103 if (!ctx) return;104105 let animationFrameId: number;106 let frame = 0;107108 // Set canvas dimensions to match parent container109 const resizeCanvas = () => {110 if (!canvas) return;111 canvas.width = canvas.offsetWidth;112 canvas.height = canvas.offsetHeight;113 };114115 resizeCanvas();116 window.addEventListener("resize", resizeCanvas);117118 const beams: Beam[] = [];119120 // Create initial beams with patterns121 const createBeam = (patternOverride?: number): Beam => {122 const isHorizontal = Math.random() > 0.5;123 const pattern =124 patternOverride !== undefined ? patternOverride : getRandomPattern();125126 // Calculate beam length based on the beamLength prop127 const length =128 beamLength.min + Math.random() * (beamLength.max - beamLength.min);129130 // Determine starting progress based on randomStarts131 const startProgress = randomStarts ? Math.random() * (1 - length) : 0;132133 return {134 color: colors[Math.floor(Math.random() * colors.length)],135 position:136 Math.floor(137 (Math.random() * (isHorizontal ? canvas.height : canvas.width)) /138 gridSize139 ) * gridSize,140 progress: startProgress,141 speed: (0.2 + Math.random() * 0.6) * baseSpeed, // Apply base speed multiplier142 width: 2 + Math.random() * 2,143 isHorizontal,144 opacity: 0.5 + Math.random() * 0.5,145 delay:146 beamDelay.min +147 Math.floor(Math.random() * (beamDelay.max - beamDelay.min)),148 pattern,149 length: length, // Store the beam length150 };151 };152153 // Create beams with specific patterns - one of each type for each direction154 const initializePatternedBeams = () => {155 // Horizontal beams with different patterns156 for (let i = 0; i < 3; i++) {157 const beam = createBeam(i);158 beam.isHorizontal = true;159 beam.position = gridSize * (1 + i * 2);160 beam.delay = i * 40; // Staggered delays161 beams.push(beam);162 }163164 // Vertical beams with different patterns165 for (let i = 0; i < 3; i++) {166 const beam = createBeam(i);167 beam.isHorizontal = false;168 beam.position = gridSize * (2 + i * 3);169 beam.delay = 30 + i * 40; // Different staggered delays170 beams.push(beam);171 }172173 // Add additional random beams up to initialBeams count174 const additionalBeams = Math.max(0, initialBeams - 6); // We already added 6 beams175 for (let i = 0; i < additionalBeams; i++) {176 beams.push(createBeam());177 }178 };179180 initializePatternedBeams();181182 // Update beam based on its pattern183 const updateBeamProgress = (beam: Beam) => {184 // Don't move if still in delay period185 if (beam.delay > 0) {186 beam.delay--;187 return;188 }189190 let speedFactor = 1;191192 switch (beam.pattern) {193 case 0: // Steady movement194 speedFactor = 1;195 break;196 case 1: // Pulsing - speed varies with sine wave197 speedFactor = 0.5 + Math.sin(frame / 50) * 0.5;198 break;199 case 2: // Accelerate-decelerate200 // Slower at beginning and end, faster in the middle201 speedFactor =202 beam.progress < 0.5 ? beam.progress * 2 : (1 - beam.progress) * 2;203 speedFactor = 0.3 + speedFactor * 0.7; // Keep minimum speed204 break;205 }206207 beam.progress += (beam.speed / 400) * speedFactor; // Base speed div by 400 (slower)208 };209210 // Animation loop211 const animate = () => {212 if (!canvas || !ctx) return;213 frame++;214215 ctx.clearRect(0, 0, canvas.width, canvas.height);216217 // Draw grid218 ctx.strokeStyle = "rgba(229, 231, 235, 0.1)"; // Light gray with transparency219 ctx.lineWidth = 1;220221 // Draw vertical grid lines222 for (let x = 0; x <= canvas.width; x += gridSize) {223 ctx.beginPath();224 ctx.moveTo(x, 0);225 ctx.lineTo(x, canvas.height);226 ctx.stroke();227 }228229 // Draw horizontal grid lines230 for (let y = 0; y <= canvas.height; y += gridSize) {231 ctx.beginPath();232 ctx.moveTo(0, y);233 ctx.lineTo(canvas.width, y);234 ctx.stroke();235 }236237 // Draw and update beams238 beams.forEach((beam, index) => {239 ctx.beginPath();240 ctx.globalAlpha = beam.opacity;241242 // For pulsing beams, also pulse opacity243 if (beam.pattern === 1 && beam.delay === 0) {244 ctx.globalAlpha = beam.opacity * (0.7 + Math.sin(frame / 50) * 0.3);245 }246247 ctx.strokeStyle = beam.color;248 ctx.lineWidth = beam.width;249250 if (beam.isHorizontal) {251 const startX = canvas.width * beam.progress;252 const endX = startX + canvas.width * beam.length;253 ctx.moveTo(startX, beam.position);254 ctx.lineTo(Math.min(endX, canvas.width), beam.position);255 } else {256 const startY = canvas.height * beam.progress;257 const endY = startY + canvas.height * beam.length;258 ctx.moveTo(beam.position, startY);259 ctx.lineTo(beam.position, Math.min(endY, canvas.height));260 }261262 ctx.stroke();263 ctx.globalAlpha = 1;264265 // Update beam progress based on pattern266 updateBeamProgress(beam);267268 // Reset beam when it reaches the end (fully off screen)269 if (beam.progress > 1) {270 // For patterned beams, maintain their pattern271 if (index < 6) {272 // The first 6 are our patterned beams273 beam.progress = randomStarts274 ? Math.random() * (1 - beam.length)275 : 0;276 beam.delay =277 beamDelay.min +278 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));279280 // Maybe change color281 if (Math.random() > 0.7) {282 beam.color = colors[Math.floor(Math.random() * colors.length)];283 }284 } else {285 // Random beams can change completely286 if (Math.random() > 0.3) {287 beam.progress = randomStarts288 ? Math.random() * (1 - beam.length)289 : 0;290 beam.delay =291 beamDelay.min +292 Math.floor(Math.random() * (beamDelay.max - beamDelay.min));293 } else {294 beams[index] = createBeam();295 }296 }297 }298 });299300 // Add a new random beam occasionally but keep total reasonable301 if (beams.length < maxBeams && frame % 300 === 0) {302 beams.push(createBeam());303 }304305 animationFrameId = requestAnimationFrame(animate);306 };307308 animate();309310 // Clean up311 return () => {312 window.removeEventListener("resize", resizeCanvas);313 cancelAnimationFrame(animationFrameId);314 };315 }, [316 baseSpeed,317 maxBeams,318 initialBeams,319 beamDelay,320 defaultPattern,321 patternDistribution,322 colors,323 gridSize,324 randomStarts,325 beamLength,326 ]);327328 return (329 <div className="relative w-full h-[40vh] bg-gray-900 overflow-hidden">330 {/* Canvas for grid and beams */}331 <canvas ref={canvasRef} className="absolute inset-0 w-full h-[40vh]" />332333 {/* Overlay gradient for better text visibility */}334 <div className="absolute inset-0 bg-gradient-to-b from-gray-900/70 to-gray-900/90"></div>335336 {/* Content */}337 <div className="relative z-10 flex flex-col items-center justify-center h-full px-4 text-center">338 <h1 className="text-4xl md:text-6xl font-bold text-white mb-4">339 {title || "Building The Future"}340 </h1>341 <p className="text-xl md:text-2xl text-gray-300 max-w-2xl">342 {subtitle ||343 "Create something amazing with our next-generation technology platform"}344 </p>345 <div className="mt-8">346 <button className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg mr-4 transition-colors">347 Get Started348 </button>349 <button className="bg-transparent border border-white text-white font-bold py-3 px-6 rounded-lg hover:bg-white/10 transition-colors">350 Learn More351 </button>352 </div>353 </div>354 </div>355 );356};357358export default GridBeams;
Props
| Name | Type | Default | Description |
|---|---|---|---|
| title | string | Modern Solutions | Title of the grid beams |
| subtitle | string | Innovative technology for tomorrow's challenges | Subtitle of the grid beams |
| baseSpeed | number | 1.0 | Base speed of the grid beams |
| maxBeams | number | 14 | Maximum number of beams |
| initialBeams | number | 10 | Initial number of beams |
| beamDelay | object | { min: 0, max: 200 } | Delay configuration for beams |
| defaultPattern | string | steady | Default pattern for beams. Use "Steady", "Pulse", or "Accelerate-Decelerate" |
| patternDistribution | object | { steady: 0.3, pulse: 0.4, 'accelerate-decelerate': 0.3 } | Distribution of patterns. Must sum up to 1. |
| colors | string[] | ['#3B82F6', '#8B5CF6', '#EC4899', '#10B981'] | Custom colors for beams |
| gridSize | number | 40 | Size of grid cells in pixels |