AI CSS Animations

Voice Orb Listening to Speaking

A glossy sky orb with clouds drifting inside wobbles gently while listening, then beats in bigger pulses as it speaks, and the label swaps to match. Gradients only, one shared clock.

Also known as: voice agent animation, chatgpt voice orb css, animated orb css, voice mode orb.

Listening Speaking

HTML

<div class="aia-voice-orb-states" role="status" aria-label="Voice mode: listening, then speaking">
  <div class="aia-voice-orb-states-orb"><span class="aia-voice-orb-states-clouds"></span></div>
  <div class="aia-voice-orb-states-label">
    <span class="aia-voice-orb-states-listen">Listening</span>
    <span class="aia-voice-orb-states-speak">Speaking</span>
  </div>
</div>

CSS

.aia-voice-orb-states {
  --c: var(--aia-color, #7c5cff);
  font-size: var(--aia-size, 16px);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.4;
  --t: 8s;
  display: grid;
  justify-items: center;
  gap: 1.1em;
}
.aia-voice-orb-states-orb {
  position: relative;
  width: 7.5em;
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  background:
    radial-gradient(circle at 50% 120%, color-mix(in srgb, var(--c) 80%, #000), transparent 60%),
    linear-gradient(180deg, color-mix(in srgb, var(--c) 30%, #fff), color-mix(in srgb, var(--c) 75%, #fff) 40%, var(--c) 80%);
  box-shadow:
    inset 0 0.35em 0.9em rgba(255, 255, 255, 0.55),
    inset 0 -0.5em 1.2em color-mix(in srgb, var(--c) 70%, #000),
    0 0.9em 2.2em -0.7em color-mix(in srgb, var(--c) 70%, transparent);
  animation: aia-voice-orb-states-pulse var(--t) cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
/* Two copies of the cloud field side by side; sliding one width loops cleanly. */
.aia-voice-orb-states-clouds {
  position: absolute;
  inset: 0 auto 0 0;
  width: 200%;
  background:
    radial-gradient(ellipse 26% 16% at 12% 56%, rgba(255, 255, 255, 0.85), transparent 70%),
    radial-gradient(ellipse 18% 13% at 22% 48%, rgba(255, 255, 255, 0.75), transparent 70%),
    radial-gradient(ellipse 30% 14% at 36% 80%, rgba(255, 255, 255, 0.6), transparent 70%),
    radial-gradient(ellipse 16% 10% at 40% 36%, rgba(255, 255, 255, 0.55), transparent 70%);
  background-size: 50% 100%;
  filter: blur(0.22em);
  opacity: 0.8;
  animation: aia-voice-orb-states-drift calc(var(--t) * 1.5) linear infinite;
}
.aia-voice-orb-states-label {
  display: grid;
  font-size: 0.95em;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.aia-voice-orb-states-label > span {
  grid-area: 1 / 1;
  text-align: center;
  opacity: 0;
  color: color-mix(in srgb, currentColor 70%, transparent);
  animation: aia-voice-orb-states-listen var(--t) ease infinite;
}
.aia-voice-orb-states-label > .aia-voice-orb-states-speak { animation-name: aia-voice-orb-states-speak; }
@keyframes aia-voice-orb-states-drift {
  to { transform: translateX(-50%); }
}
@keyframes aia-voice-orb-states-pulse {
  0%, 100% { scale: 1; }
  8%  { scale: 1.03; }
  14% { scale: 0.99; }
  22% { scale: 1.045; }
  30% { scale: 1; }
  38% { scale: 1.03; }
  47% { scale: 1; }
  54% { scale: 1.11; }
  58% { scale: 1.02; }
  63% { scale: 1.14; }
  67% { scale: 1.03; }
  72% { scale: 1.08; }
  76% { scale: 1.01; }
  82% { scale: 1.12; }
  87% { scale: 1.02; }
  92% { scale: 1.06; }
}
@keyframes aia-voice-orb-states-listen {
  0%, 44%, 100% { opacity: 1; translate: 0 0; }
  49%, 96% { opacity: 0; translate: 0 -0.3em; }
}
@keyframes aia-voice-orb-states-speak {
  0%, 46%, 100% { opacity: 0; translate: 0 0.3em; }
  51%, 94% { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .aia-voice-orb-states-orb,
  .aia-voice-orb-states-clouds,
  .aia-voice-orb-states-label > span { animation: none !important; }
  .aia-voice-orb-states-listen { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .aia-voice-orb-states, .aia-voice-orb-states *, .aia-voice-orb-states::before, .aia-voice-orb-states::after, .aia-voice-orb-states *::before, .aia-voice-orb-states *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --aia-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --aia-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar ai animations