AI CSS Animations

Diffusion Image Reveal

A frame of boiling grain slowly denoises into a dusk landscape while a step counter climbs to 30 of 30. The scene is pure gradients, the grain an SVG turbulence filter.

Also known as: image generation progress animation css, ai image generation animation, diffusion loading animation, noise to image reveal.

Generating

HTML

<div class="aia-diffusion-reveal" role="status" aria-label="Generating image">
  <div class="aia-diffusion-reveal-frame">
    <div class="aia-diffusion-reveal-scene">
      <span class="aia-diffusion-reveal-far"></span>
      <span class="aia-diffusion-reveal-near"></span>
    </div>
    <svg class="aia-diffusion-reveal-noise" aria-hidden="true">
      <filter id="aia-diffusion-reveal-grain"><feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0.2"/></filter>
      <rect width="100%" height="100%" filter="url(#aia-diffusion-reveal-grain)"/>
    </svg>
  </div>
  <div class="aia-diffusion-reveal-caption">
    <span>Generating</span>
    <span class="aia-diffusion-reveal-step"></span>
  </div>
</div>

CSS

@property --aia-diffusion-reveal-n {
  syntax: "<integer>";
  inherits: false;
  initial-value: 0;
}
.aia-diffusion-reveal {
  --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: 6s;
  display: grid;
  gap: 0.6em;
  width: 15em;
}
.aia-diffusion-reveal-frame {
  position: relative;
  height: 9.6em;
  border-radius: 0.8em;
  overflow: hidden;
  background: #3a3a40;
  box-shadow: 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent), 0 0.8em 1.6em -0.9em rgba(0, 0, 0, 0.45);
}
.aia-diffusion-reveal-scene {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 68% 56%, #fff4dc 0 6%, transparent 6.5%),
    radial-gradient(circle at 68% 56%, color-mix(in oklab, var(--c) 25%, #ffb35c), transparent 38%),
    linear-gradient(180deg, color-mix(in oklab, var(--c) 70%, #0b0b2a), color-mix(in oklab, var(--c) 45%, #ff7a59) 58%, #ffc98f 74%);
  animation: aia-diffusion-reveal-denoise var(--t) cubic-bezier(0.25, 0.6, 0.35, 1) infinite;
}
.aia-diffusion-reveal-far,
.aia-diffusion-reveal-near {
  position: absolute;
  inset: 0;
}
.aia-diffusion-reveal-far {
  background: linear-gradient(180deg, color-mix(in oklab, var(--c) 45%, #5b3a66), color-mix(in oklab, var(--c) 30%, #2a2140));
  clip-path: polygon(0 66%, 14% 52%, 26% 60%, 40% 44%, 55% 58%, 63% 54%, 78% 62%, 90% 50%, 100% 58%, 100% 100%, 0 100%);
}
.aia-diffusion-reveal-near {
  background: linear-gradient(180deg, #24182f, #120d1a);
  clip-path: polygon(0 78%, 18% 68%, 34% 76%, 50% 66%, 66% 74%, 82% 70%, 100% 80%, 100% 100%, 0 100%);
}
.aia-diffusion-reveal-noise {
  position: absolute;
  inset: -20%;
  width: 140%;
  height: 140%;
  mix-blend-mode: hard-light;
  animation:
    aia-diffusion-reveal-grain var(--t) cubic-bezier(0.25, 0.6, 0.35, 1) infinite,
    aia-diffusion-reveal-boil 0.4s steps(4) infinite;
}
.aia-diffusion-reveal-caption {
  display: flex;
  justify-content: space-between;
  font-size: 0.82em;
  font-weight: 500;
  color: color-mix(in srgb, currentColor 65%, transparent);
}
.aia-diffusion-reveal-step {
  font-variant-numeric: tabular-nums;
  counter-reset: aia-diffusion-reveal-n var(--aia-diffusion-reveal-n);
  animation: aia-diffusion-reveal-count var(--t) cubic-bezier(0.25, 0.6, 0.35, 1) infinite;
}
.aia-diffusion-reveal-step::before { content: "Step " counter(aia-diffusion-reveal-n) " of 30"; }
@keyframes aia-diffusion-reveal-denoise {
  0% { filter: blur(1.2em) saturate(0.3); scale: 1.12; }
  72%, 90% { filter: blur(0) saturate(1); scale: 1; }
  100% { filter: blur(1.2em) saturate(0.3); scale: 1.12; }
}
@keyframes aia-diffusion-reveal-grain {
  0% { opacity: 1; }
  72%, 90% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes aia-diffusion-reveal-boil {
  0% { translate: 0 0; }
  25% { translate: -4% 3%; }
  50% { translate: 3% -2%; }
  75% { translate: -2% -4%; }
  100% { translate: 0 0; }
}
@keyframes aia-diffusion-reveal-count {
  0% { --aia-diffusion-reveal-n: 0; }
  72%, 100% { --aia-diffusion-reveal-n: 30; }
}
@media (prefers-reduced-motion: reduce) {
  .aia-diffusion-reveal-scene,
  .aia-diffusion-reveal-noise,
  .aia-diffusion-reveal-step { animation: none; }
  .aia-diffusion-reveal-noise { opacity: 0; }
  .aia-diffusion-reveal-step { --aia-diffusion-reveal-n: 30; }
}

@media (prefers-reduced-motion: reduce) {
  .aia-diffusion-reveal, .aia-diffusion-reveal *, .aia-diffusion-reveal::before, .aia-diffusion-reveal::after, .aia-diffusion-reveal *::before, .aia-diffusion-reveal *::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