AI CSS Animations

Gantry Pick and Place

A cartesian gantry robot moves only along its three axes: the bridge rolls in x, the carriage in y, the z-axis drops, grips the accent part and sets it on a fixture across the table.

Also known as: pick and place animation, robot arm animation, isometric factory, hairline animation.

HTML

<div class="hln-gantry-picker" role="img" aria-label="A gantry robot picks a part and places it on a fixture"><svg viewBox="-52 -25.77 122 66.55" aria-hidden="true"><g><polygon points="-38,15 18,43 18,42 -38,14"/><polygon points="56,24 18,43 18,42 56,23"/><polygon points="0,-5 56,23 18,42 -38,14"/></g><g><polygon points="-30,14 18,38 18,33 -30,9"/><polygon points="48,23 18,38 18,33 48,18"/><polygon points="0,-6 48,18 18,33 -30,9"/></g><line x1="6" y1="-3" x2="-24" y2="12" class="hln-gantry-picker-l"/><line x1="12" y1="0" x2="-18" y2="15" class="hln-gantry-picker-l"/><line x1="18" y1="3" x2="-12" y2="18" class="hln-gantry-picker-l"/><line x1="24" y1="6" x2="-6" y2="21" class="hln-gantry-picker-l"/><line x1="30" y1="9" x2="0" y2="24" class="hln-gantry-picker-l"/><line x1="36" y1="12" x2="6" y2="27" class="hln-gantry-picker-l"/><line x1="42" y1="15" x2="12" y2="30" class="hln-gantry-picker-l"/><g><polygon points="-2,-4 0,-3 0,-21 -2,-22"/><polygon points="2,-4 0,-3 0,-21 2,-22"/><polygon points="0,-23 2,-22 0,-21 -2,-22"/></g><g><polygon points="42,18 44,19 44,1 42,0"/><polygon points="46,18 44,19 44,1 46,0"/><polygon points="44,-1 46,0 44,1 42,0"/></g><g><polygon points="-3,-22.5 45,1.5 45,0 -3,-24"/><polygon points="47.5,0.25 45,1.5 45,0 47.5,-1.25"/><polygon points="-0.5,-25.25 47.5,-1.25 45,0 -3,-24"/></g><polygon class="hln-gantry-picker-l" points="-1,-0.5 8,4 0,8 -9,3.5"/><g><polygon points="8.5,21.75 15.5,25.25 15.5,24.65 8.5,21.15"/><polygon points="22.5,21.75 15.5,25.25 15.5,24.65 22.5,21.15"/><polygon points="15.5,17.65 22.5,21.15 15.5,24.65 8.5,21.15"/></g><g class="hln-gantry-picker-part"><g class="hln-gantry-picker-pop"><g class="hln-gantry-picker-a"><polygon points="-4.5,3.75 -0.5,5.75 -0.5,1.75 -4.5,-0.25"/><polygon points="3.5,3.75 -0.5,5.75 -0.5,1.75 3.5,-0.25"/><polygon points="-0.5,-2.25 3.5,-0.25 -0.5,1.75 -4.5,-0.25"/></g></g></g><g><polygon points="-29.5,-9.25 18.5,14.75 18.5,13.25 -29.5,-10.75"/><polygon points="21,13.5 18.5,14.75 18.5,13.25 21,12"/><polygon points="-27,-12 21,12 18.5,13.25 -29.5,-10.75"/></g><g class="hln-gantry-picker-bx"><g><polygon points="-26,-8.5 -22,-6.5 -22,-8.5 -26,-10.5"/><polygon points="8,-21.5 -22,-6.5 -22,-8.5 8,-23.5"/><polygon points="4,-25.5 8,-23.5 -22,-8.5 -26,-10.5"/></g><g class="hln-gantry-picker-cy"><g class="hln-gantry-picker-bz"><g><polygon points="-2.5,-0.25 -0.5,0.75 -0.5,-12.25 -2.5,-13.25"/><polygon points="1.5,-0.25 -0.5,0.75 -0.5,-12.25 1.5,-13.25"/><polygon points="-0.5,-14.25 1.5,-13.25 -0.5,-12.25 -2.5,-13.25"/></g><g><polygon points="-4.4,0 0.2,2.3 0.2,1.5 -4.4,-0.8"/><polygon points="3.4,0.7 0.2,2.3 0.2,1.5 3.4,-0.1"/><polygon points="-1.2,-2.4 3.4,-0.1 0.2,1.5 -4.4,-0.8"/></g></g><g><polygon points="-4.5,-8.75 -1,-7 -1,-14 -4.5,-15.75"/><polygon points="4,-9.5 -1,-7 -1,-14 4,-16.5"/><polygon points="0.5,-18.25 4,-16.5 -1,-14 -4.5,-15.75"/></g></g></g><g><polygon points="-28,9 -26,10 -26,-8 -28,-9"/><polygon points="-24,9 -26,10 -26,-8 -24,-9"/><polygon points="-26,-10 -24,-9 -26,-8 -28,-9"/></g><g><polygon points="16,31 18,32 18,14 16,13"/><polygon points="20,31 18,32 18,14 20,13"/><polygon points="18,12 20,13 18,14 16,13"/></g></svg></div>

CSS

.hln-gantry-picker {
  --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;
  --u: 1px;
}
.hln-gantry-picker svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffffff;
  stroke: #1c1d21;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.hln-gantry-picker svg * {
  vector-effect: non-scaling-stroke;
}
.hln-gantry-picker-l {
  stroke: #9a9ca3;
}
.hln-gantry-picker-a {
  fill: var(--c);
}
.hln-gantry-picker-bx {
  animation: hln-gantry-picker-bx 6s linear infinite;
}
.hln-gantry-picker-cy {
  animation: hln-gantry-picker-cy 6s linear infinite;
}
.hln-gantry-picker-bz {
  animation: hln-gantry-picker-bz 6s linear infinite;
}
.hln-gantry-picker-part {
  animation: hln-gantry-picker-part 6s linear infinite;
}
.hln-gantry-picker-pop {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: hln-gantry-picker-pop 6s linear infinite;
}
@keyframes hln-gantry-picker-bx {
  0% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  8% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  12% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  22% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  34% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  42% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  50% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); }
  54% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  62% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  70% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 13)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  100% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
}
@keyframes hln-gantry-picker-cy {
  0% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  8% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  12% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  22% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  34% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  42% { transform: translate(calc(var(--u) * -10), calc(var(--u) * 5)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  50% { transform: translate(calc(var(--u) * -10), calc(var(--u) * 5)); }
  54% { transform: translate(calc(var(--u) * -10), calc(var(--u) * 5)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  62% { transform: translate(calc(var(--u) * -10), calc(var(--u) * 5)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  70% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  100% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
}
@keyframes hln-gantry-picker-bz {
  0% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  8% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  12% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  22% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  34% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  42% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  50% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  54% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  62% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  70% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  80% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); }
  100% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); }
}
@keyframes hln-gantry-picker-part {
  0% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  8% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
  12% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  22% { transform: translate(calc(var(--u) * 0), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  34% { transform: translate(calc(var(--u) * 26), calc(var(--u) * 5)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  42% { transform: translate(calc(var(--u) * 16), calc(var(--u) * 10)); animation-timing-function: cubic-bezier(.4, 0, .3, 1.1); }
  50% { transform: translate(calc(var(--u) * 16), calc(var(--u) * 18)); }
  54% { transform: translate(calc(var(--u) * 16), calc(var(--u) * 18)); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  89.9% { transform: translate(calc(var(--u) * 16), calc(var(--u) * 18)); }
  90%, 100% { transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); }
}
@keyframes hln-gantry-picker-pop {
  0%, 84% { transform: scale(1); opacity: 1; animation-timing-function: ease-in; }
  90% { transform: scale(1); opacity: 0; }
  90.1% { transform: scale(0); opacity: 1; animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  97%, 100% { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hln-gantry-picker * {
    animation-play-state: paused !important;
    animation-delay: calc(var(--delay, 0s) - 3.4s) !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hln-gantry-picker, .hln-gantry-picker *, .hln-gantry-picker::before, .hln-gantry-picker::after, .hln-gantry-picker *::before, .hln-gantry-picker *::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