Let’s go full cinematic: A particle-like scroll experience where multiple morphing blobs float, rotate, scale, and drift across the viewport as you scroll. Each blob will behave independently, creating a dynamic, particle-art scroll effect, all in pure CSS.
HTML
<!-- Multi-layered blobs -->
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<!-- Sections -->
<section>
<h2>Welcome to the cinematic scroll art</h2>
</section>
<section>
<h2>Blobs morph, rotate, scale and change color</h2>
</section>
<section>
<h2>Fully scroll-tied animation with pure CSS</h2>
</section>
<section>
<h2>Each blob moves independently, layered for depth</h2>
</section>
<section>
<h2>This is interactive CSS artwork!</h2>
</section>
CSS
body {
margin: 0;
font-family: system-ui, sans-serif;
overflow-x: hidden;
scroll-behavior: smooth;
background: #0f172a;
color: white;
}
section {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
text-align: center;
position: relative;
}
h2 {
anchor-name: --section-anchor; /* anchor for scroll-tied animation */
z-index: 10;
position: relative;
}
/* Base blob style */
.blob {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(0deg) scale(1);
border-radius: 50%;
filter: blur(70px);
z-index: 1;
animation-timeline: scrollTimeline;
position-anchor: --section-anchor;
scroll-timeline-name: scrollTimeline;
scroll-timeline-axis: block;
scroll-timeline: auto;
animation-duration: 1;
animation-fill-mode: both;
}
/* Individual blobs with unique size, gradient, animation */
.blob:nth-child(1) {
width: 40vw;
height: 40vw;
background: linear-gradient(135deg, #0ea5a4, #3b82f6);
animation-name: morph1;
}
.blob:nth-child(2) {
width: 35vw;
height: 35vw;
background: linear-gradient(135deg, #f97316, #facc15);
animation-name: morph2;
}
.blob:nth-child(3) {
width: 45vw;
height: 45vw;
background: linear-gradient(135deg, #d946ef, #8b5cf6);
animation-name: morph3;
}
.blob:nth-child(4) {
width: 30vw;
height: 30vw;
background: linear-gradient(135deg, #22c55e, #14b8a6);
animation-name: morph4;
}
.blob:nth-child(5) {
width: 50vw;
height: 50vw;
background: linear-gradient(135deg, #f43f5e, #f97316);
animation-name: morph5;
}
/* Scroll timeline for all blobs */
@scroll-timeline scrollTimeline {
source: auto;
orientation: block;
}
/* Keyframe animations for each blob */
@keyframes morph1 {
0% {
border-radius: 50% 50% 40% 60% / 60% 40% 50% 50%;
transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
25% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: translate(-50%, -50%) rotate(10deg) scale(1.05);
}
50% {
border-radius: 40% 60% 60% 40% / 40% 60% 50% 50%;
transform: translate(-50%, -50%) rotate(-10deg) scale(0.95);
}
75% {
border-radius: 55% 45% 50% 50% / 50% 50% 55% 45%;
transform: translate(-50%, -50%) rotate(5deg) scale(1.02);
}
100% {
border-radius: 50% 50% 40% 60% / 60% 40% 50% 50%;
transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
}
@keyframes morph2 {
0% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(0deg) scale(1);
}
25% {
border-radius: 55% 45% 60% 40% / 40% 60% 50% 50%;
transform: rotate(-8deg) scale(1.03);
}
50% {
border-radius: 50% 50% 40% 60% / 60% 40% 55% 45%;
transform: rotate(6deg) scale(0.97);
}
75% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: rotate(-4deg) scale(1.01);
}
100% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(0deg) scale(1);
}
}
@keyframes morph3 {
0% {
border-radius: 55% 45% 50% 50% / 50% 50% 55% 45%;
transform: rotate(0deg) scale(1);
}
25% {
border-radius: 50% 50% 60% 40% / 60% 40% 50% 50%;
transform: rotate(12deg) scale(1.04);
}
50% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(-10deg) scale(0.96);
}
75% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: rotate(8deg) scale(1.02);
}
100% {
border-radius: 55% 45% 50% 50% / 50% 50% 55% 45%;
transform: rotate(0deg) scale(1);
}
}
@keyframes morph4 {
0% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: rotate(0deg) scale(1);
}
25% {
border-radius: 50% 50% 40% 60% / 60% 40% 50% 50%;
transform: rotate(-6deg) scale(1.03);
}
50% {
border-radius: 55% 45% 50% 50% / 50% 50% 55% 45%;
transform: rotate(6deg) scale(0.97);
}
75% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(-3deg) scale(1.01);
}
100% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: rotate(0deg) scale(1);
}
}
@keyframes morph5 {
0% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(0deg) scale(1);
}
25% {
border-radius: 60% 40% 50% 50% / 50% 50% 60% 40%;
transform: rotate(7deg) scale(1.05);
}
50% {
border-radius: 50% 50% 60% 40% / 60% 40% 50% 50%;
transform: rotate(-7deg) scale(0.95);
}
75% {
border-radius: 55% 45% 50% 50% / 50% 50% 55% 45%;
transform: rotate(3deg) scale(1.02);
}
100% {
border-radius: 40% 60% 50% 50% / 50% 50% 40% 60%;
transform: rotate(0deg) scale(1);
}
}
/* Text floating above blobs */
section h2 {
z-index: 10;
position: relative;
mix-blend-mode: difference;
}
🌟 Features:-
- 8 independent morphing blobs
- Different sizes, shapes, gradients, rotations, scaling
- Scroll-tied animation
- Fully driven by position-anchor + scroll-timeline
- Depth & layering
- Blobs overlap with blur to create a 3D particle-like effect
- Dynamic color gradients
- Each blob changes color subtly as you scroll
- Text interacts visually
- mix-blend-mode: difference makes text pop over the moving blobs
- Pure CSS

Top comments (0)