webdevpuneet.com

Canvas Fluid Cursor Trail — Free Soft Blended Trail Snippet

Canvas Fluid Cursor Trail · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="fc-wrap">
  <canvas id="fcCanvas" class="fc-canvas"></canvas>
  <p class="fc-hint">Move your cursor across the panel.</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Velocity-based stretch
Faster movement elongates each blob.
Additive blending
Overlapping blobs glow brighter, not just stack.
Trail fade via overlay wash
A translucent rect ages old frames cheaply.
Hue tied to speed
Color shifts subtly with movement velocity.
Independent blob aging
Each blob has its own lifespan and damping.
Touch-friendly
Responds to touchmove as well as mousemove.
No external library
Pure Canvas 2D API, honest about not being a real fluid sim.
DPR-aware rendering
Crisp on high-density displays.

About this UI Snippet

Canvas Fluid Cursor Trail — A Lightweight, Glowing Cursor Trail

Screenshot of the Canvas Fluid Cursor Trail snippet rendered live

The fluid cursor trail snippet follows your cursor with a soft, glowing streak of blended blobs that stretch along your movement direction and fade out behind you. It's worth being upfront about what this is and isn't: it's a tasteful *approximation* of a fluid look, built from layered radial gradients, velocity-based stretching, and additive blending on the Canvas 2D API — not a real Navier-Stokes fluid simulation, and it doesn't need to be one to look good.

Velocity, not just position, drives the shape

Every pointer move, spawnBlob() compares the current pointer position to the last recorded one to get a velocity vector. That velocity feeds three things at once: the blob's own drift (vx * 0.15), its stretch factor (faster movement elongates the blob along the direction of travel via ctx.rotate + ctx.scale), and its hue, so quick flicks read visually differently from slow, deliberate movement.

Additive blending is what makes it glow

Each blob is drawn with ctx.globalCompositeOperation = 'lighter', which adds color values where blobs overlap instead of simply layering opaque shapes on top of each other. Where several fresh, bright blobs overlap near the cursor, colors blow out toward white-hot; where they're sparse and faded, they stay a soft, dim glow — that additive overlap is most of what sells the "fluid" read, along with the radial gradient giving each blob a soft falloff instead of a hard edge.

The trail fades via a translucent overlay, not per-blob alpha alone

Instead of clearing the canvas every frame, tick() paints a low-opacity dark rectangle over the whole canvas (rgba(5,6,10,0.14)) before drawing new blobs. That partial-opacity wash is what leaves old blobs visibly lingering and dimming across several frames — a cheap way to get a persistent trail without storing and re-rendering a history array of past frames.

Individually aging, independently moving blobs

Each blob is a plain object with its own position, velocity (with damping via *= 0.94), lifespan, size, and hue, pushed into a blobs array and filtered out once its life reaches zero. There's no shared physics grid or pressure field — this is closer to a lightweight particle system tuned to look fluid-ish than a genuine fluid solver, and that honesty is intentional: it stays fast and dependency-free.

Customizing it

Adjust the fade rectangle's opacity for a longer or shorter trail, tune the hue formula for a different palette, or change globalCompositeOperation to 'screen' or 'overlay' for a different blend character. Pair it with particle network or starfield for other ambient canvas backgrounds, or canvas ripple click effect for a click-driven companion interaction.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA canvas panel and hint text render.
  2. 2
    Move the cursor over the panelA glowing, stretched blob trail follows it.
  3. 3
    Move quicklyBlobs stretch and shift hue with higher velocity.
  4. 4
    Hold stillThe trail fades out and stops growing.
  5. 5
    Leave the panelNew blobs stop spawning until the cursor re-enters.
  6. 6
    Resize the windowThe canvas adapts to the new panel size.

Real-world uses

Common Use Cases

Hero ambient layers
Add a glowing cursor accent alongside a starfield, where faster movement stretches each blob along the direction of travel.
Interactive portfolio sections
Pair with a particle network section on a portfolio page for a layered, motion-rich showcase that responds to the pointer.
Creative agency sites
Give hero content a glowing pointer accent, using additive blending so overlapping blobs glow brighter instead of merely stacking.
Music and event pages
Reinforce an energetic mood with colour that shifts subtly with movement speed, ageing old frames cheaply through a translucent overlay.
Combined interaction effects
Combine with a canvas ripple click effect so hover leaves a trail and clicks send out a wave.
Related: Canvas Procedural Lightning
See the Canvas Procedural Lightning for a related animations pattern worth pairing with this one.
Related: Number to Word Morph Counter
See the Number to Word Morph Counter for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

No, and it's not trying to be. A genuine fluid simulation solves the Navier-Stokes equations across a velocity field, which is significantly more expensive to compute. This snippet approximates a fluid look using layered, velocity-stretched radial gradients and additive blending — a lightweight visual trick that looks fluid-ish without the underlying physics.

Two things together: ctx.globalCompositeOperation = 'lighter' adds overlapping colors rather than layering opaque shapes, so dense clusters of blobs near the cursor blow out brighter; and each blob is drawn as a radial gradient fading to transparent, giving it a soft, glowing edge instead of a hard circle outline.

Instead of clearing the canvas each frame, tick() paints a low-opacity dark rectangle over the entire canvas before drawing new blobs. That partial wash slightly dims everything already there on every frame, so older blobs visibly fade over several frames — a much cheaper approach than storing and re-rendering a growing history of past positions.

Blob size, stretch factor, and hue are all derived from the pointer's velocity between frames. Faster movement produces larger, more elongated blobs with a shifted hue, while slow, deliberate movement produces smaller, rounder, more static-colored blobs — that's what gives fast flicks and slow drags visually distinct trails.

Move the canvas setup, pointer listeners, and animation loop into a mount effect scoped to a canvas ref, and cancel the requestAnimationFrame loop plus remove event listeners in the cleanup function. Keep the blobs array and pointer state outside of component re-renders (in refs) so the animation loop doesn't get recreated on every render.