This commit is contained in:
111
src/lib/components/BackgroundBlobs.svelte
Normal file
111
src/lib/components/BackgroundBlobs.svelte
Normal file
@@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
accentColor: string;
|
||||
breakColor: string;
|
||||
}
|
||||
|
||||
let { accentColor, breakColor }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
<!-- Gradient blobs -->
|
||||
<div
|
||||
class="blob blob-1"
|
||||
style="background: radial-gradient(circle, {accentColor} 0%, transparent 70%);"
|
||||
></div>
|
||||
<div
|
||||
class="blob blob-2"
|
||||
style="background: radial-gradient(circle, {breakColor} 0%, transparent 70%);"
|
||||
></div>
|
||||
<div
|
||||
class="blob blob-3"
|
||||
style="background: radial-gradient(circle, {accentColor} 0%, transparent 70%);"
|
||||
></div>
|
||||
<div
|
||||
class="blob blob-4"
|
||||
style="background: radial-gradient(circle, {breakColor} 0%, transparent 70%);"
|
||||
></div>
|
||||
|
||||
<!-- Film grain overlay -->
|
||||
<svg class="absolute inset-0 h-full w-full" style="opacity: 0.08; mix-blend-mode: overlay;">
|
||||
<filter id="grain-filter">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.45" numOctaves="3" stitchTiles="stitch">
|
||||
<animate
|
||||
attributeName="seed"
|
||||
from="0"
|
||||
to="100"
|
||||
dur="2s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</feTurbulence>
|
||||
</filter>
|
||||
<rect width="100%" height="100%" filter="url(#grain-filter)" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.blob {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
opacity: 0.4;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.blob-1 {
|
||||
top: -15%;
|
||||
left: -10%;
|
||||
animation: drift-1 30s ease-in-out infinite;
|
||||
}
|
||||
.blob-2 {
|
||||
bottom: -15%;
|
||||
right: -10%;
|
||||
animation: drift-2 35s ease-in-out infinite;
|
||||
}
|
||||
.blob-3 {
|
||||
top: 40%;
|
||||
right: -15%;
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
animation: drift-3 28s ease-in-out infinite;
|
||||
}
|
||||
.blob-4 {
|
||||
bottom: 20%;
|
||||
left: -15%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
animation: drift-4 32s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes drift-1 {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
20% { transform: translate(300px, 200px) scale(1.15); }
|
||||
40% { transform: translate(150px, 450px) scale(0.9); }
|
||||
60% { transform: translate(350px, 350px) scale(1.1); }
|
||||
80% { transform: translate(100px, 100px) scale(0.95); }
|
||||
}
|
||||
|
||||
@keyframes drift-2 {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
20% { transform: translate(-250px, -150px) scale(1.1); }
|
||||
40% { transform: translate(-100px, -400px) scale(0.95); }
|
||||
60% { transform: translate(-300px, -200px) scale(1.15); }
|
||||
80% { transform: translate(-50px, -300px) scale(0.9); }
|
||||
}
|
||||
|
||||
@keyframes drift-3 {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
25% { transform: translate(-300px, -200px) scale(1.1); }
|
||||
50% { transform: translate(-150px, 150px) scale(0.9); }
|
||||
75% { transform: translate(-350px, -50px) scale(1.15); }
|
||||
}
|
||||
|
||||
@keyframes drift-4 {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
25% { transform: translate(280px, -180px) scale(1.15); }
|
||||
50% { transform: translate(100px, 200px) scale(0.9); }
|
||||
75% { transform: translate(320px, 50px) scale(1.1); }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user