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" />
|
<div className="absolute inset-0 bg-black/50" />
|
||||||
|
|
||||||
{/* Call card */}
|
{/* Call card */}
|
||||||
<div className="relative glass-modal rounded-lg w-[340px] overflow-hidden animate-fade-in animate-slide-up">
|
<div className="relative glass-modal call-refraction rounded-lg w-[340px] overflow-hidden animate-fade-in animate-slide-up">
|
||||||
{/* Ripple rings */}
|
{/* Liquid ripple orbs — soft radial gradients with blur */}
|
||||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
{[0, 1.3, 2.6].map((delay, i) => (
|
||||||
<div
|
<div
|
||||||
className="absolute top-1/2 left-1/2 w-[160px] h-[160px] rounded-full border border-status-online/30 animate-call-ripple"
|
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"
|
||||||
<div
|
style={{
|
||||||
className="absolute top-1/2 left-1/2 w-[160px] h-[160px] rounded-full border border-status-online/30 animate-call-ripple"
|
animationDelay: `${delay}s`,
|
||||||
style={{ animationDelay: '1.5s' }}
|
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>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* 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 */}
|
{/* Caller avatar */}
|
||||||
<div className="rounded-full animate-call-glow">
|
<div className="rounded-full animate-call-glow">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@@ -350,35 +350,94 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── Incoming Call Animations ── */
|
/* ── Incoming Call Animations ── */
|
||||||
@keyframes callRipple {
|
|
||||||
0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.6; }
|
/* Liquid ripple: soft gradient orb that expands and dissolves */
|
||||||
100% { transform: translate(-50%, -50%) scale(1.8); opacity: 0; }
|
@keyframes callRippleLiquid {
|
||||||
|
0% {
|
||||||
|
scale: 0.3;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
opacity: 0.12;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
scale: 2.8;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes callGlow {
|
/* Soft multi-layered halo around avatar */
|
||||||
0%, 100% { box-shadow: 0 0 20px rgba(134, 239, 172, 0.15); }
|
@keyframes callGlowSoft {
|
||||||
50% { box-shadow: 0 0 30px rgba(134, 239, 172, 0.25); }
|
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 {
|
/* Traveling light refraction across glass card surface */
|
||||||
0%, 100% { box-shadow: 0 0 12px rgba(134, 239, 172, 0.15); }
|
@keyframes callRefraction {
|
||||||
50% { box-shadow: 0 0 20px rgba(134, 239, 172, 0.3); }
|
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 {
|
.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 {
|
.animate-call-glow {
|
||||||
animation: callGlow 3s ease-in-out infinite;
|
animation: callGlowSoft 4s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate-call-button-glow {
|
.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) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.animate-call-ripple,
|
.animate-call-ripple,
|
||||||
.animate-call-glow,
|
.animate-call-glow,
|
||||||
.animate-call-button-glow { animation: none !important; }
|
.animate-call-button-glow { animation: none !important; }
|
||||||
|
.call-refraction::after { animation: none !important; opacity: 0; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user