惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
V
Vulnerabilities – Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Proofpoint News Feed
G
GRAHAM CLULEY
P
Privacy International News Feed
The Hacker News
The Hacker News
Forbes - Security
Forbes - Security
U
Unit 42
N
News and Events Feed by Topic
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cisco Blogs
A
About on SuperTechFans
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
D
Docker
I
Intezer
Spread Privacy
Spread Privacy
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术
S
Security @ Cisco Blogs
F
Full Disclosure
S
Secure Thoughts
M
MIT News - Artificial intelligence
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
W
WeLiveSecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Project Zero
Project Zero
Recorded Future
Recorded Future
Cyberwarzone
Cyberwarzone
S
Security Affairs
AWS News Blog
AWS News Blog
H
Help Net Security
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
Vercel News
Vercel News
P
Proofpoint News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Register - Security
The Register - Security
S
Schneier on Security
F
Fortinet All Blogs
C
CERT Recently Published Vulnerability Notes
L
LINUX DO - 最新话题
T
Tor Project blog
T
The Exploit Database - CXSecurity.com
MongoDB | Blog
MongoDB | Blog
Webroot Blog
Webroot Blog

Codrops

The Art of Continuous Transformation: How Garden Eight Blends Integrity with Play | Codrops Building Cerebrium: Making Serverless Infrastructure Tangible | Codrops Building Ridgeline: Engineering a Real-Time 3D Experience in Webflow | Codrops Magnetic Commerce: Building the Dash Creative Website | Codrops The Craft Behind Memorable Digital Experiences: Inside Unseen Studio | Codrops ZERO: The Engineering Behind a Defiant Interactive Narrative | Codrops Meet the Speakers of the First Three.js Conference | Codrops The Architecture Behind Trionn: Coordinating GSAP, Three.js, Lenis, and Web Audio | Codrops Where Stories Become Interactive Worlds: How makemepulse Brings Ideas to Life Across Web, XR, and Beyond | Codrops The Sleepers: Creating an Atmospheric WebGL Experience with Lightweight Techniques | Codrops Building an Interactive Wave Propagation Cube Grid with Three.js | Codrops Ten Years Away: Designing an Interactive Comic for Studio375’s Tenth Anniversary | Codrops Building a Scroll-Driven 3D Gallery Using a Blender Camera Path with Three.js and GSAP | Codrops From Years of Client Work to a Next.js + Sanity Starter Kit | Codrops Sculpting a Digital Athlete: Capturing Stefanos Tsitsipas Beyond the Court | Codrops Building Persistent Page Transitions with WebGPU and Vanilla JavaScript | Codrops Inside Bisous: Designing an Editorial Experience for Cinematic CGI | Codrops Engineering the Web Experience Behind Shopify’s Spring ’26 Edition: Everywhere | Codrops Shaping Stories into Experience: The Work of Kevin Lam | Codrops Testing What Users Actually See with Vitest and Chromatic | Codrops Podium: Building a Website Where Running Becomes Storytelling | Codrops Designing Beyond the Surface: How DashDigital Turns Complexity into Clarity | Codrops Creative Entrepreneurship: Designing the Machine | Codrops Exploring 3D Image Rotations on Scroll | Codrops Always Building, Always Learning: Cyd Stumpel’s Journey Through the Modern Web | Codrops Designing A Better Lou: Reducing Cognitive Load Through Design, Content, and Systems | Codrops Sketching the Impossible: A 3D Portfolio Built Without a Single 3D Model | Codrops Building Horeca: Advanced Motion Design in Webflow Without the Performance Trade-Offs | Codrops Building an Interactive Digital Stamp Collection with Shaders, Postcards, and Playful Inspection | Codrops No Two Paths Alike: Inside San Rita’s Approach to Digital Experiences | Codrops The Making of the New Lesse Studio Website: Clarity, Performance, and Intentionality | Codrops Creating a Thumbnail Flow Animation with GSAP MotionPath | Codrops Forging Her Own Path: Houmahani Kane’s Journey in Creative Development | Codrops Beaucoup and the Pursuit of Memorable Experiences | Codrops The Future of Emotional Technology: Comfort Websites for Growth and Self-Awareness | Codrops The Never Ending Story: Building a Seamless Infinite Scroll Experience with GSAP & Lenis | Codrops Whooshes, Snaps and Shaders: Adrien Vanderpotte and the Feeling of the Interface | Codrops Building a Scroll-Driven 3D Cube Gallery in Webflow with GSAP | Codrops Creating Scroll-Driven SVG Map Animations with GSAP | Codrops 80s Business Tech and Seamless Scene Transitions: Inside Shader.se’s Scroll-Driven WebGPU Pipeline | Codrops Merlin: The Code Boutique Turning Motion Into Digital Magic | Codrops Designing Ourselves: The New Obys Identity and Website | Codrops Exploring the HTML-in-Canvas Proposal | Codrops Le:mma Studio: Building the Feeling Behind the Screen | Codrops From Shader Uniforms to Clip-Path Wipes: How GSAP Drives My Portfolio | Codrops Reverse-Engineering Claude AI’s Mascot Animations with SVG and GSAP | Codrops Akaru: Crafting Precision-Driven Digital Experiences | Codrops Designing Against the Gallery: A Two-Year Journey to a Layered Portfolio Experience | Codrops Between Human and Machine: Sofia Papadopoulou’s Approach to Augmented Creativity | Codrops More Than a Portfolio: Building a Scroll-Driven 3D World with Something to Say | Codrops Rhumb Studio: Small but Mighty, Shaped by Curiosity | Codrops Susurrus: Crafting a Cozy Watercolor World with Three.js and Shaders | Codrops Building 4WIDE: Turning Distortion, Blur, and Motion into a Coherent Experience | Codrops A Playful Clip Menu with GSAP’s easeReverse | Codrops False Earth: From WebGL Limits to a WebGPU-Driven World | Codrops Interactive Storytelling for the Web: Building Immersive Stories with Timelines, 3D, and Layered Scenes | Codrops The Art of Complex Motion: Corentin Bernadou’s World of Shaders and Experimentation | Codrops They Call Me Giulio: The Making of a Cinematic Cyberpunk Portfolio | Codrops Lusion: Where Digital Craft Meets Ambitious Experimentation | Codrops The Exat Microsite: Pushing a Typography Showcase to New Creative Extremes | Codrops A Single DM, a First SOTD, and the Start of Chanh M. Ho’s Creative Journey | Codrops Creating Custom Page Transitions in Astro with Barba.js and GSAP | Codrops R—K ’26: The Thinking and Code Behind a Portfolio Led by Presence | Codrops Building the Maxima Therapy Website: React, GSAP, and Dabbling with AI | Codrops Where Engineering Meets Craft: Edoardo Lunardi’s Obsession with the Details | Codrops Animating 160,000 Cubes in Three.js to Visualize Dithering | Codrops Arnaud Rocca’s Portfolio: From a GSAP-Powered Motion System to Fluid WebGL | Codrops Where Confidence Needs No Decoration: The Malvah.Studio Story | Codrops Motion Highlights #17 | Codrops
Made With Gsap: Building a Fun Gravity-Based Mouse Trail | Codrops
By Made With Gsap · 2026-05-20 · via Codrops

To celebrate the launch of our new collection of effects, we partnered with Codrops for a fun little tutorial exploring an interactive animation where images appear following the mouse cursor. The twist: once an image has appeared, it falls to the bottom of the viewport, bounces, and then disappears.

Visit the demo link to download the ZIP files or copy the component directly into your Webflow project. Let’s get started!

HTML Structure

The structure here is quite simple. We will simply call the set of images we want for our effect:

<section class="codrops_mwg">
    <div class="medias">
        <img src="./assets/medias/01.png" alt="">
        <img src="./assets/medias/02.png" alt="">
        <img src="./assets/medias/03.png" alt="">
        <img src="./assets/medias/04.png" alt="">
    </div>
</section>

Some CSS

Now, I will hide these images using a bit of CSS.

.codrops_mwg .medias img {
    width: 1px;
    height: 1px;
    top: 0;
    left: 0;
    position: absolute;
    visibility: hidden;
    pointer-events: none;
}

A quick explanation: we could have loaded these images directly via JavaScript to keep the DOM clean. So why didn’t we do that? Because this technique allows us to load the images immediately, even if they are hidden. This way, there will be no delay when an image is created with our script.

Here’s how I retrieve all the URLs of the images used in this effect. These URLs are now stored in my images array.

const root = document.querySelector('.codrops_mwg')
const images = [] 
root.querySelectorAll('.medias img').forEach(image => {
    images.push(image.getAttribute('src'))
})

Starting the animation

We’ll trigger a function whenever the cursor moves a certain distance. Here we track both X and Y movements to compute the total distance traveled:

const root = document.querySelector('.codrops_mwg')
let incr = 0, 
    oldIncrX = 0,
    oldIncrY = 0 

root.addEventListener("mousemove", e => {
    const valX = e.clientX 
    const valY = e.clientY 

    // Add the positive difference between the last two positions (X + Y) 
    incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) 

    oldIncrX = valX 
    oldIncrY = valY
})

Here, we calculate the delta between the current cursor position and the previous position on both axes. We then add this total difference to our incr variable. We also store the deltas because we’ll need them later to determine the direction the image should drift while falling.

Triggering the Image Creation Function

Next, we’ll call the function to create an image once incr exceeds a specific threshold. To make the effect responsive, we’ll set the threshold to window.innerWidth / 8.

const root = document.querySelector('.codrops_mwg') 
let incr = 0, 
    oldIncrX = 0, 
    oldIncrY = 0, 
    resetDist = window.innerWidth / 8 

root.addEventListener("mousemove", e => { 
    const valX = e.clientX 
    const valY = e.clientY 

    incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) 

    if(incr > resetDist) { 
        incr = 0 
        createMedia(valX, valY - root.getBoundingClientRect().top, valX - oldIncrX, valY - oldIncrY) 
    } 
    
    oldIncrX = valX 
    oldIncrY = valY 
})

Notice that we pass two extra parameters to createMedia()deltaX and deltaY. These represent the direction the cursor was moving at the moment the image is created. We’ll use them to make the image drift in the same direction as it falls.

For the y position, we adjust by subtracting the distance from the top of the root element to the top of the viewport. This ensures the effect works correctly even if the page is scrolled down:

e.clientY - root.getBoundingClientRect().top

Inside the createMedia() Function

The createMedia() function now accepts four parameters: xydeltaX, and deltaY. We start by creating an image.

const image = document.createElement("img")
image.setAttribute('src', images[indexImg]) root.appendChild(image)

We also add a small guard: if the cursor is too close to the bottom of the viewport, we skip the creation to avoid a visually broken fall:

const H = window.innerHeight if (y > H - 200) return

Let’s create a simple GSAP Timeline(). When the timeline finishes, the image is removed from the DOM:

const tl = gsap.timeline({ 
    onComplete: () => { 
        root.removeChild(image); 
        tl && tl.kill() 
    } 
})

The first tween handles the appearance with the same elastic bounce, but without setting x and y — those will be handled by separate tweens running simultaneously:

tl.fromTo(image, { 
    xPercent: -50 + (Math.random() - 0.5) * 80, 
    yPercent: -50 + (Math.random() - 0.5) * 10, 
    scaleX: 1.3, 
    scaleY: 1.3, 
    rotation:(Math.random() - 0.5) * 20 
}, { 
    scaleX:1, 
    scaleY:1, 
    ease: 'elastic.out(2, 0.6)', 
    duration: 0.4
})

Next, we animate the horizontal position. The image drifts in the direction the cursor was moving, using deltaX. This tween starts at the same time as the previous one thanks to the '<' position parameter:

tl.fromTo(image, { 
    x, 
}, { 
    x: '+=' + deltaX * 2, 
    rotation: 0, 
    ease: 'power1.in', 
duration: 0.4 }, '<')

Simultaneously, we animate the vertical position. The image falls from its initial y position to the bottom of the viewport. The yPercent: -95 combined with scale: 0.9 ensures the bottom edge of the image lands precisely at the bottom of the viewport:

tl.fromTo(image, { 
    y
}, { 
    y: '+=' + (H - y), 
    scale: 0.9, 
    yPercent: -95, 
    ease: 'back.in(1.1)', 
    duration: 0.4 
}, '<')

Finally, the bounce. After hitting the bottom, the image bounces back up and disappears. We continue drifting horizontally and add a random rotation for a natural feel:

tl.to(image, { 
    x: '+=' + deltaX * 1.6, 
    rotation:(Math.random() - 0.5) * 40, 
    ease: 'power1.in', 
    duration: 0.3 
}) 
tl.to(image, { 
    yPercent: 150, 
    ease: 'back.in(' + (1.5 + (1 - y/H)) + ')', 
    duration: 0.3 
}, '<')

Notice the dynamic easing: 'back.in(' + (1.5 + (1 - y/H)) + ')'. The higher the image starts, the stronger the overshoot on the bounce, creating a more dramatic effect for images that fall from further up.

Going further

By tweaking the random values or exploring other easing options from GSAP’s documentation, you can achieve different visual effects. Try adjusting the back.in intensity for more or less dramatic bounces. The GSAP Easing documentation page is a great playground for this!

About Made With Gsap

Made With Gsap is a platform featuring an ever-growing collection of 100+ unique and well-crafted JS effects. We’ve just released 50 new additions, plus a brand-new effect dropping every week.

To celebrate the launch of this new collection, we’re offering 10% off your first subscription period with the code Codrops10 — available until the end of May.

Thanks again to Manoela and Codrops for the opportunity to share this fun bouncy effect and for continuously inspiring the creative development community.

If you’d like to follow the adventure, you can find us on Instagram, LinkedIn, Youtube, X (Twitter) and Bluesky.