From 57767a112e390be07aaf008ce7082bd3cce9e41c Mon Sep 17 00:00:00 2001 From: Linus Olofsson <61837116+LinusOlofsson-maker@users.noreply.github.com> Date: Thu, 21 May 2026 04:34:19 +0200 Subject: [PATCH] fix(logo-pulse): visible entry/exit threads + restore pulse color (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(pulse): split halves now meet simultaneously + no backtracking Two bugs fixed after Linus feedback: 1. Path-form: top/bottom split halves used Bezier curves that could loop back on themselves when entry.x lay outside box X-range. Now use clamped startX/endX (max(xL+r, min(xR-r, entry.x))) so pathen alltid rör sig framåt (entry.x → exit.x), aldrig vänder. 2. Synchronized meeting: previously each blob moved at fixed velocity along its own path → shorter path arrived first and waited. Now both blobs share a phase2T (0→1) progress fraction, so they meet at exit-point simultaneously. The path with different length simply moves at a slightly different speed (averaged). Phase2 duration based on avg(topLen,bottomLen)/velocity so total animation time stays consistent. * feat: logo-pulse with pink->green color transition Adds a 4th pulse target: the IMAGES BY OLOFSSON hero-text logo. 20% chance per pulse-slot when logo is visible (footer scrolled in). Flow: 1. New purple wave-thread on bottom-left (mirror of cyan wave1 on right) 2. Pulse glides in along purple thread to logo-left edge 3. Pulse enters logo + tints smoky-path stroke pink (#e879f9) + adds pink text-shadow halo on h1 4. Mid-passage: tint transitions to green (#4fd1c5) — matches default smoke + cyan glow 5. Pulse exits logo via wave1 (existing cyan thread on right) 6. Logo tint reverts to default (white smokeShift animation) CSS-side: data-logo-tint attribute on #text-wrapper drives stroke + text-shadow overrides with 0.6-0.8s transitions for smooth fade. * fix(logo-pulse): dynamic paths anchored to logo + 50% probability Previous version tried to use existing wave1+threadPurple paths for logo-pulse glide-in/out, but those paths are in SVG-fixed coordinates that don't align with logo's viewport position when hero is scrolled into view. wave1 has translateX(2283) which pushes it off-screen for ultrawide viewports. Fix: build dynamic Bezier paths anchored to the logo's actual getBoundingClientRect() position at pulse-time: - Entry path: from (offLeft, logoY+dipOffset) curves up into logo-left - Exit path: from logo-right curves up to (offRight, logoY-riseOffset) Paths are appended to box-trail-group, used for one pulse, then removed in cleanup. No reliance on fixed wave-thread coordinates. Also raises LOGO_PROBABILITY 20%->50% so the effect is visible more often when hero is in view. * fix(logo-pulse): visible entry/exit threads + restore pulse color after Two bugs fixed: 1. Entry+exit paths were stroke=transparent — pulse appeared to spawn out of nothing. Now stroke=url(#gradPurple) on entry (subtle pink thread visible from off-screen left) and stroke=url(#gradMain) on exit (cyan thread visible going off-screen right). Both at stroke-width 0.8 + opacity 0.55 to match other wave-thread style. 2. After logo-pulse completed, pulse-gradient stops were left in pink state — next regular wave-pulse rendered as stale pink instead of cyan/theme color. Now updatePulseColors(false) is called in cleanup to restore default cyan-tema. --- src/components/WaveBackground.astro | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/WaveBackground.astro b/src/components/WaveBackground.astro index 98f5b58..cee0638 100644 --- a/src/components/WaveBackground.astro +++ b/src/components/WaveBackground.astro @@ -447,17 +447,23 @@ const pulseCore = theme === 'purple' ? '#fdf4ff' : '#f0fdfa'; const NS_local = 'http://www.w3.org/2000/svg'; // Entry path (lila): från off-screen vänster (dipY) kurvar upp till logo-left + // SYNLIG via gradPurple stroke så användaren ser varifrån pulsen kommer const entryPath = document.createElementNS(NS_local, 'path'); entryPath.setAttribute('d', `M ${offLeft} ${dipY} C ${logoLeftX - 200} ${dipY}, ${logoLeftX - 80} ${logoY}, ${logoLeftX} ${logoY}`); entryPath.setAttribute('fill', 'none'); - entryPath.setAttribute('stroke', 'transparent'); + entryPath.setAttribute('stroke', 'url(#gradPurple)'); + entryPath.setAttribute('stroke-width', '0.8'); + entryPath.setAttribute('opacity', '0.55'); boxGroup.appendChild(entryPath); - // Exit path (grön): från logo-right kurvar upp till off-screen höger (riseY) + // Exit path (cyan): från logo-right kurvar upp till off-screen höger (riseY) + // SYNLIG via gradMain (default cyan) så användaren ser varthän pulsen går const exitPath = document.createElementNS(NS_local, 'path'); exitPath.setAttribute('d', `M ${logoRightX} ${logoY} C ${logoRightX + 80} ${logoY}, ${logoRightX + 200} ${riseY}, ${offRight} ${riseY}`); exitPath.setAttribute('fill', 'none'); - exitPath.setAttribute('stroke', 'transparent'); + exitPath.setAttribute('stroke', 'url(#gradMain)'); + exitPath.setAttribute('stroke-width', '0.8'); + exitPath.setAttribute('opacity', '0.55'); boxGroup.appendChild(exitPath); const entryLen = entryPath.getTotalLength(); @@ -539,6 +545,9 @@ const pulseCore = theme === 'purple' ? '#fdf4ff' : '#f0fdfa'; // Cleanup dynamic paths if (entryPath.parentNode) entryPath.parentNode.removeChild(entryPath); if (exitPath.parentNode) exitPath.parentNode.removeChild(exitPath); + // ÅTERSTÄLL pulse-gradient till default cyan-tema så nästa + // vanliga wave-pulse inte har stale rosa färg + updatePulseColors(false); isPulsing = false; } }