AI CSS Animations

Response Branch Switcher

A regenerated reply with three versions: the arrows press, the reply slides sideways to the next branch and the 2 / 3 switcher ticks along, then it walks back. The counter is a @property integer.

Also known as: regenerate response versions, chatgpt response 2 of 3, message branch navigation.

Write a tagline for our coffee subscription

Fresh beans at your door, roasted the week they ship.

Your morning ritual, roasted to order and on repeat.

Never run out of good coffee again.

HTML

<div class="aia-response-branches" role="status" aria-label="Reply version 2 of 3">
  <p class="aia-response-branches-user">Write a tagline for our coffee subscription</p>
  <div class="aia-response-branches-reply">
    <span class="aia-response-branches-av" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l1.9 5.1 5.1 1.9-5.1 1.9L12 17.5l-1.9-5.1L5 10.5l5.1-1.9z"/></svg></span>
    <div class="aia-response-branches-view">
      <div class="aia-response-branches-track">
        <p>Fresh beans at your door, roasted the week they ship.</p>
        <p>Your morning ritual, roasted to order and on repeat.</p>
        <p>Never run out of good coffee again.</p>
      </div>
    </div>
  </div>
  <div class="aia-response-branches-bar">
    <button type="button" class="aia-response-branches-prev" aria-label="Previous version"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m14.5 6-6 6 6 6"/></svg></button>
    <span class="aia-response-branches-n" aria-hidden="true"></span>
    <button type="button" class="aia-response-branches-next" aria-label="Next version"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9.5 6 6 6-6 6"/></svg></button>
    <span class="aia-response-branches-sep" aria-hidden="true"></span>
    <button type="button" aria-label="Copy"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8.5" y="8.5" width="12" height="12" rx="2"/><path d="M15.5 8.5V5.5a2 2 0 0 0-2-2h-8a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h3"/></svg></button>
    <button type="button" aria-label="Regenerate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 12a8.5 8.5 0 1 0 2.6-6.1L3.5 8.5"/><path d="M3.5 3.5v5h5"/></svg></button>
  </div>
</div>

CSS

@property --aia-response-branches-k {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
@property --aia-response-branches-v {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}
.aia-response-branches {
  --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;
  position: relative;
  box-sizing: border-box;
  padding: 0.9em 1em;
  border-radius: 0.9em;
  background: color-mix(in srgb, currentColor 3%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 11%, transparent), 0 0.1em 0.2em color-mix(in srgb, currentColor 4%, transparent), 0 0.9em 2em -1.1em rgb(0 0 0 / 0.3);
  --d: 8s;
  --k: var(--aia-response-branches-k);
  width: 21em;
  padding: 0.8em 0.9em 0.55em;
  animation: aia-response-branches-clock var(--d) cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
.aia-response-branches-user {
  width: fit-content;
  max-width: 85%;
  margin: 0 0 0.7em auto;
  padding: 0.45em 0.8em;
  border-radius: 1em 1em 0.3em 1em;
  background: color-mix(in srgb, var(--c) 14%, transparent);
  font-size: 0.8em;
}
.aia-response-branches-reply {
  display: grid;
  grid-template-columns: 1.5em 1fr;
  gap: 0.6em;
  align-items: start;
}
.aia-response-branches-av {
  display: grid;
  place-items: center;
  width: 1.5em;
  height: 1.5em;
  border-radius: 50%;
  background: var(--c);
  color: #fff;
}
.aia-response-branches-av svg {
  width: 0.85em;
  height: 0.85em;
  fill: currentColor;
  stroke: none;
}
.aia-response-branches-view {
  overflow: hidden;
  height: 2.9em;
}
.aia-response-branches-track {
  display: flex;
  width: 300%;
  transform: translateX(calc(var(--k) * -33.3333%));
}
.aia-response-branches-track p {
  --i: 0;
  flex: 1;
  box-sizing: border-box;
  margin: 0;
  padding-right: 0.8em;
  font-size: 0.86em;
  line-height: 1.45;
  opacity: clamp(0, 1 - max(var(--k) - var(--i), var(--i) - var(--k)) * 1.6, 1);
}
.aia-response-branches-track p:nth-child(2) { --i: 1; }
.aia-response-branches-track p:nth-child(3) { --i: 2; }
.aia-response-branches-bar {
  display: flex;
  align-items: center;
  gap: 0.1em;
  margin: 0.35em 0 0 1.75em;
}
.aia-response-branches-bar button {
  position: relative;
  display: grid;
  place-items: center;
  width: 1.75em;
  height: 1.75em;
  padding: 0;
  border: 0;
  border-radius: 0.45em;
  background: transparent;
  color: color-mix(in srgb, currentColor 55%, transparent);
  cursor: pointer;
}
.aia-response-branches-bar button:focus-visible {
  outline: 2px solid var(--c);
  outline-offset: 1px;
}
.aia-response-branches-bar svg {
  width: 1.05em;
  height: 1.05em;
}
.aia-response-branches-prev {
  opacity: calc(1 - clamp(0, (0.5 - var(--k)) * 2, 1) * 0.6);
  animation: aia-response-branches-press-prev var(--d) ease infinite;
}
.aia-response-branches-next {
  opacity: calc(1 - clamp(0, (var(--k) - 1.5) * 2, 1) * 0.6);
  animation: aia-response-branches-press-next var(--d) ease infinite;
}
.aia-response-branches-n {
  min-width: 2.6em;
  color: color-mix(in srgb, currentColor 60%, transparent);
  font: 600 0.72em ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  text-align: center;
  --aia-response-branches-v: calc(var(--k) + 1);
  counter-reset: v var(--aia-response-branches-v);
}
.aia-response-branches-n::before { content: counter(v) " / 3"; }
.aia-response-branches-sep {
  width: 1px;
  height: 1em;
  margin: 0 0.35em;
  background: color-mix(in srgb, currentColor 14%, transparent);
}
@keyframes aia-response-branches-clock {
  0%, 14% { --aia-response-branches-k: 0; }
  20%, 39% { --aia-response-branches-k: 1; }
  45%, 64% { --aia-response-branches-k: 2; }
  70%, 89% { --aia-response-branches-k: 1; }
  95%, 100% { --aia-response-branches-k: 0; }
}
@keyframes aia-response-branches-press-next {
  0%, 9%, 17%, 34%, 42%, 100% { background: transparent; color: color-mix(in srgb, currentColor 55%, transparent); transform: none; }
  12%, 37% { background: color-mix(in srgb, var(--c) 16%, transparent); color: var(--c); transform: scale(0.86); }
  14%, 39% { background: color-mix(in srgb, var(--c) 12%, transparent); color: var(--c); transform: none; }
}
@keyframes aia-response-branches-press-prev {
  0%, 59%, 67%, 84%, 92%, 100% { background: transparent; color: color-mix(in srgb, currentColor 55%, transparent); transform: none; }
  62%, 87% { background: color-mix(in srgb, var(--c) 16%, transparent); color: var(--c); transform: scale(0.86); }
  64%, 89% { background: color-mix(in srgb, var(--c) 12%, transparent); color: var(--c); transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .aia-response-branches,
  .aia-response-branches-prev,
  .aia-response-branches-next {
    animation: none;
    --aia-response-branches-k: 1;
  }
}

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