Browse Source

feat: add interactive canvas dot grid and hero section components with cursor-responsive hover effects

master
sina_sajjadi 2 weeks ago
parent
commit
f0bf527d8e
  1. 144
      components/sections/HeroDotCanvas.tsx
  2. 2
      components/sections/HeroSection.tsx
  3. 35
      public/assets/images/hero_back.svg

144
components/sections/HeroDotCanvas.tsx

@ -25,21 +25,17 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
const minY = 3; // Grid extends to the top of the card const minY = 3; // Grid extends to the top of the card
const maxY = 555; const maxY = 555;
// Scaling constants per user reference:
// dotmin: default radius of the dots (1.5px)
// dotsizebase: peak radius directly under the cursor (2.5px - smaller and more refined)
// decay: size drop-off per grid unit (0.32) -> ~38px tight interaction radius
// Scaling constants per original reference:
const dotmin = 1.5; const dotmin = 1.5;
const dotsizebase = 4.5; const dotsizebase = 4.5;
const decay = 0.3; const decay = 0.3;
const DOT_HOVER_BRIGHTNESS = 0.03; // Extra brightness boost when hovered (0.13 = subtle/soft, increase for brighter dots)
const LOGO_HOVER_BRIGHTNESS = 0.28; // Peak brightness multiplier for logos (scales based on default brightness)
const DOT_HOVER_BRIGHTNESS = 0.03; // Extra brightness boost when hovered
const LOGO_HOVER_BRIGHTNESS = 0.28; // Peak brightness multiplier for logos
// Reaction delay & trailing lag constants: // Reaction delay & trailing lag constants:
// Lower values = smoother delay and trailing inertia
const LERP_LAG = 0.07; // Delay in tracking cursor movement
const FADE_IN_LAG = 0.07; // Delay to smoothly bloom up
const FADE_OUT_LAG = 0.04; // Lingering delay before returning to rest
const LERP_LAG = 0.07;
const FADE_IN_LAG = 0.07;
const FADE_OUT_LAG = 0.04;
// Pre-calculate dot grid coordinates // Pre-calculate dot grid coordinates
const dots: { x: number; y: number }[] = []; const dots: { x: number; y: number }[] = [];
@ -49,8 +45,6 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
} }
} }
const numCols = Math.round((maxX - minX) / rowsize) + 1; // 155
const numRows = Math.round((maxY - minY) / rowsize) + 1; // 43
const maxRadius = ((dotsizebase - dotmin) / decay) * rowsize; // ~120px const maxRadius = ((dotsizebase - dotmin) / decay) * rowsize; // ~120px
// Cursor tracking state // Cursor tracking state
@ -84,8 +78,6 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
// Sizing matches Next.js Image object-cover object-top // Sizing matches Next.js Image object-cover object-top
scale = height / SVG_HEIGHT; scale = height / SVG_HEIGHT;
offsetX = (width - SVG_WIDTH * scale) / 2; offsetX = (width - SVG_WIDTH * scale) / 2;
draw();
}; };
// Load the illuminated bright logo patterns for cursor reaction // Load the illuminated bright logo patterns for cursor reaction
@ -93,7 +85,6 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
let brightLogoLoaded = false; let brightLogoLoaded = false;
brightLogoImg.onload = () => { brightLogoImg.onload = () => {
brightLogoLoaded = true; brightLogoLoaded = true;
draw();
}; };
brightLogoImg.src = "/assets/images/hero_logo_patterns.svg"; brightLogoImg.src = "/assets/images/hero_logo_patterns.svg";
@ -105,9 +96,7 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
spotCtx = spotCanvas.getContext("2d"); spotCtx = spotCanvas.getContext("2d");
} }
// Bottom curved cutout path from line 1145 of hero_back.svg (covers bottom corners)
// Bottom curved cutout path from line 1144 of hero_back.svg (covers bottom corners)
const bottomPath = const bottomPath =
typeof Path2D !== "undefined" typeof Path2D !== "undefined"
? new Path2D( ? new Path2D(
@ -115,16 +104,18 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
) )
: null; : null;
const draw = () => {
const draw = (t: number) => {
ctx.clearRect(0, 0, width, height); ctx.clearRect(0, 0, width, height);
// 1. Single-pass dot rendering: // 1. Single-pass dot rendering:
// Every dot is drawn EXACTLY ONCE with its dynamic radius r
// Eliminates any duplicate dot layers completely!
ctx.fillStyle = "rgba(255, 255, 255, 0.18)";
// Preserves original look, with dynamic, fast acoustic sound-wave undulation
ctx.fillStyle = "rgba(255, 255, 255, 0.22)";
ctx.beginPath(); ctx.beginPath();
for (let i = 0; i < dots.length; i++) { for (let i = 0; i < dots.length; i++) {
const dot = dots[i]; const dot = dots[i];
// Static dot grid (no wave animation on dots per user request)
const screenX = dot.x * scale + offsetX; const screenX = dot.x * scale + offsetX;
const screenY = dot.y * scale; const screenY = dot.y * scale;
@ -132,9 +123,12 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
let r = dotmin; let r = dotmin;
if (currentStrength > 0.005) { if (currentStrength > 0.005) {
const scaler = Math.hypot((currentX - dot.x) / rowsize, (currentY - dot.y) / rowsize);
const addedSize = Math.max(0, (dotsizebase - dotmin) - scaler * decay);
r = dotmin + addedSize * currentStrength;
const scaler = Math.hypot(
(currentX - dot.x) / rowsize,
(currentY - dot.y) / rowsize
);
const addedSize = Math.max(0, dotsizebase - dotmin - scaler * decay);
r += addedSize * currentStrength;
} }
ctx.moveTo(screenX + r, screenY); ctx.moveTo(screenX + r, screenY);
@ -142,8 +136,7 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
} }
ctx.fill(); ctx.fill();
// 2. Apply vertical fade gradient mask matching the SVG's dotFadeMask
// Invisible dots on top stay invisible; transparent dots stay transparent!
// 2. Apply vertical fade gradient mask matching original dotFadeMask
ctx.globalCompositeOperation = "destination-in"; ctx.globalCompositeOperation = "destination-in";
const fadeGrad = ctx.createLinearGradient(0, 45 * scale, 0, 566 * scale); const fadeGrad = ctx.createLinearGradient(0, 45 * scale, 0, 566 * scale);
fadeGrad.addColorStop(0, "rgba(255, 255, 255, 0)"); fadeGrad.addColorStop(0, "rgba(255, 255, 255, 0)");
@ -153,8 +146,7 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
ctx.fillStyle = fadeGrad; ctx.fillStyle = fadeGrad;
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
// 3. Cut out the bottom curved shape matching line 1145 of hero_back.svg:
// Preserves the authentic curved arch of the dots pattern (matching previous commits)
// 3. Cut out the bottom curved shape matching line 1144 of hero_back.svg
if (bottomPath) { if (bottomPath) {
ctx.globalCompositeOperation = "destination-out"; ctx.globalCompositeOperation = "destination-out";
ctx.save(); ctx.save();
@ -167,28 +159,29 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
// 4. Subtle hover illumination on dots: // 4. Subtle hover illumination on dots:
// Uses source-atop so it ONLY gently highlights the already-drawn & masked dots,
// strictly guaranteeing that NO dots outside the bottom curve are ever illuminated!
if (DOT_HOVER_BRIGHTNESS > 0.001 && currentStrength > 0.005) { if (DOT_HOVER_BRIGHTNESS > 0.001 && currentStrength > 0.005) {
ctx.globalCompositeOperation = "source-atop"; ctx.globalCompositeOperation = "source-atop";
const scX = currentX * scale + offsetX; const scX = currentX * scale + offsetX;
const scY = currentY * scale; const scY = currentY * scale;
const pRad = maxRadius * scale; const pRad = maxRadius * scale;
const dotLight = ctx.createRadialGradient(scX, scY, 0, scX, scY, pRad); const dotLight = ctx.createRadialGradient(scX, scY, 0, scX, scY, pRad);
dotLight.addColorStop(0, `rgba(255, 255, 255, ${(DOT_HOVER_BRIGHTNESS * 6 * currentStrength).toFixed(3)})`);
dotLight.addColorStop(0.6, `rgba(255, 255, 255, ${(DOT_HOVER_BRIGHTNESS * 2 * currentStrength).toFixed(3)})`);
dotLight.addColorStop(
0,
`rgba(255, 255, 255, ${(DOT_HOVER_BRIGHTNESS * 6 * currentStrength).toFixed(3)})`
);
dotLight.addColorStop(
0.6,
`rgba(255, 255, 255, ${(DOT_HOVER_BRIGHTNESS * 2 * currentStrength).toFixed(3)})`
);
dotLight.addColorStop(1, "rgba(255, 255, 255, 0)"); dotLight.addColorStop(1, "rgba(255, 255, 255, 0)");
ctx.fillStyle = dotLight; ctx.fillStyle = dotLight;
ctx.fillRect(scX - pRad, scY - pRad, pRad * 2, pRad * 2); ctx.fillRect(scX - pRad, scY - pRad, pRad * 2, pRad * 2);
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
} }
// 5. Pixel-precise radial spotlight for the TeamBy logo patterns:
// - Logos DO NOT scale (preserve exact geometric dimensions)
// - Radial gradient centered at cursor provides continuous falloff
// - Any icon at the edge of the radius is partially illuminated only where the radius reaches!
// 5. Pixel-precise radial spotlight for TeamBy logo patterns:
if (currentStrength > 0.005 && brightLogoLoaded && spotCanvas && spotCtx) { if (currentStrength > 0.005 && brightLogoLoaded && spotCanvas && spotCtx) {
const spotRadiusSvg = maxRadius; // 120px in SVG units matching cursor reach
const spotRadiusSvg = maxRadius;
const spotRadiusScreen = spotRadiusSvg * scale; const spotRadiusScreen = spotRadiusSvg * scale;
const spotSize = Math.ceil(spotRadiusScreen * 2); const spotSize = Math.ceil(spotRadiusScreen * 2);
@ -205,19 +198,18 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
const scX = currentX * scale + offsetX; const scX = currentX * scale + offsetX;
const scY = currentY * scale; const scY = currentY * scale;
// Clear offscreen spotlight canvas
spotCtx.clearRect(0, 0, spotSize, spotSize); spotCtx.clearRect(0, 0, spotSize, spotSize);
// Position the full bright logo SVG so that cursor point (scX, scY) lands at (spotRadiusScreen, spotRadiusScreen)
spotCtx.save(); spotCtx.save();
spotCtx.translate(spotRadiusScreen - scX, spotRadiusScreen - scY); spotCtx.translate(spotRadiusScreen - scX, spotRadiusScreen - scY);
spotCtx.drawImage(brightLogoImg, offsetX, 0, SVG_WIDTH * scale, SVG_HEIGHT * scale);
spotCtx.drawImage(
brightLogoImg,
offsetX,
0,
SVG_WIDTH * scale,
SVG_HEIGHT * scale
);
spotCtx.restore(); spotCtx.restore();
// Calculate the logo's intrinsic default brightness at this cursor position in hero_back.svg:
// - Logos under the glowing light orbs at (1325, 194) and (531, 194) are naturally bright
// - Logos in darker areas are naturally dark
// - Logos near the top taper to 0 via top atmospheric fade
const dLeft = Math.hypot((currentX - 531) / 220, (currentY - 194) / 180); const dLeft = Math.hypot((currentX - 531) / 220, (currentY - 194) / 180);
const dRight = Math.hypot((currentX - 1325) / 220, (currentY - 194) / 180); const dRight = Math.hypot((currentX - 1325) / 220, (currentY - 194) / 180);
const orbLight = Math.max(0, 1 - Math.min(dLeft, dRight)); const orbLight = Math.max(0, 1 - Math.min(dLeft, dRight));
@ -226,52 +218,62 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
const topFade = tTop * tTop * (3 - 2 * tTop); const topFade = tTop * tTop * (3 - 2 * tTop);
const defaultBrightness = (0.2 + 0.8 * orbLight) * topFade; const defaultBrightness = (0.2 + 0.8 * orbLight) * topFade;
const peakBoost = LOGO_HOVER_BRIGHTNESS * (0.2 + 0.8 * defaultBrightness) * topFade * currentStrength;
const peakBoost =
LOGO_HOVER_BRIGHTNESS *
(0.2 + 0.8 * defaultBrightness) *
topFade *
currentStrength;
// Feather with smooth radial gradient centered at (spotRadiusScreen, spotRadiusScreen):
spotCtx.globalCompositeOperation = "destination-in"; spotCtx.globalCompositeOperation = "destination-in";
const rad = spotCtx.createRadialGradient( const rad = spotCtx.createRadialGradient(
spotRadiusScreen, spotRadiusScreen, 0,
spotRadiusScreen, spotRadiusScreen, spotRadiusScreen
spotRadiusScreen,
spotRadiusScreen,
0,
spotRadiusScreen,
spotRadiusScreen,
spotRadiusScreen
); );
rad.addColorStop(0, `rgba(255, 255, 255, ${peakBoost.toFixed(3)})`); rad.addColorStop(0, `rgba(255, 255, 255, ${peakBoost.toFixed(3)})`);
rad.addColorStop(0.5, `rgba(255, 255, 255, ${(peakBoost * 0.45).toFixed(3)})`);
rad.addColorStop(0.85, `rgba(255, 255, 255, ${(peakBoost * 0.12).toFixed(3)})`);
rad.addColorStop(
0.5,
`rgba(255, 255, 255, ${(peakBoost * 0.45).toFixed(3)})`
);
rad.addColorStop(
0.85,
`rgba(255, 255, 255, ${(peakBoost * 0.12).toFixed(3)})`
);
rad.addColorStop(1, "rgba(255, 255, 255, 0)"); rad.addColorStop(1, "rgba(255, 255, 255, 0)");
spotCtx.fillStyle = rad; spotCtx.fillStyle = rad;
spotCtx.fillRect(0, 0, spotSize, spotSize); spotCtx.fillRect(0, 0, spotSize, spotSize);
spotCtx.globalCompositeOperation = "source-over"; spotCtx.globalCompositeOperation = "source-over";
// Blit the illuminated logo spotlight onto the main canvas
ctx.drawImage(spotCanvas, scX - spotRadiusScreen, scY - spotRadiusScreen, spotSize, spotSize);
ctx.drawImage(
spotCanvas,
scX - spotRadiusScreen,
scY - spotRadiusScreen,
spotSize,
spotSize
);
} }
}; };
// Smooth animation loop for subtle acoustic dot waviness and hover reaction
const loop = () => { const loop = () => {
if (isHovering) { if (isHovering) {
currentX += (targetX - currentX) * LERP_LAG; currentX += (targetX - currentX) * LERP_LAG;
currentY += (targetY - currentY) * LERP_LAG; currentY += (targetY - currentY) * LERP_LAG;
currentStrength += (targetStrength - currentStrength) * FADE_IN_LAG; currentStrength += (targetStrength - currentStrength) * FADE_IN_LAG;
} else {
} else if (currentStrength > 0.001) {
currentStrength += (0 - currentStrength) * FADE_OUT_LAG; currentStrength += (0 - currentStrength) * FADE_OUT_LAG;
}
draw();
if (isHovering || currentStrength > 0.005) {
animFrameId = requestAnimationFrame(loop);
} else { } else {
currentStrength = 0; currentStrength = 0;
draw();
animFrameId = null;
} }
};
const startLoop = () => {
if (!animFrameId) {
const t = performance.now() * 0.001;
draw(t);
animFrameId = requestAnimationFrame(loop); animFrameId = requestAnimationFrame(loop);
}
}; };
const handleMouseMove = (e: MouseEvent) => { const handleMouseMove = (e: MouseEvent) => {
@ -279,7 +281,6 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
const targetArea = section || canvas; const targetArea = section || canvas;
const sRect = targetArea.getBoundingClientRect(); const sRect = targetArea.getBoundingClientRect();
// Check if cursor is anywhere within the hero section
if ( if (
e.clientX >= sRect.left && e.clientX >= sRect.left &&
e.clientX <= sRect.right && e.clientX <= sRect.right &&
@ -287,7 +288,6 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
e.clientY <= sRect.bottom e.clientY <= sRect.bottom
) { ) {
const cRect = canvas.getBoundingClientRect(); const cRect = canvas.getBoundingClientRect();
// Convert client coordinates to SVG grid coordinate space
targetX = (e.clientX - cRect.left - offsetX) / scale; targetX = (e.clientX - cRect.left - offsetX) / scale;
targetY = (e.clientY - cRect.top) / scale; targetY = (e.clientY - cRect.top) / scale;
targetStrength = 1; targetStrength = 1;
@ -297,25 +297,23 @@ export function HeroDotCanvas({ sectionRef }: HeroDotCanvasProps) {
currentX = targetX; currentX = targetX;
currentY = targetY; currentY = targetY;
} }
startLoop();
} else if (isHovering) { } else if (isHovering) {
targetStrength = 0; targetStrength = 0;
isHovering = false; isHovering = false;
startLoop();
} }
}; };
const handleMouseLeave = () => { const handleMouseLeave = () => {
targetStrength = 0; targetStrength = 0;
isHovering = false; isHovering = false;
startLoop();
}; };
resize(); resize();
const ro = new ResizeObserver(() => resize()); const ro = new ResizeObserver(() => resize());
ro.observe(canvas); ro.observe(canvas);
animFrameId = requestAnimationFrame(loop);
window.addEventListener("mousemove", handleMouseMove, { passive: true }); window.addEventListener("mousemove", handleMouseMove, { passive: true });
window.addEventListener("mouseleave", handleMouseLeave); window.addEventListener("mouseleave", handleMouseLeave);

2
components/sections/HeroSection.tsx

@ -17,7 +17,7 @@ export function HeroSection() {
{/* Background Graphic & Curve (back_4178_60221: x: 32, y: 230, w: 1856, h: 566) */} {/* Background Graphic & Curve (back_4178_60221: x: 32, y: 230, w: 1856, h: 566) */}
<div className="absolute top-[230px] left-1/2 -translate-x-1/2 w-[1856px] max-w-[calc(100vw-64px)] h-[566px] rounded-b-[32px] overflow-hidden z-0"> <div className="absolute top-[230px] left-1/2 -translate-x-1/2 w-[1856px] max-w-[calc(100vw-64px)] h-[566px] rounded-b-[32px] overflow-hidden z-0">
<Image <Image
src="/assets/images/hero_back.svg"
src="/assets/images/hero_back.svg?v=faded_waves_v8"
alt="" alt=""
fill fill
priority priority

35
public/assets/images/hero_back.svg

@ -1016,19 +1016,29 @@
<path d="M567.876 344.795C295.596 341.558 23.316 330.933 -220.116 318.315C-233.837 317.604 -247.467 316.886 -261 316.163V614H-220.116H567.876H2117V316C1603.93 330.781 1089.77 350.894 567.876 344.795Z" fill="#001766"/> <path d="M567.876 344.795C295.596 341.558 23.316 330.933 -220.116 318.315C-233.837 317.604 -247.467 316.886 -261 316.163V614H-220.116H567.876H2117V316C1603.93 330.781 1089.77 350.894 567.876 344.795Z" fill="#001766"/>
</g> </g>
<g filter="url(#filter1_f_4179_62380)"> <g filter="url(#filter1_f_4179_62380)">
<path d="M-32 854.998L1888 855V255.003C1888 255.003 1536.5 335 928 335.001C319.5 335.003 -32 255 -32 255V854.998Z" fill="#0029B2"/>
<path d="M-32 854.998L1888 855V255.003C1888 255.003 1536.5 335 928 335.001C319.5 335.003 -32 255 -32 255V854.998Z" fill="#0029B2">
<animate attributeName="d" dur="5.2s" repeatCount="indefinite" values="M-32 855L1888 855V255C1888 255 1536.5 335 928 335C319.5 335 -32 255 -32 255V855Z;M-32 855L1888 855V170C1888 170 1480 260 928 445C380 250 -32 330 -32 330V855Z;M-32 855L1888 855V330C1888 330 1590 410 928 235C260 420 -32 170 -32 170V855Z;M-32 855L1888 855V215C1888 215 1505 295 928 375C345 295 -32 285 -32 285V855Z;M-32 855L1888 855V255C1888 255 1536.5 335 928 335C319.5 335 -32 255 -32 255V855Z" />
</path>
</g> </g>
<g filter="url(#filter2_f_4179_62380)"> <g filter="url(#filter2_f_4179_62380)">
<path d="M-32 804.998L1888 805V305.002C1888 305.002 1532.5 385.001 928 385.001C323.5 385.001 -32 305 -32 305V804.998Z" fill="#3D6FE5"/>
<path d="M-32 804.998L1888 805V305.002C1888 305.002 1532.5 385.001 928 385.001C323.5 385.001 -32 305 -32 305V804.998Z" fill="#3D6FE5">
<animate attributeName="d" dur="5.8s" repeatCount="indefinite" values="M-32 805L1888 805V305C1888 305 1532.5 385 928 385C323.5 385 -32 305 -32 305V805Z;M-32 805L1888 805V220C1888 220 1475 310 928 495C385 300 -32 380 -32 380V805Z;M-32 805L1888 805V380C1888 380 1590 460 928 285C260 470 -32 220 -32 220V805Z;M-32 805L1888 805V265C1888 265 1505 345 928 425C345 345 -32 335 -32 335V805Z;M-32 805L1888 805V305C1888 305 1532.5 385 928 385C323.5 385 -32 305 -32 305V805Z" />
</path>
</g> </g>
<g filter="url(#filter3_f_4179_62380)">
<path d="M-32 754.999L1888 755V355.002C1888 355.002 1532.5 435.001 928 435.001C323.5 435.001 -32 355 -32 355V754.999Z" fill="#4B80FF"/>
<g filter="url(#filter3_f_4179_62380)" mask="url(#waveFadeMask)">
<path d="M-32 754.999L1888 755V355.002C1888 355.002 1532.5 435.001 928 435.001C323.5 435.001 -32 355 -32 355V754.999Z" fill="#4B80FF">
<animate attributeName="d" dur="7.4s" repeatCount="indefinite" values="M-32 755L1888 755V355C1888 355 1532.5 435 928 435C323.5 435 -32 355 -32 355V755Z;M-32 755L1888 755V270C1888 270 1475 360 928 545C385 350 -32 430 -32 430V755Z;M-32 755L1888 755V430C1888 430 1590 510 928 335C260 520 -32 270 -32 270V755Z;M-32 755L1888 755V315C1888 315 1505 395 928 475C345 395 -32 385 -32 385V755Z;M-32 755L1888 755V355C1888 355 1532.5 435 928 435C323.5 435 -32 355 -32 355V755Z" />
</path>
</g> </g>
<g filter="url(#filter4_f_4179_62380)" style="mix-blend-mode:plus-lighter">
<path d="M-32 704.999L1888 705V405.001C1888 405.001 1531 485.001 928 485.001C325 485.001 -32 405 -32 405V704.999Z" fill="#2D4D99"/>
<g filter="url(#filter4_f_4179_62380)" mask="url(#waveFadeMask)" style="mix-blend-mode:plus-lighter">
<!-- <path d="M-32 704.999L1888 705V405.001C1888 405.001 1531 485.001 928 485.001C325 485.001 -32 405 -32 405V704.999Z" fill="#2D4D99">
<animate attributeName="d" dur="5.6s" repeatCount="indefinite" values="M-32 705L1888 705V405C1888 405 1531 485 928 485C325 485 -32 405 -32 405V705Z;M-32 705L1888 705V320C1888 320 1475 410 928 595C385 400 -32 480 -32 480V705Z;M-32 705L1888 705V480C1888 480 1590 560 928 385C260 570 -32 320 -32 320V705Z;M-32 705L1888 705V365C1888 365 1505 445 928 525C345 445 -32 435 -32 435V705Z;M-32 705L1888 705V405C1888 405 1531 485 928 485C325 485 -32 405 -32 405V705Z" />
</path> -->
</g> </g>
<g filter="url(#filter5_f_4179_62380)">
<path d="M-32 654.999L1888 655V455.001C1888 455.001 1532.5 535 928 535C323.5 535 -32 455 -32 455V654.999Z" fill="white"/>
<g filter="url(#filter5_f_4179_62380)" mask="url(#waveFadeMask)">
<!-- <path d="M-32 654.999L1888 655V455.001C1888 455.001 1532.5 535 928 535C323.5 535 -32 455 -32 455V654.999Z" fill="white">
<animate attributeName="d" dur="6.0s" repeatCount="indefinite" values="M-32 655L1888 655V455C1888 455 1532.5 535 928 535C323.5 535 -32 455 -32 455V655Z;M-32 655L1888 655V370C1888 370 1475 460 928 645C385 450 -32 530 -32 530V655Z;M-32 655L1888 655V530C1888 530 1590 610 928 435C260 620 -32 370 -32 370V655Z;M-32 655L1888 655V415C1888 415 1505 495 928 575C345 495 -32 485 -32 485V655Z;M-32 655L1888 655V455C1888 455 1532.5 535 928 535C323.5 535 -32 455 -32 455V655Z" />
</path> -->
</g> </g>
<g opacity="0.9"> <g opacity="0.9">
<path d="M1344.17 392.934C1343.49 392.934 1342.95 393.481 1342.95 394.157C1342.95 394.832 1343.49 395.379 1344.17 395.379C1344.84 395.379 1345.39 394.832 1345.39 394.157C1345.39 393.481 1344.84 392.934 1344.17 392.934Z" fill="#9ECBFF"/> <path d="M1344.17 392.934C1343.49 392.934 1342.95 393.481 1342.95 394.157C1342.95 394.832 1343.49 395.379 1344.17 395.379C1344.84 395.379 1345.39 394.832 1345.39 394.157C1345.39 393.481 1344.84 392.934 1344.17 392.934Z" fill="#9ECBFF"/>
@ -1202,6 +1212,15 @@
<stop stop-color="#03070D"/> <stop stop-color="#03070D"/>
<stop offset="1" stop-color="#03070D" stop-opacity="0"/> <stop offset="1" stop-color="#03070D" stop-opacity="0"/>
</linearGradient> </linearGradient>
<linearGradient id="waveFadeGrad" x1="0" y1="50" x2="0" y2="380" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="white" stop-opacity="0"/>
<stop offset="0.35" stop-color="white" stop-opacity="0.2"/>
<stop offset="0.65" stop-color="white" stop-opacity="0.75"/>
<stop offset="1" stop-color="white" stop-opacity="1"/>
</linearGradient>
<mask id="waveFadeMask" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2100" height="1000">
<rect x="-100" y="-100" width="2100" height="1000" fill="url(#waveFadeGrad)"/>
</mask>
<clipPath id="clip0_4179_62380"> <clipPath id="clip0_4179_62380">
<path d="M0 0H1856V514.8C1856 532.722 1856 541.683 1852.51 548.528C1849.44 554.549 1844.55 559.444 1838.53 562.512C1831.68 566 1822.72 566 1804.8 566H51.1999C33.2783 566 24.3175 566 17.4723 562.512C11.4511 559.444 6.55574 554.549 3.48779 548.528C0 541.683 0 532.722 0 514.8V0Z" fill="white"/> <path d="M0 0H1856V514.8C1856 532.722 1856 541.683 1852.51 548.528C1849.44 554.549 1844.55 559.444 1838.53 562.512C1831.68 566 1822.72 566 1804.8 566H51.1999C33.2783 566 24.3175 566 17.4723 562.512C11.4511 559.444 6.55574 554.549 3.48779 548.528C0 541.683 0 532.722 0 514.8V0Z" fill="white"/>
</clipPath> </clipPath>

Loading…
Cancel
Save