AI CSS Animations

Flat-Pack Cabinet Assembly

Panels of a flat-pack cabinet fly in from every side and snap together on springs: back, base, sides, shelf and top, with the accent drawer sliding home last before it all lifts away.

Also known as: furniture assembly animation, isometric exploded view, hairline animation.

HTML

<div class="hln-flatpack-assembly" role="img" aria-label="A flat-pack cabinet assembles itself piece by piece"><svg viewBox="-40 -25.91 84 45.82" aria-hidden="true"><g><polygon points="-36,6 4,26 4,25 -36,5"/><polygon points="38,9 4,26 4,25 38,8"/><polygon points="-2,-12 38,8 4,25 -36,5"/></g><polyline points="4,19 8,21 9.5,20.25" fill="none"/><g class="hln-flatpack-assembly-back"><g><polygon points="0.7,-1.85 13.7,4.65 13.7,-14.35 0.7,-20.85"/><polygon points="14.5,4.25 13.7,4.65 13.7,-14.35 14.5,-14.75"/><polygon points="1.5,-21.25 14.5,-14.75 13.7,-14.35 0.7,-20.85"/></g></g><g class="hln-flatpack-assembly-base"><g><polygon points="-10,4 6,12 6,10 -10,2"/><polygon points="16,7 6,12 6,10 16,5"/><polygon points="0,-3 16,5 6,10 -10,2"/></g></g><g class="hln-flatpack-assembly-left"><g><polygon points="-10,2 -8.5,2.75 -8.5,-16.25 -10,-17"/><polygon points="1.5,-2.25 -8.5,2.75 -8.5,-16.25 1.5,-21.25"/><polygon points="0,-22 1.5,-21.25 -8.5,-16.25 -10,-17"/></g></g><g class="hln-flatpack-assembly-shelf"><g><polygon points="-8.5,-6.25 4.5,0.25 4.5,-0.95 -8.5,-7.45"/><polygon points="13.7,-4.35 4.5,0.25 4.5,-0.95 13.7,-5.55"/><polygon points="0.7,-12.05 13.7,-5.55 4.5,-0.95 -8.5,-7.45"/></g></g><g class="hln-flatpack-assembly-drawer"><g class="hln-flatpack-assembly-a"><polygon points="-8.5,2.75 4.5,9.25 4.5,1.75 -8.5,-4.75"/><polygon points="13.5,4.75 4.5,9.25 4.5,1.75 13.5,-2.75"/><polygon points="0.5,-9.25 13.5,-2.75 4.5,1.75 -8.5,-4.75"/></g><line x1="-4" y1="0" x2="0" y2="2"/></g><g class="hln-flatpack-assembly-right"><g><polygon points="4.5,9.25 6,10 6,-9 4.5,-9.75"/><polygon points="16,5 6,10 6,-9 16,-14"/><polygon points="14.5,-14.75 16,-14 6,-9 4.5,-9.75"/></g></g><g class="hln-flatpack-assembly-top"><g><polygon points="-11,-17 6,-8.5 6,-10.3 -11,-18.8"/><polygon points="17,-14 6,-8.5 6,-10.3 17,-15.8"/><polygon points="0,-24.3 17,-15.8 6,-10.3 -11,-18.8"/></g></g><line x1="-8.5" y1="5.25" x2="3.5" y2="11.25" class="hln-flatpack-assembly-l"/></svg></div>

CSS

.hln-flatpack-assembly {
  --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-flatpack-assembly svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffffff;
  stroke: #1c1d21;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.hln-flatpack-assembly svg * {
  vector-effect: non-scaling-stroke;
}
.hln-flatpack-assembly-l {
  stroke: #9a9ca3;
}
.hln-flatpack-assembly-a {
  fill: var(--c);
}
.hln-flatpack-assembly-back {
  animation: hln-flatpack-assembly-back 8s linear infinite;
}
@keyframes hln-flatpack-assembly-back {
  0% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -16)); }
  0% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -16)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  3% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * -4.8)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  9%, 86% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  92%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-base {
  animation: hln-flatpack-assembly-base 8s linear infinite;
}
@keyframes hln-flatpack-assembly-base {
  0% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -10)); }
  6% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -10)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  9% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * -3)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  15%, 84.33% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  90.33%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-left {
  animation: hln-flatpack-assembly-left 8s linear infinite;
}
@keyframes hln-flatpack-assembly-left {
  0% { opacity: 0; transform: translate(calc(var(--u) * -16), calc(var(--u) * -8)); }
  12% { opacity: 0; transform: translate(calc(var(--u) * -16), calc(var(--u) * -8)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  15% { opacity: 1; transform: translate(calc(var(--u) * -4.8), calc(var(--u) * -2.4)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  21%, 82.67% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  88.67%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-shelf {
  animation: hln-flatpack-assembly-shelf 8s linear infinite;
}
@keyframes hln-flatpack-assembly-shelf {
  0% { opacity: 0; transform: translate(calc(var(--u) * -16), calc(var(--u) * 8)); }
  18% { opacity: 0; transform: translate(calc(var(--u) * -16), calc(var(--u) * 8)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  21% { opacity: 1; transform: translate(calc(var(--u) * -4.8), calc(var(--u) * 2.4)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  27%, 81% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  87%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-drawer {
  animation: hln-flatpack-assembly-drawer 8s linear infinite;
}
@keyframes hln-flatpack-assembly-drawer {
  0% { opacity: 0; transform: translate(calc(var(--u) * -18), calc(var(--u) * 9)); }
  36% { opacity: 0; transform: translate(calc(var(--u) * -18), calc(var(--u) * 9)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  39% { opacity: 1; transform: translate(calc(var(--u) * -5.4), calc(var(--u) * 2.7)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  45%, 76% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  82%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-right {
  animation: hln-flatpack-assembly-right 8s linear infinite;
}
@keyframes hln-flatpack-assembly-right {
  0% { opacity: 0; transform: translate(calc(var(--u) * 16), calc(var(--u) * 8)); }
  24% { opacity: 0; transform: translate(calc(var(--u) * 16), calc(var(--u) * 8)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  27% { opacity: 1; transform: translate(calc(var(--u) * 4.8), calc(var(--u) * 2.4)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  33%, 79.33% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  85.33%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
.hln-flatpack-assembly-top {
  animation: hln-flatpack-assembly-top 8s linear infinite;
}
@keyframes hln-flatpack-assembly-top {
  0% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -14)); }
  30% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -14)); animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  33% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * -4.2)); animation-timing-function: cubic-bezier(.3, 1.45, .5, 1); }
  39%, 77.67% { opacity: 1; transform: translate(calc(var(--u) * 0), calc(var(--u) * 0)); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  83.67%, 100% { opacity: 0; transform: translate(calc(var(--u) * 0), calc(var(--u) * -6)); }
}
@media (prefers-reduced-motion: reduce) {
  .hln-flatpack-assembly * {
    animation-play-state: paused !important;
    animation-delay: calc(var(--delay, 0s) - 5s) !important;
  }
}

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