mouse-animations
v1.0.0
Published
Cursor & mouse effects library for TypeScript & JavaScript — trail, ripple, custom cursor, magnetic, particles, parallax, tilt, spotlight, flashlight, invert, image cursor. Zero dependencies, under 5 kB gzipped, optional jQuery plugin.
Downloads
361
Maintainers
Readme
mouse-animations
Cursor and mouse effects for the web: trails, ripples, magnetic pulls, particles, parallax layers, 3D tilts, spotlights, and more. Drop it into any stack — vanilla JS, React, Vue, Svelte, or jQuery. Zero dependencies, under 5 kB gzipped, fully typed.
Effects
| Effect | Description | |------------------|-------------------------------------------------------------------| | Trail | Fading dot trail that follows the cursor on a canvas overlay | | Ripple | Expanding circle at each click position | | CustomCursor | Dot + smoothly lagging outer ring replacing the native cursor | | Magnetic | Pulls matching elements toward the cursor as it approaches | | Particles | Burst of coloured particles on each click | | Parallax | Elements shift subtly as the mouse moves across the viewport | | Tilt | 3D perspective tilt that follows the cursor within each element | | Spotlight | Radial gradient glow that follows the cursor inside each element | | Flashlight | Full-page dark overlay with a transparent circle following the cursor | | Invert | Colored circle that inverts content beneath it via mix-blend-mode | | Image | Replaces the native cursor with a custom image or inline SVG |
Installation
npm
npm install mouse-animationsCDN (no build step)
<script type="module">
import { Trail } from "https://esm.sh/mouse-animations";
// or: https://cdn.jsdelivr.net/npm/mouse-animations/+esm
</script>Usage
Each effect is an independent class. Instantiate to start, call destroy() to clean up.
import { Trail } from "mouse-animations";
const trail = new Trail({ color: "#a78bfa", size: 8 });
trail.disable(); // pause and clear visible state (DOM elements remain)
trail.enable(); // resume
trail.destroy(); // stop and remove all DOM elementsAll classes share the same interface:
interface MouseAnimationsBase {
enable(): void; // start or resume the effect
disable(): void; // pause and clear visible state (DOM elements remain)
destroy(): void; // stop and remove all DOM elements
}All option types are exported and included — no @types/ package needed:
import type {
TrailOptions, RippleOptions, CustomCursorOptions,
MagneticOptions, ParticlesOptions, ParallaxOptions,
TiltOptions, SpotlightOptions, FlashlightOptions, InvertOptions, ImageOptions,
} from "mouse-animations";API
Trail
Renders a fading dot trail that follows the cursor on a canvas overlay.
import { Trail } from "mouse-animations";
const trail = new Trail({
color: "#ffffff", // dot color
size: 6, // max dot radius in px
length: 20, // number of trail points to keep
decay: 0.05, // alpha subtracted per frame (0–1)
blur: 0, // CSS blur in px
});Ripple
Creates an expanding ripple circle at each click position.
import { Ripple } from "mouse-animations";
const ripple = new Ripple({
color: "rgba(255,255,255,0.4)", // fill color
duration: 600, // animation duration in ms
maxSize: 100, // max ripple diameter in px
});CustomCursor
Replaces the native cursor with a dot and a smoothly lagging outer ring.
import { CustomCursor } from "mouse-animations";
const cursor = new CustomCursor({
innerSize: 8, // inner dot size in px
outerSize: 36, // outer ring size in px
innerColor: "#ffffff", // inner dot color
outerColor: "rgba(255,255,255,0.5)", // outer ring color
smoothness: 0.15, // outer ring lerp factor (0–1); lower = more lag
hideDefault: true, // hide the native cursor
});Magnetic
Applies a magnetic pull to matching elements as the cursor approaches them. The transform is restored when the cursor leaves.
import { Magnetic } from "mouse-animations";
const magnetic = new Magnetic({
selector: ".btn", // CSS selector for elements to magnetise (required)
strength: 0.3, // pull strength multiplier
radius: 100, // activation radius in px
ease: 0.15, // lerp ease factor (0–1)
});Particles
Bursts coloured canvas particles from each click position.
import { Particles } from "mouse-animations";
const particles = new Particles({
count: 20, // particles per click
colors: ["#ff6b6b", "#ffd93d", "#6bcb77", "#4d96ff"], // colors picked at random
size: 6, // max particle radius in px
spread: 8, // initial speed spread
decay: 0.02, // alpha decay per frame
});Parallax
Shifts matching elements as the mouse moves across the viewport, creating a depth illusion.
import { Parallax } from "mouse-animations";
const parallax = new Parallax({
selector: ".layer", // CSS selector for elements to shift (required)
depth: 20, // max translation in px at the viewport edge
ease: 0.1, // lerp ease factor (0–1)
});Tilt
Applies a 3D perspective tilt to matching elements as the cursor moves over them, with an optional glare highlight.
import { Tilt } from "mouse-animations";
const tilt = new Tilt({
selector: ".card", // CSS selector for elements to tilt (required)
maxTilt: 15, // max tilt angle in degrees
perspective: 800, // CSS perspective distance in px
ease: 0.1, // lerp ease factor (0–1)
glare: false, // show a glare highlight overlay
});Spotlight
Renders a radial gradient glow that follows the cursor inside each matched element. Works best on dark cards and panels.
Unlike
Magnetic,Parallax, andTilt, theselectoroption is optional here. If omitted, no elements are targeted until you pass one.
import { Spotlight } from "mouse-animations";
const glow = new Spotlight({
selector: ".card", // optional — omit to skip targeting
color: "rgba(255,255,255,0.12)",
size: 200,
});Flashlight
Creates a full-page dark overlay with a transparent circle that follows the cursor, revealing the content beneath like a beam of light in the dark.
import { Flashlight } from "mouse-animations";
const flashlight = new Flashlight({
backdrop: "rgba(0,0,0,0.85)", // overlay tint
size: 200, // light radius
blur: 0, // blur outside the light
smoothness: 0.15, // lerp smoothness (0–1)
});Invert
Renders an opaque circle that follows the cursor and inverts the colors of everything beneath it using mix-blend-mode: difference. Works on text, images, and any colored content.
The inversion result depends on the circle color. White (
#ffffff, default) produces the classic full inversion. Use a different color if the page background is light — for example#000000inverts on white backgrounds identically.
import { Invert } from "mouse-animations";
const cursor = new Invert({
size: 40, // circle diameter in px
color: "#ffffff", // circle color — affects the inversion output. Default: '#ffffff'
smoothness: 1, // lerp factor (0–1); 1 = instant snap, lower = lag
hideDefault: true, // hide the native cursor
});Image
Replaces the native cursor with a custom image URL or inline SVG string.
Note: The name
Imageshadows the DOM built-inImageconstructor (HTMLImageElement) within the same file. If you need both, use an alias:import { Image as CursorImage } from "mouse-animations";
import { Image } from "mouse-animations";
const cursor = new Image({
src: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>...</svg>",
width: 32, // cursor element width in px
height: 32, // cursor element height in px
offsetX: 0, // horizontal offset from cursor position in px
offsetY: 0, // vertical offset from cursor position in px
smoothness: 1, // lerp factor (0–1); 1 = instant snap, lower = lag
hideDefault: true, // hide the native cursor
overrideAll: false, // inject * { cursor: none !important } — defeats cursor: pointer on buttons/links
states: { // alternate images per interaction state (optional)
hover: "<svg .../>", // built-in: shown over a, button, input, select, textarea…
active: "<svg .../>", // built-in: shown while mousedown is held
".my-zone": "<svg .../>", // custom: any CSS selector matched via closest()
},
});An image URL is also accepted as src:
new Image({ src: "/my-cursor.png", width: 40, height: 40 });State-based cursors
Use states to show a different cursor image on interactive elements or while the mouse button is held. Any key other than the built-ins is treated as a CSS selector matched via closest().
const cursor = new Image({
src: starSvg,
overrideAll: true,
states: {
hover: handSvg, // a, button, input, select, textarea…
active: clickSvg, // while mousedown is held
".danger-zone": warnSvg, // any CSS selector
},
});setSource(state, src)
Swap a cursor image at runtime without recreating the instance:
cursor.setSource("normal", newSvg);
cursor.setSource("hover", newHandSvg);
cursor.setSource(".danger-zone", "/new-warn.png");jQuery plugin
All effects are available as jQuery methods. jQuery >=3.0.0 is an optional peer dependency.
npm install mouse-animations jqueryimport "mouse-animations/jquery";
// Global effects — bound to a container element
$("body").trail({ color: "#a78bfa", size: 8 });
$("body").ripple({ duration: 700, maxSize: 120 });
$("body").customCursor({ innerColor: "#a78bfa", smoothness: 0.12 });
$("body").particles({ count: 24 });
$("body").invert({ size: 40, color: "#ffffff" });
$("body").image({ src: "<svg .../>", overrideAll: true, states: { hover: "<svg .../>" } });
$("body").flashlight({ backdrop: "rgba(0,0,0,0.85)", size: 200 });
// Selector-based effects — one instance covers all matched elements.
// The selector option is optional: if omitted, a unique class is stamped
// onto the matched elements automatically.
$(".btn").magnetic({ strength: 0.4, radius: 120 });
$(".layer").parallax({ depth: 20, ease: 0.1 });
$(".card").tilt({ maxTilt: 15, perspective: 800, glare: true });
$(".card").spotlight({ color: "rgba(255,255,255,0.12)", size: 200 });
// All plugins support enable / disable / destroy
$("body").trail("disable");
$("body").trail("enable");
$("body").trail("destroy");Combining effects
All effects are independent and can run simultaneously:
import { Trail, Ripple, Particles, CustomCursor, Magnetic, Parallax, Tilt, Spotlight, Flashlight, Invert, Image } from "mouse-animations";
const trail = new Trail({ color: "#a78bfa" });
const ripple = new Ripple({ color: "rgba(167,139,250,0.35)" });
const particles = new Particles({ count: 24 });
const cursor = new CustomCursor({ innerColor: "#a78bfa" });
const magnetic = new Magnetic({ selector: ".magnetic-btn" });
const parallax = new Parallax({ selector: ".layer" });
const tilt = new Tilt({ selector: ".card", glare: true });
const spotlight = new Spotlight({ selector: ".card" });
const flashlight = new Flashlight({ backdrop: "rgba(0,0,0,0.85)", size: 200 });
const invert = new Invert({ size: 40 });
const image = new Image({ src: starSvg, overrideAll: true });
// Clean up all at once
[trail, ripple, particles, cursor, magnetic, parallax, tilt, spotlight, flashlight, invert, image].forEach((e) => e.destroy());License
MIT
