Your cursor, but alive. Mix and match a custom cursor model, a movement trail and a click effect, with optional synthesised sound, and drop it on any website with one script tag. Zero dependencies, plain JavaScript, one 2D canvas.
17 cursor models Β· 9 trails Β· 16 click effects Β· sound that is synthesised in the browser, no audio files
It runs on any site. Here it is injected into a Google search with the crosshair and gunshot:
Live studio Β· Browser extension Β· Write a plugin
<script src="https://cdn.jsdelivr.net/gh/devkancheti4-design/cursorfx@main/dist/cursorfx.js"></script>
<script>
CursorFX.init({ cursor: 'f1car', trail: null, click: 'animals', sound: true });
</script>Or download dist/cursorfx.js and serve it yourself. The studio page (index.html) lets you pick a combination, tweak options, and copies the exact snippet for you.
| name | what it does | sound | |
|---|---|---|---|
f1car |
ποΈ | An F1 car that steers with your pointer. Synthesised V10 engine with an 8-speed gearbox, upshift cracks, backfires, tyre smoke and exhaust flames. Hold to boost. | yes |
orb |
β¨ | Glowing orb with a rainbow comet tail and a ring that pulses on click. | |
ring |
β | The modern dot-and-ring cursor. The ring lags, grows over links and shrinks on click. | |
ghost |
π» | A ghost floats after the pointer, its eyes follow your movement, and it leaves fading echoes. | |
emoji |
π± | Any emoji on a spring: it bounces, tilts and stretches. | |
spotlight |
π¦ | Dims the page except a soft circle of light around the pointer. | |
blob |
π«§ | A gooey blob that stretches with velocity and drags droplets. | |
ribbon |
π | A silk ribbon that twists and narrows behind the pointer. | |
rocket |
π | A rocket that turns to follow movement, with a flame that grows with speed. | thruster |
crosshair |
β | A shooting reticle with guide lines and live x/y coordinates. Blooms and kicks with recoil when you fire. | |
clock |
π°οΈ | A working analog clock follows the pointer. | |
textflag |
π | Your words trail behind the pointer and wave like a flag. | |
pixel |
πΉοΈ | A chunky 8-bit arrow. |
Four battle-royale style guns, each with six skins: gold, neon, crimson, camo, frost and carbon. The muzzle tip is the hotspot, so a shot lands exactly where it points, and a small outlined reticle marks the spot on light and dark pages alike. Every shot kicks the gun back and up around its grip, throws a muzzle flash and ejects a brass casing. Pair any of them with the gunshot click effect, which fires continuously while you hold the button and tells the gun each time it fires.
| name | model | default skin | |
|---|---|---|---|
gun-rifle |
π― | Assault rifle with a curved magazine | gold |
gun-sniper |
π | Scoped long rifle with a thumbhole stock and a glinting lens | frost |
gun-shotgun |
π₯ | Lever-action shotgun with a tube magazine | crimson |
gun-pistol |
π« | Heavy pistol with a serrated slide | neon |
CursorFX.init({ cursor: 'gun-sniper', click: 'gunshot', options: { 'gun-sniper': { skin: 'neon', aim: 'right' } } });The designs are original. They take the look of a battle-royale weapon skin, not any game's actual artwork.
| name | what it does | |
|---|---|---|
sparkles |
β¨ | Fairy dust: twinkling four-point sparkles drift down. |
rainbow |
π | Seven-band rainbow ribbon. |
bubbles |
π«§ | Soap bubbles rise and pop. |
emojirain |
π | Your emoji tumble out and fall. |
snow |
βοΈ | Snowflakes drift and sway. |
petals |
πΈ | Cherry-blossom petals flutter down. |
fire |
π₯ | Flames lick behind the pointer, hotter as you speed up. |
stars |
β | Golden stars twinkle along the path. |
neon |
π‘ | A glowing neon tube traces your path and fades. |
| name | what it does | sound | |
|---|---|---|---|
animals |
π¦ | Particles explode and reassemble into a different animal each click. Move through it to push the particles aside. Optional: placement: 'corner' keeps it small and off your content, opacity makes it translucent, dissolveAfter controls how long it stays. |
whoosh |
gunshot |
π― | Fires a shot: muzzle flash, sparks, smoke, an ejected casing and a cracked bullet hole that fades away after a few seconds. Hold to keep firing. Pairs with the crosshair cursor, which blooms and kicks with recoil. |
bang |
waves |
π | The page itself ripples: real content bends and refracts outward from the click (backdrop-filter displacement, Chromium; rings elsewhere). style: 'jelly' wobbles the whole page. |
drip |
ripple |
γ°οΈ | Concentric water rings drawn on top. | drip |
butterflies |
π¦ | A flock of butterflies flutters out and flies away. | flutter |
fireworks |
π | A rocket streaks up and bursts into sparks. | launch + bang |
hearts |
β€οΈ | Hearts float up and sway. | blip |
confetti |
π | A confetti cannon with tumbling paper. | pop |
bubbles |
π«§ | A cloud of bubbles rises and pops one by one. | pops |
stars |
π | Spinning golden stars with a chime. | chime |
ink |
ποΈ | An ink splat that spreads and drips. | splat |
shockwave |
π₯ | A flash, an expanding ring and flying sparks. | boom |
emojiburst |
π | A burst of your chosen emoji. | pop |
textburst |
π¬ | Comic-book words: POW! BOOM! WOW! | zap |
birds |
π¦ | A flock takes flight and scatters. | chirp |
notes |
π΅ | Music notes float up; each click plays a pentatonic note, so clicking becomes a melody. | note |
Any layer can be null to turn it off. Sound is off unless you pass sound: true, and browsers only start audio after the first click or key press.
No npm needed. Grab dist/cursorfx.js (the whole library in one file) or dist/cursorfx-extension.zip (the browser extension) from the studio's Download row or from the Releases page, or clone the repo. The studio page works when opened straight from a downloaded folder, because everything is plain scripts.
Open a request issue describing the cursor, trail or click effect you want. When it is built, the plugin ships with a credits field carrying your name, which shows on its card in the studio and in CREDITS.md. Details in CONTRIBUTING.md.
CursorFX.init(config) // start; safe to call before DOM is ready
// config.cursorScale (default 1) scales any cursor model around the pointer
CursorFX.set(config) // change any part of the config on the fly
CursorFX.destroy() // remove the canvas, listeners and audio
CursorFX.list() // { cursor: [...], trail: [...], click: [...] } with labels, icons, descriptions, defaults
CursorFX.trigger(x, y) // fire the click effect programmatically (defaults to the pointer position)
CursorFX.preview(kind, name, { w, h, options, frames, step })
// render one plugin to its own canvas, stepped by hand; works in hidden tabs
CursorFX.getConfig()Config:
{
cursor: 'ring', // cursor model name or null
trail: 'sparkles', // trail name or null
click: 'ripple', // click effect name or null
sound: false, // enable synthesised sound
volume: 0.8,
hideNative: true, // hide the OS cursor while a cursor model is active
zIndex: 2147483646,
options: { // per-plugin options, keyed by plugin name
emoji: { emoji: 'π¦', size: 44 },
textflag: { text: 'HELLO WORLD' },
animals: { animals: ['π', 'π¦'], dissolveAfter: 0 },
},
}Add data-cursorfx-ignore to any element to stop clicks inside it from firing the click effect (the studio panel uses this). Add data-cursor="pointer" to make a non-interactive element count as hoverable for cursors that react to links and buttons.
Every plugin is a small object with a create function that returns update and render hooks. Register it after loading the bundle, then use its name in the config.
CursorFX.registerClick('smiley', {
label: 'Smiley', icon: 'π', description: 'A smiley pops out of every click.',
defaults: { size: 40 },
create(opts, api) {
const { state, util, audio } = api;
const list = util.particleList();
return {
trigger(x, y) {
list.add({ x, y, vy: -3, life: 60, max: 60 });
audio.tone({ freq: 880, dur: 0.2 }); // silently ignored when sound is off
},
update(f) { list.step(f, (p) => { p.y += p.vy * f; p.vy += 0.1 * f; }); },
render(g) {
list.items.forEach((p) => util.drawSprite(g, util.sprite('π', opts.size), p.x, p.y, 1, 0, p.life / p.max));
},
};
},
});
CursorFX.set({ click: 'smiley' });stategives you the pointer:x, y, vx, vy, speed, heading, down, hover, seen, inside, w, h, time, reduceMotion.utilhasrand, pick, clamp, lerp, hsla, rrect, star, heart, sprite, drawSprite, samplePoints, particleList.audiohaspop, tone, whoosh(all no-ops when sound is off or not yet unlocked), plusget()for a rawAudioContextandbus()to connect your own nodes.- Frame values are in per-frame units at 60 fps; scale motion by
fso it looks the same at 120 Hz. - Cursors use
update/renderplus optionalonEnter,onDown,onUp. Trails useupdate/render. Click effects addtrigger(x, y, event).
Optional metadata: credits: { requestedBy: 'u/name', builtBy: 'you' } is shown on the plugin's card and returned by CursorFX.list(). choices: { skin: [{ value, label, color }] } turns an option into a picker: a dropdown in the studio and a row of swatches in both desktop widgets.
Plugins live in src/cursors, src/trails and src/clicks. Run npm run build to rebundle dist/cursorfx.js and the extension zip.
desktop/macos/ is a native menu bar app that puts the same effects over your entire screen: the desktop, Finder, every app. It draws a click-through, always-on-top overlay on each display, follows the system mouse, hides the arrow, and plays the sounds.
- Download
CursorFX-macOS.zipfrom the Releases page, unzip, and dragCursorFX.appinto Applications. It is not notarised, so the first time right-click it and choose Open. - Turn on Open at login in the widget, or the menu bar item is gone after every restart.
- A cursor glyph appears in the menu bar, left of your other items. Click it for a Control Center style widget: a master switch to turn the custom mouse off, swipeable icon strips for cursor, trail and click effect, a size slider, and switches for sound, hiding the arrow, fading the cursor while you type (it comes back when the mouse moves, like the system arrow), and opening at login.
- Build it yourself with
./desktop/macos/build.sh, which needs the Xcode Command Line Tools. Addinstallto replace the copy in Applications and relaunch it. It embedsdist/cursorfx.js, so every plugin you add to the library shows up in the menu.
desktop/windows/ is the same thing for Windows, built on Electron: one transparent click-through window per display, fed by the global pointer position, with a PowerShell helper supplying the mouse clicks and keystrokes that Electron cannot see on its own. It needs no drivers, no modules and no administrator rights.
- Download
CursorFX-Windows.zipfrom the Releases page, unzip it, and runCursorFX.exe. SmartScreen warns that the publisher is unknown because the build is not signed: choose More info, then Run anyway. - A cursor icon appears in the notification area. Left-click it for the panel, right-click for the same controls as a menu.
- Open at login is a switch in the panel. It registers with Windows the usual way, so Settings, Apps, Startup can turn it off later.
- Build it with
npm installthennpm run distinsidedesktop/windows, on a Windows machine.npm startruns it from source anywhere.
Details and the design notes are in desktop/windows/README.md.
| A web page | Browser extension | macOS app | Windows app | |
|---|---|---|---|---|
| 17 cursors, 9 trails, 16 click effects | yes | yes | yes | yes |
| Gun skins | options.skin |
fixed | skin row | skin row |
| Cursor size | cursorScale |
fixed | slider | slider |
| Sound | sound: true |
switch | switch | switch |
| Turn it all off | remove the script | switch | master switch | master switch |
| Hide the real arrow | hideNative |
hideNative |
switch | switch |
| Fade while typing | no | no | switch | switch |
| Open at login | not applicable | starts with the browser | switch | switch |
| Covers | that one page | every page you visit | every app and the desktop | every app and the desktop |
The two desktop apps have the same controls. They differ only in how they reach the operating system, which is what the table in desktop/windows/README.md covers.
No overlay app yet. The browser extension below covers Chrome, Edge and Brave, and a port would follow the same shape as the two above. To start your own build at login, drop a .desktop file in ~/.config/autostart/ with an Exec= line pointing at the binary.
The extension/ folder is a Manifest V3 extension that runs CursorFX on every page you visit. Load it unpacked from chrome://extensions (Chrome, Edge, Brave, Arc) and pick your cursor, trail, click effect and sound from the toolbar popup. Settings sync through your browser profile.
npm run build # bundle src/ into dist/cursorfx.js and copy it into extension/
npm start # serve the studio at http://localhost:8765There is no build tooling to install. Plugins are plain scripts that register themselves, so you can also load src/core.js and individual plugin files directly.
- Respects
prefers-reduced-motion: particle counts are halved and bursts softened. - Eases off to a low frame rate once the pointer has been still for a moment, and snaps back to full speed the instant anything moves. An overlay spends most of its life idle, and redrawing it costs the same whether or not anything is happening. Measured numbers for the two desktop apps are in desktop/windows/README.md.
- One overlay canvas with
pointer-events: none, so the page underneath stays fully interactive. - Particles are pooled and drawn with cached sprites; the animals effect batches thousands of dots per frame.
- Sound is synthesised with the Web Audio API and unlocked by the first user gesture, per browser policy.
MIT.

