animations

This commit is contained in:
Timo Knuth 2026-01-09 10:14:27 +01:00
parent 1c5f272f33
commit 91b819e9c1
2 changed files with 127 additions and 71 deletions

View File

@ -0,0 +1,12 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"Bash(npm install:*)",
"Bash(ls:*)",
"Bash(node scripts/optimize-images.js:*)",
"Bash(node scripts/optimize-images.cjs:*)",
"Skill(frontend-design)"
]
}
}

View File

@ -2,22 +2,22 @@ import { motion } from 'framer-motion';
import { useMemo } from 'react';
const BackgroundAnimations = () => {
// Reduced particles for better performance (30 -> 12)
// Particles with better visibility (increased opacity and size)
const particles = useMemo(() => {
return Array.from({ length: 12 }, (_, i) => ({
return Array.from({ length: 18 }, (_, i) => ({
id: i,
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 2 + 1,
duration: Math.random() * 12 + 8,
size: Math.random() * 4 + 2, // Larger particles (2-6px instead of 1-3px)
duration: Math.random() * 10 + 6,
delay: Math.random() * 4,
opacity: Math.random() * 0.5 + 0.2,
opacity: Math.random() * 0.4 + 0.5, // Much higher opacity (0.5-0.9)
}));
}, []);
// Reduced circuit nodes for performance (12 -> 6)
// Circuit nodes for tech effect
const circuitNodes = useMemo(() => {
return Array.from({ length: 6 }, (_, i) => ({
return Array.from({ length: 8 }, (_, i) => ({
id: i,
x: Math.random() * 80 + 10,
y: Math.random() * 80 + 10,
@ -25,10 +25,10 @@ const BackgroundAnimations = () => {
}));
}, []);
// Reduced connection lines (half as many)
// Connection lines between nodes
const connectionLines = useMemo(() => {
const lines = [];
for (let i = 0; i < circuitNodes.length - 1; i += 2) {
for (let i = 0; i < circuitNodes.length - 1; i++) {
if (i + 1 < circuitNodes.length) {
lines.push({
id: i,
@ -44,72 +44,106 @@ const BackgroundAnimations = () => {
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none" style={{ willChange: 'transform' }}>
{/* Simplified Static Grid Background - no animation for better performance */}
<div
className="absolute inset-0 opacity-30"
{/* Animated Grid Background */}
<motion.div
className="absolute inset-0"
style={{
backgroundImage: `
linear-gradient(to right, rgba(51, 102, 255, 0.03) 1px, transparent 1px),
linear-gradient(to bottom, rgba(51, 102, 255, 0.03) 1px, transparent 1px)
linear-gradient(to right, rgba(51, 102, 255, 0.08) 1px, transparent 1px),
linear-gradient(to bottom, rgba(51, 102, 255, 0.08) 1px, transparent 1px)
`,
backgroundSize: '80px 80px',
backgroundSize: '60px 60px',
willChange: 'transform',
}}
animate={{
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* SVG Container for Lines and Nodes - optimized */}
<svg className="absolute inset-0 w-full h-full" style={{ opacity: 0.5, willChange: 'transform' }}>
{/* SVG Container for Lines and Nodes */}
<svg className="absolute inset-0 w-full h-full" style={{ willChange: 'transform' }}>
{/* Simplified Connection Lines - static for better performance */}
{/* Animated Connection Lines */}
{connectionLines.map((line) => (
<line
<motion.line
key={line.id}
x1={`${line.x1}%`}
y1={`${line.y1}%`}
x2={`${line.x2}%`}
y2={`${line.y2}%`}
stroke="rgba(51, 102, 255, 0.2)"
strokeWidth="1"
opacity="0.4"
/>
))}
{/* Reduced Vertical Data Streams (8 -> 4) */}
{[...Array(4)].map((_, i) => (
<motion.line
key={`vertical-${i}`}
x1={`${15 + i * 25}%`}
y1="0%"
x2={`${15 + i * 25}%`}
y2="100%"
stroke="rgba(51, 102, 255, 0.15)"
strokeWidth="1"
strokeDasharray="10 20"
initial={{ strokeDashoffset: 0 }}
animate={{ strokeDashoffset: 100 }}
stroke="rgba(51, 102, 255, 0.4)"
strokeWidth="1.5"
initial={{ pathLength: 0, opacity: 0 }}
animate={{ pathLength: 1, opacity: [0.3, 0.7, 0.3] }}
transition={{
duration: 4,
repeat: Infinity,
ease: "linear",
delay: i * 0.5,
pathLength: { duration: 2, delay: line.id * 0.3 },
opacity: { duration: 3, repeat: Infinity, ease: "easeInOut" },
}}
/>
))}
{/* Simplified Circuit Nodes - reduced animation */}
{/* Vertical Data Streams */}
{[...Array(6)].map((_, i) => (
<motion.line
key={`vertical-${i}`}
x1={`${10 + i * 18}%`}
y1="0%"
x2={`${10 + i * 18}%`}
y2="100%"
stroke="rgba(51, 102, 255, 0.3)"
strokeWidth="1.5"
strokeDasharray="8 16"
initial={{ strokeDashoffset: 0 }}
animate={{ strokeDashoffset: 100 }}
transition={{
duration: 3,
repeat: Infinity,
ease: "linear",
delay: i * 0.4,
}}
/>
))}
{/* Circuit Nodes with pulse ring */}
{circuitNodes.map((node) => (
<g key={node.id}>
{/* Core node with simple pulse */}
{/* Pulse ring */}
<motion.circle
cx={`${node.x}%`}
cy={`${node.y}%`}
r="2.5"
fill="#3366ff"
r="6"
fill="none"
stroke="#3366ff"
strokeWidth="1"
animate={{
opacity: [0.6, 1, 0.6],
r: [6, 12, 6],
opacity: [0.8, 0, 0.8],
}}
transition={{
duration: 3,
duration: 2.5,
repeat: Infinity,
delay: node.pulseDelay,
ease: "easeOut",
}}
/>
{/* Core node */}
<motion.circle
cx={`${node.x}%`}
cy={`${node.y}%`}
r="4"
fill="#3366ff"
animate={{
opacity: [0.7, 1, 0.7],
r: [3, 4.5, 3],
}}
transition={{
duration: 2,
repeat: Infinity,
delay: node.pulseDelay,
ease: "easeInOut",
@ -119,7 +153,7 @@ const BackgroundAnimations = () => {
))}
</svg>
{/* Optimized Floating Data Particles with GPU acceleration */}
{/* Floating Data Particles - highly visible */}
{particles.map((particle) => (
<motion.div
key={particle.id}
@ -129,13 +163,12 @@ const BackgroundAnimations = () => {
height: `${particle.size}px`,
left: `${particle.x}%`,
top: `${particle.y}%`,
opacity: particle.opacity,
boxShadow: '0 0 6px rgba(51, 102, 255, 0.6)',
boxShadow: '0 0 12px rgba(51, 102, 255, 0.9), 0 0 24px rgba(51, 102, 255, 0.5)',
willChange: 'transform, opacity',
}}
animate={{
y: [0, -600],
opacity: [0, particle.opacity, 0],
y: [0, -500],
opacity: [0, particle.opacity, particle.opacity, 0],
}}
transition={{
duration: particle.duration,
@ -146,24 +179,35 @@ const BackgroundAnimations = () => {
/>
))}
{/* Simplified Static Scanline Effect - no animation */}
<div
className="absolute inset-0 opacity-20 pointer-events-none"
{/* Scanline Effect */}
<motion.div
className="absolute inset-0 pointer-events-none"
style={{
background: `repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(51, 102, 255, 0.02) 2px,
rgba(51, 102, 255, 0.02) 4px
rgba(51, 102, 255, 0.04) 2px,
rgba(51, 102, 255, 0.04) 4px
)`,
}}
animate={{
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* Reduced Radial Glows (3 -> 2) with simpler animation */}
{/* Radial Glows */}
{[
{ x: 25, y: 40 },
{ x: 75, y: 60 },
{ x: 20, y: 30, size: 300 },
{ x: 80, y: 70, size: 350 },
{ x: 50, y: 50, size: 400 },
].map((pos, i) => (
<motion.div
key={`glow-${i}`}
@ -171,28 +215,28 @@ const BackgroundAnimations = () => {
style={{
left: `${pos.x}%`,
top: `${pos.y}%`,
width: '180px',
height: '180px',
background: 'radial-gradient(circle, rgba(51, 102, 255, 0.12) 0%, transparent 70%)',
width: `${pos.size}px`,
height: `${pos.size}px`,
background: 'radial-gradient(circle, rgba(51, 102, 255, 0.25) 0%, transparent 70%)',
transform: 'translate(-50%, -50%)',
willChange: 'transform',
}}
animate={{
scale: [1, 1.15, 1],
opacity: [0.4, 0.6, 0.4],
scale: [1, 1.3, 1],
opacity: [0.5, 0.8, 0.5],
}}
transition={{
duration: 6,
duration: 5,
repeat: Infinity,
delay: i * 2,
delay: i * 1.5,
ease: "easeInOut",
}}
/>
))}
{/* Static Corner Accent Glows - no blur for better performance */}
<div className="absolute top-0 left-0 w-64 h-64 bg-gradient-to-br from-neon/8 to-transparent rounded-full opacity-40 pointer-events-none" />
<div className="absolute bottom-0 right-0 w-80 h-80 bg-gradient-to-tl from-neon/8 to-transparent rounded-full opacity-40 pointer-events-none" />
{/* Corner Accent Glows */}
<div className="absolute top-0 left-0 w-96 h-96 bg-gradient-to-br from-neon/20 to-transparent rounded-full opacity-60 pointer-events-none" />
<div className="absolute bottom-0 right-0 w-[500px] h-[500px] bg-gradient-to-tl from-neon/20 to-transparent rounded-full opacity-60 pointer-events-none" />
</div>
);
};