How to Enhance AI Chatbot Launcher Button Animation (Waves)

Howdy folks!

Two requests concerning this topic:

  1. Can you provide a CSS code that will allow me to enhance the animation (Waves) surrounding the AI Chatbot launcher button? Providing a CSS code for other types of animations would be nice as well. Examples:

    a. Neon Pulse
    b. Magnetic

  2. Can you kindly update the AI Chatbot widget’s General Settings > LAUNCHER BUTTON section to include at least three (3) launcher button animations? Details:

Thank you!

1 Like

Hey @AeroConsultants, nice to see a familiar face again! (or more like a profile pic :grin:)

I absolutely get where you’re coming from – animations would be really fun and engaging!

As for point 1, I’ll ask the devs if custom animations is something we can manage to recreate for you with the tools we have. Will get back to you on that in some time, as always :slightly_smiling_face:

In the meantime, could you please share the details on how do you want to enhance the waves? Maybe some specific parts of it you want to change?

To address point 2 though, I made a feature request on your behalf: Add animations to Launcher Button. I’m sure it gets a lot of attention and votes!

2 Likes

Hey @Irene!

We meet again. Ditto! :slight_smile:

Thanks for your support - as always.

In response:

  1. For the enhance waves, I was thinking about using the CSS code (etc.) your widget currently uses for the launcher button, but amending it to create something like this (with 3-5 waves emanating away from the launcher button and the wave colors matching the site’s theme ). Currently, the waves are not quite visible depending on the size selected for the widget button or the site’s background color. Makes sense?

    For 1.a (Neon), something like this (with option to change the brightness and speed of the orbiting ring)

    For 1.b (Magnetic or Orbiting Particles), something like this. (with option to change the color and speed of the orbiting particles). Very cool and AI-friendly!

I hope this helps.

(Voted!)

Cheers! :clinking_glasses:

1 Like

Thank you so much for the details!

I passed your comments to our devs, and they came up with this script for adding an animation:

(() => {
	const ANIMATION = 'neon'; // magnetic | neon | default
	const MAGNETIC_DOTS_COLOR = 'red';
	const NEON_COLOR = '#0ff';

	const WIDGET_ID = '9019baa4-6ea8-4e64-9856-5eab9dc16b55';
	const WIDGET_ROOT = `.eapps-ai-chatbot-${WIDGET_ID}-custom-css-root`;
	const WIDGET_BUTTON = `${WIDGET_ROOT} [class*="FloatingButton__FloatingButtonContainer-sc"] > button`;
	const WIDGET_DEFAULT_ANIMATION = `${WIDGET_ROOT} [class*="AnimationFrame__Frame-sc"]`;

	const waitForElement = (selector, root = document) =>
		new Promise((resolve) => {
			const check = () => {
				const el = root.querySelector(selector);
				if (el) return resolve(el);
			};

			check();

			const observer = new MutationObserver(() => {
				if (check()) observer.disconnect();
			});

			observer.observe(root, { childList: true, subtree: true });
		});

	const injectStyle = (css) => {
		const style = document.createElement('style');
		style.textContent = css;
		document.body.appendChild(style);
	};

	const HIDE_DEFAULT_ANIMATION = `
${WIDGET_DEFAULT_ANIMATION} { display: none; }
`;

	const NEON_ANIMATION = `
${WIDGET_BUTTON}::before,
${WIDGET_BUTTON}::after {
  content: "";
  position: absolute;
  inset: -4px;
  border: 2px solid ${NEON_COLOR};
  border-radius: inherit;
  animation: pulseOut 2s ease-out infinite;
  opacity: 0;
}

${WIDGET_BUTTON}::after {
  animation-delay: 1s;
}

@keyframes pulseOut {
  0%   { transform: scale(1);   opacity: 1; }
  100% { transform: scale(1.5); opacity: 0; }
}
`;

	const MAGNETIC_ANIMATION = `
.particles-field {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.particle {
  position: absolute;
  width: 4px;
  height: 4px;
  background: ${MAGNETIC_DOTS_COLOR};
  border-radius: 50%;
}

${WIDGET_BUTTON}:hover .particles-field {
  opacity: 1 !important;
}

@keyframes particleFloat {
  0%   { transform: translate(var(--x), var(--y)) scale(0); }
  50%  { transform: translate(calc(var(--x) * -1), calc(var(--y) * -1)) scale(1); }
  100% { transform: translate(var(--x), var(--y)) scale(0); }
}
`;

	const createParticles = (container, count = 50) => {
		for (let i = 0; i < count; i++) {
			const particle = document.createElement('div');
			particle.className = 'particle';
			particle.style.setProperty('--x', `${Math.random() * 200 - 100}px`);
			particle.style.setProperty('--y', `${Math.random() * 200 - 100}px`);
			particle.style.animation = `particleFloat ${1 + Math.random() * 2}s infinite`;
			particle.style.left = `${Math.random() * 100}%`;
			particle.style.top = `${Math.random() * 100}%`;
			container.appendChild(particle);
		}
	};

	waitForElement(WIDGET_BUTTON).then((button) => {
		if (ANIMATION === 'default') return;

		if (ANIMATION === 'magnetic') {
			injectStyle(MAGNETIC_ANIMATION + HIDE_DEFAULT_ANIMATION);

			const field = document.createElement('div');
			field.className = 'particles-field';
			button.appendChild(field);

			createParticles(field);
			return;
		}

		if (ANIMATION === 'neon') {
			injectStyle(NEON_ANIMATION + HIDE_DEFAULT_ANIMATION);
		}
	});
})();

The first 3 lines are customizable:

  1. In the first one you can choose the desired animation from the list after // sign.
  2. The second one lets you choose the color of magnetic animation.
  3. And the third one - the color of the neon animation.

Please try it out – I hope this enhances the appearance of your bot just like you wanted to :slightly_smiling_face:

3 Likes

Hi @Irene!

Wow! You guys are geniuses. Thank you so much!

Worked perfectly, except for one little thing: When I use the “magnetic” option, the magnetic particles appear only on widget hover (check our site for a live demo). Would it be possible to make the magnetic particles appear on widget load? (same behavior as the “neon” option). Also, it would be great to have an option to adjust the speed of the neon rings and orbiting particles.

Thank you!

1 Like

Solved!

My above request has been satisfied, thanks to the wonders of AI (ChatGPT).

Details:

  1. The code provided below allows the user to control the speed of the neon rings and magnetic particles. The comment (//) entries provide the details.

  2. To display the “magnetic particles” on widget load, the “:hover” rule was removed from the original CSS given below.

${WIDGET_BUTTON}:hover .particles-field {
  opacity: 1 !important;
}

Result: (here’s the entire modified code)

(() => {
  const ANIMATION = 'magnetic'; // magnetic | neon | default

  /* --- SPEED SETTINGS --- */
  const NEON_SPEED = 2;              // seconds per pulse
  const MAGNETIC_SPEED_MIN = 1;      // particle animation minimum seconds
  const MAGNETIC_SPEED_MAX = 3;      // particle animation maximum seconds
  /* ------------------ */

  const MAGNETIC_DOTS_COLOR = '#999';
  const NEON_COLOR = '#707070';

  const WIDGET_ID = '9019baa4-6ea8-4e64-9856-5eab9dc16b55';
  const WIDGET_ROOT = `.eapps-ai-chatbot-${WIDGET_ID}-custom-css-root`;
  const WIDGET_BUTTON = `${WIDGET_ROOT} [class*="FloatingButton__FloatingButtonContainer-sc"] > button`;
  const WIDGET_DEFAULT_ANIMATION = `${WIDGET_ROOT} [class*="AnimationFrame__Frame-sc"]`;

  const waitForElement = (selector, root = document) =>
    new Promise((resolve) => {
      const check = () => {
        const el = root.querySelector(selector);
        if (el) return resolve(el);
      };
      check();
      const observer = new MutationObserver(() => {
        if (check()) observer.disconnect();
      });
      observer.observe(root, {
        childList: true,
        subtree: true
      });
    });

  const injectStyle = (css) => {
    const style = document.createElement('style');
    style.textContent = css;
    document.body.appendChild(style);
  };

  const HIDE_DEFAULT_ANIMATION = `
${WIDGET_DEFAULT_ANIMATION} { display: none; }
`;

  /* --- NEON WITH SPEED VARIABLE --- */
  const NEON_ANIMATION = `
${WIDGET_BUTTON}::before,
${WIDGET_BUTTON}::after {
  content: "";
  position: absolute;
  inset: -4px;
  border: 2px solid ${NEON_COLOR};
  border-radius: inherit;
  animation: pulseOut ${NEON_SPEED}s ease-out infinite;
  opacity: 0;
}

${WIDGET_BUTTON}::after {
  animation-delay: ${NEON_SPEED / 2}s;
}

@keyframes pulseOut {
  0%   { transform: scale(1);   opacity: 1; }
  100% { transform: scale(1.5); opacity: 0; }
}
`;

  /* --- MAGNETIC BASE ANIMATION CSS --- */
  const MAGNETIC_ANIMATION = `
.particles-field {
  position: absolute;
  inset: 0;
  opacity: 1; /* <-- now visible immediately */
  transition: opacity 0.3s ease;
}

.particle {
  position: absolute;
  width: 4px;
  height: 4px;
  background: ${MAGNETIC_DOTS_COLOR};
  border-radius: 50%;
}

/* removed hover effect entirely */

@keyframes particleFloat {
  0%   { transform: translate(var(--x), var(--y)) scale(0); }
  50%  { transform: translate(calc(var(--x) * -1), calc(var(--y) * -1)) scale(1); }
  100% { transform: translate(var(--x), var(--y)) scale(0); }
}
`;

  const createParticles = (container, count = 50) => {
    for (let i = 0; i < count; i++) {
      const particle = document.createElement('div');
      particle.className = 'particle';

      particle.style.setProperty('--x', `${Math.random() * 200 - 100}px`);
      particle.style.setProperty('--y', `${Math.random() * 200 - 100}px`);

      const duration =
        MAGNETIC_SPEED_MIN +
        Math.random() * (MAGNETIC_SPEED_MAX - MAGNETIC_SPEED_MIN);

      particle.style.animation = `particleFloat ${duration}s infinite`;

      particle.style.left = `${Math.random() * 100}%`;
      particle.style.top = `${Math.random() * 100}%`;

      container.appendChild(particle);
    }
  };

  waitForElement(WIDGET_BUTTON).then((button) => {
    if (ANIMATION === 'default') return;

    if (ANIMATION === 'magnetic') {
      injectStyle(MAGNETIC_ANIMATION + HIDE_DEFAULT_ANIMATION);
      const field = document.createElement('div');
      field.className = 'particles-field';
      button.appendChild(field);
      createParticles(field);
      return;
    }

    if (ANIMATION === 'neon') {
      injectStyle(NEON_ANIMATION + HIDE_DEFAULT_ANIMATION);
    }
  });
})();
3 Likes

I admire your eagerness to explore and customise the solutions provided to suit your needs! And thanks so much for adding to our Community – we appreciate the collaboration :slightly_smiling_face:

2 Likes

Thanks for checking with the devs about whether custom animations are possible. Really appreciate you looking into it. I’ll wait for your update on that whenever you have more info.

About the waves, I can definitely share a bit more. What I’m hoping for is:

  • slightly smoother transitions between the wave peaks,

  • maybe a bit more motion depth so it feels more layered,

  • and if possible, a subtle glow or pulse to make the waves feel more alive rather than static.

Even small tweaks like speed variation or directional shifts could make a big difference.

Also, thanks for creating the feature request for animations on the Launcher Button — that’s awesome. Fingers crossed it gets some traction.

I’ve been noting down a few UI animation patterns and references here too, in case it’s useful:
https://inatbixindir.tr

2 Likes

Dear @Rohan_Khan, thank you for sharing your thoughts! Feel free to add any details in the Wishlist thread about the animations – it’ll really help us understand everyone’s vision better :smiling_face: