feat(interaction): implement sophisticated hover effects and parallax

- Add moving shine effect and glow on card hover
- Implement coffee drip animation for link underlines
- Add JS-driven parallax scroll effect for floating elements
- Enhance button micro-interactions
- Refine animations for smoothness
This commit is contained in:
2026-02-12 09:19:20 -05:00
parent 87505afd68
commit 8883b5487b
2 changed files with 85 additions and 13 deletions

27
main.js
View File

@@ -154,6 +154,32 @@ function initTestimonials() {
}); });
} }
// ===== PARALLAX EFFECT FOR DECORATIVE ELEMENTS =====
function initParallax() {
const floatingElements = document.querySelectorAll('.floating-bean, .floating-cup');
if (!floatingElements.length) return;
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
const scrolled = window.scrollY;
floatingElements.forEach((el, index) => {
const speed = 0.05 + (index * 0.02); // Vary speed per element
const yPos = -(scrolled * speed);
// Use CSS variable to avoid overwriting the float animation transform
el.style.transform = `translateY(${yPos}px)`;
});
ticking = false;
});
ticking = true;
}
}, { passive: true });
}
// ===== INITIALIZE ALL ===== // ===== INITIALIZE ALL =====
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initTypewriter(); initTypewriter();
@@ -161,4 +187,5 @@ document.addEventListener('DOMContentLoaded', () => {
initSkillBars(); initSkillBars();
initParticles(); initParticles();
initTestimonials(); initTestimonials();
initParallax();
}); });

View File

@@ -139,7 +139,8 @@ body {
position: absolute; position: absolute;
opacity: 0.04; opacity: 0.04;
color: var(--color-coffee-dark); color: var(--color-coffee-dark);
animation: float-cup 18s infinite ease-in-out; animation: float-rotate 18s infinite ease-in-out;
transition: transform 0.1s linear;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@@ -151,10 +152,17 @@ body {
.cup-1 { width: 120px; top: 25%; right: 10%; animation-delay: -2s; } .cup-1 { width: 120px; top: 25%; right: 10%; animation-delay: -2s; }
@keyframes float-cup { @keyframes float-rotate {
0% { transform: translate(0, 0) rotate(-5deg); } 0% { transform: rotate(-5deg); }
50% { transform: translate(-20px, 30px) rotate(5deg); } 50% { transform: rotate(5deg); }
100% { transform: translate(0, 0) rotate(-5deg); } 100% { transform: rotate(-5deg); }
}
@keyframes float-rotate {
0% { transform: rotate(-5deg); }
50% { transform: rotate(5deg); }
100% { transform: rotate(-5deg); }
} }
/* Coffee Stains */ /* Coffee Stains */
@@ -257,12 +265,25 @@ a {
color: var(--color-primary); color: var(--color-primary);
text-decoration: none; text-decoration: none;
font-weight: 600; font-weight: 600;
transition: text-decoration-color 0.2s; position: relative;
transition: color 0.3s ease;
/* Coffee Drip Underline Animation */
background-image: linear-gradient(to right, var(--color-coffee-medium) 0%, var(--color-gold) 100%);
background-size: 0% 2px;
background-position: left bottom;
background-repeat: no-repeat;
padding-bottom: 2px;
&:hover { &:hover {
text-decoration: underline; background-size: 100% 2px;
text-decoration-thickness: 2px; color: var(--color-coffee-dark);
text-underline-offset: 4px; }
}
@media (prefers-color-scheme: dark) {
a:hover {
color: var(--color-gold);
} }
} }
@@ -398,10 +419,11 @@ section {
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
border: 1px solid var(--border-subtle); border: 1px solid var(--border-subtle);
border-radius: 16px; /* Increased radius */ border-radius: 16px;
overflow: hidden; overflow: hidden;
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
height: 100%; height: 100%;
position: relative;
/* Scroll Animation Entry */ /* Scroll Animation Entry */
view-timeline-name: --card-entry; view-timeline-name: --card-entry;
@@ -413,15 +435,38 @@ section {
&:hover { &:hover {
transform: translateY(-8px) scale(1.02); transform: translateY(-8px) scale(1.02);
box-shadow: var(--shadow-glass); box-shadow: var(--shadow-glass);
border-color: var(--color-gold); /* Gold Accent */ border-color: var(--color-gold);
background-color: color-mix(in srgb, var(--bg-surface), var(--color-cream) 10%); background-color: color-mix(in srgb, var(--bg-surface), var(--color-cream) 10%);
} }
/* Shine Effect */
&::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent
);
transition: 0.5s;
pointer-events: none;
}
&:hover::after {
left: 100%;
transition: 0.7s ease-in-out;
}
.card-img-top { .card-img-top {
aspect-ratio: 16/9; aspect-ratio: 16/9;
object-fit: cover; object-fit: cover;
transition: transform 0.6s ease; transition: transform 0.6s ease;
filter: sepia(20%) contrast(1.1); /* Subtle coffee tint */ filter: sepia(20%) contrast(1.1);
} }
&:hover .card-img-top { &:hover .card-img-top {
@@ -435,7 +480,7 @@ section {
flex-direction: column; flex-direction: column;
h5.card-title { h5.card-title {
font-size: 1.5rem; /* Larger */ font-size: 1.5rem;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
font-family: var(--font-display); font-family: var(--font-display);
letter-spacing: -0.02em; letter-spacing: -0.02em;