fix: soften incoming call animations with liquid ripple and refraction effects
Replace hard-edged ring ripples with blurred radial gradient orbs, add subtle glass refraction shimmer, and use gentler glow/breathing curves for a calmer incoming call experience.
This commit is contained in:
@@ -54,20 +54,23 @@ export function IncomingCallModal() {
|
||||
<div className="absolute inset-0 bg-black/50" />
|
||||
|
||||
{/* Call card */}
|
||||
<div className="relative glass-modal rounded-lg w-[340px] overflow-hidden animate-fade-in animate-slide-up">
|
||||
{/* Ripple rings */}
|
||||
<div className="relative glass-modal call-refraction rounded-lg w-[340px] overflow-hidden animate-fade-in animate-slide-up">
|
||||
{/* Liquid ripple orbs — soft radial gradients with blur */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div
|
||||
className="absolute top-1/2 left-1/2 w-[160px] h-[160px] rounded-full border border-status-online/30 animate-call-ripple"
|
||||
/>
|
||||
<div
|
||||
className="absolute top-1/2 left-1/2 w-[160px] h-[160px] rounded-full border border-status-online/30 animate-call-ripple"
|
||||
style={{ animationDelay: '1.5s' }}
|
||||
/>
|
||||
{[0, 1.3, 2.6].map((delay, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[180px] h-[180px] rounded-full blur-xl animate-call-ripple"
|
||||
style={{
|
||||
animationDelay: `${delay}s`,
|
||||
background: 'radial-gradient(circle, rgba(134,239,172,0.18) 0%, rgba(134,239,172,0.06) 35%, rgba(134,239,172,0.02) 55%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative p-8 flex flex-col items-center gap-4">
|
||||
<div className="relative z-[2] p-8 flex flex-col items-center gap-4">
|
||||
{/* Caller avatar */}
|
||||
<div className="rounded-full animate-call-glow">
|
||||
<Avatar
|
||||
|
||||
@@ -350,35 +350,94 @@
|
||||
}
|
||||
|
||||
/* ── Incoming Call Animations ── */
|
||||
@keyframes callRipple {
|
||||
0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.6; }
|
||||
100% { transform: translate(-50%, -50%) scale(1.8); opacity: 0; }
|
||||
|
||||
/* Liquid ripple: soft gradient orb that expands and dissolves */
|
||||
@keyframes callRippleLiquid {
|
||||
0% {
|
||||
scale: 0.3;
|
||||
opacity: 0.45;
|
||||
}
|
||||
70% {
|
||||
opacity: 0.12;
|
||||
}
|
||||
100% {
|
||||
scale: 2.8;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes callGlow {
|
||||
0%, 100% { box-shadow: 0 0 20px rgba(134, 239, 172, 0.15); }
|
||||
50% { box-shadow: 0 0 30px rgba(134, 239, 172, 0.25); }
|
||||
/* Soft multi-layered halo around avatar */
|
||||
@keyframes callGlowSoft {
|
||||
0%, 100% {
|
||||
box-shadow:
|
||||
0 0 20px rgba(134, 239, 172, 0.06),
|
||||
0 0 40px rgba(134, 239, 172, 0.04),
|
||||
0 0 80px rgba(134, 239, 172, 0.02);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 24px rgba(134, 239, 172, 0.12),
|
||||
0 0 48px rgba(134, 239, 172, 0.06),
|
||||
0 0 96px rgba(134, 239, 172, 0.03);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes callButtonGlow {
|
||||
0%, 100% { box-shadow: 0 0 12px rgba(134, 239, 172, 0.15); }
|
||||
50% { box-shadow: 0 0 20px rgba(134, 239, 172, 0.3); }
|
||||
/* Traveling light refraction across glass card surface */
|
||||
@keyframes callRefraction {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(200%); }
|
||||
}
|
||||
|
||||
/* Gentle breathing glow on accept button */
|
||||
@keyframes callButtonBreath {
|
||||
0%, 100% {
|
||||
box-shadow:
|
||||
0 0 12px rgba(134, 239, 172, 0.08),
|
||||
0 0 28px rgba(134, 239, 172, 0.04);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 18px rgba(134, 239, 172, 0.16),
|
||||
0 0 36px rgba(134, 239, 172, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-call-ripple {
|
||||
animation: callRipple 3s ease-out infinite;
|
||||
animation: callRippleLiquid 4s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
|
||||
}
|
||||
|
||||
.animate-call-glow {
|
||||
animation: callGlow 3s ease-in-out infinite;
|
||||
animation: callGlowSoft 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-call-button-glow {
|
||||
animation: callButtonGlow 2s ease-in-out infinite;
|
||||
animation: callButtonBreath 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Light refraction shimmer overlay on the call card */
|
||||
.call-refraction::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
background: linear-gradient(
|
||||
105deg,
|
||||
transparent 0%,
|
||||
transparent 35%,
|
||||
rgba(134, 239, 172, 0.03) 42%,
|
||||
rgba(134, 239, 172, 0.05) 50%,
|
||||
rgba(134, 239, 172, 0.03) 58%,
|
||||
transparent 65%,
|
||||
transparent 100%
|
||||
);
|
||||
animation: callRefraction 6s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.animate-call-ripple,
|
||||
.animate-call-glow,
|
||||
.animate-call-button-glow { animation: none !important; }
|
||||
.call-refraction::after { animation: none !important; opacity: 0; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user