Most eLearning courses built in Articulate Storyline 360 rely heavily on linear navigation, Next buttons, static clicks and predictable interactions. If you’re new to customization, start with our Storyline 360 JavaScript triggers guide to understand how scripting works inside Storyline.
While functional, these courses often lack the micro-interactions that drive real learner engagement.
Click Preview to watch the how to Add Mouse Cursor Animation in Articulate Storyline 360 Using JavaScript.
Mouse cursor animation using JavaScript becomes a powerful enhancement.
By integrating subtle cursor effects like trails, clicks or hover animations, you can:
- Elevate learner engagement
- Create immersive, UX-driven learning environments
- Introduce gamification without heavy development (see eLearning gamification strategies)
- Make your courses feel modern and premium
What Is Mouse Cursor Animation in eLearning?
Mouse cursor animation refers to interactive visual effects that respond to user movement or clicks inside a course. These effects are a key part of modern UX, learn more in our interactive eLearning design tips guide.
Common Types of Cursor Effects:
To overcome this limitation, we use JavaScript in Storyline 360 to add advanced features and customization.
- Cursor trail effects (particles following movement)
- Click animations (ripples, bubbles, sparks)
- Hover glow effects (interactive highlights)
- Dynamic particle systems
These can be implemented using JavaScript triggers, covered in detail in our Storyline 360 advanced customization tutorial.
What are the benefits of cursor animation in eLearning?
Course Development Benefits:
- Enhances visual feedback loops
- Reinforces interaction cues
- Supports experiential learning (see interactive eLearning design)
Engagement Benefits:
- Adds gamification elements (eLearning gamification strategies)
- Encourages exploration behavior
- Breaks monotony of static slides
Business Impact:
- Improves course completion rates
- Increases learner satisfaction
- Strengthens UX-driven learning (related: advanced eLearning UX techniques)
Step-by-Step: Add Mouse Cursor Animation in Storyline 360 Course
Step 1: Open Your Storyline Project
● Launch Storyline 360
● Open your .story file
● Navigate to the target slide
Step 2: Add a JavaScript Trigger
● Select the slide
● Open the Triggers panel
● Click “Create New Trigger”
● Set:
- Action: Execute JavaScript
- When: Timeline starts
If you’re unsure about triggers, revisit Storyline 360 JavaScript triggers guide before proceeding.
Step 3: Insert the Cursor Animation JavaScript Code into the JavaScript Editor
To implement effects efficiently, understanding scripting basics is helpful, see Storyline JavaScript best practices.
Type 1: Basic Cursor Effect
How It Works:
This effect changes how the cursor looks or behaves when moving across the slide.
Steps:
● Add a trigger → Execute JavaScript
● Paste the following JavaScript code
(function () {
// �� Run only once
if (window.__cursorInitialized) return;
window.__cursorInitialized = true;
const container = document.body;
let mouseX = 0, mouseY = 0;
let currentX = 0, currentY = 0;
let prevMouseX = 0, prevMouseY = 0;
let dpr = window.devicePixelRatio || 1;
/* =========================
CURSOR
========================= */
let cursor = document.querySelector(“.global-cursor”);
if (!cursor) {
cursor = document.createElement(“div”);
cursor.classList.add(“global-cursor”);
Object.assign(cursor.style, {
position: “fixed”,
width: “30px”,
height: “30px”,
borderRadius: “50%”,
pointerEvents: “none”,
zIndex: “9999”,
filter: “blur(5px)”
});
document.body.appendChild(cursor);
}
/* =========================
CANVAS
========================= */
let canvas = document.querySelector(“.global-trail”);
if (!canvas) {
canvas = document.createElement(“canvas”);
canvas.classList.add(“global-trail”);
Object.assign(canvas.style, {
position: “fixed”,
top: “0”,
left: “0”,
pointerEvents: “none”,
zIndex: “9998”
});
document.body.appendChild(canvas);
}
const ctx = canvas.getContext(“2d”);
/* =========================
RESIZE
========================= */
function resizeCanvas() {
dpr = window.devicePixelRatio || 1;
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
canvas.style.width = window.innerWidth + “px”;
canvas.style.height = window.innerHeight + “px”;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
resizeCanvas();
window.addEventListener(“resize”, resizeCanvas);
/* =========================
MOUSE TRACK
========================= */
document.addEventListener(“mousemove”, (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
/* =========================
ANIMATION
========================= */
function animate() {
const dx = mouseX – prevMouseX;
const dy = mouseY – prevMouseY;
const speed = Math.sqrt(dx * dx + dy * dy);
const lag = Math.min(speed / 50, 0.2);
currentX += (mouseX – currentX) * (0.1 + lag);
currentY += (mouseY – currentY) * (0.1 + lag);
const hue = (Date.now() / 8) % 360;
// cursor
cursor.style.transform =
`translate(${currentX – 15}px, ${currentY – 15}px)`;
cursor.style.background =
`hsla(${hue}, 100%, 60%, 0.7)`;
prevMouseX = mouseX;
prevMouseY = mouseY;
/* ===== TRAIL ===== */
ctx.globalCompositeOperation = “destination-out”;
ctx.fillStyle = “rgba(0,0,0,0.2)”;
ctx.fillRect(0, 0, canvas.width / dpr, canvas.height / dpr);
ctx.globalCompositeOperation = “lighter”;
ctx.beginPath();
ctx.arc(currentX, currentY, 12, 0, Math.PI * 2);
ctx.fillStyle = `hsla(${hue}, 100%, 60%, 0.2)`;
ctx.shadowBlur = 20;
ctx.shadowColor = `hsla(${hue}, 100%, 60%, 0.8)`;
ctx.fill();
ctx.shadowBlur = 0;
requestAnimationFrame(animate);
}
animate();
/* =========================
CLICK PULSE (FIXED)
========================= */
document.addEventListener(“click”, (e) => {
const x = e.clientX;
const y = e.clientY;
const pulse = document.createElement(“div”);
Object.assign(pulse.style, {
position: “fixed”,
left: (x – 20) + “px”,
top: (y – 20) + “px”,
width: “40px”,
height: “40px”,
borderRadius: “50%”,
border: “2px solid white”,
pointerEvents: “none”,
zIndex: “10000”,
animation: “pulseAnim 0.6s ease-out”
});
document.body.appendChild(pulse);
setTimeout(() => pulse.remove(), 600);
});
/* =========================
CSS (ADD ONLY ONCE)
========================= */
if (!document.querySelector(“#cursor-style”)) {
const style = document.createElement(“style”);
style.id = “cursor-style”;
style.innerHTML = `
@keyframes pulseAnim {
0% { transform: scale(0.5); opacity: 1; }
100% { transform: scale(2); opacity: 0; }
}
`;
document.head.appendChild(style);
}
})();
● Click OK
Result:
Once the trigger executes:
● The mouse cursor transforms visually
● Effects appear dynamically while moving across the slide
Best for: Use this in UI-heavy slides, paired with interactive eLearning design tips.
Type 2: Click-Based Bubble Effect
How It Works:
This effect creates bubbles or particles when the user clicks.
Repeat the same process:
● Create trigger → Execute JavaScript
● Paste the following JavaScript code
(function () {
// �� Prevent duplicate run
if (window.__trailEffectInit) return;
window.__trailEffectInit = true;
const container = document.body;
/* =========================
MOUSE MOVE TRAIL
========================= */
document.addEventListener(“mousemove”, function (e) {
let x = e.clientX;
let y = e.clientY;
let trail = document.createElement(“div”);
Object.assign(trail.style, {
position: “fixed”,
left: (x – 10) + “px”,
top: (y – 10) + “px”,
width: “20px”,
height: “20px”,
borderRadius: “50%”,
background: “rgba(0,150,255,0.2)”,
pointerEvents: “none”,
zIndex: “9999”,
animation: “fadeTrail 0.6s linear”
});
container.appendChild(trail);
setTimeout(() => trail.remove(), 600);
});
/* =========================
CLICK BURST EFFECT
========================= */
document.addEventListener(“click”, function (e) {
let x = e.clientX;
let y = e.clientY;
for (let i = 0; i < 6; i++) {
let burst = document.createElement("div");
Object.assign(burst.style, {
position: "fixed",
left: x + "px",
top: y + "px",
width: "8px",
height: "8px",
background: "#00aaff",
borderRadius: "50%",
pointerEvents: "none",
zIndex: "10000",
animation: "burstAnim 0.6s ease-out forwards"
});
let angle = (i * 60) * (Math.PI / 180);
let distance = 60;
burst.style.setProperty('--x', Math.cos(angle) * distance + 'px');
burst.style.setProperty('--y', Math.sin(angle) * distance + 'px');
container.appendChild(burst);
setTimeout(() => burst.remove(), 600);
}
});
/* =========================
CSS (ONLY ONCE)
========================= */
if (!document.querySelector(“#trail-style”)) {
const style = document.createElement(“style”);
style.id = “trail-style”;
style.innerHTML = `
@keyframes fadeTrail {
0% { transform: scale(1); opacity: 0.4; }
100% { transform: scale(2); opacity: 0; }
}
@keyframes burstAnim {
0% { transform: translate(0,0); opacity: 1; }
100% { transform: translate(var(–x), var(–y)); opacity: 0; }
}
`;
document.head.appendChild(style);
}
})();
● Click OK
Result:
Once the trigger executes:
● Cursor interaction becomes playful
● Bubbles appear on every click
Best for: Perfect for gamified modules, combine with eLearning gamification strategies.
Type 3: Advanced Cursor Interaction
How It Works:
A more dynamic or animated cursor effect (e.g., trailing particles, glow effects).
Steps:
● Create trigger → Execute JavaScript
● Paste the following JavaScript code
(function () {
if (window.__cursorFX) return;
window.__cursorFX = true;
const container = document.body;
/* =========================
�� CURSOR
========================= */
let cursor = document.createElement(“div”);
Object.assign(cursor.style, {
position: “fixed”,
width: “40px”,
height: “40px”,
borderRadius: “50%”,
background: “rgba(0,150,255,0.2)”,
pointerEvents: “none”,
transition: “transform 0.08s ease-out”,
zIndex: “999999”
});
container.appendChild(cursor);
/* =========================
�� MOUSE MOVE
========================= */
document.addEventListener(“mousemove”, function (e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.transform = `translate(${x – 20}px, ${y – 20}px)`;
// Trail
let trail = document.createElement(“div”);
Object.assign(trail.style, {
position: “fixed”,
left: (x – 5) + “px”,
top: (y – 5) + “px”,
width: “10px”,
height: “10px”,
borderRadius: “50%”,
background: “rgba(0,150,255,0.3)”,
pointerEvents: “none”,
zIndex: “999998”,
animation: “fadeTrail 0.5s linear”
});
container.appendChild(trail);
setTimeout(() => trail.remove(), 500);
});
/* =========================
�� CLICK BURST
========================= */
document.addEventListener(“click”, function (e) {
let x = e.clientX;
let y = e.clientY;
for (let i = 0; i < 8; i++) {
let burst = document.createElement("div");
Object.assign(burst.style, {
position: "fixed",
left: x + "px",
top: y + "px",
width: "6px",
height: "6px",
background: "#00aaff",
borderRadius: "50%",
pointerEvents: "none",
zIndex: "1000000",
animation: "burstAnim 0.6s ease-out forwards"
});
let angle = (i * 45) * (Math.PI / 180);
let distance = 80;
burst.style.setProperty('--x', Math.cos(angle) * distance + 'px');
burst.style.setProperty('--y', Math.sin(angle) * distance + 'px');
container.appendChild(burst);
setTimeout(() => burst.remove(), 600);
}
});
/* =========================
�� MAGNETIC (SAFE VERSION)
========================= */
function applyMagnet() {
const slide = document.querySelector(“#slide”);
if (!slide) return;
let magnets = slide.querySelectorAll(“button, .magnetic”);
magnets.forEach(el => {
if (el.__magnetApplied) return;
el.__magnetApplied = true;
el.addEventListener(“mousemove”, function (e) {
let rect = el.getBoundingClientRect();
let x = e.clientX – rect.left – rect.width / 2;
let y = e.clientY – rect.top – rect.height / 2;
el.style.transform =
`translate(${x * 0.15}px, ${y * 0.15}px)`;
});
el.addEventListener(“mouseleave”, function () {
el.style.transform = “translate(0,0)”;
});
});
}
applyMagnet();
// Reapply on slide change
const observer = new MutationObserver(() => {
applyMagnet();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
/* =========================
�� CSS
========================= */
if (!document.querySelector(“#cursor-fx-style”)) {
const style = document.createElement(“style”);
style.id = “cursor-fx-style”;
style.innerHTML = `
@keyframes fadeTrail {
0% { transform: scale(1); opacity: 0.5; }
100% { transform: scale(2); opacity: 0; }
}
@keyframes burstAnim {
0% { transform: translate(0,0); opacity: 1; }
100% { transform: translate(var(–x), var(–y)); opacity: 0; }
}
`;
document.head.appendChild(style);
}
})();
● Click OK
Result:
Once the trigger executes:
● Enhanced visual feedback
● Smooth animation tied to cursor movement
Best for: Best for high-end learning, see Storyline 360 advanced customization.
Step 4: Preview and Test
After adding your triggers:
● Click Preview → This Slide
● Move and click your mouse
● Observe how each effect behaves
Tip: For accurate results, test published output to learn more in Storyline publishing best practices.
Best Practices for JavaScript Cursor Animations in Storyline 360 Courses
Performance Optimization
- Keep scripts lightweight (see Storyline JavaScript best practices)
- Avoid excessive particles
UX Considerations
- Align animations with learning goals
- Avoid distractions
- Follow interactive eLearning design tips
Compatibility
- Test across devices
- Learn responsive strategies in mobile-friendly eLearning design
Summary
Mouse cursor animation in Articulate Storyline 360 is a small enhancement with a massive impact.
When used strategically, it can:
- Turn passive content into interactive experiences
- Increase learner engagement and retention
- Give your courses a polished, modern feel
The key is balance enhance, don’t distract.
Frequently Asked Questions (FAQs)
What is the difference between cursor animation and hover effects in eLearning?
Cursor animation involves dynamic visuals that follow or respond to cursor movement, while hover effects are triggered when the cursor stays over a specific object. Both can be combined in Storyline 360 to create richer interactions.
How do you add JavaScript in Storyline 360?
To add JavaScript in Storyline 360:
- Select a slide
- Open the Triggers panel
- Click Create New Trigger
- Choose Execute JavaScript
- Paste your script
- Click OK to save
This method allows you to extend Storyline functionality beyond built-in features, including cursor animations.
Can you create cursor effects in Storyline 360 without JavaScript?
No, native cursor animation is not directly supported in Articulate Storyline 360. To create advanced cursor effects like particle trails or click animations, you must use JavaScript triggers.
Is it safe to use JavaScript in Storyline 360?
Yes, using JavaScript in Articulate Storyline 360 is safe when you use clean, tested code. Avoid untrusted external scripts and ensure compatibility across browsers.
Are cursor animations supported in HTML5 published Storyline courses?
Yes, cursor animations created with JavaScript work in HTML5 output, which is the default publishing format in Articulate Storyline 360. However, performance depends on script optimization and browser compatibility.

