sumnima sumnima sumnima sumnima sumnima sumnima sumnima
Categories
blog Deepseek extesion firefox

GrabFox – firefox extension

It all began with a simple need: to download AliExpress images for sample products for BigCommerce demo store for themes.

Trying to download high-quality images from a product page? Good luck.

That perfect shot is always locked in a lightbox slider. Right-click is disabled.

I tried existing image downloaders and grabbers, but they all fell short. So I built GrabFox – a simple tool that actually works for grabbing product images quickly and reliably.

#Deepseek

Categories
bash blog

image format – terminal command

setopt nullglob
mkdir -p jpg_output; for ext in png jpg jpeg heic tiff webp  gif avif; do
  for img in *."$ext"; do
    [ -f "$img" ] && magick "$img" "jpg_output/${img%.*}.png" 
  done
done
Categories
blog wordpress

blockquote – copy and code style

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {

  function setupCodeBlock(block, lang = '') {
    block.style.position = 'relative';

    // Collect all child lines
    let codeEls = Array.from(block.querySelectorAll('div, p, span'));
    if (codeEls.length === 0) codeEls = [block];

    // Generate raw code text with indentation
    let rawCode = '';
    let indentLevel = 0;
    codeEls.forEach(el => {
      let text = el.textContent.trim();
      if (text.includes('}')) indentLevel = Math.max(indentLevel - 1, 0);
      rawCode += '    '.repeat(indentLevel) + text + '\n'; // 4 spaces per indent
      if (text.includes('{')) indentLevel++;
    });

    // Create <pre><code> for Highlight.js
    const pre = document.createElement('pre');
    const code = document.createElement('code');
    code.className = lang + ' hljs';
    code.textContent = rawCode.replace(/[“”]/g,'"').replace(/[‘’]/g,"'");
    pre.appendChild(code);

    // Clear old content and append new
    while (block.firstChild) block.removeChild(block.firstChild);
    block.appendChild(pre);

    // Highlight.js
    hljs.highlightElement(code);

    // Create copy button
    const copyBtn = document.createElement('button');
    copyBtn.className = 'copy-btn';
    copyBtn.innerText = 'Copy';
    block.appendChild(copyBtn);

    // Copy button event
    copyBtn.addEventListener('click', () => {
      navigator.clipboard.writeText(code.textContent).then(() => {
        copyBtn.innerText = 'Copied!';
        setTimeout(() => copyBtn.innerText = 'Copy', 1500);
      });
    });
  }

  // Apply to all spoiler-body
  document.querySelectorAll('.spoiler-body').forEach(block => {
    const langSpan = block.closest('.spoiler').querySelector('.spoiler-head span');
    const lang = langSpan ? langSpan.textContent.toLowerCase() : '';
    setupCodeBlock(block, lang);
  });

});
</script>


<style>

.hljs { 
background: transparent;
}
.post-message blockquote,
.spoiler-body {
  background: #0d1117;
  color: #c9d1d9;
  padding: 14px;
  border-radius: 6px;
  line-height: 18px;
  overflow-x: auto;
  tab-size: 4;
  font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 14px;
  white-space: pre; /* preserve tabs and spaces */
  margin: 1em 0;
  position: relative;
}

 

.post-message blockquote div,
.post-message blockquote p,
.post-message blockquote span,
.spoiler-body div,
.spoiler-body p,
.spoiler-body span {
  margin: 0;
}
#af-wrapper .spoiler .spoiler-body { 
margin: 0px;
}
.copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  background: #161b22;
  border: 1px solid #30363d;
  color: #c9d1d9;
  padding: 4px 10px;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s ease-in-out, background 0.2s;
}

.post-message blockquote:hover .copy-btn,
.spoiler-body:hover .copy-btn,
.copy-btn:hover {
  opacity: 1;
}

.copy-btn:hover {
  background: #21262d;
}




 

.copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  background: #161b22;
  border: 1px solid #30363d;
  color: #c9d1d9;
  padding: 4px 10px;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s ease-in-out, background 0.2s;
}

.spoiler-body:hover .copy-btn,
.copy-btn:hover {
  opacity: 1;
}

.copy-btn:hover {
  background: #21262d;
}

</style>
Categories
blog javascript locomotiveScroll

locomotiveScroll – overflow div

 locomotiveScroll.lenisInstance.options.content.addEventListener('wheel', (event) => {
   const paths = event.composedPath();
 
   const stopPropagationIfMatch = (selector) =>
     paths.some(el => el instanceof HTMLElement && el.matches(selector) && event.stopPropagation());
 
   stopPropagationIfMatch('.productView-images'); 
   stopPropagationIfMatch('.navPage-subMenu');
   stopPropagationIfMatch('.gallery-grid');
   stopPropagationIfMatch('.halfGrid');
   stopPropagationIfMatch('.productOptions-list');
   stopPropagationIfMatch('.quickSearchResults');
 });
    
Categories
blog css scss

cheat.css

 font-family: fontFamily("headingSans"); 
 
 font-weight: fontWeight("bold");
 
 
 font-size: fontSize("largest");
 
 container("border");
 
  
 filter: blur(20px);
 -webkit-transition: all 2s ease;
 transition: all 2s ease;
 
 
 backdrop-filter: blur(10px);
 
 background: rgba( $header-bg,0.8); 
 
 
 @include breakpoint("medium") 
 
 
 $screen-small: 801px;
 $screen-medium: 1261px;
 $screen-large: 1600px;
 
 
 
 stencilColor('button--primary-backgroundColor');
 stencilColor('button--primary-color');
 

 
 display: flex;
 justify-content: center;
 align-items: center;
 
 
 overflow: auto;
 white-space: nowrap;
 
 
 &::after {
     content: '';
     position: absolute;
     width: 100%;
     transform: scaleX(0);
     height: 1px;
     bottom: 0;
     left: 0;
     background-color: stencilColor("navUser-color-hover");
     transform-origin: bottom right;
     transition: transform 0.25s ease-out;
 }
 
 &:hover::after {
     transform: scaleX(1);
     transform-origin: bottom left;
 }
 


    overflow: auto;                 
    scrollbar-width: none;        
    -ms-overflow-style: none;     
 
    &::-webkit-scrollbar {
        display: none;                  
    }
    
    
    
    
    
    #product-listing-container,#tab-related {
	 display: flex;
	 flex-wrap: wrap;
	 padding: 0;
	 margin: 0;
	 list-style: none;
	 align-items: stretch;
	 justify-content: flex-start;
	 width: 100%;
}
 ul.productGrid, ul.product-list {
	 width: 100%;
	 display: flex;
	 flex-wrap: wrap;
	 li {
		 flex: 0 0 50%;
		 display: flex;
		 padding: 0px !important;
		 @include breakpoint("medium") {
			 flex: 0 0 25%; 
		}
		 .card {
			 display: flex;
			 flex-direction: column;
			 flex: 1;
			 box-sizing: border-box;
			 height: 100%;
			 margin-bottom: 1rem;
			 .call-button {
				 margin-top: auto;
				 .button {
					 background: stencilColor('button--primary-backgroundColor');
					 color: stencilColor('button--primary-color');
				}
			}
		}
	}
}


Categories
bigcommerce blog stencil

.card–alternate color reset.

.card--alternate color does not remain consistent and keeps changing. This behavior negatively affects the overall design and user experience, as the inconsistent styling looks unpolished and distracting each time it occurs. It would be much better if the color could remain stable or be easily overridden through custom CSS.


.card--alternate {
  border: 3px solid inherit; 

  .card-body {
    background-color: transparent; 
  }

  &:hover {
    border-color: inherit;

    .card-body {
      background-color: inherit;

      .card-text {
        color: inherit;
      }
    }

    .card-title > a {
      color: inherit;
    }
  }
}

#cornerstone #bigcommerce

Categories
blog svg t-shirt

Ventura for t-shirt

Categories
blog chatgpt song

मनको कुरा (Whispers of the Heart)

a song from the perspective of a single female, with a sense of hesitation, shyness, and subtle longing, not fully bold love yet. soft, dreamy, and introspective:

Verse 1:
साँझको हावा — चुपचाप कुरा बनाउँदै
तिमीलाई सम्झँदा — मुटु अलिक हिचकिचाउँदै
सपनाको रङहरू — आँखामा झल्किँदै
तर शब्दहरू — अझै बोकी रहन्छु म

Chorus:
तिमी र म —
तिमी र म —
कहिल्यै बोल्न नसके नि
मन भित्र — 
मीठा कुरा 

यो हाँसो — 
सपनामा भित्र 
लुकेको छ

अलिक
हिच-किचा-उँछु
तर माया छ 

Verse 2:
ताराहरू झिलिमिली — रातभरि साथ  साथी  – बन्दै
तिम्रो याद — मनको कुनामा आई – बसदै
फूलहरूको खुश्बू — हावा सँग सँगै – खेल्दै
तर हाँसोमा — अलिक डर लुकेको जस्तो छ

Chorus:
तिमी र म —
तिमी र म —
कहिल्यै बोल्न नसके नि
मन भित्र — 
मीठा कुरा 

यो हाँसो — 
तिमी सँगै 
लुकेको छ

अलिक
हिच-किचा-उँछु
तर माया छ 


@copyright Rawi Rai

chatgpt – RAW

Title: मनको कुरा (Whispers of the Heart)

Verse 1:
साँझको हावा — मेरो अनुहारमा छुँदै
तिमीलाई देख्दा — मन अलिक हिचकिचाउँछ
सपनाको रङहरू — आँखामा झल्किँदै
तर शब्दहरू — अझै बोकी राख्छु म

Chorus:
तिमी र म — कहिल्यै बोल्न नसके पनि
मन भित्र — मीठा कुरा झन् बढ्दै
यो हाँसो — शंका भित्र लुकेको छ
माया छ तर — अलिक हिचकिचाउँछ

Verse 2:
ताराहरू झिलिमिली — मेरो रातभरि साथी
तिम्रो याद — मनको कुनामा छिपेको
फूलहरूको खुश्बू — तिमीलाई सम्झाउँछ
तर हाँसोमा — डर लुकेको जस्तो छ

Bridge:
के म भन्न सक्छु? — यो दिलको कुरा
के तिमी बुझ्ने छौ? — मेरो अनकही माया
सपनाको बाटो — सँगै हिँड्न चाहन्छु
तर पहिलो कदम — अलिक डर लाग्छ

Chorus (Repeat):
तिमी र म — कहिल्यै बोल्न नसके पनि
मन भित्र — मीठा कुरा झन् बढ्दै
यो हाँसो — शंका भित्र लुकेको छ
माया छ तर — अलिक हिचकिचाउँछ

Categories
blog

Protected: print

This content is password-protected. To view it, please enter the password below.

Categories
blog js

Chaos emoji

I was planning to add more load to the homepage until it felt heavy, but I ended up creating a fun, game-like chaos effect with falling emojis, gravity and chaos mode.

<div id="container"></div>
<div id="controls"></div>

<script>
// Create and append styles
const style = document.createElement('style');
style.textContent = `
  #container {
    position: fixed;
    width: 100%;
    height: 100%;
    top:0px;
    left:0px;
    z-index:9;
  }

  .emoji {
    position: absolute;
    user-select: none;
    cursor: pointer;
    font-size: 3rem;
    transition: transform 0.2s;
    z-index: 1;
  }

  .emoji:hover {
    transform: scale(1.2);
    z-index: 2;
  }

  #controls {
position: fixed;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
border-radius: 10px;
display: flex;
gap: 10px;
z-index: 100;
text-align: center;
justify-content: center;
align-items: center;
}

button {
border: medium;
padding: 0;
cursor: pointer;
font-weight: bold;
transition: 0.2s;
font-size: 2.5rem;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 100px;
height: 70px;
width: 70px;
 transform: scale(0.9);
opacity:0.6;
}
button[title="Add More"] {
  display: none;
}

  button:hover { 
    transform: scale(1);
  text-decoration: none;
  opacity:1 !important;
  }
`;
document.head.appendChild(style);

// Initialize the application
const container = document.getElementById("container");
const controlsDiv = document.getElementById("controls");

const emojis = ["🍎","🍊","🍋","🍉","🍇","🍌","🍒","🍑","🍍","🥭","🥝","🍓",
   "⚽","🏀","🏐","🎾","🥎","🏉","🦄","🐇","🐱","🐶","🐰","🦊","🐻","🐼",
               "🐨","🐯","🦁","🐮","🐷","🐸","🐙","🐳","🐠","🦋","🐥","🌺","🌸","💐","🌷","🌹","🥀","🌻","🌼","👑","🎀","🎁","🎂","🍦","🍭","🍬","🧁","🎂","🍰","🧸","🎈","🎉","🎊","🪅","🪩","🎁","🎀","👗","👚","👛","👜","💍","💎","📿","❤️","💖","💝","💗","💓","💞","💕","❣️","⭐","🌟","✨","⚡️","🌈","☁️","☀️","🌙"];

const balls = [];
let num = 35;
let gravityEnabled = true;
let chaosMode = false;

// Create control buttons with emoji icons
const addBtn = document.createElement("button");
addBtn.innerHTML = '🍇';
addBtn.title = "Add More";
controlsDiv.appendChild(addBtn);

const gravityBtn = document.createElement("button");
gravityBtn.innerHTML = '🌍';
gravityBtn.title = "Toggle Gravity";
controlsDiv.appendChild(gravityBtn);

const chaosBtn = document.createElement("button");
chaosBtn.innerHTML = '🌈';
chaosBtn.title = "Super Chaos";
controlsDiv.appendChild(chaosBtn);

// Initialize the animation
function init() {
  // Clear existing balls
  balls.forEach(ball => {
    if (ball.el.parentNode) {
      ball.el.parentNode.removeChild(ball.el);
    }
  });
  balls.length = 0;
  
  // Create new balls
  for (let i = 0; i < num; i++) {
    createBall();
  }
}

// Create a single ball
function createBall() {
  const el = document.createElement("div");
  el.className = "emoji";
  el.textContent = emojis[Math.floor(Math.random() * emojis.length)];
  const size = 2 + Math.random() * 2;
  el.style.fontSize = size + "rem";
  container.appendChild(el);

  const side = Math.floor(Math.random() * 4);
  let x, y, vx, vy;
  
  if (side === 0) { // top
    x = Math.random() * window.innerWidth;
    y = -50;
    vx = (Math.random() - 0.5) * 4;
    vy = Math.random() * 3 + 2;
  } else if (side === 1) { // left
    x = -50;
    y = Math.random() * window.innerHeight;
    vx = Math.random() * 3 + 2;
    vy = (Math.random() - 0.5) * 4;
  } else if (side === 2) { // right
    x = window.innerWidth + 50;
    y = Math.random() * window.innerHeight;
    vx = -(Math.random() * 3 + 2);
    vy = (Math.random() - 0.5) * 4;
  } else { // bottom
    x = Math.random() * window.innerWidth;
    y = window.innerHeight + 50;
    vx = (Math.random() - 0.5) * 4;
    vy = -(Math.random() * 3 + 2);
  }

  const ball = {
    el,
    x, y,
    vx, vy,
    gravity: 0.3 + Math.random() * 0.3,
    bounce: 0.6 + Math.random() * 0.3,
    friction: 0.98,
    size: size
  };
  
  balls.push(ball);

  // Hover effect - bigger bounce
  el.addEventListener("mouseenter", () => {
    ball.vy = -15;
    ball.vx += (Math.random() - 0.5) * 5;
  });
  
  // Click to remove
  el.addEventListener("click", (e) => {
    e.stopPropagation();
    container.removeChild(el);
    const index = balls.indexOf(ball);
    if (index > -1) {
      balls.splice(index, 1);
    }
  });
}

// Animation loop
function animate() {
  balls.forEach(ball => {
    if (gravityEnabled) {
      ball.vy += ball.gravity;
    }
    
    ball.x += ball.vx;
    ball.y += ball.vy;

    const ballBox = ball.el.getBoundingClientRect();

    // Bounce off screen edges
    if (ball.y + ballBox.height >= window.innerHeight) {
      ball.y = window.innerHeight - ballBox.height;
      ball.vy *= -ball.bounce;
      ball.vx *= ball.friction;
    }

    if (ball.y <= 0) {
      ball.y = 0;
      ball.vy *= -ball.bounce;
      ball.vx *= ball.friction;
    }

    if (ball.x <= 0) {
      ball.x = 0;
      ball.vx *= -ball.bounce;
    }
    
    if (ball.x + ballBox.width >= window.innerWidth) {
      ball.x = window.innerWidth - ballBox.width;
      ball.vx *= -ball.bounce;
    }

    // Apply chaos mode effects
    if (chaosMode) {
      ball.vx += (Math.random() - 0.5) * 0.5;
      ball.vy += (Math.random() - 0.5) * 0.5;
      
      // Occasionally change color for fun
      if (Math.random() < 0.01) {
        ball.el.style.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
      }
    }

    ball.el.style.left = ball.x + "px";
    ball.el.style.top = ball.y + "px";
  });

  requestAnimationFrame(animate);
}

// Event listeners for buttons
addBtn.addEventListener("click", () => {
  for (let i = 0; i < 5; i++) {
    createBall();
  }
});

gravityBtn.addEventListener("click", () => {
  gravityEnabled = !gravityEnabled;
  gravityBtn.innerHTML = gravityEnabled ? '🌍' : '🚀';
  gravityBtn.title = gravityEnabled ? "Gravity On" : "Gravity Off";
});

chaosBtn.addEventListener("click", () => {
  chaosMode = !chaosMode;
  chaosBtn.innerHTML = chaosMode ? '🌪️' : '🌈';
  chaosBtn.title = chaosMode ? "Normal Mode" : "Super Chaos"; 
});

// Handle window resize
window.addEventListener("resize", () => {
  balls.forEach(ball => {
    // Keep balls within new screen bounds
    ball.x = Math.min(ball.x, window.innerWidth - ball.el.getBoundingClientRect().width);
    ball.y = Math.min(ball.y, window.innerHeight - ball.el.getBoundingClientRect().height);
  });
});

// Initialize and start animation
init();
animate();
</script>
Expand

2.0v 15 sep 2025

  • Auto Start Mode chaosMode/gravityEnabled
<div id="container"></div>
<div id="controls"></div>

<script>
// Create and append styles
const style = document.createElement('style');
style.textContent = `
  #container {
    position: fixed;
    width: 100%;
    height: 100%;
    top:0px;
    left:0px;
    z-index:3;
  }

  .emoji {
    position: absolute;
    user-select: none;
    cursor: pointer;
    font-size: 3rem;
    transition: transform 0.2s;
    z-index: 1;
  }

  .emoji:hover {
    transform: scale(1.2);
    z-index: 2;
  }

  #controls {
    position: fixed;
    bottom: 0px;
    left: 50%;
    transform: translateX(-50%);
    padding: 10px 20px;
    border-radius: 10px;
    display: flex;
    gap: 10px;
    z-index: 100;
    text-align: center;
    justify-content: center;
    align-items: center; 
    max-width: 90%;
  }

  button {
    border: medium;
    padding: 0;
    cursor: pointer;
    font-weight: bold;
    transition: 0.2s;
    font-size: 2.5rem;
    background-color: rgba(255, 255, 255, 0.8);
    border-radius: 100px;
    height: 70px;
    width: 70px;
    transform: scale(0.9);
    opacity:0;
  }
  button[title="Add More"] {
    display: none;
  }

  button:hover { 
    transform: scale(1);
    text-decoration: none;
    opacity:1 !important;
  }

  #controls:hover button{
    opacity:1 !important;
  }
  
  .active-mode {
    box-shadow: 0 0 15px 5px rgba(255, 255, 0, 0.7);
    animation: pulse 1s infinite;
  }
  
  @keyframes pulse {
    0% { transform: scale(0.9); }
    50% { transform: scale(1); }
    100% { transform: scale(0.9); }
  }
`;
document.head.appendChild(style);

// Initialize the application
const container = document.getElementById("container");
const controlsDiv = document.getElementById("controls");

const emojis = ["🍎","🍊","🍋","🍉","🍇","🍌","🍒","🍑","🍍","🥭","🥝","🍓",
   "⚽","🏀","🏐","🎾","🥎","🏉","🦄","🐇","🐱","🐶","🐰","🦊","🐻","🐼",
               "🐨","🐯","🦁","🐮","🐷","🐸","🐙","🐳","🐠","🦋","🐥","🌺","🌸","💐","🌷","🌹","🥀","🌻","🌼","👑","🎀","🎁","🎂","🍦","🍭","🍬","🧁","🎂","🍰","🧸","🎈","🎉","🎊","🪅","🪩","🎁","🎀","👗","👚","👛","👜","💍","💎","📿","❤️","💖","💝","💗","💓","💞","💕","❣️","⭐","🌟","✨","⚡️","🌈","☁️","☀️","🌙"];

const balls = [];
let num = 15;
let gravityEnabled = true;
let chaosMode = false;
let autoModeInterval;
let autoModeDelay = 2000; // Start with 2 seconds
let autoModeActiveTime = 5000; // Start with 5 seconds active

// Create control buttons with emoji icons
const addBtn = document.createElement("button");
addBtn.innerHTML = '🍇';
addBtn.title = "Add More";
controlsDiv.appendChild(addBtn);

const gravityBtn = document.createElement("button");
gravityBtn.innerHTML = '🌍';
gravityBtn.title = "Toggle Gravity";
controlsDiv.appendChild(gravityBtn);

const chaosBtn = document.createElement("button");
chaosBtn.innerHTML = '🌈';
chaosBtn.title = "Super Chaos";
controlsDiv.appendChild(chaosBtn);

const autoBtn = document.createElement("button");
autoBtn.innerHTML = '⏱️';
autoBtn.title = "Auto Mode";
controlsDiv.appendChild(autoBtn);

// Initialize the animation
function init() {
  // Clear existing balls
  balls.forEach(ball => {
    if (ball.el.parentNode) {
      ball.el.parentNode.removeChild(ball.el);
    }
  });
  balls.length = 0;
  
  // Create new balls
  for (let i = 0; i < num; i++) {
    createBall();
  }
}

// Create a single ball
function createBall() {
  const el = document.createElement("div");
  el.className = "emoji";
  el.textContent = emojis[Math.floor(Math.random() * emojis.length)];
  const size = 2 + Math.random() * 2;
  el.style.fontSize = size + "rem";
  container.appendChild(el);

  const side = Math.floor(Math.random() * 4);
  let x, y, vx, vy;
  
  if (side === 0) { // top
    x = Math.random() * window.innerWidth;
    y = -50;
    vx = (Math.random() - 0.5) * 4;
    vy = Math.random() * 3 + 2;
  } else if (side === 1) { // left
    x = -50;
    y = Math.random() * window.innerHeight;
    vx = Math.random() * 3 + 2;
    vy = (Math.random() - 0.5) * 4;
  } else if (side === 2) { // right
    x = window.innerWidth + 50;
    y = Math.random() * window.innerHeight;
    vx = -(Math.random() * 3 + 2);
    vy = (Math.random() - 0.5) * 4;
  } else { // bottom
    x = Math.random() * window.innerWidth;
    y = window.innerHeight + 50;
    vx = (Math.random() - 0.5) * 4;
    vy = -(Math.random() * 3 + 2);
  }

  const ball = {
    el,
    x, y,
    vx, vy,
    gravity: 0.3 + Math.random() * 0.3,
    bounce: 0.6 + Math.random() * 0.3,
    friction: 0.98,
    size: size
  };
  
  balls.push(ball);

  // Hover effect - bigger bounce
  el.addEventListener("mouseenter", () => {
    ball.vy = -15;
    ball.vx += (Math.random() - 0.5) * 5;
  });
  
  // Click to remove
  el.addEventListener("click", (e) => {
    e.stopPropagation();
    container.removeChild(el);
    const index = balls.indexOf(ball);
    if (index > -1) {
      balls.splice(index, 1);
    }
  });
}

// Animation loop
function animate() {
  balls.forEach(ball => {
    if (gravityEnabled) {
      ball.vy += ball.gravity;
    }
    
    ball.x += ball.vx;
    ball.y += ball.vy;

    const ballBox = ball.el.getBoundingClientRect();

    // Bounce off screen edges
    if (ball.y + ballBox.height >= window.innerHeight) {
      ball.y = window.innerHeight - ballBox.height;
      ball.vy *= -ball.bounce;
      ball.vx *= ball.friction;
    }

    if (ball.y <= 0) {
      ball.y = 0;
      ball.vy *= -ball.bounce;
      ball.vx *= ball.friction;
    }

    if (ball.x <= 0) {
      ball.x = 0;
      ball.vx *= -ball.bounce;
    }
    
    if (ball.x + ballBox.width >= window.innerWidth) {
      ball.x = window.innerWidth - ballBox.width;
      ball.vx *= -ball.bounce;
    }

    // Apply chaos mode effects
    if (chaosMode) {
      ball.vx += (Math.random() - 0.5) * 0.5;
      ball.vy += (Math.random() - 0.5) * 0.5;
      
      // Occasionally change color for fun
      if (Math.random() < 0.01) {
        ball.el.style.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
      }
    }

    ball.el.style.left = ball.x + "px";
    ball.el.style.top = ball.y + "px";
  });

  requestAnimationFrame(animate);
}

// Auto mode function
function startAutoMode() {
  // Clear any existing interval
  if (autoModeInterval) {
    clearInterval(autoModeInterval);
  }
  
  // Reset to initial values
  autoModeDelay = 2000;
  autoModeActiveTime = 5000;
  
  // Start the cycle
  autoModeInterval = setInterval(() => {
    // Enable both modes after the delay
    setTimeout(() => {
      gravityEnabled = true;
      chaosMode = true;
      updateButtonStates();
      
      // Disable after active time
      setTimeout(() => {
        gravityEnabled = false;
        chaosMode = false;
        updateButtonStates();
        
        // Multiply both delay and active time for next cycle
        autoModeDelay *= 3; // Changed from *2 to *3
        autoModeActiveTime *= 3; // Changed from fixed 5s to multiplied by 3
      }, autoModeActiveTime);
    }, autoModeDelay);
  }, autoModeDelay + autoModeActiveTime); // Total cycle time = delay + active time
}

// Update button visual states
function updateButtonStates() {
  if (gravityEnabled) {
    gravityBtn.classList.add('active-mode');
  } else {
    gravityBtn.classList.remove('active-mode');
  }
  
  if (chaosMode) {
    chaosBtn.classList.add('active-mode');
  } else {
    chaosBtn.classList.remove('active-mode');
  }
  
  gravityBtn.innerHTML = gravityEnabled ? '🌍' : '🚀';
  gravityBtn.title = gravityEnabled ? "Gravity On" : "Gravity Off";
  
  chaosBtn.innerHTML = chaosMode ? '🌪️' : '🌈';
  chaosBtn.title = chaosMode ? "Normal Mode" : "Super Chaos";
}

// Event listeners for buttons
addBtn.addEventListener("click", () => {
  for (let i = 0; i < 5; i++) {
    createBall();
  }
});

gravityBtn.addEventListener("click", () => {
  gravityEnabled = !gravityEnabled;
  updateButtonStates();
});

chaosBtn.addEventListener("click", () => {
  chaosMode = !chaosMode;
  updateButtonStates();
});

autoBtn.addEventListener("click", () => {
  startAutoMode();
  autoBtn.classList.add('active-mode');
});

// Handle window resize
window.addEventListener("resize", () => {
  balls.forEach(ball => {
    // Keep balls within new screen bounds
    ball.x = Math.min(ball.x, window.innerWidth - ball.el.getBoundingClientRect().width);
    ball.y = Math.min(ball.y, window.innerHeight - ball.el.getBoundingClientRect().height);
  });
});

// Initialize and start animation
init();
animate();

// Start auto mode after page loads
setTimeout(() => {
  startAutoMode();
  autoBtn.classList.add('active-mode');
}, 1000);
</script>
Expand

Credit : Deepseek

Categories
blog javascript

emoji cursors!

document.addEventListener("DOMContentLoaded", function() {
  // run only on archive/category pages
  if (!document.body.classList.contains("archive") || !document.body.classList.contains("category")) return;

  const emojis = [
    "🧸","🎈","🍭","🪁","🐻","🐼","🐨","🦄","🍦","🐰",
    "🌼","🌸","🌺","🌻","🌷",
    "🎨","🛷",
    "🍉","🍓","🌈"
  ];

  const articles = document.querySelectorAll("article.type-post");

  articles.forEach((article, i) => {
    // assign one emoji per article
    const randomEmoji = emojis[Math.floor(Math.random() * emojis.length)];

    // build and encode SVG containing the emoji
    const svg = `<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100">
                   <text y="80" font-size="80">${randomEmoji}</text>
                 </svg>`;
    const encoded = encodeURIComponent(svg);

    // make a unique class for this article
    const className = `emoji-cursor-${i}`;

    // create a style rule that applies the cursor to the article AND ALL ITS CHILDREN
    const styleEl = document.createElement('style');
    styleEl.textContent = `.${className}, .${className} * { cursor: url("data:image/svg+xml;utf8,${encoded}"), auto !important; }`;
    document.head.appendChild(styleEl);

    // toggle the class on hover so the cursor appears/disappears reliably
    article.addEventListener('mouseenter', () => article.classList.add(className));
    article.addEventListener('mouseleave', () => article.classList.remove(className));
  });
});