github.com/angrybunnyman.com

Portrait of the Man as a...

Portrait of a Egg

Post Nutrition Label

  • Content Type: Text
  • Read Time: 10 min
  • Topics: HTML, CSS, JS, Easter Eggs
  • Mood: Devious

Add a little weirdness to your blog: triple-click an image and it crackles with error energy and glows for a brief moment. This post shows the exact code, how it works, and a plain-language walkthrough of the JavaScript so non-coders can follow along.

originally posted as the 21st post for Blaugust

What we’re building

HTML

Wrap any image you want to enchant:

<div class="egg center">
  <img src="your-image.jpg" alt="Describe the image here" />
</div>

If you already use a .center class to center images, apply it to the container (.egg) instead of the <img>. See the CSS below.

CSS

Drop this into your site CSS. It handles the glow, the glitch slice, and respects prefers-reduced-motion.

:root {
  --egg-glow: var(--accent-color, #8cffd0);
  --egg-glow-2: #ff3b3b; /* secondary 'error' tint */
  --egg-flash-duration: 900ms;
}

/* The container is the “effect layer” */
.egg {
  position: relative;
  display: inline-block;
}

.center {
  display: block;
  margin-left: auto !important;
  margin-right: auto !important;
  width: 50% !important; /* adjust to taste */
}

/* Fill the container width with image */
.egg img {
  display: block;
  max-width: 100%;
  height: auto;
  transition: filter 120ms ease;
}

/* Overlay layers for both animation layers*/
.egg::before,
.egg::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: screen; /* works on light/dark backgrounds */
}

.egg::before {
  background:
    repeating-linear-gradient(
      0deg,
      rgba(255,255,255,0.0) 0 2px,
      rgba(255,255,255,0.03) 2px 3px
    ); /* subtle scanlines */
}

.egg::after {
  background:
    radial-gradient(60% 40% at 50% 50%, var(--egg-glow) 0%, transparent 70%),
    radial-gradient(40% 30% at 55% 45%, var(--egg-glow-2) 0%, transparent 60%);
  filter: blur(8px) saturate(1.2);
}

/* Active state: brief jitter + glow */
.egg.egg-active img {
  animation: egg-jitter 90ms steps(2, end) 0s 6;
  filter:
    drop-shadow(0 0 0.5rem var(--egg-glow))
    drop-shadow(0 0 1.2rem var(--egg-glow-2));
}

.egg.egg-active::before,
.egg.egg-active::after {
  opacity: 1;
  animation:
    egg-slice var(--egg-flash-duration) ease-out,
    egg-pulse var(--egg-flash-duration) ease-out;
}

/* Animations */
@keyframes egg-jitter {
  0%   { transform: translate(0, 0) }
  20%  { transform: translate(-1px,  0.5px) }
  40%  { transform: translate( 1px, -0.5px) }
  60%  { transform: translate(-0.5px, -1px) }
  80%  { transform: translate( 0.5px,  1px) }
  100% { transform: translate(0, 0) }
}

/* Simulated “error” slices scanning through */
@keyframes egg-slice {
  0%   { clip-path: inset(0 0 90% 0) }
  15%  { clip-path: inset(85% 0 0 0) }
  30%  { clip-path: inset(0 0 80% 0) }
  45%  { clip-path: inset(70% 0 0 0) }
  60%  { clip-path: inset(0 0 65% 0) }
  75%  { clip-path: inset(50% 0 0 0) }
  100% { clip-path: inset(0 0 0 0) }
}

/* Glow that blooms and fades */
@keyframes egg-pulse {
  0%   { opacity: 0; filter: blur(12px) saturate(1.2) }
  15%  { opacity: 1; filter: blur(10px) saturate(1.4) }
  60%  { opacity: 0.7; filter: blur(8px)  saturate(1.3) }
  100% { opacity: 0; filter: blur(6px)  saturate(1.1) }
}

/* Respect motion preferences */
@media (prefers-reduced-motion: reduce) {
  .egg.egg-active img {
    animation: none;
    filter: drop-shadow(0 0 0.9rem var(--egg-glow));
  }
  .egg.egg-active::before,
  .egg.egg-active::after {
    animation: none;
    opacity: 1;
  }
}

Customize the look

JavaScript

The more complex script I've had to figure out... it listens for triple-clicks on any .egg container and toggles the active class briefly.

<script>
(function () {
  const TRIPLE_WINDOW_MS = 500;  // time window to detect 3 rapid clicks
  const ACTIVE_MS = 900;         // how long the effect class stays on

  // Delegate clicks so any .egg on the page just works
  document.addEventListener('click', (e) => {
    const container = e.target.closest('.egg');
    if (!container) return;

    const now = performance.now();
    const state = container._eggState || (container._eggState = { last: 0, count: 0, timer: null });

    // Reset if too slow between clicks
    if (now - state.last > TRIPLE_WINDOW_MS) state.count = 0;
    state.last = now;
    state.count++;

    if (state.count === 3) {
      state.count = 0; // ready for the next triple

      // retrigger animation if spam-clicked
      container.classList.remove('egg-active');
      // force reflow so CSS animations restart cleanly
      // eslint-disable-next-line no-unused-expressions
      container.offsetWidth;
      container.classList.add('egg-active');

      clearTimeout(state.timer);
      state.timer = setTimeout(() => {
        container.classList.remove('egg-active');
      }, ACTIVE_MS);
    }
  }, { passive: true });
})();
</script>

Plain-language translation of the JavaScript

Accessibility notes

Reply on Bluesky ⤤ Reply by Email (or just say hi!) Reply on Mastodon ⤤

#egg