Skip to content

Instantly share code, notes, and snippets.

@dhananjay431
Created October 2, 2024 16:35
Show Gist options
  • Save dhananjay431/10778fe56c3c7469a733eb30d5912dc6 to your computer and use it in GitHub Desktop.
Save dhananjay431/10778fe56c3c7469a733eb30d5912dc6 to your computer and use it in GitHub Desktop.
Amazing Sparks Mouse Effect

Amazing Sparks Mouse Effect

Interactive mouse effect generating sparks with physically realistic behavior. Made with jQuery.

A Pen by Nazar Kyselov on CodePen.

License.

<body>
<!-- Start fire glows -->
<!-- This doesn't relate to any functionality. Just for prettiness -->
<div class="fire-glow fire-glow-1">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<div class="fire-glow fire-glow-2">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<div class="fire-glow fire-glow-3">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<div class="fire-glow fire-glow-4">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<div class="fire-glow fire-glow-5">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<div class="fire-glow fire-glow-6">
<div class="container">
<span class="inner-glow inner-glow-1"></span>
<span class="inner-glow inner-glow-2"></span>
<span class="inner-glow inner-glow-3"></span>
</div>
</div>
<!-- End fire glows -->
<!-- Include jQuery with CDN -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="main.js"></script>
</body>
const config = {
colors: [
// spark possible colors
"#eddc01",
"#f2b125",
"#fd9407",
"#ff7308",
"#eb5508",
"#fe1a17",
"#e93702"
],
sizes: [4, 6, 8], // diameter in px
minimalDistance: 20, // minimal distance between spawned
gravitation: 0.2,
airResistance: 0.98,
shrink: 0.1
};
//? store coordinates of the prev and last generated spark
var prev = { x: 0, y: 0 },
last = { x: 0, y: 0 };
//? cash frequantly used elements
const $body = $("body");
const $document = $(document);
const appendElement = (el) => $body.append(el),
removeElement = (el) => setTimeout(() => $(el).remove());
//? pick random element in defined range from array
const rand = (min, max) => Math.floor(Math.random() * (max - min + 1) + min),
pickRandom = (arr) => arr[rand(0, arr.length - 1)];
const calcDistance = (a, b) =>
Math.floor(Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2));
const calcAngleRadians = (startPoint, endPoint) =>
Math.atan2(startPoint.y - endPoint.y, endPoint.x - startPoint.x);
const updateCoords = (position) => {
//? update position of prev generated spark
prev.x = last.x;
prev.y = last.y;
//? and the last spark
last.x = position.x;
last.y = position.y;
};
const generateSpeed = () => {
var angle = (Math.random() * 360 * Math.PI) / 180; //? random angle in radians
var speed = Math.random() * 2 + 1; //? random speed
//? additional speed that depends on the speed and direction of mouse movement
var addSpeed = (calcDistance(prev, last) / config.minimalDistance) * 2;
var addSpeedY = addSpeed * Math.sin(calcAngleRadians(prev, last));
var addSpeedX = addSpeed * Math.cos(calcAngleRadians(prev, last));
//? output X and Y axis speeds
var speedY = speed * Math.sin(angle) + addSpeedY;
var speedX = speed * Math.cos(angle) + addSpeedX;
return { speedX, speedY };
};
const animateSpark = (spark) => {
//? constants for physically realistic animation
var { speedX, speedY } = generateSpeed();
const gravitation = config.gravitation;
const airResistance = config.airResistance;
const shrink = config.shrink;
function animate() {
spark.css({
top: "-=" + speedY,
left: "+=" + speedX,
width: "-=" + shrink,
height: "-=" + shrink
});
//? gravitation imitation
speedY -= gravitation;
//? air resistance imitation
speedX *= airResistance;
//? if a spark is beyond the page or its size is smaller than 0
if (
$(spark).top > $(window).height ||
$(spark).left < 0 ||
$(spark).width() <= 0
) {
removeElement(spark);
} else {
requestAnimationFrame(animate);
}
}
animate();
};
const createSpark = (position) => {
const spark = $("<div></div>");
const size = pickRandom(config.sizes);
spark.addClass("spark");
spark.append(`<div class="spark-glow"></div>`);
$(spark).css({
left: position.x,
top: position.y,
background: pickRandom(config.colors),
width: size,
height: size
});
animateSpark(spark);
appendElement(spark);
updateCoords(position);
};
$document.mousemove((e) => {
const position = {
x: e.clientX,
y: e.clientY
};
if (calcDistance(last, position) > config.minimalDistance)
createSpark(position);
});
/* ========= Reset styles ========== */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background: linear-gradient(to bottom, #1a0001, #270002, #380103, #4c0101);
display: flex;
align-items: flex-end;
justify-content: center;
overflow: hidden;
position: relative;
}
/* ========= Fire-glows ========== */
.fire-glow {
position: absolute;
filter: blur(100px);
}
.fire-glow-1 {
width: 700px;
height: 700px;
left: -200px;
bottom: -400px;
opacity: 0.5;
}
.fire-glow-2 {
width: 800px;
height: 800px;
right: -200px;
bottom: -300px;
opacity: 0.5;
}
.fire-glow-3 {
width: 900px;
height: 900px;
left: 50%;
bottom: -600px;
transform: translateX(-50%);
opacity: 0.7;
}
.fire-glow-4 {
width: 1000px;
height: 1000px;
left: 10%;
bottom: -600px;
transform: translateX(-25%);
opacity: 0.55;
}
.fire-glow-5 {
width: 1100px;
height: 1100px;
right: 10%;
bottom: -700px;
transform: translateX(25%);
opacity: 0.55;
}
.fire-glow-6 {
width: 1200px;
height: 1200px;
bottom: -700px;
left: -200px;
opacity: 1;
transform: translateX(-50%);
opacity: 0.7;
}
.container {
position: relative;
width: inherit;
height: inherit;
}
.inner-glow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 100%;
}
.inner-glow-1 {
height: 25%;
width: 25%;
background-color: #d86306;
animation: flickerAnimation 4s ease-in-out infinite;
z-index: 10;
}
.inner-glow-2 {
height: 65%;
width: 65%;
background-color: #a62602;
animation: flickerAnimation 3s ease-in-out infinite;
z-index: 9;
}
.inner-glow-3 {
height: 100%;
width: 100%;
background-color: #670101;
animation: flickerAnimation 3.6s ease-in-out infinite;
}
@keyframes flickerAnimation {
0%,
100% {
opacity: 0.9;
scale: 0.98;
}
15%,
80% {
opacity: 1;
scale: 1;
}
30%,
60% {
opacity: 0.8;
scale: 1.05;
}
45%,
75% {
opacity: 0.95;
scale: 0.97;
}
}
/* ======== Sparks ======== */
.spark {
position: absolute;
border-radius: 100%;
scale: 1;
z-index: 999;
}
.spark .spark-glow {
width: 200%;
height: 200%;
transform: translate(-25%, -25%);
background-color: inherit;
border-radius: 100%;
filter: blur(8px) brightness(1.5);
z-index: 99;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment