fix(pulse): tone down white core (#10)

* feat: random light pulse along threads + box outlines

A blurred light pulse glides along one of the 5 wave threads
(wave1/2/3, thread1/2) every 2.5-7s. Color matches the active
theme (cyan on home/portfolio/about, pink/magenta on contact).

Pulse also follows the outline of designated boxes marked with
data-trail-box:
  - Home: 'Looking for inspiration?' + 'Ready to collaborate?'
  - Contact: 'Waiting to hear from you' card

Boxes are rebuilt on every pulse so they stay aligned during scroll
and respect viewport (off-screen boxes are skipped).

Pulse uses requestAnimationFrame + path.getPointAtLength for native
smoothness, fade-in 15% / hold 70% / fade-out 15%, screen blend
mode so it blends with the dark background.

* feat(pulse): slower, brighter, comet-shaped pulse along paths

Slower (9-13s per glide vs 4.5-6.5s), three-layer comet shape
(soft halo + mid glow + bright core), rotated to path tangent,
ease-in-out timing, mix-blend-mode screen.

Fixes: pulse not tracking path was a parallax-offset coordinate
mismatch. Cleaned up via getSpeedKey() helper.

* fix(pulse): tone down white core so theme color dominates

Core was pure white (#ffffff) which washed out the theme color.
Now tinted (#fdf4ff for purple, #f0fdfa for cyan) and smaller
(10x3 vs 14x4) with 75% opacity so the purple/pink and cyan
glow layers come through more visibly.

* feat(pulse): double the glide duration

Threads: 18-26s (was 9-13s). Boxes: 14-18s (was 7-9s).
This commit is contained in:
Linus Olofsson
2026-05-20 23:02:28 +02:00
committed by GitHub
parent 7bad958a38
commit af9a71a37e
+4 -4
View File
@@ -6,7 +6,7 @@ const mainColor = theme === 'purple' ? '#c026d3' : '#4fd1c5';
const secondaryColor = theme === 'purple' ? '#db2777' : '#22d3ee';
const pulseMain = theme === 'purple' ? '#f0abfc' : '#a5f3fc';
const pulseSec = theme === 'purple' ? '#fbcfe8' : '#cffafe';
const pulseCore = '#ffffff';
const pulseCore = theme === 'purple' ? '#fdf4ff' : '#f0fdfa';
---
<div
@@ -73,7 +73,7 @@ const pulseCore = '#ffffff';
<g id="pulse-blob" opacity="0">
<ellipse id="pulse-halo" rx="55" ry="22" fill="url(#pulseHaloGradient)" filter="url(#pulseGlowSoft)" />
<ellipse id="pulse-mid" rx="32" ry="11" fill="url(#pulseMidGradient)" filter="url(#pulseGlowMid)" />
<ellipse id="pulse-core" rx="14" ry="4" fill="url(#pulseCoreGradient)" filter="url(#pulseGlowSharp)" />
<ellipse id="pulse-core" rx="10" ry="3" fill="url(#pulseCoreGradient)" filter="url(#pulseGlowSharp)" opacity="0.75" />
</g>
</g>
</svg>
@@ -255,8 +255,8 @@ const pulseCore = '#ffffff';
const choice = allTargets[Math.floor(Math.random() * allTargets.length)];
const isBox = choice.getAttribute('data-trail-box-path') === 'true';
const duration = isBox
? 7000 + Math.random() * 2000
: 9000 + Math.random() * 4000;
? 14000 + Math.random() * 4000
: 18000 + Math.random() * 8000;
runPulse(choice, duration);
schedule();
}