feat: replace static icons with animated SVG components in GPU capabilities

- Replaced Heroicons with custom animated SVG components for each GPU capability card
- Added four new animation components: InterferenceAnimation, KubernetesAcceleration, RenderingSimulation, and RAGPipeline
- Updated card layout to accommodate full-width animations above text content
This commit is contained in:
2025-11-08 00:56:07 +01:00
parent 5ab909bd12
commit 22e2e4b80c
6 changed files with 698 additions and 23 deletions

View File

@@ -0,0 +1,296 @@
"use client";
export default function InferenceAnimation() {
return (
<svg
width="382"
height="282"
viewBox="0 0 382 282"
xmlns="http://www.w3.org/2000/svg"
role="img"
aria-labelledby="title desc"
>
<title id="title">AI / ML Inference & Training Animation</title>
<desc id="desc">
Animated neural graph sending signals to a glowing GPU chip on a dark
background.
</desc>
{/* ---------- DEFINITIONS ---------- */}
<defs>
{/* Dark grid pattern */}
<pattern id="grid" width="16" height="16" patternUnits="userSpaceOnUse">
<path d="M16 0H0V16" fill="none" stroke="#0f1621" strokeWidth="1" />
</pattern>
{/* Cyan gradient */}
<linearGradient id="cyanglow" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stopColor="#00E5FF">
<animate
attributeName="stop-color"
values="#00E5FF;#00B8DB;#00E5FF"
dur="4s"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stopColor="#00B8DB">
<animate
attributeName="stop-color"
values="#00B8DB;#00E5FF;#00B8DB"
dur="4s"
repeatCount="indefinite"
/>
</stop>
</linearGradient>
{/* Soft outer glow */}
<filter id="softGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="6" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
{/* Sharper glow for nodes */}
<filter id="nodeGlow" x="-150%" y="-150%" width="400%" height="400%">
<feGaussianBlur stdDeviation="3" result="ng" />
<feMerge>
<feMergeNode in="ng" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
{/* Dashed link style */}
<style>{`
.link {
stroke: #11cdef;
stroke-width: 1.75;
stroke-linecap: round;
stroke-dasharray: 6 10;
opacity: 0.9;
}
.muted { opacity: 0.65; }
.chip-line { stroke: #93c5fd; stroke-width: 1; opacity: 0.7; }
`}</style>
{/* Reusable motion path for packet */}
<path
id="path1"
d="M 64 156 C 110 118, 160 130, 206 140 S 280 158, 316 150"
fill="none"
/>
<path
id="path2"
d="M 64 116 C 116 96, 160 104, 204 112 S 280 126, 316 112"
fill="none"
/>
</defs>
{/* ---------- BACKGROUND ---------- */}
<rect width="382" height="282" fill="transparent" />
<rect width="382" height="282" fill="url(#grid)" opacity="0.55" />
{/* ---------- GPU CHIP (RIGHT) ---------- */}
<g transform="translate(252,62)">
{/* Outer casing */}
<rect
x="0"
y="0"
width="112"
height="158"
rx="18"
fill="#0e1724"
stroke="url(#cyanglow)"
strokeWidth="2"
filter="url(#softGlow)"
/>
{/* Inner frame */}
<rect
x="12"
y="14"
width="88"
height="130"
rx="10"
fill="#0b1320"
stroke="#163447"
strokeWidth="1.5"
/>
{/* Matrix / cores */}
{[...Array(5)].map((_, r) => (
<line
key={`row-${r}`}
x1="20"
x2="92"
y1={28 + r * 24}
y2={28 + r * 24}
className="chip-line"
/>
))}
{[...Array(6)].map((_, c) => (
<line
key={`col-${c}`}
y1="26"
y2="126"
x1={22 + c * 12}
x2={22 + c * 12}
className="chip-line"
/>
))}
{/* Pulsing GPU die */}
<rect
x="40"
y="58"
width="32"
height="32"
rx="6"
fill="url(#cyanglow)"
opacity="0.85"
>
<animate
attributeName="opacity"
values="0.5;0.95;0.5"
dur="2.2s"
repeatCount="indefinite"
/>
</rect>
{/* Glow ring */}
<rect
x="36"
y="54"
width="40"
height="40"
rx="8"
stroke="url(#cyanglow)"
strokeWidth="2"
fill="none"
>
<animate
attributeName="stroke-width"
values="2;4;2"
dur="2.2s"
repeatCount="indefinite"
/>
</rect>
</g>
{/* ---------- NEURAL GRAPH (LEFT/MID) ---------- */}
<g transform="translate(28,34)">
{/* Links */}
<g className="muted">
{/* lower cluster to chip */}
<path className="link" d="M36 148 L96 124" >
<animate
attributeName="stroke-dashoffset"
values="0;-32"
dur="1.6s"
repeatCount="indefinite"
/>
</path>
<path className="link" d="M96 124 L152 138" >
<animate
attributeName="stroke-dashoffset"
values="0;-32"
dur="1.6s"
repeatCount="indefinite"
/>
</path>
<path className="link" d="M152 138 L212 132" >
<animate
attributeName="stroke-dashoffset"
values="0;-32"
dur="1.6s"
repeatCount="indefinite"
/>
</path>
{/* upper cluster to mid */}
<path className="link" d="M40 76 L92 88" >
<animate
attributeName="stroke-dashoffset"
values="0;-28"
dur="1.4s"
repeatCount="indefinite"
/>
</path>
<path className="link" d="M92 88 L140 96" >
<animate
attributeName="stroke-dashoffset"
values="0;-28"
dur="1.4s"
repeatCount="indefinite"
/>
</path>
<path className="link" d="M140 96 L206 106" >
<animate
attributeName="stroke-dashoffset"
values="0;-28"
dur="1.4s"
repeatCount="indefinite"
/>
</path>
{/* vertical cross links */}
<path className="link" d="M92 88 L96 124" >
<animate
attributeName="stroke-dashoffset"
values="0;-24"
dur="1.2s"
repeatCount="indefinite"
/>
</path>
<path className="link" d="M140 96 L152 138" >
<animate
attributeName="stroke-dashoffset"
values="0;-24"
dur="1.2s"
repeatCount="indefinite"
/>
</path>
</g>
{/* Nodes */}
{[
{ x: 36, y: 148, r: 6 },
{ x: 40, y: 76, r: 6 },
{ x: 96, y: 124, r: 7 },
{ x: 92, y: 88, r: 7 },
{ x: 140, y: 96, r: 7 },
{ x: 152, y: 138, r: 7 },
{ x: 206, y: 106, r: 6.5 },
{ x: 212, y: 132, r: 6.5 },
].map((n, i) => (
<g key={i} filter="url(#nodeGlow)">
<circle cx={n.x} cy={n.y} r={n.r} fill="#06121a" stroke="#163447" />
<circle cx={n.x} cy={n.y} r={n.r - 2} fill="url(#cyanglow)" opacity="0.9">
<animate
attributeName="opacity"
values="0.6;1;0.6"
dur={`${1.2 + (i % 4) * 0.2}s`}
repeatCount="indefinite"
/>
</circle>
</g>
))}
{/* Data packets moving along paths */}
<g>
<circle r="3.2" fill="url(#cyanglow)">
<animateMotion dur="2.6s" repeatCount="indefinite">
<mpath href="#path1" />
</animateMotion>
</circle>
<circle r="2.8" fill="url(#cyanglow)" opacity="0.85">
<animateMotion dur="2.2s" begin="0.4s" repeatCount="indefinite">
<mpath href="#path2" />
</animateMotion>
</circle>
</g>
</g>
{/* ---------- LABELS ---------- */}
</svg>
);
}