feat(lens): refine the swarm scale palette and motion

This commit is contained in:
moe-berri 2026-10-03 19:52:13 -07:00
parent e3fc273bb5
commit db7feb8d87
2 changed files with 72 additions and 59 deletions

View file

@ -3,26 +3,26 @@ import styles from "./LensIntroduction.module.css";
const dotColors = [
"fill-sky-400 dark:fill-sky-300",
"fill-indigo-400 dark:fill-indigo-300",
"fill-violet-400 dark:fill-violet-300",
"fill-amber-400 dark:fill-amber-300",
"fill-cyan-400 dark:fill-cyan-300",
"fill-rose-400 dark:fill-rose-300",
];
const gridDots = Array.from({ length: 583 }, (_, index) => {
const column = index % 53;
const row = Math.floor(index / 53);
const variation = (index * 73 + index * index * 19) % 101;
return {
x: 5 + column * 10,
y: 4 + row * 10,
color: dotColors[variation % dotColors.length],
duration: `${5.5 + (row % 3) * 0.7}s`,
delay: `${-((53 - column) * 0.1 + row * 0.43 + variation * 0.016)}s`,
};
});
const swarmRows = Array.from({ length: 11 }, (_, row) => ({
y: 4 + row * 10,
duration: `${[4.8, 5.2, 5.6, 5][row % 4]}s`,
delay: `${-row * 0.17}s`,
dots: Array.from({ length: 80 }, (_, column) => {
const seed = (column % 24) + row * 31;
const variation = (seed * 73 + seed * seed * 19) % 101;
return {
x: column * 10 - 235,
color: dotColors[variation % dotColors.length],
opacity: variation < 15 ? 0 : 0.5 + variation * 0.005,
};
}),
}));
const organizedColumns = Array.from({ length: 50 }, (_, column) => column).filter((column) => column % 8 < 6);
const organizedColumns = Array.from({ length: 58 }, (_, column) => column - 8);
export function GatewayFlow() {
const id = useId();
@ -49,9 +49,15 @@ export function GatewayFlow() {
focusable="false"
>
<defs>
<pattern id={`${id}-grid`} width="10" height="10" patternUnits="userSpaceOnUse">
<pattern id={`${id}-grid`} width="40" height="40" patternUnits="userSpaceOnUse">
<circle cx="5" cy="4" r="1" className="fill-muted-foreground/15" />
</pattern>
<filter id={`${id}-soft-edge`} x="-10%" y="-30%" width="120%" height="160%">
<feGaussianBlur stdDeviation="3" />
</filter>
<clipPath id={`${id}-after-gate`}>
<rect x="500" width="500" height="108" />
</clipPath>
<linearGradient id={`${id}-incoming`} x1="480" x2="530" y1="0" y2="0" gradientUnits="userSpaceOnUse">
<stop stopColor="white" />
<stop offset="1" stopColor="black" />
@ -60,9 +66,19 @@ export function GatewayFlow() {
<rect width="1000" height="108" fill={`url(#${id}-incoming)`} />
</mask>
<mask id={`${id}-swarm-shape`}>
<g fill="none" stroke="white" strokeWidth="24" strokeLinecap="round" filter={`url(#${id}-soft-edge)`}>
<path d="M -30 20 C 80 0 142 38 244 22 S 402 36 530 54" />
<path d="M -30 54 C 90 76 174 32 278 52 S 420 60 530 54" />
<path d="M -30 90 C 80 112 172 66 276 86 S 420 68 530 54" />
</g>
</mask>
<mask id={`${id}-organized-shape`}>
<path
d="M 0 5 C 200 5 270 8 380 30 S 465 39 500 39 C 620 39 730 18 1000 12 L 1000 96 C 730 90 620 69 500 69 C 465 69 440 69 380 78 S 200 103 0 103 Z"
fill="white"
d="M 490 54 C 620 54 664 66 772 58 S 920 42 1020 52"
fill="none"
stroke="white"
strokeWidth="32"
filter={`url(#${id}-soft-edge)`}
/>
</mask>
<linearGradient id={`${id}-fade`}>
@ -75,7 +91,7 @@ export function GatewayFlow() {
<rect width="1000" height="108" fill={`url(#${id}-fade)`} />
</mask>
<radialGradient id={`${id}-glow`} className="text-indigo-500 dark:text-indigo-400">
<stop stopColor="currentColor" stopOpacity="0.2" />
<stop stopColor="currentColor" stopOpacity="0.14" />
<stop offset="1" stopColor="currentColor" stopOpacity="0" />
</radialGradient>
<linearGradient id={`${id}-gate`} x1="0" y1="0" x2="0" y2="1">
@ -86,36 +102,39 @@ export function GatewayFlow() {
</defs>
<g mask={`url(#${id}-edges)`}>
<rect width="1000" height="108" fill={`url(#${id}-grid)`} />
<ellipse cx="500" cy="54" rx="58" ry="54" fill={`url(#${id}-glow)`} className={styles.gatewayGlow} />
{organizedColumns.map((column) => (
<g
key={column}
className={`${styles.organizedDots} fill-indigo-500 dark:fill-indigo-400`}
style={{ animationDelay: `${-(50 - column) * 0.1}s` }}
>
{[34, 44, 54, 64, 74].map((y) => (
<circle key={y} cx={505 + column * 10} cy={y} r="1.8" />
))}
<ellipse cx="500" cy="54" rx="44" ry="40" fill={`url(#${id}-glow)`} className={styles.gatewayGlow} />
<g clipPath={`url(#${id}-after-gate)`}>
<g mask={`url(#${id}-organized-shape)`}>
<g className={`${styles.organizedDots} fill-indigo-500 dark:fill-indigo-400`}>
{organizedColumns.map((column) => (
<g key={column} opacity={0.6 + (((column + 8) * 3) % 8) * 0.05}>
{[34, 44, 54, 64, 74].map((y) => (
<circle key={y} cx={505 + column * 10} cy={y} r="2.3" />
))}
</g>
))}
</g>
</g>
))}
</g>
<g mask={`url(#${id}-swarm-shape)`}>
<g mask={`url(#${id}-before-gate)`}>
{gridDots.map((dot, index) => (
<circle
{swarmRows.map((row, index) => (
<g
key={index}
cx={dot.x}
cy={dot.y}
r="1.8"
className={`${styles.swarmDot} ${dot.color}`}
style={{ animationDuration: dot.duration, animationDelay: dot.delay }}
/>
className={styles.swarmRow}
style={{ animationDuration: row.duration, animationDelay: row.delay }}
>
{row.dots.map((dot, column) => (
<circle key={column} cx={dot.x} cy={row.y} r="2.3" className={dot.color} opacity={dot.opacity} />
))}
</g>
))}
</g>
</g>
</g>
<rect x="497" y="10" width="6" height="88" rx="3" className="fill-background/90" />
<rect x="497" y="30" width="6" height="48" rx="3" className="fill-background/90" />
<path
d="M 490 10 H 497 V 98 H 490 M 510 10 H 503 V 98 H 510"
d="M 490 30 H 497 V 78 H 490 M 510 30 H 503 V 78 H 510"
fill="none"
stroke={`url(#${id}-gate)`}
strokeWidth="1.4"

View file

@ -1,9 +1,9 @@
.swarmDot {
animation: swarm-flow 6s ease-in-out infinite;
.swarmRow {
animation: swarm-flow 5.2s linear infinite;
}
.organizedDots {
animation: organized-flow 6s ease-in-out infinite;
animation: organized-flow 1.6s linear infinite;
}
.gatewayGlow {
@ -79,31 +79,25 @@
}
@keyframes swarm-flow {
0%,
100% {
opacity: 0.15;
from {
transform: translateX(0);
}
45% {
opacity: 1;
}
70% {
opacity: 0.55;
to {
transform: translateX(240px);
}
}
@keyframes organized-flow {
0%,
100% {
opacity: 0.2;
from {
transform: translateX(0);
}
40%,
55% {
opacity: 1;
to {
transform: translateX(80px);
}
}
@media (prefers-reduced-motion: reduce) {
.swarmDot,
.swarmRow,
.organizedDots {
animation: none;
opacity: 0.75;