Two isometric database cylinders trade one accent packet along a floor line, and each lid pulses as the write lands. Hairline SVG with CSS translate, scale and opacity.
Also known as: database replication animation, hairline isometric, data sync icon.
<div class="hln-database-sync" role="img" aria-label="Two databases syncing a record back and forth"> <svg viewBox="-110 -60 220 120" aria-hidden="true"><g transform="translate(0 15) scale(1.3)"><g><path d="M-50.97 -41V-17A16.97 8.49 0 0 0 -17.03 -17V-41Z"/><path class="hln-database-sync-in" fill="none" d="M-50.97 -25A16.97 8.49 0 0 0 -17.03 -25"/><path class="hln-database-sync-in" fill="none" d="M-50.97 -33A16.97 8.49 0 0 0 -17.03 -33"/><ellipse cx="-34" cy="-41" rx="16.97" ry="8.49"/></g><g class="hln-database-sync-ring hln-database-sync-ring-a"><ellipse cx="-34" cy="-41" rx="16.97" ry="8.49"/></g><line class="hln-database-sync-in" x1="-22" y1="-11" x2="22" y2="11"/><g class="hln-database-sync-move"><g class="hln-database-sync-pkt"><g><polygon points="-5,0 0,2.5 0,-2.5 -5,-5"/><polygon points="5,0 0,2.5 0,-2.5 5,-5"/><polygon points="0,-7.5 5,-5 0,-2.5 -5,-5"/></g></g></g><g><path d="M17.03 -7V17A16.97 8.49 0 0 0 50.97 17V-7Z"/><path class="hln-database-sync-in" fill="none" d="M17.03 9A16.97 8.49 0 0 0 50.97 9"/><path class="hln-database-sync-in" fill="none" d="M17.03 1A16.97 8.49 0 0 0 50.97 1"/><ellipse cx="34" cy="-7" rx="16.97" ry="8.49"/></g><g class="hln-database-sync-ring hln-database-sync-ring-b"><ellipse cx="34" cy="-7" rx="16.97" ry="8.49"/></g></g></svg> </div>
.hln-database-sync {
--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-database-sync svg {
width: 100%;
height: 100%;
overflow: visible;
fill: #ffffff;
stroke: #1c1d21;
stroke-width: 1.25;
stroke-linejoin: round;
stroke-linecap: round;
}
.hln-database-sync svg * {
vector-effect: non-scaling-stroke;
}
.hln-database-sync .hln-database-sync-in {
stroke: #9a9ca3;
}
.hln-database-sync .hln-database-sync-move {
translate: calc(-19.5 * var(--u)) calc(-9.75 * var(--u));
animation: hln-database-sync-move 6s infinite;
}
.hln-database-sync .hln-database-sync-pkt {
transform-box: fill-box;
transform-origin: 50% 80%;
animation: hln-database-sync-pkt 6s infinite;
}
.hln-database-sync .hln-database-sync-pkt polygon {
fill: var(--c);
}
.hln-database-sync .hln-database-sync-ring {
fill: none;
stroke: var(--c);
opacity: 0;
transform-box: fill-box;
transform-origin: 50% 50%;
}
.hln-database-sync .hln-database-sync-ring-b {
animation: hln-database-sync-ring 6s infinite;
}
.hln-database-sync .hln-database-sync-ring-a {
animation: hln-database-sync-ring 6s 3s infinite;
}
@keyframes hln-database-sync-move {
0%, 8% { translate: calc(-19.5 * var(--u)) calc(-9.75 * var(--u)); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
30%, 58% { translate: calc(19.5 * var(--u)) calc(9.75 * var(--u)); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
80%, 100% { translate: calc(-19.5 * var(--u)) calc(-9.75 * var(--u)); }
}
@keyframes hln-database-sync-pkt {
0% { scale: 0; animation-timing-function: cubic-bezier(0.3, 1.45, 0.45, 1); }
8%, 28% { scale: 1; animation-timing-function: ease-in; }
33%, 50% { scale: 0; animation-timing-function: cubic-bezier(0.3, 1.45, 0.45, 1); }
58%, 78% { scale: 1; animation-timing-function: ease-in; }
83%, 100% { scale: 0; }
}
@keyframes hln-database-sync-ring {
0%, 30% { opacity: 0; scale: 1; }
31% { opacity: 1; scale: 1; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
46%, 100% { opacity: 0; scale: 1.5; }
}
@media (prefers-reduced-motion: reduce) {
.hln-database-sync * {
animation: none !important;
}
.hln-database-sync .hln-database-sync-move { translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
.hln-database-sync, .hln-database-sync *, .hln-database-sync::before, .hln-database-sync::after, .hln-database-sync *::before, .hln-database-sync *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hln-color on the element or a parent.
Currently previewing #3b82f6.--hln-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.