AI CSS Animations

Espresso Machine Pour

A hairline isometric espresso machine pours a thin accent stream into the cup, and the crema line rises inside the rim. The level is clipped to the cup opening, so the front wall stays solid.

Also known as: hairline isometric, isometric coffee machine, coffee pour animation css.

HTML

<div class="hln-coffee-pour" role="img" aria-label="An espresso machine pouring into a cup">
  <svg viewBox="-110 -60 220 120" aria-hidden="true">
    <g transform="translate(-.6 6.7) scale(.92)">
      <g><polygon points="-34.83,14 -34.77,13.72 -34.61,13.46 -34.35,13.21 -34,13 -2,-3 -1.57,-3.18 -1.08,-3.31 -0.55,-3.39 0,-3.41 0.55,-3.39 1.08,-3.31 1.57,-3.18 2,-3 34,13 34.35,13.21 34.61,13.46 34.77,13.72 34.83,14 34.83,18 34.77,18.28 34.61,18.54 34.35,18.79 34,19 2,35 1.57,35.18 1.08,35.31 0.55,35.39 0,35.41 -0.55,35.39 -1.08,35.31 -1.57,35.18 -2,35 -34,19 -34.35,18.79 -34.61,18.54 -34.77,18.28 -34.83,18"/><polygon points="34,13 34.35,13.21 34.61,13.46 34.77,13.72 34.83,14 34.77,14.28 34.61,14.54 34.35,14.79 34,15 2,31 1.57,31.18 1.08,31.31 0.55,31.39 0,31.41 -0.55,31.39 -1.08,31.31 -1.57,31.18 -2,31 -34,15 -34.35,14.79 -34.61,14.54 -34.77,14.28 -34.83,14 -34.77,13.72 -34.61,13.46 -34.35,13.21 -34,13 -2,-3 -1.57,-3.18 -1.08,-3.31 -0.55,-3.39 0,-3.41 0.55,-3.39 1.08,-3.31 1.57,-3.18 2,-3"/></g>
      <line class="hln-coffee-pour-l" x1="-9" y1="6.5" x2="-27" y2="15.5"/>
      <line class="hln-coffee-pour-l" x1="-3" y1="9.5" x2="-21" y2="18.5"/>
      <line class="hln-coffee-pour-l" x1="3" y1="12.5" x2="-15" y2="21.5"/>
      <line class="hln-coffee-pour-l" x1="9" y1="15.5" x2="-9" y2="24.5"/>
      <line class="hln-coffee-pour-l" x1="15" y1="18.5" x2="-3" y2="27.5"/>
      <g><polygon points="-12,2 24,20 24,-26 -12,-44"/><polygon points="36,14 24,20 24,-26 36,-32"/><polygon points="0,-50 36,-32 24,-26 -12,-44"/></g>
      <g><polygon points="-28,-22 8,-4 8,-18 -28,-36"/><polygon points="24,-12 8,-4 8,-18 24,-26"/><polygon points="-12,-44 24,-26 8,-18 -28,-36"/></g>
      <g transform="matrix(1 .5 0 -1 -28 -22)"><circle class="hln-coffee-pour-l" cx="26" cy="7" r="1.6"/><circle class="hln-coffee-pour-l" cx="31" cy="7" r="1.6"/><line class="hln-coffee-pour-l" x1="5" y1="7" x2="15" y2="7"/></g>
      <line class="hln-coffee-pour-l" x1="2" y1="-46" x2="28" y2="-33"/>
      <line class="hln-coffee-pour-l" x1="-1" y1="-44.5" x2="25" y2="-31.5"/>
      <line class="hln-coffee-pour-l" x1="-4" y1="-43" x2="22" y2="-30"/>
      <g><path d="M-11.78,-16 V-11.6 A7.78,3.89 0 0 0 3.78,-11.6 V-16 Z"/><ellipse cx="-4" cy="-16" rx="7.78" ry="3.89"/></g>
      <g><polygon points="-0.5,-9.25 13.5,-2.25 13.5,-4.45 -0.5,-11.45"/><polygon points="16.5,-3.75 13.5,-2.25 13.5,-4.45 16.5,-5.95"/><polygon points="2.5,-12.95 16.5,-5.95 13.5,-4.45 -0.5,-11.45"/></g>
      <g><path d="M-11.78,6 V16 A7.78,3.89 0 0 0 3.78,16 V6 Z"/><ellipse cx="-4" cy="6" rx="7.78" ry="3.89"/></g>
      <path class="hln-coffee-pour-o" d="M1.4,10.7 C5,12.1 5,17.3 1.4,15.1"/>
      <clipPath id="hln-coffee-pour-rim"><ellipse cx="-4" cy="6" rx="6.93" ry="3.46"/></clipPath>
      <g class="hln-coffee-pour-pour"><line class="hln-coffee-pour-a hln-coffee-pour-flow" x1="-4" y1="-11.4" x2="-4" y2="9.4"/></g>
      <g clip-path="url(#hln-coffee-pour-rim)"><ellipse class="hln-coffee-pour-l hln-coffee-pour-lvl" cx="-4" cy="9.2" rx="6.93" ry="3.46"/></g>
    </g>
  </svg>
</div>

CSS

.hln-coffee-pour {
  --c: var(--hln-color, #ff4f2e);
  font-size: var(--hln-size, 16px);
  position: relative;
  display: grid;
  place-items: center;
  width: 22em;
  height: 12em;
  border-radius: 0.75em;
  background: #f6f5f1;
  overflow: hidden;
}
.hln-coffee-pour svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffffff;
  stroke: #1c1d21;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.hln-coffee-pour svg * {
  vector-effect: non-scaling-stroke;
}
.hln-coffee-pour .hln-coffee-pour-o {
  fill: none;
}
.hln-coffee-pour .hln-coffee-pour-l {
  stroke: #9a9ca3;
}
.hln-coffee-pour .hln-coffee-pour-a {
  stroke: var(--c);
}
.hln-coffee-pour .hln-coffee-pour-flow {
  transform-box: fill-box;
  transform-origin: 50% 0;
  animation: hln-coffee-pour-flow 6s infinite;
}
.hln-coffee-pour .hln-coffee-pour-pour {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: hln-coffee-pour-stop 6s infinite;
}
.hln-coffee-pour .hln-coffee-pour-lvl {
  transform: matrix(1, 0, 0, 1, 0, -2.2);
  animation: hln-coffee-pour-fill 6s infinite;
}
@keyframes hln-coffee-pour-flow {
  0% { transform: scale(1, 0); }
  8.33% { transform: scale(1, 0); animation-timing-function: cubic-bezier(.55,0,.85,.3); }
  14.17% { transform: scale(1, 1); }
  100% { transform: scale(1, 1); }
}
@keyframes hln-coffee-pour-stop {
  0% { transform: scale(1, 1); }
  55% { transform: scale(1, 1); animation-timing-function: cubic-bezier(.55,0,.85,.3); }
  60.83% { transform: scale(1, 0); }
  100% { transform: scale(1, 0); }
}
@keyframes hln-coffee-pour-fill {
  0% { transform: matrix(1, 0, 0, 1, 0, 0); opacity: 0; }
  13.33% { transform: matrix(1, 0, 0, 1, 0, 0); opacity: 0; }
  15% { transform: matrix(1, 0, 0, 1, 0, 0); opacity: 1; animation-timing-function: cubic-bezier(.65,0,.35,1); }
  60% { transform: matrix(1, 0, 0, 1, 0, -2.2); opacity: 1; }
  85% { transform: matrix(1, 0, 0, 1, 0, -2.2); opacity: 1; animation-timing-function: cubic-bezier(.65,0,.35,1); }
  91.67% { transform: matrix(1, 0, 0, 1, 0, -2.2); opacity: 0; }
  100% { transform: matrix(1, 0, 0, 1, 0, 0); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hln-coffee-pour * {
    animation: none !important;
  }
}

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

Customizing this snippet

  • Color: set --hln-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --hln-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 hairline animations