Skip to content

Commit 5c74bba

Browse files
Bikram GoleBikram Gole
authored andcommitted
Optimize launch pulse effect to reduce animation lag
1 parent 6b92133 commit 5c74bba

2 files changed

Lines changed: 105 additions & 56 deletions

File tree

script.js

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ let terminalHistory = [];
185185
let terminalHistoryIndex = 0;
186186
let terminalDraft = "";
187187
let blackflagShotLockUntil = 0;
188+
let pulseWaveLayer = null;
189+
let pulseWaveRing = null;
190+
let pulseCoreFlash = null;
191+
let sparkBatchId = 0;
188192
const typewriterTokens = new WeakMap();
189193
const heroTaglineVariants = [
190194
"Aura Farmer // Chaotic Fun 🚀",
@@ -504,39 +508,65 @@ function triggerPulseBackdrop(clientX = null, clientY = null) {
504508
const x = typeof clientX === "number" && clientX > 0 ? clientX : width * 0.5;
505509
const y = typeof clientY === "number" && clientY > 0 ? clientY : height * 0.35;
506510

507-
const layer = document.createElement("div");
508-
layer.className = "pulse-wave";
509-
layer.style.setProperty("--pulse-x", `${Math.round((x / width) * 100)}%`);
510-
layer.style.setProperty("--pulse-y", `${Math.round((y / height) * 100)}%`);
511+
const isConstrained =
512+
window.matchMedia?.("(max-width: 820px)")?.matches
513+
|| window.matchMedia?.("(pointer: coarse)")?.matches
514+
|| false;
515+
const isFirefoxLike = navigator.userAgent.includes("Firefox") || navigator.userAgent.includes("LibreWolf");
516+
517+
if (!pulseWaveLayer) {
518+
pulseWaveLayer = document.createElement("div");
519+
pulseWaveLayer.className = "pulse-wave";
520+
pulseWaveRing = document.createElement("span");
521+
pulseWaveRing.className = "pulse-wave-ring";
522+
pulseWaveLayer.appendChild(pulseWaveRing);
523+
document.body.appendChild(pulseWaveLayer);
524+
}
511525

512-
document.body.appendChild(layer);
526+
if (!pulseCoreFlash) {
527+
pulseCoreFlash = document.createElement("span");
528+
pulseCoreFlash.className = "pulse-core-flash";
529+
document.body.appendChild(pulseCoreFlash);
530+
}
513531

514-
// Force animation start reliably across restricted browsers.
515-
void layer.offsetWidth;
516-
layer.classList.add("is-active");
517-
requestAnimationFrame(() => layer.classList.add("is-active"));
532+
const px = `${Math.round((x / width) * 100)}%`;
533+
const py = `${Math.round((y / height) * 100)}%`;
534+
pulseWaveLayer.style.setProperty("--pulse-x", px);
535+
pulseWaveLayer.style.setProperty("--pulse-y", py);
536+
pulseCoreFlash.style.left = `${x}px`;
537+
pulseCoreFlash.style.top = `${y}px`;
518538

519-
// Extra visible fallback flash for browsers that suppress blend/animation effects.
520-
const flash = document.createElement("span");
521-
flash.className = "pulse-core-flash";
522-
flash.style.left = `${x}px`;
523-
flash.style.top = `${y}px`;
524-
document.body.appendChild(flash);
525-
if (typeof flash.animate === "function") {
526-
flash.animate(
527-
[
528-
{ transform: "translate(-50%, -50%) scale(0.45)", opacity: 0.9 },
529-
{ transform: "translate(-50%, -50%) scale(3.6)", opacity: 0 },
530-
],
531-
{ duration: 420, easing: "cubic-bezier(0.2, 0.7, 0.3, 1)", fill: "forwards" }
532-
).onfinish = () => flash.remove();
533-
} else {
534-
window.setTimeout(() => flash.remove(), 450);
535-
}
539+
pulseWaveLayer.getAnimations().forEach((animation) => animation.cancel());
540+
pulseWaveRing?.getAnimations().forEach((animation) => animation.cancel());
541+
pulseCoreFlash.getAnimations().forEach((animation) => animation.cancel());
536542

537-
const cleanup = () => layer.remove();
538-
layer.addEventListener("animationend", cleanup, { once: true });
539-
window.setTimeout(cleanup, 1150);
543+
const waveDuration = isConstrained ? 640 : 820;
544+
const waveScaleTo = isConstrained ? 1.12 : 1.2;
545+
pulseWaveLayer.animate(
546+
[
547+
{ transform: "scale(0.92)", opacity: 0 },
548+
{ opacity: isFirefoxLike ? 0.62 : 0.82, offset: 0.18 },
549+
{ opacity: 0.3, offset: 0.6 },
550+
{ transform: `scale(${waveScaleTo})`, opacity: 0 },
551+
],
552+
{ duration: waveDuration, easing: "cubic-bezier(0.16, 0.82, 0.27, 1)", fill: "forwards" }
553+
);
554+
555+
pulseWaveRing?.animate(
556+
[
557+
{ transform: "translate(-50%, -50%) scale(0.34)", opacity: 0.95 },
558+
{ transform: `translate(-50%, -50%) scale(${isConstrained ? 9.5 : 13})`, opacity: 0 },
559+
],
560+
{ duration: waveDuration, easing: "ease-out", fill: "forwards" }
561+
);
562+
563+
pulseCoreFlash.animate(
564+
[
565+
{ transform: "translate(-50%, -50%) scale(0.45)", opacity: 0.9 },
566+
{ transform: "translate(-50%, -50%) scale(3.4)", opacity: 0 },
567+
],
568+
{ duration: isConstrained ? 320 : 420, easing: "cubic-bezier(0.2, 0.7, 0.3, 1)", fill: "forwards" }
569+
);
540570
}
541571

542572
function playPulseSound(pulseCount = 1) {
@@ -1779,16 +1809,30 @@ function showToast(message) {
17791809
}
17801810

17811811
function spawnSparks(total) {
1782-
for (let i = 0; i < total; i += 1) {
1783-
window.setTimeout(() => {
1784-
const spark = document.createElement("span");
1785-
spark.className = "spark";
1786-
spark.style.left = `${Math.random() * 98}vw`;
1787-
spark.style.setProperty("--dx", `${Math.random() * 110 - 55}px`);
1788-
document.body.appendChild(spark);
1789-
window.setTimeout(() => spark.remove(), 1200);
1790-
}, i * 38);
1812+
const isConstrained =
1813+
window.matchMedia?.("(max-width: 820px)")?.matches
1814+
|| window.matchMedia?.("(pointer: coarse)")?.matches
1815+
|| false;
1816+
const isFirefoxLike = navigator.userAgent.includes("Firefox") || navigator.userAgent.includes("LibreWolf");
1817+
const densityScale = isConstrained ? 0.35 : (isFirefoxLike ? 0.55 : 1);
1818+
const batchTotal = Math.max(3, Math.round(total * densityScale));
1819+
const batchId = `s${Date.now()}-${sparkBatchId += 1}`;
1820+
const fragment = document.createDocumentFragment();
1821+
1822+
for (let i = 0; i < batchTotal; i += 1) {
1823+
const spark = document.createElement("span");
1824+
spark.className = "spark";
1825+
spark.dataset.sparkBatch = batchId;
1826+
spark.style.left = `${Math.random() * 98}vw`;
1827+
spark.style.setProperty("--dx", `${Math.random() * 110 - 55}px`);
1828+
spark.style.setProperty("--spark-delay", `${i * 28}ms`);
1829+
fragment.appendChild(spark);
17911830
}
1831+
1832+
document.body.appendChild(fragment);
1833+
window.setTimeout(() => {
1834+
document.querySelectorAll(`[data-spark-batch="${batchId}"]`).forEach((node) => node.remove());
1835+
}, 1400 + batchTotal * 28);
17921836
}
17931837

17941838
let matrixCanvas = null;

styles.css

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,6 +2642,8 @@ body[data-theme="liquidglass"] .theme-cycle-btn {
26422642
z-index: 50;
26432643
pointer-events: none;
26442644
animation: spark-rise 1100ms linear forwards;
2645+
animation-delay: var(--spark-delay, 0ms);
2646+
will-change: transform, opacity;
26452647
}
26462648

26472649
@keyframes spark-rise {
@@ -2662,6 +2664,7 @@ body[data-theme="liquidglass"] .theme-cycle-btn {
26622664
radial-gradient(680px 460px at var(--pulse-x, 50%) var(--pulse-y, 35%), rgba(68, 130, 244, 0.26), transparent 78%);
26632665
mix-blend-mode: screen;
26642666
filter: blur(1px) saturate(132%);
2667+
will-change: transform, opacity;
26652668
}
26662669

26672670
body.browser-firefox .pulse-wave {
@@ -2684,10 +2687,11 @@ body.browser-firefox .pulse-wave {
26842687
background:
26852688
radial-gradient(circle, rgba(235, 248, 255, 0.95) 0%, rgba(145, 210, 255, 0.85) 42%, rgba(255, 170, 96, 0.52) 70%, rgba(255, 170, 96, 0) 100%);
26862689
box-shadow: 0 0 20px rgba(151, 215, 255, 0.82), 0 0 34px rgba(255, 161, 85, 0.5);
2690+
opacity: 0;
2691+
will-change: transform, opacity;
26872692
}
26882693

2689-
.pulse-wave::after {
2690-
content: "";
2694+
.pulse-wave-ring {
26912695
position: absolute;
26922696
left: var(--pulse-x, 50%);
26932697
top: var(--pulse-y, 35%);
@@ -2698,26 +2702,27 @@ body.browser-firefox .pulse-wave {
26982702
box-shadow: 0 0 16px rgba(122, 186, 255, 0.62), 0 0 28px rgba(255, 158, 74, 0.35);
26992703
transform: translate(-50%, -50%) scale(0.34);
27002704
opacity: 0;
2705+
will-change: transform, opacity;
27012706
}
27022707

2703-
.pulse-wave.is-active {
2704-
animation: pulse-bg-wave 840ms cubic-bezier(0.16, 0.82, 0.27, 1) forwards;
2705-
}
2706-
2707-
.pulse-wave.is-active::after {
2708-
animation: pulse-ring 840ms ease-out forwards;
2709-
}
2710-
2711-
@keyframes pulse-bg-wave {
2712-
0% { transform: scale(0.88); opacity: 0; }
2713-
18% { opacity: 0.9; }
2714-
62% { opacity: 0.35; }
2715-
100% { transform: scale(1.22); opacity: 0; }
2708+
body.force-terminal-fallback .pulse-wave {
2709+
inset: -8%;
2710+
filter: none;
2711+
background:
2712+
radial-gradient(140px 140px at var(--pulse-x, 50%) var(--pulse-y, 35%), rgba(164, 218, 255, 0.85), transparent 66%),
2713+
radial-gradient(360px 260px at calc(var(--pulse-x, 50%) + 8%) calc(var(--pulse-y, 35%) - 8%), rgba(255, 162, 85, 0.34), transparent 72%),
2714+
radial-gradient(520px 380px at var(--pulse-x, 50%) var(--pulse-y, 35%), rgba(71, 139, 255, 0.26), transparent 78%);
27162715
}
27172716

2718-
@keyframes pulse-ring {
2719-
0% { transform: translate(-50%, -50%) scale(0.34); opacity: 0.95; }
2720-
100% { transform: translate(-50%, -50%) scale(14); opacity: 0; }
2717+
@media (max-width: 820px) {
2718+
.pulse-wave {
2719+
inset: -8%;
2720+
filter: none;
2721+
background:
2722+
radial-gradient(140px 140px at var(--pulse-x, 50%) var(--pulse-y, 35%), rgba(164, 218, 255, 0.85), transparent 66%),
2723+
radial-gradient(360px 260px at calc(var(--pulse-x, 50%) + 8%) calc(var(--pulse-y, 35%) - 8%), rgba(255, 162, 85, 0.34), transparent 72%),
2724+
radial-gradient(520px 380px at var(--pulse-x, 50%) var(--pulse-y, 35%), rgba(71, 139, 255, 0.26), transparent 78%);
2725+
}
27212726
}
27222727

27232728
.matrix-layer {

0 commit comments

Comments
 (0)